Add sigsetjmp/siglongjmp bound checking support

tcctok.h:
- Add sigsetjmp/__sigsetjmp/siglongjmp

tccgen.c:
- redirect sigsetjmp/siglongjmp to bcheck.c code

i386-gen.c/x86_64-gen.c
- gcall_or_jmp: Set func_bound_add_epilog also when sigsetjmp is called
- gen_bounds_epilog: Only call __bound_local_new when needed (unrelated)

bcheck.c:
- Add __bound_siglongjmp
- __bound_setjmp/__bound_long_jump: Check no_checking
- Optimize __bound_local_delete (unrelated)

Modify testcase:
- 114_bound_signal
This commit is contained in:
herman ten brugge 2020-05-25 12:26:55 +02:00
parent 045632defb
commit 3b617fdc53
6 changed files with 188 additions and 137 deletions

View file

@ -363,7 +363,12 @@ static void gcall_or_jmp(int is_jmp)
if (tcc_state->do_bounds_check && if (tcc_state->do_bounds_check &&
(vtop->sym->v == TOK_alloca || (vtop->sym->v == TOK_alloca ||
vtop->sym->v == TOK_setjmp || vtop->sym->v == TOK_setjmp ||
vtop->sym->v == TOK__setjmp)) vtop->sym->v == TOK__setjmp
#ifndef TCC_TARGET_PE
|| vtop->sym->v == TOK_sigsetjmp
|| vtop->sym->v == TOK___sigsetjmp
#endif
))
func_bound_add_epilog = 1; func_bound_add_epilog = 1;
#endif #endif
} else { } else {
@ -1092,15 +1097,18 @@ static void gen_bounds_epilog(void)
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
*bounds_ptr = 0; *bounds_ptr = 0;
/* generate bound local allocation */
saved_ind = ind;
ind = func_bound_ind;
sym_data = get_sym_ref(&char_pointer_type, lbounds_section, sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
func_bound_offset, lbounds_section->data_offset); func_bound_offset, lbounds_section->data_offset);
/* generate bound local allocation */
if (func_bound_offset != lbounds_section->data_offset) {
saved_ind = ind;
ind = func_bound_ind;
greloc(cur_text_section, sym_data, ind + 1, R_386_32); greloc(cur_text_section, sym_data, ind + 1, R_386_32);
ind = ind + 5; ind = ind + 5;
gen_static_call(TOK___bound_local_new); gen_static_call(TOK___bound_local_new);
ind = saved_ind; ind = saved_ind;
}
/* generate bound check local freeing */ /* generate bound check local freeing */
o(0x5250); /* save returned value, if any */ o(0x5250); /* save returned value, if any */

View file

