raw
ch1_mpi                 1 /* secmem.c  -	memory allocation from a secure heap
ch1_mpi 2 * Modified by No Such Labs. (C) 2015. See README.
ch1_mpi 3 *
ch1_mpi 4 * This file was originally part of Gnu Privacy Guard (GPG), ver. 1.4.10,
ch1_mpi 5 * SHA256(gnupg-1.4.10.tar.gz):
ch1_mpi 6 * 0bfd74660a2f6cedcf7d8256db4a63c996ffebbcdc2cf54397bfb72878c5a85a
ch1_mpi 7 * (C) 1994-2005 Free Software Foundation, Inc.
ch1_mpi 8 *
ch1_mpi 9 * This program is free software: you can redistribute it and/or modify
ch1_mpi 10 * it under the terms of the GNU General Public License as published by
ch1_mpi 11 * the Free Software Foundation, either version 3 of the License, or
ch1_mpi 12 * (at your option) any later version.
ch1_mpi 13 *
ch1_mpi 14 * This program is distributed in the hope that it will be useful,
ch1_mpi 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ch1_mpi 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ch1_mpi 17 * GNU General Public License for more details.
ch1_mpi 18 *
ch1_mpi 19 * You should have received a copy of the GNU General Public License
ch1_mpi 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
ch1_mpi 21 */
ch1_mpi 22
ch1_mpi 23 #include "knobs.h"
ch1_mpi 24
ch1_mpi 25 #include <stdio.h>
ch1_mpi 26 #include <stdlib.h>
ch1_mpi 27 #include <string.h>
ch1_mpi 28 #include <errno.h>
ch1_mpi 29 #include <stdarg.h>
ch1_mpi 30 #include <unistd.h>
ch1_mpi 31 #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
ch1_mpi 32 #include <sys/mman.h>
ch1_mpi 33 #include <sys/types.h>
ch1_mpi 34 #include <fcntl.h>
ch1_mpi 35 #ifdef USE_CAPABILITIES
ch1_mpi 36 #include <sys/capability.h>
ch1_mpi 37 #endif
ch1_mpi 38 #ifdef HAVE_PLOCK
ch1_mpi 39 #include <sys/lock.h>
ch1_mpi 40 #endif
ch1_mpi 41 #endif
ch1_mpi 42
ch1_mpi 43 #include "types.h"
ch1_mpi 44 #include "memory.h"
ch1_mpi 45 #include "util.h"
ch1_mpi 46
ch1_mpi 47 /* MinGW doesn't seem to prototype getpagesize, though it does have
ch1_mpi 48 it. */
ch1_mpi 49 #if !HAVE_DECL_GETPAGESIZE
ch1_mpi 50 int getpagesize(void);
ch1_mpi 51 #endif
ch1_mpi 52
ch1_mpi 53 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
ch1_mpi 54 #define MAP_ANONYMOUS MAP_ANON
ch1_mpi 55 #endif
ch1_mpi 56 /* It seems that Slackware 7.1 does not know about EPERM */
ch1_mpi 57 #if !defined(EPERM) && defined(ENOMEM)
ch1_mpi 58 #define EPERM ENOMEM
ch1_mpi 59 #endif
ch1_mpi 60
ch1_mpi 61
ch1_mpi 62 #define DEFAULT_POOLSIZE 16384
ch1_mpi 63
ch1_mpi 64 typedef struct memblock_struct MEMBLOCK;
ch1_mpi 65 struct memblock_struct {
ch1_mpi 66 unsigned size;
ch1_mpi 67 union {
ch1_mpi 68 MEMBLOCK *next;
ch1_mpi 69 PROPERLY_ALIGNED_TYPE aligned;
ch1_mpi 70 } u;
ch1_mpi 71 };
ch1_mpi 72
ch1_mpi 73
ch1_mpi 74
ch1_mpi 75 static void *pool;
ch1_mpi 76 static volatile int pool_okay; /* may be checked in an atexit function */
ch1_mpi 77 #ifdef HAVE_MMAP
ch1_mpi 78 static volatile int pool_is_mmapped;
ch1_mpi 79 #endif
ch1_mpi 80 static size_t poolsize; /* allocated length */
ch1_mpi 81 static size_t poollen; /* used length */
ch1_mpi 82 static MEMBLOCK *unused_blocks;
ch1_mpi 83 static unsigned max_alloced;
ch1_mpi 84 static unsigned cur_alloced;
ch1_mpi 85 static unsigned max_blocks;
ch1_mpi 86 static unsigned cur_blocks;
ch1_mpi 87 static int disable_secmem;
ch1_mpi 88 static int show_warning;
ch1_mpi 89 static int no_warning;
ch1_mpi 90 static int suspend_warning;
ch1_mpi 91
ch1_mpi 92
ch1_mpi 93 static void
ch1_mpi 94 print_warn(void)
ch1_mpi 95 {
ch1_mpi 96 if (!no_warning)
ch1_mpi 97 {
ch1_mpi 98 log_info("WARNING: using insecure memory!\n");
ch1_mpi 99 }
ch1_mpi 100 }
ch1_mpi 101
ch1_mpi 102
ch1_mpi 103 static void
ch1_mpi 104 lock_pool( void *p, size_t n )
ch1_mpi 105 {
ch1_mpi 106 #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
ch1_mpi 107 int err;
ch1_mpi 108
ch1_mpi 109 cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
ch1_mpi 110 err = mlock( p, n );
ch1_mpi 111 if( err && errno )
ch1_mpi 112 err = errno;
ch1_mpi 113 cap_set_proc( cap_from_text("cap_ipc_lock+p") );
ch1_mpi 114
ch1_mpi 115 if( err ) {
ch1_mpi 116 if( errno != EPERM
ch1_mpi 117 #ifdef EAGAIN /* OpenBSD returns this */
ch1_mpi 118 && errno != EAGAIN
ch1_mpi 119 #endif
ch1_mpi 120 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
ch1_mpi 121 && errno != ENOSYS
ch1_mpi 122 #endif
ch1_mpi 123 #ifdef ENOMEM /* Linux can return this */
ch1_mpi 124 && errno != ENOMEM
ch1_mpi 125 #endif
ch1_mpi 126 )
ch1_mpi 127 log_error("can't lock memory: %s\n", strerror(err));
ch1_mpi 128 show_warning = 1;
ch1_mpi 129 }
ch1_mpi 130
ch1_mpi 131 #elif defined(HAVE_MLOCK)
ch1_mpi 132 uid_t uid;
ch1_mpi 133 int err;
ch1_mpi 134
ch1_mpi 135 uid = getuid();
ch1_mpi 136
ch1_mpi 137 #ifdef HAVE_BROKEN_MLOCK
ch1_mpi 138 /* ick. but at least we get secured memory. about to lock
ch1_mpi 139 entire data segment. */
ch1_mpi 140 #ifdef HAVE_PLOCK
ch1_mpi 141 # ifdef _AIX
ch1_mpi 142 /* The configure for AIX returns broken mlock but the plock has
ch1_mpi 143 the strange requirement to somehow set the stack limit first.
ch1_mpi 144 The problem might turn out in indeterministic program behaviour
ch1_mpi 145 and hanging processes which can somehow be solved when enough
ch1_mpi 146 processes are clogging up the memory. To get this problem out
ch1_mpi 147 of the way we simply don't try to lock the memory at all.
ch1_mpi 148 */
ch1_mpi 149 errno = EPERM;
ch1_mpi 150 err = errno;
ch1_mpi 151 # else /* !_AIX */
ch1_mpi 152 err = plock( DATLOCK );
ch1_mpi 153 if( err && errno )
ch1_mpi 154 err = errno;
ch1_mpi 155 # endif /*_AIX*/
ch1_mpi 156 #else /*!HAVE_PLOCK*/
ch1_mpi 157 if( uid ) {
ch1_mpi 158 errno = EPERM;
ch1_mpi 159 err = errno;
ch1_mpi 160 }
ch1_mpi 161 else {
ch1_mpi 162 err = mlock( p, n );
ch1_mpi 163 if( err && errno )
ch1_mpi 164 err = errno;
ch1_mpi 165 }
ch1_mpi 166 #endif /*!HAVE_PLOCK*/
ch1_mpi 167 #else
ch1_mpi 168 err = mlock( p, n );
ch1_mpi 169 if( err && errno )
ch1_mpi 170 err = errno;
ch1_mpi 171 #endif
ch1_mpi 172
ch1_mpi 173 if( uid && !geteuid() ) {
ch1_mpi 174 /* check that we really dropped the privs.
ch1_mpi 175 * Note: setuid(0) should always fail */
ch1_mpi 176 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
ch1_mpi 177 log_fatal("failed to reset uid: %s\n", strerror(errno));
ch1_mpi 178 }
ch1_mpi 179
ch1_mpi 180 if( err ) {
ch1_mpi 181 if( errno != EPERM
ch1_mpi 182 #ifdef EAGAIN /* OpenBSD returns this */
ch1_mpi 183 && errno != EAGAIN
ch1_mpi 184 #endif
ch1_mpi 185 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
ch1_mpi 186 && errno != ENOSYS
ch1_mpi 187 #endif
ch1_mpi 188 #ifdef ENOMEM /* Linux can return this */
ch1_mpi 189 && errno != ENOMEM
ch1_mpi 190 #endif
ch1_mpi 191 )
ch1_mpi 192 log_error("can't lock memory: %s\n", strerror(err));
ch1_mpi 193 show_warning = 1;
ch1_mpi 194 }
ch1_mpi 195
ch1_mpi 196 #elif defined ( __QNX__ )
ch1_mpi 197 /* QNX does not page at all, so the whole secure memory stuff does
ch1_mpi 198 * not make much sense. However it is still of use because it
ch1_mpi 199 * wipes out the memory on a free().
ch1_mpi 200 * Therefore it is sufficient to suppress the warning
ch1_mpi 201 */
ch1_mpi 202 #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
ch1_mpi 203 /* It does not make sense to print such a warning, given the fact that
ch1_mpi 204 * this whole Windows !@#$% and their user base are inherently insecure
ch1_mpi 205 */
ch1_mpi 206 #else
ch1_mpi 207 log_info("Please note that you don't have secure memory on this system\n");
ch1_mpi 208 #endif
ch1_mpi 209 }
ch1_mpi 210
ch1_mpi 211
ch1_mpi 212 static void
ch1_mpi 213 init_pool( size_t n)
ch1_mpi 214 {
ch1_mpi 215 long int pgsize_val;
ch1_mpi 216 size_t pgsize;
ch1_mpi 217
ch1_mpi 218 poolsize = n;
ch1_mpi 219
ch1_mpi 220 if( disable_secmem )
ch1_mpi 221 log_bug("secure memory is disabled");
ch1_mpi 222
ch1_mpi 223 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
ch1_mpi 224 pgsize_val = sysconf (_SC_PAGESIZE);
ch1_mpi 225 #elif defined(HAVE_GETPAGESIZE)
ch1_mpi 226 pgsize_val = getpagesize ();
ch1_mpi 227 #else
ch1_mpi 228 pgsize_val = -1;
ch1_mpi 229 #endif
ch1_mpi 230 pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096;
ch1_mpi 231
ch1_mpi 232
ch1_mpi 233 #ifdef HAVE_MMAP
ch1_mpi 234 poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
ch1_mpi 235 #ifdef MAP_ANONYMOUS
ch1_mpi 236 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
ch1_mpi 237 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
ch1_mpi 238 #else /* map /dev/zero instead */
ch1_mpi 239 { int fd;
ch1_mpi 240
ch1_mpi 241 fd = open("/dev/zero", O_RDWR);
ch1_mpi 242 if( fd == -1 ) {
ch1_mpi 243 log_error("can't open /dev/zero: %s\n", strerror(errno) );
ch1_mpi 244 pool = (void*)-1;
ch1_mpi 245 }
ch1_mpi 246 else {
ch1_mpi 247 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
ch1_mpi 248 MAP_PRIVATE, fd, 0);
ch1_mpi 249 close (fd);
ch1_mpi 250 }
ch1_mpi 251 }
ch1_mpi 252 #endif
ch1_mpi 253 if( pool == (void*)-1 )
ch1_mpi 254 log_info("can't mmap pool of %u bytes: %s - using malloc\n",
ch1_mpi 255 (unsigned)poolsize, strerror(errno));
ch1_mpi 256 else {
ch1_mpi 257 pool_is_mmapped = 1;
ch1_mpi 258 pool_okay = 1;
ch1_mpi 259 }
ch1_mpi 260
ch1_mpi 261 #endif
ch1_mpi 262 if( !pool_okay ) {
ch1_mpi 263 pool = malloc( poolsize );
ch1_mpi 264 if( !pool )
ch1_mpi 265 log_fatal("can't allocate memory pool of %u bytes\n",
ch1_mpi 266 (unsigned)poolsize);
ch1_mpi 267 else
ch1_mpi 268 pool_okay = 1;
ch1_mpi 269 }
ch1_mpi 270 lock_pool( pool, poolsize );
ch1_mpi 271 poollen = 0;
ch1_mpi 272 }
ch1_mpi 273
ch1_mpi 274
ch1_mpi 275 /* concatenate unused blocks */
ch1_mpi 276 static void
ch1_mpi 277 compress_pool(void)
ch1_mpi 278 {
ch1_mpi 279 /* fixme: we really should do this */
ch1_mpi 280 }
ch1_mpi 281
ch1_mpi 282 void
ch1_mpi 283 secmem_set_flags( unsigned flags )
ch1_mpi 284 {
ch1_mpi 285 int was_susp = suspend_warning;
ch1_mpi 286
ch1_mpi 287 no_warning = flags & 1;
ch1_mpi 288 suspend_warning = flags & 2;
ch1_mpi 289
ch1_mpi 290 /* and now issue the warning if it is not longer suspended */
ch1_mpi 291 if( was_susp && !suspend_warning && show_warning ) {
ch1_mpi 292 show_warning = 0;
ch1_mpi 293 print_warn();
ch1_mpi 294 }
ch1_mpi 295 }
ch1_mpi 296
ch1_mpi 297 unsigned
ch1_mpi 298 secmem_get_flags(void)
ch1_mpi 299 {
ch1_mpi 300 unsigned flags;
ch1_mpi 301
ch1_mpi 302 flags = no_warning ? 1:0;
ch1_mpi 303 flags |= suspend_warning ? 2:0;
ch1_mpi 304 return flags;
ch1_mpi 305 }
ch1_mpi 306
ch1_mpi 307 /* Returns 1 if memory was locked, 0 if not. */
ch1_mpi 308 int
ch1_mpi 309 secmem_init( size_t n )
ch1_mpi 310 {
ch1_mpi 311 if( !n ) {
ch1_mpi 312 #ifdef USE_CAPABILITIES
ch1_mpi 313 /* drop all capabilities */
ch1_mpi 314 cap_set_proc( cap_from_text("all-eip") );
ch1_mpi 315 #elif !defined(HAVE_DOSISH_SYSTEM)
ch1_mpi 316 uid_t uid;
ch1_mpi 317 disable_secmem=1;
ch1_mpi 318 uid = getuid();
ch1_mpi 319 if( uid != geteuid() ) {
ch1_mpi 320 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
ch1_mpi 321 log_fatal("failed to drop setuid\n" );
ch1_mpi 322 }
ch1_mpi 323 #endif
ch1_mpi 324 }
ch1_mpi 325 else {
ch1_mpi 326 if( n < DEFAULT_POOLSIZE )
ch1_mpi 327 n = DEFAULT_POOLSIZE;
ch1_mpi 328 if( !pool_okay )
ch1_mpi 329 init_pool(n);
ch1_mpi 330 else
ch1_mpi 331 log_error("Oops, secure memory pool already initialized\n");
ch1_mpi 332 }
ch1_mpi 333
ch1_mpi 334 return !show_warning;
ch1_mpi 335 }
ch1_mpi 336
ch1_mpi 337
ch1_mpi 338 void *
ch1_mpi 339 secmem_malloc( size_t size )
ch1_mpi 340 {
ch1_mpi 341 MEMBLOCK *mb, *mb2;
ch1_mpi 342 int compressed=0;
ch1_mpi 343
ch1_mpi 344 if( !pool_okay ) {
ch1_mpi 345 log_info(
ch1_mpi 346 "operation is not possible without initialized secure memory\n");
ch1_mpi 347 log_info("(you may have used the wrong program for this task)\n");
ch1_mpi 348 exit(2);
ch1_mpi 349 }
ch1_mpi 350 if( show_warning && !suspend_warning ) {
ch1_mpi 351 show_warning = 0;
ch1_mpi 352 print_warn();
ch1_mpi 353 }
ch1_mpi 354
ch1_mpi 355 /* Blocks are always a multiple of 32. Note that we allocate an
ch1_mpi 356 extra of the size of an entire MEMBLOCK. This is required
ch1_mpi 357 becuase we do not only need the SIZE info but also extra space
ch1_mpi 358 to chain up unused memory blocks. */
ch1_mpi 359 size += sizeof(MEMBLOCK);
ch1_mpi 360 size = ((size + 31) / 32) * 32;
ch1_mpi 361
ch1_mpi 362 retry:
ch1_mpi 363 /* try to get it from the used blocks */
ch1_mpi 364 for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
ch1_mpi 365 if( mb->size >= size ) {
ch1_mpi 366 if( mb2 )
ch1_mpi 367 mb2->u.next = mb->u.next;
ch1_mpi 368 else
ch1_mpi 369 unused_blocks = mb->u.next;
ch1_mpi 370 goto leave;
ch1_mpi 371 }
ch1_mpi 372 /* allocate a new block */
ch1_mpi 373 if( (poollen + size <= poolsize) ) {
ch1_mpi 374 mb = (void*)((char*)pool + poollen);
ch1_mpi 375 poollen += size;
ch1_mpi 376 mb->size = size;
ch1_mpi 377 }
ch1_mpi 378 else if( !compressed ) {
ch1_mpi 379 compressed=1;
ch1_mpi 380 compress_pool();
ch1_mpi 381 goto retry;
ch1_mpi 382 }
ch1_mpi 383 else
ch1_mpi 384 return NULL;
ch1_mpi 385
ch1_mpi 386 leave:
ch1_mpi 387 cur_alloced += mb->size;
ch1_mpi 388 cur_blocks++;
ch1_mpi 389 if( cur_alloced > max_alloced )
ch1_mpi 390 max_alloced = cur_alloced;
ch1_mpi 391 if( cur_blocks > max_blocks )
ch1_mpi 392 max_blocks = cur_blocks;
ch1_mpi 393
ch1_mpi 394 return &mb->u.aligned.c;
ch1_mpi 395 }
ch1_mpi 396
ch1_mpi 397
ch1_mpi 398 void *
ch1_mpi 399 secmexrealloc( void *p, size_t newsize )
ch1_mpi 400 {
ch1_mpi 401 MEMBLOCK *mb;
ch1_mpi 402 size_t size;
ch1_mpi 403 void *a;
ch1_mpi 404
ch1_mpi 405 mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
ch1_mpi 406 size = mb->size;
ch1_mpi 407 if (size < sizeof(MEMBLOCK))
ch1_mpi 408 log_bug ("secure memory corrupted at block %p\n", (void *)mb);
ch1_mpi 409 size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
ch1_mpi 410
ch1_mpi 411 if( newsize <= size )
ch1_mpi 412 return p; /* It is easier not to shrink the memory. */
ch1_mpi 413 a = secmem_malloc( newsize );
ch1_mpi 414 if ( a ) {
ch1_mpi 415 memcpy(a, p, size);
ch1_mpi 416 memset((char*)a+size, 0, newsize-size);
ch1_mpi 417 secmem_free(p);
ch1_mpi 418 }
ch1_mpi 419 return a;
ch1_mpi 420 }
ch1_mpi 421
ch1_mpi 422
ch1_mpi 423 void
ch1_mpi 424 secmem_free( void *a )
ch1_mpi 425 {
ch1_mpi 426 MEMBLOCK *mb;
ch1_mpi 427 size_t size;
ch1_mpi 428
ch1_mpi 429 if( !a )
ch1_mpi 430 return;
ch1_mpi 431
ch1_mpi 432 mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
ch1_mpi 433 size = mb->size;
ch1_mpi 434 /* This does not make much sense: probably this memory is held in the
ch1_mpi 435 * cache. We do it anyway: */
ch1_mpi 436 wipememory2(mb, 0xff, size );
ch1_mpi 437 wipememory2(mb, 0xaa, size );
ch1_mpi 438 wipememory2(mb, 0x55, size );
ch1_mpi 439 wipememory2(mb, 0x00, size );
ch1_mpi 440 mb->size = size;
ch1_mpi 441 mb->u.next = unused_blocks;
ch1_mpi 442 unused_blocks = mb;
ch1_mpi 443 cur_blocks--;
ch1_mpi 444 cur_alloced -= size;
ch1_mpi 445 }
ch1_mpi 446
ch1_mpi 447
ch1_mpi 448 /* Check whether P points into the pool. */
ch1_mpi 449 static int
ch1_mpi 450 ptr_into_pool_p (const void *p)
ch1_mpi 451 {
ch1_mpi 452 /* We need to convert pointers to addresses. This is required by
ch1_mpi 453 C-99 6.5.8 to avoid undefined behaviour. Using size_t is at
ch1_mpi 454 least only implementation defined. See also
ch1_mpi 455 http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
ch1_mpi 456 */
ch1_mpi 457 size_t p_addr = (size_t)p;
ch1_mpi 458 size_t pool_addr = (size_t)pool;
ch1_mpi 459
ch1_mpi 460 return p_addr >= pool_addr && p_addr < pool_addr+poolsize;
ch1_mpi 461 }
ch1_mpi 462
ch1_mpi 463
ch1_mpi 464 int
ch1_mpi 465 m_is_secure( const void *p )
ch1_mpi 466 {
ch1_mpi 467 return pool_okay && ptr_into_pool_p (p);
ch1_mpi 468 }
ch1_mpi 469
ch1_mpi 470
ch1_mpi 471
ch1_mpi 472 /****************
ch1_mpi 473 * Warning: This code might be called by an interrupt handler
ch1_mpi 474 * and frankly, there should really be such a handler,
ch1_mpi 475 * to make sure that the memory is wiped out.
ch1_mpi 476 * We hope that the OS wipes out mlocked memory after
ch1_mpi 477 * receiving a SIGKILL - it really should do so, otherwise
ch1_mpi 478 * there is no chance to get the secure memory cleaned.
ch1_mpi 479 */
ch1_mpi 480 void
ch1_mpi 481 secmem_term()
ch1_mpi 482 {
ch1_mpi 483 if( !pool_okay )
ch1_mpi 484 return;
ch1_mpi 485
ch1_mpi 486 wipememory2( pool, 0xff, poolsize);
ch1_mpi 487 wipememory2( pool, 0xaa, poolsize);
ch1_mpi 488 wipememory2( pool, 0x55, poolsize);
ch1_mpi 489 wipememory2( pool, 0x00, poolsize);
ch1_mpi 490 #ifdef HAVE_MMAP
ch1_mpi 491 if( pool_is_mmapped )
ch1_mpi 492 munmap( pool, poolsize );
ch1_mpi 493 #endif
ch1_mpi 494 pool = NULL;
ch1_mpi 495 pool_okay = 0;
ch1_mpi 496 poolsize=0;
ch1_mpi 497 poollen=0;
ch1_mpi 498 unused_blocks=NULL;
ch1_mpi 499 }
ch1_mpi 500
ch1_mpi 501
ch1_mpi 502 void
ch1_mpi 503 secmem_dump_stats()
ch1_mpi 504 {
ch1_mpi 505 if( disable_secmem )
ch1_mpi 506 return;
ch1_mpi 507 fprintf(stderr,
ch1_mpi 508 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
ch1_mpi 509 cur_alloced, max_alloced, cur_blocks, max_blocks,
ch1_mpi 510 (ulong)poollen, (ulong)poolsize );
ch1_mpi 511 }