From ea6cb2d3bb1796aef2c195079fe91311a43f4b82 Mon Sep 17 00:00:00 2001 From: Jakob Kaivo Date: Tue, 4 Jun 2024 13:09:32 -0400 Subject: implement jmp_buf tracking and disallow setjmp macro suppression --- src/setjmp/___setjmp.x86-64.s | 26 +++++++++++++++++++ src/setjmp/__setjmp.c | 41 ++++++++++++++++++++++++++++++ src/setjmp/__setjmp.x86-64.s | 26 ------------------- src/setjmp/__setjmp_h.c | 3 +++ src/setjmp/_setjmp.h | 58 +++++++++++++++++++++++++++++++++++++++++++ src/setjmp/longjmp.c | 2 ++ src/setjmp/setjmp.c | 35 ++++++-------------------- 7 files changed, 137 insertions(+), 54 deletions(-) create mode 100644 src/setjmp/___setjmp.x86-64.s create mode 100644 src/setjmp/__setjmp.c delete mode 100644 src/setjmp/__setjmp.x86-64.s create mode 100644 src/setjmp/__setjmp_h.c create mode 100644 src/setjmp/_setjmp.h (limited to 'src/setjmp') diff --git a/src/setjmp/___setjmp.x86-64.s b/src/setjmp/___setjmp.x86-64.s new file mode 100644 index 00000000..00b139b1 --- /dev/null +++ b/src/setjmp/___setjmp.x86-64.s @@ -0,0 +1,26 @@ +.global ___setjmp +___setjmp: + /* setjmp() in C sets env[0] to 0 */ + mov %rbx, 0x08(%rdi) + mov %rcx, 0x10(%rdi) + mov %rdx, 0x18(%rdi) + mov %rsp, 0x20(%rdi) + mov %rbp, 0x28(%rdi) + mov %rsi, 0x30(%rdi) + mov %rdi, 0x38(%rdi) + mov %r8, 0x40(%rdi) + mov %r9, 0x48(%rdi) + mov %r10, 0x50(%rdi) + mov %r11, 0x58(%rdi) + mov %r12, 0x60(%rdi) + mov %r13, 0x68(%rdi) + mov %r14, 0x70(%rdi) + mov %r15, 0x78(%rdi) + mov 0x00(%rbp), %rax + mov %rax, 0x80(%rdi) + mov 0x08(%rbp), %rax + mov %rax, 0x88(%rdi) + mov 0x00(%rsp), %rax + mov %rax, 0x90(%rdi) + xor %rax, %rax + ret diff --git a/src/setjmp/__setjmp.c b/src/setjmp/__setjmp.c new file mode 100644 index 00000000..cbd6a144 --- /dev/null +++ b/src/setjmp/__setjmp.c @@ -0,0 +1,41 @@ +#include +#include +#include "_setjmp.h" +#include "_safety.h" + +/** save program state **/ + +int __setjmp(jmp_buf env) +{ + int ret = 0; + extern int ___setjmp(jmp_buf); + SIGNAL_SAFE(0); + memset(env, 0, sizeof(jmp_buf)); + ret = ___setjmp(env); + ADD_JMP_BUF(env); + return ret; +} + +CHECK_1(int, 0, __setjmp, jmp_buf) + +/*** +saves the current state of the calling environment +in the TYPEDEF(jmp_buf) ARGUMENT(env). +***/ + +/* +RETURN(0, the environment has been saved by THIS()) +RETURN(NONZERO, the environment has been restored by FUNCTION(longjmp)) + +CONSTRAINT: entire controlling expression of a selection or iteration statement +CONSTRAINT: one operand of a relational or equality operator which is the entire controlling expression of a selction or iteration statement +CONSTRAINT: the operand of a unary ! as the entire controlling expression of a selection or iteration statement +CONSTRAINT: an entire expression statement + +UNSPECIFIED(Whether THIS() is a macro or identifier with external linkage) + +UNDEFINED(A macro definition of THIS() is suppressed in order to access an actual function) +UNDEFINED(A program defines an external identifier named LITERAL(setjmp)) + +STDC(1) +*/ diff --git a/src/setjmp/__setjmp.x86-64.s b/src/setjmp/__setjmp.x86-64.s deleted file mode 100644 index 00b139b1..00000000 --- a/src/setjmp/__setjmp.x86-64.s +++ /dev/null @@ -1,26 +0,0 @@ -.global ___setjmp -___setjmp: - /* setjmp() in C sets env[0] to 0 */ - mov %rbx, 0x08(%rdi) - mov %rcx, 0x10(%rdi) - mov %rdx, 0x18(%rdi) - mov %rsp, 0x20(%rdi) - mov %rbp, 0x28(%rdi) - mov %rsi, 0x30(%rdi) - mov %rdi, 0x38(%rdi) - mov %r8, 0x40(%rdi) - mov %r9, 0x48(%rdi) - mov %r10, 0x50(%rdi) - mov %r11, 0x58(%rdi) - mov %r12, 0x60(%rdi) - mov %r13, 0x68(%rdi) - mov %r14, 0x70(%rdi) - mov %r15, 0x78(%rdi) - mov 0x00(%rbp), %rax - mov %rax, 0x80(%rdi) - mov 0x08(%rbp), %rax - mov %rax, 0x88(%rdi) - mov 0x00(%rsp), %rax - mov %rax, 0x90(%rdi) - xor %rax, %rax - ret diff --git a/src/setjmp/__setjmp_h.c b/src/setjmp/__setjmp_h.c new file mode 100644 index 00000000..b4d0dcd6 --- /dev/null +++ b/src/setjmp/__setjmp_h.c @@ -0,0 +1,3 @@ +#include "_setjmp.h" + +struct __setjmp_h __setjmp_h; diff --git a/src/setjmp/_setjmp.h b/src/setjmp/_setjmp.h new file mode 100644 index 00000000..1bf19fe6 --- /dev/null +++ b/src/setjmp/_setjmp.h @@ -0,0 +1,58 @@ +#ifndef ___SETJMP_H__ +#define ___SETJMP_H__ + +#include +#include "_safety.h" + +struct __valid_jmp_buf { +}; + +extern struct __setjmp_h { + struct valid_jmp_buf { + unsigned long int *buf; + unsigned long int sum; + } *valid; + size_t nvalid; +} __setjmp_h; + + +#ifndef NDEBUG +static inline unsigned long int jmp_sum(jmp_buf env) +{ + long unsigned int ret = 0; + for (size_t i = 0; i < sizeof(jmp_buf) / sizeof(unsigned long int); i++) { + ret ^= env[i]; + } + return ret; +} + +#define ADD_JMP_BUF(__env) do { \ + struct valid_jmp_buf __v = { \ + (unsigned long int *)(__env), \ + jmp_sum(__env), \ + }; \ + ADD_PREV(__v, __setjmp_h.valid, __setjmp_h.nvalid); \ +} while (0) + +#define ASSERT_JMP_BUF(__env) do { \ + int __found = 0; \ + for (size_t __i = 0; __i < __setjmp_h.nvalid; __i++) { \ + if (__setjmp_h.valid[__i].buf == (unsigned long int *)(__env)) { \ + if (jmp_sum(__env) != __setjmp_h.valid[__i].sum) { \ + UNDEFINED("jmp_buf has been modified!"); \ + } \ + __found = 1; \ + break; \ + } \ + } \ + if (!__found) { \ + UNDEFINED("In call to longjmp(): Provided jmp_buf was not returned by a previous call to setjmp()"); \ + } \ +} while (0) + +#else +#define ADD_JMP_BUF(__env) (void)(__env) +#define ASSERT_JMP_BUF(__env) (void)(__env) +#endif + +#endif diff --git a/src/setjmp/longjmp.c b/src/setjmp/longjmp.c index 117910fc..2208aec7 100644 --- a/src/setjmp/longjmp.c +++ b/src/setjmp/longjmp.c @@ -1,4 +1,5 @@ #include +#include "_setjmp.h" #include "_safety.h" /** restore calling environment **/ @@ -7,6 +8,7 @@ _Noreturn void longjmp(jmp_buf env, int val) { extern _Noreturn void ___longjmp(jmp_buf); SIGNAL_SAFE(0); + ASSERT_JMP_BUF(env); /* use val if nonzero, otherwise 1 */ env[0] = val ? val : 1; diff --git a/src/setjmp/setjmp.c b/src/setjmp/setjmp.c index 091f0993..3c8a199c 100644 --- a/src/setjmp/setjmp.c +++ b/src/setjmp/setjmp.c @@ -1,37 +1,16 @@ #include -#include #include "_safety.h" -/** save program state **/ +#undef setjmp -int setjmp(jmp_buf env) +int setjmp(jmp_buf jb) { - extern int ___setjmp(jmp_buf); - SIGNAL_SAFE(0); - memset(env, 0, sizeof(jmp_buf)); - return ___setjmp(env); + (void)jb; + UNDEFINED("The setjmp() macro has been suppressed to access an actual function"); + return 0; } -CHECK_1(int, 0, setjmp, jmp_buf) - -/*** -saves the current state of the calling environment -in the TYPEDEF(jmp_buf) ARGUMENT(env). -***/ - /* -RETURN(0, the environment has been saved by THIS()) -RETURN(NONZERO, the environment has been restored by FUNCTION(longjmp)) - -CONSTRAINT: entire controlling expression of a selection or iteration statement -CONSTRAINT: one operand of a relational or equality operator which is the entire controlling expression of a selction or iteration statement -CONSTRAINT: the operand of a unary ! as the entire controlling expression of a selection or iteration statement -CONSTRAINT: an entire expression statement - -UNSPECIFIED(Whether THIS() is a macro or identifier with external linkage) - -UNDEFINED(A macro definition of THIS() is suppressed in order to access an actual function) -UNDEFINED(A program defines an external identifier named LITERAL(setjmp)) - -STDC(1) +SIGNAL_SAFE(0) +STDC(0) */ -- cgit v1.2.1