@ -205,6 +205,7 @@ void __bound_exit(void);
void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd, void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
off_t offset); off_t offset);
int __bound_munmap (void *start, size_t size); int __bound_munmap (void *start, size_t size);
DLL_EXPORT void __bound_siglongjmp(jmp_buf env, int val);
#endif #endif
DLL_EXPORT void __bound_new_region(void *p, size_t size); DLL_EXPORT void __bound_new_region(void *p, size_t size);
DLL_EXPORT void __bound_setjmp(jmp_buf env); DLL_EXPORT void __bound_setjmp(jmp_buf env);
@ -510,8 +511,6 @@ void FASTCALL __bound_local_new(void *p1)
void FASTCALL __bound_local_delete(void *p1) void FASTCALL __bound_local_delete(void *p1)
{ {
size_t addr, fp, *p = p1; size_t addr, fp, *p = p1;
alloca_list_type *alloca_free_list = NULL;
jmp_list_type *jmp_free_list = NULL;
if (no_checking) if (no_checking)
return; return;
@ -524,65 +523,51 @@ void FASTCALL __bound_local_delete(void *p1)
tree = splay_delete(addr + fp, tree); tree = splay_delete(addr + fp, tree);
p += 2; p += 2;
} }
{ if (alloca_list) {
alloca_list_type *last = NULL; alloca_list_type *last = NULL;
alloca_list_type *cur = alloca_list; alloca_list_type *cur = alloca_list;
while (cur) { do {
if (cur->fp == fp) { if (cur->fp == fp) {
if (last) if (last)
last->next = cur->next; last->next = cur->next;
else else
alloca_list = cur->next; alloca_list = cur->next;
tree = splay_delete ((size_t) cur->p, tree); tree = splay_delete ((size_t) cur->p, tree);
cur->next = alloca_free_list; dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
alloca_free_list = cur; __FILE__, __FUNCTION__, cur->p);
BOUND_FREE (cur);
cur = last ? last->next : alloca_list; cur = last ? last->next : alloca_list;
} }
else { else {
last = cur; last = cur;
cur = cur->next; cur = cur->next;
} }
} while (cur);
} }
} if (jmp_list) {
{
jmp_list_type *last = NULL; jmp_list_type *last = NULL;
jmp_list_type *cur = jmp_list; jmp_list_type *cur = jmp_list;
while (cur) { do {
if (cur->fp == fp) { if (cur->fp == fp) {
if (last) if (last)
last->next = cur->next; last->next = cur->next;
else else
jmp_list = cur->next; jmp_list = cur->next;
cur->next = jmp_free_list; dprintf(stderr, "%s, %s(): remove setjmp %p\n",
jmp_free_list = cur; __FILE__, __FUNCTION__, cur->penv);
BOUND_FREE (cur);
cur = last ? last->next : jmp_list; cur = last ? last->next : jmp_list;
} }
else { else {
last = cur; last = cur;
cur = cur->next; cur = cur->next;
} }
} } while (cur);
} }
POST_SEM (); POST_SEM ();
while (alloca_free_list) {
alloca_list_type *next = alloca_free_list->next;
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
__FILE__, __FUNCTION__, alloca_free_list->p);
BOUND_FREE (alloca_free_list);
alloca_free_list = next;
}
while (jmp_free_list) {
jmp_list_type *next = jmp_free_list->next;
dprintf(stderr, "%s, %s(): remove setjmp %p\n",
__FILE__, __FUNCTION__, jmp_free_list->penv);
BOUND_FREE (jmp_free_list);
jmp_free_list = next;
}
#if BOUND_DEBUG #if BOUND_DEBUG
if (print_calls) { if (print_calls) {
p = p1; p = p1;
@ -647,6 +632,7 @@ void __bound_setjmp(jmp_buf env)
jmp_list_type *jl; jmp_list_type *jl;
void *e = (void *) env; void *e = (void *) env;
if (no_checking == 0) {
dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e); dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e);
WAIT_SEM (); WAIT_SEM ();
INCR_COUNT(bound_setjmp_count); INCR_COUNT(bound_setjmp_count);
@ -673,15 +659,19 @@ void __bound_setjmp(jmp_buf env)
jl->tid = BOUND_GET_TID; jl->tid = BOUND_GET_TID;
} }
POST_SEM (); POST_SEM ();
}
} }
void __bound_longjmp(jmp_buf env, int val) static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func)
{ {
jmp_list_type *jl; jmp_list_type *jl;
void *e = (void *)env; void *e;
BOUND_TID_TYPE tid = BOUND_GET_TID; BOUND_TID_TYPE tid;
dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e); if (no_checking == 0) {
e = (void *)env;
tid = BOUND_GET_TID;
dprintf(stderr, "%s, %s(): %p\n", __FILE__, func, e);
WAIT_SEM(); WAIT_SEM();
INCR_COUNT(bound_longjmp_count); INCR_COUNT(bound_longjmp_count);
jl = jmp_list; jl = jmp_list;
@ -695,7 +685,7 @@ void __bound_longjmp(jmp_buf env, int val)
while (cur->penv != e || cur->tid != tid) { while (cur->penv != e || cur->tid != tid) {
if (cur->tid == tid) { if (cur->tid == tid) {
dprintf(stderr, "%s, %s(): remove setjmp %p\n", dprintf(stderr, "%s, %s(): remove setjmp %p\n",
__FILE__, __FUNCTION__, cur->penv); __FILE__, func, cur->penv);
if (last) if (last)
last->next = cur->next; last->next = cur->next;
else else
@ -725,7 +715,7 @@ void __bound_longjmp(jmp_buf env, int val)
while (cur) { while (cur) {
if ((size_t) cur->p == t->start) { if ((size_t) cur->p == t->start) {
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n", dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
__FILE__, __FUNCTION__, cur->p); __FILE__, func, cur->p);
if (last) if (last)
last->next = cur->next; last->next = cur->next;
else else
@ -737,7 +727,7 @@ void __bound_longjmp(jmp_buf env, int val)
cur = cur->next; cur = cur->next;
} }
dprintf(stderr, "%s, %s(): delete %p\n", dprintf(stderr, "%s, %s(): delete %p\n",
__FILE__, __FUNCTION__, (void *) t->start); __FILE__, func, (void *) t->start);
tree = splay_delete(t->start, tree); tree = splay_delete(t->start, tree);
} }
break; break;
@ -745,9 +735,25 @@ void __bound_longjmp(jmp_buf env, int val)
jl = jl->next; jl = jl->next;
} }
POST_SEM(); POST_SEM();
}
#if !defined(_WIN32)
sig ? siglongjmp(env, val) :
#endif
longjmp (env, val); longjmp (env, val);
} }
void __bound_longjmp(jmp_buf env, int val)
{
__bound_long_jump(env,val, 0, __FUNCTION__);
}
#if !defined(_WIN32)
void __bound_siglongjmp(jmp_buf env, int val)
{
__bound_long_jump(env,val, 1, __FUNCTION__);
}
#endif
#if defined(__GNUC__) && (__GNUC__ >= 6) #if defined(__GNUC__) && (__GNUC__ >= 6)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif

View file

