X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fstore.c;h=8603a8fb11e568cef40de7e2b659e32554333c30;hb=dd09071d45761ca63f50e60eff5eed4f8e063a74;hp=c664ad9f42060dd95cb4baa5f8a8fc00f5b100d6;hpb=410b935d8ed35762b76b0edfa7a9fb9ba6500ebd;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/store.c b/src/src/store.c index c664ad9f4..8603a8fb1 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -3,7 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim maintainers 2019 - 2020 */ +/* Copyright (c) The Exim maintainers 2019 - 2021 */ /* See the file NOTICE for conditions of use and distribution. */ /* Exim gets and frees all its store through these functions. In the original @@ -41,6 +41,9 @@ The following different types of store are recognized: a single message transaction but needed for longer than the use of the main pool permits. Currently this means only receive-time DKIM information. +- There is a dedicated pool for configuration data read from the config file(s). + Once complete, it is made readonly. + . Orthogonal to the three pool types, there are two classes of memory: untainted and tainted. The latter is used for values derived from untrusted input, and the string-expansion mechanism refuses to operate on such values (obviously, @@ -165,28 +168,31 @@ static int max_nonpool_malloc; /* max value for nonpool_malloc */ static const uschar * pooluse[NPOOLS] = { [POOL_MAIN] = US"main", [POOL_PERM] = US"perm", +[POOL_CONFIG] = US"config", [POOL_SEARCH] = US"search", [POOL_MESSAGE] = US"message", [POOL_TAINT_MAIN] = US"main", [POOL_TAINT_PERM] = US"perm", -[POOL_TAINT_SEARCH] = US"search", +[POOL_TAINT_CONFIG] = US"config", [POOL_TAINT_SEARCH] = US"search", [POOL_TAINT_MESSAGE] = US"message", }; static const uschar * poolclass[NPOOLS] = { [POOL_MAIN] = US"untainted", [POOL_PERM] = US"untainted", +[POOL_CONFIG] = US"untainted", [POOL_SEARCH] = US"untainted", [POOL_MESSAGE] = US"untainted", [POOL_TAINT_MAIN] = US"tainted", [POOL_TAINT_PERM] = US"tainted", +[POOL_TAINT_CONFIG] = US"tainted", [POOL_TAINT_SEARCH] = US"tainted", [POOL_TAINT_MESSAGE] = US"tainted", }; #endif -static void * internal_store_malloc(int, const char *, int); +static void * internal_store_malloc(size_t, const char *, int); static void internal_store_free(void *, const char *, int linenumber); /******************************************************************************/ @@ -245,6 +251,19 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n", +/******************************************************************************/ +void +store_writeprotect(int pool) +{ +#if !defined(COMPILE_UTILITY) && !defined(MISSING_POSIX_MEMALIGN) +for (storeblock * b = chainbase[pool]; b; b = b->next) + if (mprotect(b, ALIGNED_SIZEOF_STOREBLOCK + b->length, PROT_READ) != 0) + DEBUG(D_any) debug_printf("config block mprotect: (%d) %s\n", errno, strerror(errno)); +#endif +} + +/******************************************************************************/ + /************************************************* * Get a block from the current pool * *************************************************/ @@ -264,20 +283,20 @@ Returns: pointer to store (panic on malloc failure) */ void * -store_get_3(int size, BOOL tainted, const char *func, int linenumber) +store_get_3(int size, BOOL tainted, const char * func, int linenumber) { int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool; /* Ensure we've been asked to allocate memory. A negative size is a sign of a security problem. -A zero size is also suspect (but we might have to allow it if we find our API -expects it in some places). */ -if (size < 1) - { +A zero size might be also suspect, but our internal usage deliberately +does this to return a current watermark value for a later release of +allocated store. */ + +if (size < 0 || size >= INT_MAX/2) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "bad memory allocation requested (%d bytes) at %s %d", size, func, linenumber); - } /* Round up the size to a multiple of the alignment. Although this looks a messy statement, because "alignment" is a constant expression, the compiler can @@ -324,7 +343,21 @@ if (size > yield_length[pool]) if (++nblocks[pool] > maxblocks[pool]) maxblocks[pool] = nblocks[pool]; - newblock = internal_store_malloc(mlength, func, linenumber); +#ifndef MISSING_POSIX_MEMALIGN + if (pool == POOL_CONFIG) + { + long pgsize = sysconf(_SC_PAGESIZE); + int err = posix_memalign((void **)&newblock, + pgsize, (mlength + pgsize - 1) & ~(pgsize - 1)); + if (err) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "failed to alloc (using posix_memalign) %d bytes of memory: '%s'" + "called from line %d in %s", + size, strerror(err), linenumber, func); + } + else +#endif + newblock = internal_store_malloc(mlength, func, linenumber); newblock->next = NULL; newblock->length = length; #ifndef RESTRICTED_MEMORY @@ -385,9 +418,9 @@ Returns: pointer to store (panic on malloc failure) */ void * -store_get_perm_3(int size, BOOL tainted, const char *func, int linenumber) +store_get_perm_3(int size, BOOL tainted, const char * func, int linenumber) { -void *yield; +void * yield; int old_pool = store_pool; store_pool = POOL_PERM; yield = store_get_3(size, tainted, func, linenumber); @@ -428,12 +461,10 @@ int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool; int inc = newsize - oldsize; int rounded_oldsize = oldsize; -if (newsize < 0) - { +if (oldsize < 0 || newsize < oldsize || newsize >= INT_MAX/2) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "bad memory extension requested (%d -> %d bytes) at %s %d", oldsize, newsize, func, linenumber); - } /* Check that the block being extended was already of the required taint status; refuse to extend if not. */ @@ -485,7 +516,8 @@ not call with a pointer returned by store_get(). Both the untainted and tainted pools corresposding to store_pool are reset. Arguments: - r place to back up to + ptr place to back up to + pool pool holding the pointer func function from which called linenumber line number in source file @@ -563,7 +595,8 @@ if ( yield_length[pool] < STOREPOOL_MIN_SIZE } bb = b->next; -b->next = NULL; +if (pool != POOL_CONFIG) + b->next = NULL; while ((b = bb)) { @@ -578,7 +611,8 @@ while ((b = bb)) nbytes[pool] -= siz; pool_malloc -= siz; nblocks[pool]--; - internal_store_free(b, func, linenumber); + if (pool != POOL_CONFIG) + internal_store_free(b, func, linenumber); #ifndef RESTRICTED_MEMORY if (store_block_order[pool] > 13) store_block_order[pool]--; @@ -802,6 +836,11 @@ if (is_tainted(block) != tainted) die_tainted(US"store_newblock", CUS func, linenumber); #endif +if (len < 0 || len > newsize) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "bad memory extension requested (%d -> %d bytes) at %s %d", + len, newsize, func, linenumber); + newtext = store_get(newsize, tainted); memcpy(newtext, block, len); if (release_ok) store_release_3(block, pool, func, linenumber); @@ -828,21 +867,29 @@ Returns: pointer to gotten store (panic on failure) */ static void * -internal_store_malloc(int size, const char *func, int line) +internal_store_malloc(size_t size, const char *func, int line) { void * yield; -size += sizeof(int); /* space to store the size, used under debug */ +/* Check specifically for a possibly result of conversion from +a negative int, to the (unsigned, wider) size_t */ + +if (size >= INT_MAX/2) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "bad memory allocation requested (" SIZE_T_FMT " bytes) at %s %d", + size, func, line); + +size += sizeof(size_t); /* space to store the size, used under debug */ if (size < 16) size = 16; -if (!(yield = malloc((size_t)size))) - log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: " +if (!(yield = malloc(size))) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc " SIZE_T_FMT " bytes of memory: " "called from line %d in %s", size, line, func); #ifndef COMPILE_UTILITY -DEBUG(D_any) *(int *)yield = size; +DEBUG(D_any) *(size_t *)yield = size; #endif -yield = US yield + sizeof(int); +yield = US yield + sizeof(size_t); if ((nonpool_malloc += size) > max_nonpool_malloc) max_nonpool_malloc = nonpool_malloc; @@ -855,8 +902,8 @@ giving warnings. */ is not filled with zeros so as to catch problems. */ if (f.running_in_test_harness) - memset(yield, 0xF0, (size_t)size - sizeof(int)); -DEBUG(D_memory) debug_printf("--Malloc %6p %5d bytes\t%-20s %4d\tpool %5d nonpool %5d\n", + memset(yield, 0xF0, size - sizeof(size_t)); +DEBUG(D_memory) debug_printf("--Malloc %6p %5lu bytes\t%-20s %4d\tpool %5d nonpool %5d\n", yield, size, func, line, pool_malloc, nonpool_malloc); #endif /* COMPILE_UTILITY */ @@ -864,7 +911,7 @@ return yield; } void * -store_malloc_3(int size, const char *func, int linenumber) +store_malloc_3(size_t size, const char *func, int linenumber) { if (n_nonpool_blocks++ > max_nonpool_blocks) max_nonpool_blocks = n_nonpool_blocks; @@ -889,10 +936,11 @@ Returns: nothing static void internal_store_free(void * block, const char * func, int linenumber) { -uschar * p = US block - sizeof(int); +uschar * p = US block - sizeof(size_t); #ifndef COMPILE_UTILITY -DEBUG(D_any) nonpool_malloc -= *(int *)p; -DEBUG(D_memory) debug_printf("----Free %6p %5d bytes\t%-20s %4d\n", block, *(int *)p, func, linenumber); +DEBUG(D_any) nonpool_malloc -= *(size_t *)p; +DEBUG(D_memory) debug_printf("----Free %6p %5ld bytes\t%-20s %4d\n", + block, *(size_t *)p, func, linenumber); #endif free(p); }