X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/2fd4074dd2ca95b14e0256f740965c40671e31eb..677481d4fcf4811e193603d0e9970d1f62c74567:/src/src/store.c?ds=sidebyside diff --git a/src/src/store.c b/src/src/store.c index b65649f4a..1fe97e6c9 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -62,9 +62,11 @@ The following different types of store are recognized: recopy a string being built into a tainted allocation if it meets a %s for a tainted argument. Any intermediate-layer function that (can) return a new allocation should behave this way; returning a tainted result if any tainted - content is used. Users of functions that modify existing allocations should - check if a tainted source and an untainted destination is used, and fail instead - (sprintf() being the classic case). + content is used. Intermediate-layer functions (eg. Ustrncpy) that modify + existing allocations fail if tainted data is written into an untainted area. + Users of functions that modify existing allocations should check if a tainted + source and an untainted destination is used, and fail instead (sprintf() being + the classic case). */ @@ -184,7 +186,6 @@ static void internal_tainted_free(storeblock *, const char *, int linenumber); /******************************************************************************/ -#ifndef TAINT_CHECK_FAST /* Test if a pointer refers to tainted memory. Slower version check, for use when platform intermixes malloc and mmap area @@ -198,24 +199,22 @@ BOOL is_tainted_fn(const void * p) { storeblock * b; -int pool; -for (pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++) +for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++) if ((b = current_block[pool])) { - char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK; - if (CS p >= bc && CS p <= bc + b->length) return TRUE; + uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK; + if (US p >= bc && US p <= bc + b->length) return TRUE; } -for (pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++) +for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++) for (b = chainbase[pool]; b; b = b->next) { - char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK; - if (CS p >= bc && CS p <= bc + b->length) return TRUE; + uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK; + if (US p >= bc && US p <= bc + b->length) return TRUE; } return FALSE; } -#endif void @@ -225,6 +224,31 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n", msg, func, line); } +static void +use_slow_taint_check(void) +{ +#ifndef COMPILE_UTILITY +DEBUG(D_any) debug_printf("switching to slow-mode taint checking\n"); +#endif +f.taint_check_slow = TRUE; +} + +static void +verify_all_untainted(void) +{ +for (int pool = 0; pool < POOL_TAINT_BASE; pool++) + for (storeblock * b = chainbase[pool]; b; b = b->next) + { + uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK; + if (is_tainted(bc)) + { + use_slow_taint_check(); + return; + } + } +} + + /************************************************* * Get a block from the current pool * @@ -758,7 +782,7 @@ int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool; BOOL release_ok = !tainted && store_last_get[pool] == block; uschar * newtext; -#ifndef MACRO_PREDEF +#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY) if (is_tainted(block) != tainted) die_tainted(US"store_newblock", CUS func, linenumber); #endif @@ -817,6 +841,7 @@ if (!(yield = mmap(NULL, (size_t)size, if (yield < tainted_base) tainted_base = yield; if ((top = US yield + size) > tainted_top) tainted_top = top; +if (!f.taint_check_slow) use_slow_taint_check(); return store_alloc_tail(yield, size, func, line, US"Mmap"); } @@ -848,6 +873,14 @@ if (!(yield = malloc((size_t)size))) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: " "called from line %d in %s", size, linenumber, func); +/* If malloc ever returns apparently tainted memory, which glibc +malloc will as it uses mmap for larger requests, we must switch to +the slower checking for tainting (checking an address against all +the tainted pool block spans, rather than just the mmap span) */ + +if (!f.taint_check_slow && is_tainted(yield)) + use_slow_taint_check(); + return store_alloc_tail(yield, size, func, linenumber, US"Malloc"); }