@ -911,6 +911,9 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
case TOK_mmap: case TOK_mmap:
case TOK_munmap: case TOK_munmap:
case TOK_longjmp: case TOK_longjmp:
#ifndef TCC_TARGET_PE
case TOK_siglongjmp:
#endif
strcpy(buf, "__bound_"); strcpy(buf, "__bound_");
strcat(buf, name); strcat(buf, name);
name = buf; name = buf;
@ -6018,7 +6021,12 @@ special_math_val:
(nb_args == 1 || nb_args == 2) && (nb_args == 1 || nb_args == 2) &&
(vtop[-nb_args].r & VT_SYM) && (vtop[-nb_args].r & VT_SYM) &&
(vtop[-nb_args].sym->v == TOK_setjmp || (vtop[-nb_args].sym->v == TOK_setjmp ||
vtop[-nb_args].sym->v == TOK__setjmp)) { vtop[-nb_args].sym->v == TOK__setjmp
#ifndef TCC_TARGET_PE
|| vtop[-nb_args].sym->v == TOK_sigsetjmp
|| vtop[-nb_args].sym->v == TOK___sigsetjmp
#endif
)) {
vpush_global_sym(&func_old_type, TOK___bound_setjmp); vpush_global_sym(&func_old_type, TOK___bound_setjmp);
vpushv(vtop - nb_args); vpushv(vtop - nb_args);
if (nb_args == 2) if (nb_args == 2)

View file

@ -315,6 +315,10 @@
DEF(TOK_realloc, "realloc") DEF(TOK_realloc, "realloc")
DEF(TOK_memalign, "memalign") DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc") DEF(TOK_calloc, "calloc")
# else
DEF(TOK_sigsetjmp, "sigsetjmp")
DEF(TOK___sigsetjmp, "__sigsetjmp")
DEF(TOK_siglongjmp, "siglongjmp")
# endif # endif
DEF(TOK_mmap, "mmap") DEF(TOK_mmap, "mmap")
DEF(TOK_munmap, "munmap") DEF(TOK_munmap, "munmap")

View file

@ -6,6 +6,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <setjmp.h>
static volatile int run = 1; static volatile int run = 1;
static int dummy[10]; static int dummy[10];
@ -70,6 +71,8 @@ main (void)
pthread_t id1, id2; pthread_t id1, id2;
struct sigaction act; struct sigaction act;
struct timespec request; struct timespec request;
sigjmp_buf sj;
sigset_t m;
memset (&act, 0, sizeof (act)); memset (&act, 0, sizeof (act));
act.sa_handler = signal_handler; act.sa_handler = signal_handler;
@ -90,5 +93,19 @@ main (void)
pthread_join(id1, NULL); pthread_join(id1, NULL);
pthread_join(id2, NULL); pthread_join(id2, NULL);
sem_destroy (&sem); sem_destroy (&sem);
sigemptyset (&m);
sigprocmask (SIG_SETMASK, &m, NULL);
if (sigsetjmp (sj, 0) == 0)
{
sigaddset (&m, SIGUSR1);
sigprocmask (SIG_SETMASK, &m, NULL);
siglongjmp (sj, 1);
printf ("failed");
return 1;
}
sigprocmask (SIG_SETMASK, NULL, &m);
if (!sigismember (&m, SIGUSR1))
printf ("failed");
return 0; return 0;
} }

View file

@ -640,7 +640,12 @@ static void gcall_or_jmp(int is_jmp)
if (tcc_state->do_bounds_check && if (tcc_state->do_bounds_check &&
(vtop->sym->v == TOK_alloca || (vtop->sym->v == TOK_alloca ||
vtop->sym->v == TOK_setjmp || vtop->sym->v == TOK_setjmp ||
vtop->sym->v == TOK__setjmp)) vtop->sym->v == TOK__setjmp
#ifndef TCC_TARGET_PE
|| vtop->sym->v == TOK_sigsetjmp
|| vtop->sym->v == TOK___sigsetjmp
#endif
))
func_bound_add_epilog = 1; func_bound_add_epilog = 1;
#endif #endif
} else { } else {
@ -747,15 +752,18 @@ static void gen_bounds_epilog(void)
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
*bounds_ptr = 0; *bounds_ptr = 0;
/* generate bound local allocation */
sym_data = get_sym_ref(&char_pointer_type, lbounds_section, sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
func_bound_offset, lbounds_section->data_offset); func_bound_offset, lbounds_section->data_offset);
/* generate bound local allocation */
if (func_bound_offset != lbounds_section->data_offset) {
saved_ind = ind; saved_ind = ind;
ind = func_bound_ind; ind = func_bound_ind;
greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
ind = ind + 10; ind = ind + 10;
gen_bounds_call(TOK___bound_local_new); gen_bounds_call(TOK___bound_local_new);
ind = saved_ind; ind = saved_ind;
}
/* generate bound check local freeing */ /* generate bound check local freeing */
o(0x5250); /* save returned value, if any */ o(0x5250); /* save returned value, if any */