Overview
Comment: | removed sneaky segfault in x86-64 syscall fn where %r8 (the register that contains the pointer to the syscall arguments from the C syscall wrapper, which need to be copied into the correct registers before the kernel is invoked) gets overwritten if the syscall valency > 5, because of overlapping ccall and syscall ABI argument registers - r8 is clobbered by argument 5 and any further attempts to use it as a ptr segfault at best. also modified the report function so that it immediate cancels compilation if a sub-process reports failure. changed allocator function signatures so they can return a condition code if the kernel reports an error; updated example code so it compiles and runs without fault. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
e50a476efef720ed926f519a291311b5 |
User & Date: | lexi on 2019-08-22 02:52:20 |
Other Links: | manifest | tags |
Context
2019-08-22
| ||
04:31 | finish moving heap allocation/free functions to the posix syscall apparatus and deprecate the direct assembly implementations of platform_mmap; update the kmem docs to match new function signatures (and remove typos) check-in: 709ffb094d user: lexi tags: trunk | |
02:52 | removed sneaky segfault in x86-64 syscall fn where %r8 (the register that contains the pointer to the syscall arguments from the C syscall wrapper, which need to be copied into the correct registers before the kernel is invoked) gets overwritten if the syscall valency > 5, because of overlapping ccall and syscall ABI argument registers - r8 is clobbered by argument 5 and any further attempts to use it as a ptr segfault at best. also modified the report function so that it immediate cancels compilation if a sub-process reports failure. changed allocator function signatures so they can return a condition code if the kernel reports an error; updated example code so it compiles and runs without fault. check-in: e50a476efe user: lexi tags: trunk | |
01:37 | add first iteration of knum header check-in: 5560c2725b user: lexi tags: trunk | |
Changes
Modified arch/posix/errnos from [cc3bf9e501] to [1054d9a4df].
5 6 7 8 9 10 11 |
ENOSPC EDQUOT EIO EAGAIN EFBIG EINTR EDESTADDRREQ |
> > > > > > |
5 6 7 8 9 10 11 12 13 14 15 16 17 |
ENOSPC EDQUOT EIO EAGAIN EFBIG EINTR EDESTADDRREQ EACCES EMFILE ENODEV ENOMEM ENXIO EOVERFLOW |
Modified build.sh from [d7b4907031] to [b5a70ac75f].
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
if test ! "$output" -ot "$src"; then return fi fi if test "$debug" = yes; then local dflag="-g dwarf2" fi report $asm $flags $dflag "-f$bin_fmt" -i "$gen" "$src" -o "$output"; } comp_co() { comp_c $1 $2 "-c -fPIC"; } comp_c(){ local src=$1 local output=$2 local flags=$3 if test -e "$output"; then |
| |
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
if test ! "$output" -ot "$src"; then
return
fi
fi
if test "$debug" = yes; then
local dflag="-g dwarf2"
fi
report $asm $flags $dflag "-f$bin_fmt" -i "$gen" -i "$PWD" "$src" -o "$output";
}
comp_co() { comp_c $1 $2 "-c -fPIC"; }
comp_c(){
local src=$1
local output=$2
local flags=$3
if test -e "$output"; then
|
Modified global/common.sh from [e60df5a627] to [582c735deb].
57 58 59 60 61 62 63 64 |
fi # the following function is called to report a command invocation # the person compiling the library. the first argument should be # an ansi format string; this is used to color-code the tool being # launched and thus should be different for each one. report() { announce $@; $@; } |
> | > > > > > > > |
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
fi # the following function is called to report a command invocation # the person compiling the library. the first argument should be # an ansi format string; this is used to color-code the tool being # launched and thus should be different for each one. report() { announce $@; $@; status=$? if test $status -ne 0; then args=($@) say "process ${args[0]} failed with status code $status" exit $status fi } |
Modified mod/kcore/syscall.fn.x86.lin.64.s from [472ad3a7d3] to [9bf0ba9bf3].
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
; altogether and access the error value of a ; syscall directly. invoke as: ; ; void k_platform_syscall_raw(s64* result, u64* errno, ; syscall, u8 valency, s64[] args) bits 64 %include "../arch/posix/x86.lin.64.s" %include "../arch/x86.cdecl.64.s" ; vim: ft=nasm %macro handle_arg 1 %assign v %1+1 mov sys.reg. %+ v, [ccall.reg.4 + 8 * %1] dec ccall.reg.3 jz .perform_call %endmacro global k_platform_syscall_raw:function k_platform_syscall_raw: ; locals: rbx = s64* result ................................................................................ ; and popping back from the stack mov rbx, ccall.reg.0 mov r12, ccall.reg.1 ; this needs to go before the loop ; or it'll get clobbered mov sys.reg.0, ccall.reg.2 ; automatically generate the code ; needed to move the arguments into ; their correct registers. see above %assign i 0 %rep 6 handle_arg i |
|
|
|
>
>
>
>
>
>
>
|
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
; altogether and access the error value of a ; syscall directly. invoke as: ; ; void k_platform_syscall_raw(s64* result, u64* errno, ; syscall, u8 valency, s64[] args) bits 64 %include "arch/posix/x86.lin.64.s" %include "arch/x86.cdecl.64.s" ; vim: ft=nasm %macro handle_arg 1 %assign v %1+1 mov sys.reg. %+ v, [r15 + 8 * %1] dec ccall.reg.3 jz .perform_call %endmacro global k_platform_syscall_raw:function k_platform_syscall_raw: ; locals: rbx = s64* result ................................................................................ ; and popping back from the stack mov rbx, ccall.reg.0 mov r12, ccall.reg.1 ; this needs to go before the loop ; or it'll get clobbered mov sys.reg.0, ccall.reg.2 ; the fourth argument is in %r8, which ; is also a syscall register, so we ; need to move it to a safe register ; to keep it from getting clobbered ; before we begin the "loop" mov r15, ccall.reg.4 ; automatically generate the code ; needed to move the arguments into ; their correct registers. see above %assign i 0 %rep 6 handle_arg i |
Modified mod/kcore/testbin.exe.c from [c4d82c1a4a] to [ae0ed8cd11].
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
if (kiosend(e.std, ptr, null) == kiocond_ok) { /* great, continue */ } else { return kbad_io; } void* region = kmheapa(2048); if (region == null) return kbad_mem; kmzero(region,2048); if (kmheapf(region) >= kmcond_fail) return kbad_mem; return kbad_ok; } |
| > | |
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
if (kiosend(e.std, ptr, null) == kiocond_ok) { /* great, continue */ } else { return kbad_io; } void* region; kmcond alloc = kmheapa(®ion, 2048); if (alloc != kmcond_ok) return kbad_mem; kmzero(region,2048); if (kmheapf(region) >= kmcond_fail) return kbad_mem; return kbad_ok; } |
Modified mod/kmem/heapa.fn.c from [641176b71f] to [e093792a2c].
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
* see also: kmheapf() "heap free" */ /* arch specific headers */ #ifdef KFenv_posix # include <posix/posix.h> #endif /* we define all our platform functions here, whether or not * they're for the correct platform - only the ones that are * called by the preprocessed form of the code will actually * be linked, linker errors are our friend here! */ extern void* kmem_platform_mmap(void* addr, unsigned long sz, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off); void* kmheapa(sz len) { /* allocate an object on the heap and return * a pointer, or NULL if the allocation failed. */ union { void* raw; ubyte* byte; kmbox* header; } region; ................................................................................ /* because munmap needs to be informed of the size of * the region we are going to unmap, we need to store * that information in the region that we are mapping. * the user will receive an adjusted pointer that can * be adjusted to point a field of type size_t that * contains the size of the allocated space.*/ region.byte = kmem_platform_mmap(null, region_size, posix_prot_read | posix_prot_write, posix_flag_anonymous | posix_map_shared, -1, 0); /* impl note: while per manpage fd is "ignored" * for MAP_ANONYMOUS, "some implementations" require * a value of -1 */ if (region.raw == (void*) -1) return null; /* worth retrieving errno? discuss */ # else Knoimpl(kmheapa,KVos); # error missing implementation # endif void* const object = (region.byte + sizeof (kmbox)); region.header -> kind = kmkind_heap; region.header -> size = len; return object; } |
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>
<
<
<
|
>
|
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
* see also: kmheapf() "heap free" */ /* arch specific headers */ #ifdef KFenv_posix # include <posix/posix.h> #endif #include <error_table.h> /* we define all our platform functions here, whether or not * they're for the correct platform - only the ones that are * called by the preprocessed form of the code will actually * be linked, linker errors are our friend here! */ extern void* kmem_platform_mmap(void* addr, unsigned long sz, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off); kmcond kmheapa(void** where, sz len) { /* allocate an object on the heap and return * a pointer, or NULL if the allocation failed. */ union { void* raw; ubyte* byte; kmbox* header; } region; ................................................................................ /* because munmap needs to be informed of the size of * the region we are going to unmap, we need to store * that information in the region that we are mapping. * the user will receive an adjusted pointer that can * be adjusted to point a field of type size_t that * contains the size of the allocated space.*/ k_platform_syscall_arg args[] = { null, region_size, posix_prot_read | posix_prot_write, posix_flag_anonymous | posix_map_shared, -1, 0 }; struct k_platform_syscall_answer r = k_platform_syscall (k_platform_syscall_mmap, Kmsz(args), args); if (r.error == 0) region.byte = (ubyte*)r.ret; else { switch (r.error) { case k_platform_error_EAGAIN: return kmcond_bad_lock; case k_platform_error_EINVAL: return kmcond_bad_size; case k_platform_error_EMFILE: return kmcond_too_many; case k_platform_error_ENOMEM: return kmcond_no_room; default: return kmcond_fail_assert; } } /* region.byte = kmem_platform_mmap(null, region_size, */ /* posix_prot_read | posix_prot_write, */ /* posix_flag_anonymous | posix_map_shared, -1, 0); */ /* impl note: while per manpage fd is "ignored" * for MAP_ANONYMOUS, "some implementations" require * a value of -1 */ # else Knoimpl(kmheapa,KVos); # error missing implementation # endif void* const object = (region.byte + sizeof (kmbox)); region.header -> kind = kmkind_heap; region.header -> size = len; *where = object; return kmcond_ok; } |
Modified mod/kmem/heapao.fn.c from [930b5d7379] to [e98ef79662].
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* heapao.fn.c - kmheapao() "allocate heap object" * ~ lexi hale <lexi@hale.su> * kmheapao() allocates a region in heap memory * and returns a kmptr struct referencing that * newly allocated region. */ kmptr kmheapao(sz size) { void* ptr = kmheapa(size); kmptr p = { .kind = (ptr != null ? kmkind_heap : kmkind_fail), .ref = ptr, .shred = false, }; return p; } |
| | > > > > | |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* heapao.fn.c - kmheapao() "allocate heap object" * ~ lexi hale <lexi@hale.su> * kmheapao() allocates a region in heap memory * and returns a kmptr struct referencing that * newly allocated region. */ kmcond kmheapao(kmptr* where, sz size) { void* ptr; kmcond e = kmheapa(&ptr, size); if (e != kmcond_ok) return e; kmptr p = { .kind = (ptr != null ? kmkind_heap : kmkind_fail), .ref = ptr, .shred = false, }; *where = p; return kmcond_ok; } |
Modified mod/kmem/mem.h from [bec7e80543] to [d8d36f64f5].
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
#ifndef KImem #define KImem #include <k/type.h> #ifndef KFclean # define Kmsz(e) ( sizeof (e) / sizeof (e) [0] ) #endif #ifdef __cplusplus extern "C" { #endif typedef enum kmcond { kmcond_ok, kmcond_unnecessary, kmcond_fail, kmcond_unhandled, kmcond_mismatch, kmcond_bad_address, } kmcond; typedef enum kmkind { kmkind_none, kmkind_fail, kmkind_linear, kmkind_heap, ................................................................................ kmkind kind; kmshred shred; void* ref; } kmptr; /* heap functions */ void* kmheapa(sz); kmptr kmheapao(sz); kmcond kmheapf(void*); /* generic functions */ kmcond kmfree(kmptr); kmkind kmtell(void*); void kmzero(void*,sz); void kmozero(kmptr); |
>
|
>
>
>
>
>
>
>
>
|
|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
#ifndef KImem #define KImem #include <k/type.h> #include <k/internal.egroup.h> #ifndef KFclean # define Kmsz(e) ( sizeof (e) / sizeof (e) [0] ) #endif #ifdef __cplusplus extern "C" { #endif typedef enum kmcond { kmcond_ok = kmcond_id, kmcond_unnecessary, kmcond_fail, kmcond_unhandled, kmcond_mismatch, kmcond_bad_address, kmcond_bad_lock, kmcond_bad_size, kmcond_no_room, kmcond_too_many, /* when something truly should * never happen: */ kmcond_fail_assert, } kmcond; typedef enum kmkind { kmkind_none, kmkind_fail, kmkind_linear, kmkind_heap, ................................................................................ kmkind kind; kmshred shred; void* ref; } kmptr; /* heap functions */ kmcond kmheapa (void**, sz); kmcond kmheapao(kmptr*, sz); kmcond kmheapf (void*); /* generic functions */ kmcond kmfree(kmptr); kmkind kmtell(void*); void kmzero(void*,sz); void kmozero(kmptr); |