git.cappig.dev / apheleiaOS.git master

1
#include <arch/signal.h>
2
3
#include "internal.h"
4
5
static bool ctx_stack_valid(const sched_thread_t *thread, size_t need_bytes) {
6
    if (!thread || !thread->context || !thread->stack || !thread->stack_size) {
7
        return false;
8
    }
9
10
    uintptr_t stack_base = (uintptr_t)thread->stack;
11
    uintptr_t stack_end = stack_base + thread->stack_size;
12
    uintptr_t ctx = thread->context;
13
14
    if (ctx < stack_base || ctx >= stack_end) {
15
        return false;
16
    }
17
18
    size_t available = (size_t)(stack_end - ctx);
19
    return need_bytes <= available;
20
}
21
22
bool ctx_candidate_valid(const sched_thread_t *thread, const arch_int_state_t *state) {
23
    if (!thread || !state || !thread->stack || !thread->stack_size) {
24
        return false;
25
    }
26
27
    uintptr_t ctx = (uintptr_t)state;
28
    uintptr_t stack_base = (uintptr_t)thread->stack;
29
    uintptr_t stack_end = stack_base + thread->stack_size;
30
31
    if (stack_end < stack_base || ctx < stack_base || ctx >= stack_end) {
32
        return false;
33
    }
34
35
    size_t sregs_off = offsetof(arch_int_state_t, s_regs);
36
    size_t kernel_frame_need = sregs_off + (3U * sizeof(arch_word_t));
37
38
    if ((size_t)(stack_end - ctx) < kernel_frame_need) {
39
        return false;
40
    }
41
42
    if (!arch_signal_is_user(state)) {
43
        return true;
44
    }
45
46
    size_t user_frame_need = sregs_off + sizeof(state->s_regs);
47
48
    if ((size_t)(stack_end - ctx) < user_frame_need) {
49
        return false;
50
    }
51
52
    return true;
53
}
54
55
bool ctx_valid(const sched_thread_t *thread) {
56
    if (!thread || !thread->context) {
57
        return false;
58
    }
59
60
    const arch_int_state_t *state = (const arch_int_state_t *)thread->context;
61
    size_t sregs_off = offsetof(arch_int_state_t, s_regs);
62
    size_t kernel_frame_need = sregs_off + (3U * sizeof(arch_word_t));
63
64
    if (!ctx_stack_valid(thread, kernel_frame_need)) {
65
        return false;
66
    }
67
68
    bool user_frame = arch_signal_is_user(state);
69
    arch_word_t ip = arch_state_ip(state);
70
71
    if (!ip) {
72
        return false;
73
    }
74
75
    if (!user_frame && arch_kernel_vaddr_base() && ip < arch_kernel_vaddr_base()) {
76
        return false;
77
    }
78
79
    if (user_frame) {
80
        if (!thread->user_thread) {
81
            return false;
82
        }
83
84
        size_t user_frame_need = sregs_off + sizeof(state->s_regs);
85
        if (!ctx_stack_valid(thread, user_frame_need)) {
86
            return false;
87
        }
88
89
        arch_word_t sp = arch_state_sp(state);
90
91
        if (!sp) {
92
            return false;
93
        }
94
95
        if (!arch_state_flags_sane(state)) {
96
            return false;
97
        }
98
99
        arch_word_t user_top = arch_user_stack_top();
100
        if (user_top && (ip >= user_top || sp > user_top)) {
101
            return false;
102
        }
103
104
        if (thread->user_stack_base && thread->user_stack_size) {
105
            arch_word_t user_base = (arch_word_t)thread->user_stack_base;
106
            arch_word_t user_end = user_base + (arch_word_t)thread->user_stack_size;
107
108
            if (user_end < user_base || sp < user_base || sp > user_end) {
109
                return false;
110
            }
111
        }
112
    }
113
114
    return true;
115
}