|
| 1 | +; errnoprobe: distinct errno codes proof (sys_errno, ABI id 62). |
| 2 | +; |
| 3 | +; The kernel ABI returns a single -1 sentinel on failure; rlibc therefore mapped |
| 4 | +; EVERY error to EIO. Now well-defined failure paths stamp a per-task errno that |
| 5 | +; sys_errno (id 62) returns, so two DIFFERENT failures yield two DIFFERENT codes: |
| 6 | +; open("/data/nope") -> -1, errno = ENOENT (2) (no such file) |
| 7 | +; read(99, ...) -> -1, errno = EBADF (9) (bad file descriptor) |
| 8 | +; The probe fails unless both calls fail, each errno matches, and the two differ. |
| 9 | +; |
| 10 | +; sys_open: rdi=path, rsi=flags, rdx=mode (id 18). sys_read: rdi=fd, rsi=buf, |
| 11 | +; rdx=len (id 19). sys_errno: () -> code (id 62). |
| 12 | + |
| 13 | +bits 64 |
| 14 | +default rel |
| 15 | + |
| 16 | +section .text |
| 17 | +global _start |
| 18 | +_start: |
| 19 | + ; --- open a nonexistent /data file -> must fail with ENOENT --- |
| 20 | + lea rdi, [rel path] |
| 21 | + xor esi, esi ; O_RDONLY |
| 22 | + xor edx, edx ; mode 0 |
| 23 | + mov eax, 18 ; SYS_OPEN |
| 24 | + int 0x80 |
| 25 | + cmp rax, -1 |
| 26 | + jne .fail ; it must NOT exist |
| 27 | + mov eax, 62 ; SYS_ERRNO |
| 28 | + int 0x80 |
| 29 | + mov r12, rax ; r12 = errno after open (expect ENOENT=2) |
| 30 | + cmp r12, 2 |
| 31 | + jne .fail |
| 32 | + |
| 33 | + ; --- read from a bad fd -> must fail with EBADF --- |
| 34 | + mov edi, 99 ; out-of-range fd |
| 35 | + lea rsi, [rel rbuf] |
| 36 | + mov edx, 1 |
| 37 | + mov eax, 19 ; SYS_READ |
| 38 | + int 0x80 |
| 39 | + cmp rax, -1 |
| 40 | + jne .fail |
| 41 | + mov eax, 62 ; SYS_ERRNO |
| 42 | + int 0x80 |
| 43 | + mov r13, rax ; r13 = errno after read (expect EBADF=9) |
| 44 | + cmp r13, 9 |
| 45 | + jne .fail |
| 46 | + |
| 47 | + ; --- the two causes must be DISTINCT (not one collapsed EIO) --- |
| 48 | + cmp r12, r13 |
| 49 | + je .fail |
| 50 | + |
| 51 | + ; --- a failure that does NOT stamp a code must leave errno CLEARED (0), not |
| 52 | + ; the STALE EBADF from the read above. read(len>4096) returns -1 before any |
| 53 | + ; errno stamp; the dispatch cleared errno on entry, so sys_errno must be 0. --- |
| 54 | + xor edi, edi |
| 55 | + lea rsi, [rel rbuf] |
| 56 | + mov edx, 5000 ; len > 4096 -> -1, un-stamped |
| 57 | + mov eax, 19 ; SYS_READ |
| 58 | + int 0x80 |
| 59 | + cmp rax, -1 |
| 60 | + jne .fail |
| 61 | + mov eax, 62 ; SYS_ERRNO |
| 62 | + int 0x80 |
| 63 | + cmp rax, 0 ; must be cleared, NOT a stale 9 (EBADF) |
| 64 | + jne .fail |
| 65 | + |
| 66 | + lea rdi, [rel okmsg] |
| 67 | + mov esi, okmsg_len |
| 68 | + xor eax, eax |
| 69 | + int 0x80 |
| 70 | + mov eax, 2 |
| 71 | + int 0x80 |
| 72 | +.fail: |
| 73 | + lea rdi, [rel failmsg] |
| 74 | + mov esi, failmsg_len |
| 75 | + xor eax, eax |
| 76 | + int 0x80 |
| 77 | + mov eax, 2 |
| 78 | + int 0x80 |
| 79 | + |
| 80 | +section .data |
| 81 | +path: db "/data/nope", 0 |
| 82 | +rbuf: times 8 db 0 |
| 83 | +okmsg: db "ERRNO: distinct ok", 10 |
| 84 | +okmsg_len equ $ - okmsg |
| 85 | +failmsg: db "ERRNO: FAIL", 10 |
| 86 | +failmsg_len equ $ - failmsg |
0 commit comments