/* t-secmem.c - Test the secmem memory allocator
* Copyright (C) 2016 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#define PGM "t-secmem"
#include "t-common.h"
#include "../src/gcrypt-testapi.h"
#define DEFAULT_PAGE_SIZE 4096
#define MINIMUM_POOL_SIZE 16384
static size_t pool_size;
static size_t chunk_size;
static void
test_secmem (void)
{
void *a[28];
void *b;
int i;
memset (a, 0, sizeof a);
/* Allocating 28*512=14k should work in the default 16k pool even
* with extra alignment requirements. */
for (i=0; i < DIM(a); i++)
a[i] = gcry_xmalloc_secure (chunk_size);
/* Allocating another 2k should fail for the default 16k pool. */
b = gcry_malloc_secure (chunk_size*4);
if (b)
fail ("allocation did not fail as expected\n");
for (i=0; i < DIM(a); i++)
xfree (a[i]);
xfree (b);
}
static void
test_secmem_overflow (void)
{
void *a[150];
int i;
memset (a, 0, sizeof a);
/* Allocating 150*512=75k should require more than one overflow buffer. */
for (i=0; i < DIM(a); i++)
{
a[i] = gcry_xmalloc_secure (chunk_size);
if (verbose && !(i %40))
xgcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
}
if (debug)
xgcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
if (verbose)
xgcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
for (i=0; i < DIM(a); i++)
xfree (a[i]);
}
/* This function is called when we ran out of core and there is no way
* to return that error to the caller (xmalloc or mpi allocation). */
static int
outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
{
static int been_here; /* Used to protect against recursive calls. */
(void)opaque;
/* Protect against a second call. */
if (been_here)
return 0; /* Let libgcrypt call its own fatal error handler. */
been_here = 1;
info ("outofcore handler invoked");
xgcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
fail ("out of core%s while allocating %lu bytes",
(flags & 1)?" in secure memory":"", (unsigned long)req_n);
die ("stopped");
/*NOTREACHED*/
return 0;
}
int
main (int argc, char **argv)
{
int last_argc = -1;
long int pgsize_val = -1;
size_t pgsize;
#if HAVE_MMAP
# if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
pgsize_val = sysconf (_SC_PAGESIZE);
# elif defined(HAVE_GETPAGESIZE)
pgsize_val = getpagesize ();
# endif
#endif
pgsize = (pgsize_val > 0)? pgsize_val : DEFAULT_PAGE_SIZE;
pool_size = (MINIMUM_POOL_SIZE + pgsize - 1) & ~(pgsize - 1);
chunk_size = pool_size / 32;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--help"))
{
fputs ("usage: " PGM " [options]\n"
"Options:\n"
" --verbose print timings etc.\n"
" --debug flyswatter\n"
, stdout);
exit (0);
}
else if (!strcmp (*argv, "--verbose"))
{
verbose++;
argc--; argv++;
}
else if (!strcmp (*argv, "--debug"))
{
verbose += 2;
debug++;
argc--; argv++;
}
else if (!strncmp (*argv, "--", 2))
die ("unknown option '%s'", *argv);
}
if (!gcry_check_version (GCRYPT_VERSION))
die ("version mismatch; pgm=%s, library=%s\n",
GCRYPT_VERSION, gcry_check_version (NULL));
if (debug)
xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
xgcry_control (GCRYCTL_INIT_SECMEM, pool_size, 0);
gcry_set_outofcore_handler (outofcore_handler, NULL);
xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
/* Libgcrypt prints a warning when the first overflow is allocated;
* we do not want to see that. */
if (!verbose)
xgcry_control (GCRYCTL_DISABLE_SECMEM_WARN, 0);
test_secmem ();
test_secmem_overflow ();
/* FIXME: We need to improve the tests, for example by registering
* our own log handler and comparing the output of
* PRIV_CTL_DUMP_SECMEM_STATS to expected pattern. */
if (verbose)
{
xgcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
xgcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
}
info ("All tests completed. Errors: %d\n", error_count);
xgcry_control (GCRYCTL_TERM_SECMEM, 0 , 0);
return !!error_count;
}