X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fstore.c;h=ad4da3c2e5faf4a794f33c7b6d2972f7be2b2745;hb=ef619222452aa41b843468d66399bbb4e95beda3;hp=8faefd492cc7d60dd081ccdb5e278c60fcde4b19;hpb=f3f9fe5c6f21a00accc994e0b79480d247f9d6db;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/store.c b/src/src/store.c index 8faefd492..ad4da3c2e 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -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,21 +168,24 @@ 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", }; @@ -201,7 +207,6 @@ for (int i = 0; i < NPOOLS; i++) yield_length[i] = -1; store_block_order[i] = 12; /* log2(allocation_size) ie. 4kB */ } -store_block_order[POOL_MAIN] = 13; } /******************************************************************************/ @@ -246,6 +251,22 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n", +/******************************************************************************/ +void +store_writeprotect(int pool) +{ +for (storeblock * b = chainbase[pool]; b; b = b->next) + { +#ifndef COMPILE_UTILITY + 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 * *************************************************/ @@ -269,6 +290,17 @@ 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 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 do a reasonable job of optimizing, especially if the value of "alignment" is a @@ -283,7 +315,9 @@ these functions are mostly called for small amounts of store. */ if (size > yield_length[pool]) { - int length = MAX(STORE_BLOCK_SIZE(store_block_order[pool]), size); + int length = MAX( + STORE_BLOCK_SIZE(store_block_order[pool]) - ALIGNED_SIZEOF_STOREBLOCK, + size); int mlength = length + ALIGNED_SIZEOF_STOREBLOCK; storeblock * newblock; @@ -312,7 +346,13 @@ if (size > yield_length[pool]) if (++nblocks[pool] > maxblocks[pool]) maxblocks[pool] = nblocks[pool]; - newblock = internal_store_malloc(mlength, func, linenumber); + if (pool == POOL_CONFIG) + { + long pgsize = sysconf(_SC_PAGESIZE); + posix_memalign((void **)&newblock, pgsize, (mlength + pgsize - 1) & ~(pgsize - 1)); + } + else + newblock = internal_store_malloc(mlength, func, linenumber); newblock->next = NULL; newblock->length = length; #ifndef RESTRICTED_MEMORY @@ -416,6 +456,11 @@ int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool; int inc = newsize - oldsize; int rounded_oldsize = oldsize; +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. */ @@ -466,7 +511,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 @@ -544,17 +590,13 @@ if ( yield_length[pool] < STOREPOOL_MIN_SIZE } bb = b->next; -b->next = NULL; - -/* If there will be only one block left in the pool, drop one -most-recent allocation size increase, ensuring it does not increase -forever. */ - -if (!bb && store_block_order[pool] > 12) store_block_order[pool]--; +if (pool != POOL_CONFIG) + b->next = NULL; while ((b = bb)) { int siz = b->length + ALIGNED_SIZEOF_STOREBLOCK; + #ifndef COMPILE_UTILITY if (debug_store) assert_no_variables(b, b->length + ALIGNED_SIZEOF_STOREBLOCK, @@ -564,7 +606,12 @@ 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]--; +#endif } /* Cut out the debugging stuff for utilities, but stop picky compilers from @@ -740,7 +787,7 @@ for (storeblock * b = chainbase[pool]; b; b = b->next) memset(bb, 0xF0, bb->length+ALIGNED_SIZEOF_STOREBLOCK); #endif /* COMPILE_UTILITY */ - free(bb); + internal_store_free(bb, func, linenumber); return; } } @@ -784,6 +831,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); @@ -814,10 +866,12 @@ internal_store_malloc(int size, const char *func, int line) { void * yield; -#ifndef COMPILE_UTILITY -DEBUG(D_memory) size += sizeof(int); /* space to store the size */ -#endif +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, line); +size += sizeof(int); /* space to store the size, used under debug */ if (size < 16) size = 16; if (!(yield = malloc((size_t)size))) @@ -825,8 +879,9 @@ if (!(yield = malloc((size_t)size))) "called from line %d in %s", size, line, func); #ifndef COMPILE_UTILITY -DEBUG(D_memory) { *(int *)yield = size; yield = US yield + sizeof(int); } +DEBUG(D_any) *(int *)yield = size; #endif +yield = US yield + sizeof(int); if ((nonpool_malloc += size) > max_nonpool_malloc) max_nonpool_malloc = nonpool_malloc; @@ -873,9 +928,9 @@ Returns: nothing static void internal_store_free(void * block, const char * func, int linenumber) { -uschar * p = block; +uschar * p = US block - sizeof(int); #ifndef COMPILE_UTILITY -DEBUG(D_memory) { p -= sizeof(int); nonpool_malloc -= *(int *)p; } +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); #endif free(p); @@ -901,7 +956,7 @@ DEBUG(D_memory) debug_printf("----Exit npools max: %3d kB\n", max_pool_malloc/1024); for (int i = 0; i < NPOOLS; i++) debug_printf("----Exit pool %d max: %3d kB in %d blocks at order %u\t%s %s\n", - i, maxbytes[i]/1024, maxblocks[i], maxorder[i], + i, (maxbytes[i]+1023)/1024, maxblocks[i], maxorder[i], poolclass[i], pooluse[i]); } #endif