-
+ 2B787A241AB819008B23B6235AEC68EA7EA5DC092859FF42FFE50A7BD00D710F39547E35EE66449377FE70BDD870F7BD4B40B7EDE228F6842671C5E167183493
eucrypt/mpi/secmem.c
(0 . 0)(1 . 511)
7099 /* secmem.c - memory allocation from a secure heap
7100 * Modified by No Such Labs. (C) 2015. See README.
7101 *
7102 * This file was originally part of Gnu Privacy Guard (GPG), ver. 1.4.10,
7103 * SHA256(gnupg-1.4.10.tar.gz):
7104 * 0bfd74660a2f6cedcf7d8256db4a63c996ffebbcdc2cf54397bfb72878c5a85a
7105 * (C) 1994-2005 Free Software Foundation, Inc.
7106 *
7107 * This program is free software: you can redistribute it and/or modify
7108 * it under the terms of the GNU General Public License as published by
7109 * the Free Software Foundation, either version 3 of the License, or
7110 * (at your option) any later version.
7111 *
7112 * This program is distributed in the hope that it will be useful,
7113 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7114 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7115 * GNU General Public License for more details.
7116 *
7117 * You should have received a copy of the GNU General Public License
7118 * along with this program. If not, see <http://www.gnu.org/licenses/>.
7119 */
7120
7121 #include "knobs.h"
7122
7123 #include <stdio.h>
7124 #include <stdlib.h>
7125 #include <string.h>
7126 #include <errno.h>
7127 #include <stdarg.h>
7128 #include <unistd.h>
7129 #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
7130 #include <sys/mman.h>
7131 #include <sys/types.h>
7132 #include <fcntl.h>
7133 #ifdef USE_CAPABILITIES
7134 #include <sys/capability.h>
7135 #endif
7136 #ifdef HAVE_PLOCK
7137 #include <sys/lock.h>
7138 #endif
7139 #endif
7140
7141 #include "types.h"
7142 #include "memory.h"
7143 #include "util.h"
7144
7145 /* MinGW doesn't seem to prototype getpagesize, though it does have
7146 it. */
7147 #if !HAVE_DECL_GETPAGESIZE
7148 int getpagesize(void);
7149 #endif
7150
7151 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
7152 #define MAP_ANONYMOUS MAP_ANON
7153 #endif
7154 /* It seems that Slackware 7.1 does not know about EPERM */
7155 #if !defined(EPERM) && defined(ENOMEM)
7156 #define EPERM ENOMEM
7157 #endif
7158
7159
7160 #define DEFAULT_POOLSIZE 16384
7161
7162 typedef struct memblock_struct MEMBLOCK;
7163 struct memblock_struct {
7164 unsigned size;
7165 union {
7166 MEMBLOCK *next;
7167 PROPERLY_ALIGNED_TYPE aligned;
7168 } u;
7169 };
7170
7171
7172
7173 static void *pool;
7174 static volatile int pool_okay; /* may be checked in an atexit function */
7175 #ifdef HAVE_MMAP
7176 static volatile int pool_is_mmapped;
7177 #endif
7178 static size_t poolsize; /* allocated length */
7179 static size_t poollen; /* used length */
7180 static MEMBLOCK *unused_blocks;
7181 static unsigned max_alloced;
7182 static unsigned cur_alloced;
7183 static unsigned max_blocks;
7184 static unsigned cur_blocks;
7185 static int disable_secmem;
7186 static int show_warning;
7187 static int no_warning;
7188 static int suspend_warning;
7189
7190
7191 static void
7192 print_warn(void)
7193 {
7194 if (!no_warning)
7195 {
7196 log_info("WARNING: using insecure memory!\n");
7197 }
7198 }
7199
7200
7201 static void
7202 lock_pool( void *p, size_t n )
7203 {
7204 #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
7205 int err;
7206
7207 cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
7208 err = mlock( p, n );
7209 if( err && errno )
7210 err = errno;
7211 cap_set_proc( cap_from_text("cap_ipc_lock+p") );
7212
7213 if( err ) {
7214 if( errno != EPERM
7215 #ifdef EAGAIN /* OpenBSD returns this */
7216 && errno != EAGAIN
7217 #endif
7218 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
7219 && errno != ENOSYS
7220 #endif
7221 #ifdef ENOMEM /* Linux can return this */
7222 && errno != ENOMEM
7223 #endif
7224 )
7225 log_error("can't lock memory: %s\n", strerror(err));
7226 show_warning = 1;
7227 }
7228
7229 #elif defined(HAVE_MLOCK)
7230 uid_t uid;
7231 int err;
7232
7233 uid = getuid();
7234
7235 #ifdef HAVE_BROKEN_MLOCK
7236 /* ick. but at least we get secured memory. about to lock
7237 entire data segment. */
7238 #ifdef HAVE_PLOCK
7239 # ifdef _AIX
7240 /* The configure for AIX returns broken mlock but the plock has
7241 the strange requirement to somehow set the stack limit first.
7242 The problem might turn out in indeterministic program behaviour
7243 and hanging processes which can somehow be solved when enough
7244 processes are clogging up the memory. To get this problem out
7245 of the way we simply don't try to lock the memory at all.
7246 */
7247 errno = EPERM;
7248 err = errno;
7249 # else /* !_AIX */
7250 err = plock( DATLOCK );
7251 if( err && errno )
7252 err = errno;
7253 # endif /*_AIX*/
7254 #else /*!HAVE_PLOCK*/
7255 if( uid ) {
7256 errno = EPERM;
7257 err = errno;
7258 }
7259 else {
7260 err = mlock( p, n );
7261 if( err && errno )
7262 err = errno;
7263 }
7264 #endif /*!HAVE_PLOCK*/
7265 #else
7266 err = mlock( p, n );
7267 if( err && errno )
7268 err = errno;
7269 #endif
7270
7271 if( uid && !geteuid() ) {
7272 /* check that we really dropped the privs.
7273 * Note: setuid(0) should always fail */
7274 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
7275 log_fatal("failed to reset uid: %s\n", strerror(errno));
7276 }
7277
7278 if( err ) {
7279 if( errno != EPERM
7280 #ifdef EAGAIN /* OpenBSD returns this */
7281 && errno != EAGAIN
7282 #endif
7283 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
7284 && errno != ENOSYS
7285 #endif
7286 #ifdef ENOMEM /* Linux can return this */
7287 && errno != ENOMEM
7288 #endif
7289 )
7290 log_error("can't lock memory: %s\n", strerror(err));
7291 show_warning = 1;
7292 }
7293
7294 #elif defined ( __QNX__ )
7295 /* QNX does not page at all, so the whole secure memory stuff does
7296 * not make much sense. However it is still of use because it
7297 * wipes out the memory on a free().
7298 * Therefore it is sufficient to suppress the warning
7299 */
7300 #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
7301 /* It does not make sense to print such a warning, given the fact that
7302 * this whole Windows !@#$% and their user base are inherently insecure
7303 */
7304 #else
7305 log_info("Please note that you don't have secure memory on this system\n");
7306 #endif
7307 }
7308
7309
7310 static void
7311 init_pool( size_t n)
7312 {
7313 long int pgsize_val;
7314 size_t pgsize;
7315
7316 poolsize = n;
7317
7318 if( disable_secmem )
7319 log_bug("secure memory is disabled");
7320
7321 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
7322 pgsize_val = sysconf (_SC_PAGESIZE);
7323 #elif defined(HAVE_GETPAGESIZE)
7324 pgsize_val = getpagesize ();
7325 #else
7326 pgsize_val = -1;
7327 #endif
7328 pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096;
7329
7330
7331 #ifdef HAVE_MMAP
7332 poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
7333 #ifdef MAP_ANONYMOUS
7334 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
7335 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
7336 #else /* map /dev/zero instead */
7337 { int fd;
7338
7339 fd = open("/dev/zero", O_RDWR);
7340 if( fd == -1 ) {
7341 log_error("can't open /dev/zero: %s\n", strerror(errno) );
7342 pool = (void*)-1;
7343 }
7344 else {
7345 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
7346 MAP_PRIVATE, fd, 0);
7347 close (fd);
7348 }
7349 }
7350 #endif
7351 if( pool == (void*)-1 )
7352 log_info("can't mmap pool of %u bytes: %s - using malloc\n",
7353 (unsigned)poolsize, strerror(errno));
7354 else {
7355 pool_is_mmapped = 1;
7356 pool_okay = 1;
7357 }
7358
7359 #endif
7360 if( !pool_okay ) {
7361 pool = malloc( poolsize );
7362 if( !pool )
7363 log_fatal("can't allocate memory pool of %u bytes\n",
7364 (unsigned)poolsize);
7365 else
7366 pool_okay = 1;
7367 }
7368 lock_pool( pool, poolsize );
7369 poollen = 0;
7370 }
7371
7372
7373 /* concatenate unused blocks */
7374 static void
7375 compress_pool(void)
7376 {
7377 /* fixme: we really should do this */
7378 }
7379
7380 void
7381 secmem_set_flags( unsigned flags )
7382 {
7383 int was_susp = suspend_warning;
7384
7385 no_warning = flags & 1;
7386 suspend_warning = flags & 2;
7387
7388 /* and now issue the warning if it is not longer suspended */
7389 if( was_susp && !suspend_warning && show_warning ) {
7390 show_warning = 0;
7391 print_warn();
7392 }
7393 }
7394
7395 unsigned
7396 secmem_get_flags(void)
7397 {
7398 unsigned flags;
7399
7400 flags = no_warning ? 1:0;
7401 flags |= suspend_warning ? 2:0;
7402 return flags;
7403 }
7404
7405 /* Returns 1 if memory was locked, 0 if not. */
7406 int
7407 secmem_init( size_t n )
7408 {
7409 if( !n ) {
7410 #ifdef USE_CAPABILITIES
7411 /* drop all capabilities */
7412 cap_set_proc( cap_from_text("all-eip") );
7413 #elif !defined(HAVE_DOSISH_SYSTEM)
7414 uid_t uid;
7415 disable_secmem=1;
7416 uid = getuid();
7417 if( uid != geteuid() ) {
7418 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
7419 log_fatal("failed to drop setuid\n" );
7420 }
7421 #endif
7422 }
7423 else {
7424 if( n < DEFAULT_POOLSIZE )
7425 n = DEFAULT_POOLSIZE;
7426 if( !pool_okay )
7427 init_pool(n);
7428 else
7429 log_error("Oops, secure memory pool already initialized\n");
7430 }
7431
7432 return !show_warning;
7433 }
7434
7435
7436 void *
7437 secmem_malloc( size_t size )
7438 {
7439 MEMBLOCK *mb, *mb2;
7440 int compressed=0;
7441
7442 if( !pool_okay ) {
7443 log_info(
7444 "operation is not possible without initialized secure memory\n");
7445 log_info("(you may have used the wrong program for this task)\n");
7446 exit(2);
7447 }
7448 if( show_warning && !suspend_warning ) {
7449 show_warning = 0;
7450 print_warn();
7451 }
7452
7453 /* Blocks are always a multiple of 32. Note that we allocate an
7454 extra of the size of an entire MEMBLOCK. This is required
7455 becuase we do not only need the SIZE info but also extra space
7456 to chain up unused memory blocks. */
7457 size += sizeof(MEMBLOCK);
7458 size = ((size + 31) / 32) * 32;
7459
7460 retry:
7461 /* try to get it from the used blocks */
7462 for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
7463 if( mb->size >= size ) {
7464 if( mb2 )
7465 mb2->u.next = mb->u.next;
7466 else
7467 unused_blocks = mb->u.next;
7468 goto leave;
7469 }
7470 /* allocate a new block */
7471 if( (poollen + size <= poolsize) ) {
7472 mb = (void*)((char*)pool + poollen);
7473 poollen += size;
7474 mb->size = size;
7475 }
7476 else if( !compressed ) {
7477 compressed=1;
7478 compress_pool();
7479 goto retry;
7480 }
7481 else
7482 return NULL;
7483
7484 leave:
7485 cur_alloced += mb->size;
7486 cur_blocks++;
7487 if( cur_alloced > max_alloced )
7488 max_alloced = cur_alloced;
7489 if( cur_blocks > max_blocks )
7490 max_blocks = cur_blocks;
7491
7492 return &mb->u.aligned.c;
7493 }
7494
7495
7496 void *
7497 secmexrealloc( void *p, size_t newsize )
7498 {
7499 MEMBLOCK *mb;
7500 size_t size;
7501 void *a;
7502
7503 mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
7504 size = mb->size;
7505 if (size < sizeof(MEMBLOCK))
7506 log_bug ("secure memory corrupted at block %p\n", (void *)mb);
7507 size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
7508
7509 if( newsize <= size )
7510 return p; /* It is easier not to shrink the memory. */
7511 a = secmem_malloc( newsize );
7512 if ( a ) {
7513 memcpy(a, p, size);
7514 memset((char*)a+size, 0, newsize-size);
7515 secmem_free(p);
7516 }
7517 return a;
7518 }
7519
7520
7521 void
7522 secmem_free( void *a )
7523 {
7524 MEMBLOCK *mb;
7525 size_t size;
7526
7527 if( !a )
7528 return;
7529
7530 mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
7531 size = mb->size;
7532 /* This does not make much sense: probably this memory is held in the
7533 * cache. We do it anyway: */
7534 wipememory2(mb, 0xff, size );
7535 wipememory2(mb, 0xaa, size );
7536 wipememory2(mb, 0x55, size );
7537 wipememory2(mb, 0x00, size );
7538 mb->size = size;
7539 mb->u.next = unused_blocks;
7540 unused_blocks = mb;
7541 cur_blocks--;
7542 cur_alloced -= size;
7543 }
7544
7545
7546 /* Check whether P points into the pool. */
7547 static int
7548 ptr_into_pool_p (const void *p)
7549 {
7550 /* We need to convert pointers to addresses. This is required by
7551 C-99 6.5.8 to avoid undefined behaviour. Using size_t is at
7552 least only implementation defined. See also
7553 http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
7554 */
7555 size_t p_addr = (size_t)p;
7556 size_t pool_addr = (size_t)pool;
7557
7558 return p_addr >= pool_addr && p_addr < pool_addr+poolsize;
7559 }
7560
7561
7562 int
7563 m_is_secure( const void *p )
7564 {
7565 return pool_okay && ptr_into_pool_p (p);
7566 }
7567
7568
7569
7570 /****************
7571 * Warning: This code might be called by an interrupt handler
7572 * and frankly, there should really be such a handler,
7573 * to make sure that the memory is wiped out.
7574 * We hope that the OS wipes out mlocked memory after
7575 * receiving a SIGKILL - it really should do so, otherwise
7576 * there is no chance to get the secure memory cleaned.
7577 */
7578 void
7579 secmem_term()
7580 {
7581 if( !pool_okay )
7582 return;
7583
7584 wipememory2( pool, 0xff, poolsize);
7585 wipememory2( pool, 0xaa, poolsize);
7586 wipememory2( pool, 0x55, poolsize);
7587 wipememory2( pool, 0x00, poolsize);
7588 #ifdef HAVE_MMAP
7589 if( pool_is_mmapped )
7590 munmap( pool, poolsize );
7591 #endif
7592 pool = NULL;
7593 pool_okay = 0;
7594 poolsize=0;
7595 poollen=0;
7596 unused_blocks=NULL;
7597 }
7598
7599
7600 void
7601 secmem_dump_stats()
7602 {
7603 if( disable_secmem )
7604 return;
7605 fprintf(stderr,
7606 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
7607 cur_alloced, max_alloced, cur_blocks, max_blocks,
7608 (ulong)poollen, (ulong)poolsize );
7609 }