-
Notifications
You must be signed in to change notification settings - Fork 0
166 lines (153 loc) · 6.81 KB
/
Copy pathnumbers.yml
File metadata and controls
166 lines (153 loc) · 6.81 KB
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
37
38
39
40
41
42
43
44
45
46
47
48
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
name: numbers
# The kernel's own table, read from the system rather than remembered.
#
# src/sys.h states a number for each call this implementation makes. A number
# that is wrong for one architecture is not a compile error and not a failed
# call: the kernel raises a signal whose name is "bad system call" and the
# program stops, which is a diagnostic that names the program rather than the
# number. So the numbers are read from the system's own header, on both
# architectures, and this workflow is where the reading is recorded.
on:
workflow_dispatch:
push:
paths:
- '.github/workflows/numbers.yml'
jobs:
numbers:
name: the kernel's numbers (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [macos-14, macos-15-intel]
steps:
- uses: actions/checkout@v4
- name: Where the table is
run: |
uname -m
xcrun --show-sdk-path
find "$(xcrun --show-sdk-path)/usr/include/sys" -name 'syscall.h'
- name: Every number this implementation uses
run: |
h="$(xcrun --show-sdk-path)/usr/include/sys/syscall.h"
for n in exit read write close wait4 chdir fchdir fork getpid getuid \
geteuid kill dup getegid getgid ioctl execve umask munmap \
mprotect madvise dup2 fsync gettimeofday readv writev \
ftruncate truncate mmap lseek __getcwd getcwd \
stat stat64 fstat fstat64 lstat lstat64 \
fstatat fstatat64 getdirentries getdirentries64 \
getentropy \
bsdthread_terminate thread_selfid \
open openat openat_nocancel renameat faccessat unlinkat \
readlinkat mkdirat rmdir unlink mkdir rename access \
ulock_wait ulock_wake __ulock_wait __ulock_wake \
futimens utimensat futimes utimes settimeofday \
fchmod fchmodat fcntl \
pipe sigaction; do
printf '%-24s' "$n"
grep -E "^#define[[:space:]]+SYS_${n}[[:space:]]" "$h" | head -1 || echo '(absent)'
done
- name: The whole table, for the record
run: |
h="$(xcrun --show-sdk-path)/usr/include/sys/syscall.h"
wc -l "$h"
grep -c '^#define' "$h"
# Uploaded rather than printed in full: it is nine hundred lines.
cp "$h" "syscall-$(uname -m).h"
- uses: actions/upload-artifact@v4
with:
name: syscall-numbers-${{ matrix.os }}
path: syscall-*.h
# Which numbers this kernel actually serves.
#
# A number that is in the system's table and not in the kernel's is not a
# failed call: the kernel raises a signal whose name is "bad system call" and
# the program stops, which is a diagnostic that names the program rather than
# the number. Reading the table above does not distinguish the two, so this
# job issues each call with arguments that cannot do harm and reports which
# of them the kernel refuses to recognise.
served:
name: the numbers this kernel serves (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [macos-14, macos-15-intel]
steps:
- uses: actions/checkout@v4
- name: Issue each call and report what the kernel does with it
run: |
cat > served.c <<'EOF'
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
static sigjmp_buf back;
static void on_bad(int s) { (void)s; siglongjmp(back, 1); }
extern long syscall(long, ...);
/* Every number src/sys.h states, with arguments chosen so that the
* call either fails harmlessly or does nothing. A call that returns
* or fails is served; a call that does neither raised the signal. */
struct probe { const char* name; long n; long a, b, c, d; };
static const struct probe probes[] = {
{ "close", 6, -1, 0, 0, 0 },
{ "wait4", 7, -1, 0, 1, 0 }, /* WNOHANG */
{ "fchdir", 13, -1, 0, 0, 0 },
{ "dup", 41, -1, 0, 0, 0 },
{ "ioctl", 54, -1, 0, 0, 0 },
{ "munmap", 73, 0, 0, 0, 0 },
{ "mprotect", 74, 0, 0, 0, 0 },
{ "madvise", 75, 0, 0, 0, 0 },
{ "dup2", 90, -1, -1, 0, 0 },
{ "fcntl", 92, -1, 50, 0, 0 }, /* F_GETPATH */
{ "fsync", 95, -1, 0, 0, 0 },
{ "gettimeofday", 116, 0, 0, 0, 0 },
{ "readv", 120, -1, 0, 0, 0 },
{ "writev", 121, -1, 0, 0, 0 },
{ "utimes", 138, 0, 0, 0, 0 },
{ "futimes", 139, -1, 0, 0, 0 },
{ "mmap", 197, 0, 0, 0, 0 },
{ "lseek", 199, -1, 0, 0, 0 },
{ "ftruncate", 201, -1, 0, 0, 0 },
{ "stat64", 338, 0, 0, 0, 0 },
{ "fstat64", 339, -1, 0, 0, 0 },
{ "lstat64", 340, 0, 0, 0, 0 },
{ "getdirentries64",344, -1, 0, 0, 0 },
{ "thread_selfid", 372, 0, 0, 0, 0 },
{ "openat", 463, -2, 0, 0, 0 },
{ "renameat", 465, -2, 0, -2, 0 },
{ "faccessat", 466, -2, 0, 0, 0 },
{ "fstatat64", 470, -2, 0, 0, 0 },
{ "unlinkat", 472, -2, 0, 0, 0 },
{ "readlinkat", 473, -2, 0, 0, 0 },
{ "mkdirat", 475, -2, 0, 0, 0 },
{ "ulock_wait", 515, 0, 0, 0, 0 },
{ "ulock_wake", 516, 0, 0, 0, 0 },
};
int main(void) {
struct sigaction sa; memset(&sa, 0, sizeof sa);
sa.sa_handler = on_bad;
sigaction(SIGSYS, &sa, 0);
int refused = 0;
for (unsigned i = 0; i < sizeof probes / sizeof *probes; i++) {
if (sigsetjmp(back, 1) == 0) {
errno = 0;
long r = syscall(probes[i].n, probes[i].a, probes[i].b,
probes[i].c, probes[i].d);
printf("%-18s %4ld served (returned %ld, errno %d)\n",
probes[i].name, probes[i].n, r, errno);
} else {
printf("%-18s %4ld REFUSED (bad system call)\n",
probes[i].name, probes[i].n);
refused++;
}
}
printf("\n%d refused\n", refused);
return refused ? 1 : 0;
}
EOF
cc -O0 -o served served.c
./served