-
+ 2B787A241AB819008B23B6235AEC68EA7EA5DC092859FF42FFE50A7BD00D710F39547E35EE66449377FE70BDD870F7BD4B40B7EDE228F6842671C5E167183493
smg_comms/mpi/secmem.c
(0 . 0)(1 . 511)
7863 /* secmem.c - memory allocation from a secure heap
7864 * Modified by No Such Labs. (C) 2015. See README.
7865 *
7866 * This file was originally part of Gnu Privacy Guard (GPG), ver. 1.4.10,
7867 * SHA256(gnupg-1.4.10.tar.gz):
7868 * 0bfd74660a2f6cedcf7d8256db4a63c996ffebbcdc2cf54397bfb72878c5a85a
7869 * (C) 1994-2005 Free Software Foundation, Inc.
7870 *
7871 * This program is free software: you can redistribute it and/or modify
7872 * it under the terms of the GNU General Public License as published by
7873 * the Free Software Foundation, either version 3 of the License, or
7874 * (at your option) any later version.
7875 *
7876 * This program is distributed in the hope that it will be useful,
7877 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7878 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7879 * GNU General Public License for more details.
7880 *
7881 * You should have received a copy of the GNU General Public License
7882 * along with this program. If not, see <http://www.gnu.org/licenses/>.
7883 */
7884
7885 #include "knobs.h"
7886
7887 #include <stdio.h>
7888 #include <stdlib.h>
7889 #include <string.h>
7890 #include <errno.h>
7891 #include <stdarg.h>
7892 #include <unistd.h>
7893 #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
7894 #include <sys/mman.h>
7895 #include <sys/types.h>
7896 #include <fcntl.h>
7897 #ifdef USE_CAPABILITIES
7898 #include <sys/capability.h>
7899 #endif
7900 #ifdef HAVE_PLOCK
7901 #include <sys/lock.h>
7902 #endif
7903 #endif
7904
7905 #include "types.h"
7906 #include "memory.h"
7907 #include "util.h"
7908
7909 /* MinGW doesn't seem to prototype getpagesize, though it does have
7910 it. */
7911 #if !HAVE_DECL_GETPAGESIZE
7912 int getpagesize(void);
7913 #endif
7914
7915 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
7916 #define MAP_ANONYMOUS MAP_ANON
7917 #endif
7918 /* It seems that Slackware 7.1 does not know about EPERM */
7919 #if !defined(EPERM) && defined(ENOMEM)
7920 #define EPERM ENOMEM
7921 #endif
7922
7923
7924 #define DEFAULT_POOLSIZE 16384
7925
7926 typedef struct memblock_struct MEMBLOCK;
7927 struct memblock_struct {
7928 unsigned size;
7929 union {
7930 MEMBLOCK *next;
7931 PROPERLY_ALIGNED_TYPE aligned;
7932 } u;
7933 };
7934
7935
7936
7937 static void *pool;
7938 static volatile int pool_okay; /* may be checked in an atexit function */
7939 #ifdef HAVE_MMAP
7940 static volatile int pool_is_mmapped;
7941 #endif
7942 static size_t poolsize; /* allocated length */
7943 static size_t poollen; /* used length */
7944 static MEMBLOCK *unused_blocks;
7945 static unsigned max_alloced;
7946 static unsigned cur_alloced;
7947 static unsigned max_blocks;
7948 static unsigned cur_blocks;
7949 static int disable_secmem;
7950 static int show_warning;
7951 static int no_warning;
7952 static int suspend_warning;
7953
7954
7955 static void
7956 print_warn(void)
7957 {
7958 if (!no_warning)
7959 {
7960 log_info("WARNING: using insecure memory!\n");
7961 }
7962 }
7963
7964
7965 static void
7966 lock_pool( void *p, size_t n )
7967 {
7968 #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
7969 int err;
7970
7971 cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
7972 err = mlock( p, n );
7973 if( err && errno )
7974 err = errno;
7975 cap_set_proc( cap_from_text("cap_ipc_lock+p") );
7976
7977 if( err ) {
7978 if( errno != EPERM
7979 #ifdef EAGAIN /* OpenBSD returns this */
7980 && errno != EAGAIN
7981 #endif
7982 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
7983 && errno != ENOSYS
7984 #endif
7985 #ifdef ENOMEM /* Linux can return this */
7986 && errno != ENOMEM
7987 #endif
7988 )
7989 log_error("can't lock memory: %s\n", strerror(err));
7990 show_warning = 1;
7991 }
7992
7993 #elif defined(HAVE_MLOCK)
7994 uid_t uid;
7995 int err;
7996
7997 uid = getuid();
7998
7999 #ifdef HAVE_BROKEN_MLOCK
8000 /* ick. but at least we get secured memory. about to lock
8001 entire data segment. */
8002 #ifdef HAVE_PLOCK
8003 # ifdef _AIX
8004 /* The configure for AIX returns broken mlock but the plock has
8005 the strange requirement to somehow set the stack limit first.
8006 The problem might turn out in indeterministic program behaviour
8007 and hanging processes which can somehow be solved when enough
8008 processes are clogging up the memory. To get this problem out
8009 of the way we simply don't try to lock the memory at all.
8010 */
8011 errno = EPERM;
8012 err = errno;
8013 # else /* !_AIX */
8014 err = plock( DATLOCK );
8015 if( err && errno )
8016 err = errno;
8017 # endif /*_AIX*/
8018 #else /*!HAVE_PLOCK*/
8019 if( uid ) {
8020 errno = EPERM;
8021 err = errno;
8022 }
8023 else {
8024 err = mlock( p, n );
8025 if( err && errno )
8026 err = errno;
8027 }
8028 #endif /*!HAVE_PLOCK*/
8029 #else
8030 err = mlock( p, n );
8031 if( err && errno )
8032 err = errno;
8033 #endif
8034
8035 if( uid && !geteuid() ) {
8036 /* check that we really dropped the privs.
8037 * Note: setuid(0) should always fail */
8038 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
8039 log_fatal("failed to reset uid: %s\n", strerror(errno));
8040 }
8041
8042 if( err ) {
8043 if( errno != EPERM
8044 #ifdef EAGAIN /* OpenBSD returns this */
8045 && errno != EAGAIN
8046 #endif
8047 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
8048 && errno != ENOSYS
8049 #endif
8050 #ifdef ENOMEM /* Linux can return this */
8051 && errno != ENOMEM
8052 #endif
8053 )
8054 log_error("can't lock memory: %s\n", strerror(err));
8055 show_warning = 1;
8056 }
8057
8058 #elif defined ( __QNX__ )
8059 /* QNX does not page at all, so the whole secure memory stuff does
8060 * not make much sense. However it is still of use because it
8061 * wipes out the memory on a free().
8062 * Therefore it is sufficient to suppress the warning
8063 */
8064 #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
8065 /* It does not make sense to print such a warning, given the fact that
8066 * this whole Windows !@#$% and their user base are inherently insecure
8067 */
8068 #else
8069 log_info("Please note that you don't have secure memory on this system\n");
8070 #endif
8071 }
8072
8073
8074 static void
8075 init_pool( size_t n)
8076 {
8077 long int pgsize_val;
8078 size_t pgsize;
8079
8080 poolsize = n;
8081
8082 if( disable_secmem )
8083 log_bug("secure memory is disabled");
8084
8085 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
8086 pgsize_val = sysconf (_SC_PAGESIZE);
8087 #elif defined(HAVE_GETPAGESIZE)
8088 pgsize_val = getpagesize ();
8089 #else
8090 pgsize_val = -1;
8091 #endif
8092 pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096;
8093
8094
8095 #ifdef HAVE_MMAP
8096 poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
8097 #ifdef MAP_ANONYMOUS
8098 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
8099 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
8100 #else /* map /dev/zero instead */
8101 { int fd;
8102
8103 fd = open("/dev/zero", O_RDWR);
8104 if( fd == -1 ) {
8105 log_error("can't open /dev/zero: %s\n", strerror(errno) );
8106 pool = (void*)-1;
8107 }
8108 else {
8109 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
8110 MAP_PRIVATE, fd, 0);
8111 close (fd);
8112 }
8113 }
8114 #endif
8115 if( pool == (void*)-1 )
8116 log_info("can't mmap pool of %u bytes: %s - using malloc\n",
8117 (unsigned)poolsize, strerror(errno));
8118 else {
8119 pool_is_mmapped = 1;
8120 pool_okay = 1;
8121 }
8122
8123 #endif
8124 if( !pool_okay ) {
8125 pool = malloc( poolsize );
8126 if( !pool )
8127 log_fatal("can't allocate memory pool of %u bytes\n",
8128 (unsigned)poolsize);
8129 else
8130 pool_okay = 1;
8131 }
8132 lock_pool( pool, poolsize );
8133 poollen = 0;
8134 }
8135
8136
8137 /* concatenate unused blocks */
8138 static void
8139 compress_pool(void)
8140 {
8141 /* fixme: we really should do this */
8142 }
8143
8144 void
8145 secmem_set_flags( unsigned flags )
8146 {
8147 int was_susp = suspend_warning;
8148
8149 no_warning = flags & 1;
8150 suspend_warning = flags & 2;
8151
8152 /* and now issue the warning if it is not longer suspended */
8153 if( was_susp && !suspend_warning && show_warning ) {
8154 show_warning = 0;
8155 print_warn();
8156 }
8157 }
8158
8159 unsigned
8160 secmem_get_flags(void)
8161 {
8162 unsigned flags;
8163
8164 flags = no_warning ? 1:0;
8165 flags |= suspend_warning ? 2:0;
8166 return flags;
8167 }
8168
8169 /* Returns 1 if memory was locked, 0 if not. */
8170 int
8171 secmem_init( size_t n )
8172 {
8173 if( !n ) {
8174 #ifdef USE_CAPABILITIES
8175 /* drop all capabilities */
8176 cap_set_proc( cap_from_text("all-eip") );
8177 #elif !defined(HAVE_DOSISH_SYSTEM)
8178 uid_t uid;
8179 disable_secmem=1;
8180 uid = getuid();
8181 if( uid != geteuid() ) {
8182 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
8183 log_fatal("failed to drop setuid\n" );
8184 }
8185 #endif
8186 }
8187 else {
8188 if( n < DEFAULT_POOLSIZE )
8189 n = DEFAULT_POOLSIZE;
8190 if( !pool_okay )
8191 init_pool(n);
8192 else
8193 log_error("Oops, secure memory pool already initialized\n");
8194 }
8195
8196 return !show_warning;
8197 }
8198
8199
8200 void *
8201 secmem_malloc( size_t size )
8202 {
8203 MEMBLOCK *mb, *mb2;
8204 int compressed=0;
8205
8206 if( !pool_okay ) {
8207 log_info(
8208 "operation is not possible without initialized secure memory\n");
8209 log_info("(you may have used the wrong program for this task)\n");
8210 exit(2);
8211 }
8212 if( show_warning && !suspend_warning ) {
8213 show_warning = 0;
8214 print_warn();
8215 }
8216
8217 /* Blocks are always a multiple of 32. Note that we allocate an
8218 extra of the size of an entire MEMBLOCK. This is required
8219 becuase we do not only need the SIZE info but also extra space
8220 to chain up unused memory blocks. */
8221 size += sizeof(MEMBLOCK);
8222 size = ((size + 31) / 32) * 32;
8223
8224 retry:
8225 /* try to get it from the used blocks */
8226 for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
8227 if( mb->size >= size ) {
8228 if( mb2 )
8229 mb2->u.next = mb->u.next;
8230 else
8231 unused_blocks = mb->u.next;
8232 goto leave;
8233 }
8234 /* allocate a new block */
8235 if( (poollen + size <= poolsize) ) {
8236 mb = (void*)((char*)pool + poollen);
8237 poollen += size;
8238 mb->size = size;
8239 }
8240 else if( !compressed ) {
8241 compressed=1;
8242 compress_pool();
8243 goto retry;
8244 }
8245 else
8246 return NULL;
8247
8248 leave:
8249 cur_alloced += mb->size;
8250 cur_blocks++;
8251 if( cur_alloced > max_alloced )
8252 max_alloced = cur_alloced;
8253 if( cur_blocks > max_blocks )
8254 max_blocks = cur_blocks;
8255
8256 return &mb->u.aligned.c;
8257 }
8258
8259
8260 void *
8261 secmexrealloc( void *p, size_t newsize )
8262 {
8263 MEMBLOCK *mb;
8264 size_t size;
8265 void *a;
8266
8267 mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
8268 size = mb->size;
8269 if (size < sizeof(MEMBLOCK))
8270 log_bug ("secure memory corrupted at block %p\n", (void *)mb);
8271 size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
8272
8273 if( newsize <= size )
8274 return p; /* It is easier not to shrink the memory. */
8275 a = secmem_malloc( newsize );
8276 if ( a ) {
8277 memcpy(a, p, size);
8278 memset((char*)a+size, 0, newsize-size);
8279 secmem_free(p);
8280 }
8281 return a;
8282 }
8283
8284
8285 void
8286 secmem_free( void *a )
8287 {
8288 MEMBLOCK *mb;
8289 size_t size;
8290
8291 if( !a )
8292 return;
8293
8294 mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
8295 size = mb->size;
8296 /* This does not make much sense: probably this memory is held in the
8297 * cache. We do it anyway: */
8298 wipememory2(mb, 0xff, size );
8299 wipememory2(mb, 0xaa, size );
8300 wipememory2(mb, 0x55, size );
8301 wipememory2(mb, 0x00, size );
8302 mb->size = size;
8303 mb->u.next = unused_blocks;
8304 unused_blocks = mb;
8305 cur_blocks--;
8306 cur_alloced -= size;
8307 }
8308
8309
8310 /* Check whether P points into the pool. */
8311 static int
8312 ptr_into_pool_p (const void *p)
8313 {
8314 /* We need to convert pointers to addresses. This is required by
8315 C-99 6.5.8 to avoid undefined behaviour. Using size_t is at
8316 least only implementation defined. See also
8317 http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
8318 */
8319 size_t p_addr = (size_t)p;
8320 size_t pool_addr = (size_t)pool;
8321
8322 return p_addr >= pool_addr && p_addr < pool_addr+poolsize;
8323 }
8324
8325
8326 int
8327 m_is_secure( const void *p )
8328 {
8329 return pool_okay && ptr_into_pool_p (p);
8330 }
8331
8332
8333
8334 /****************
8335 * Warning: This code might be called by an interrupt handler
8336 * and frankly, there should really be such a handler,
8337 * to make sure that the memory is wiped out.
8338 * We hope that the OS wipes out mlocked memory after
8339 * receiving a SIGKILL - it really should do so, otherwise
8340 * there is no chance to get the secure memory cleaned.
8341 */
8342 void
8343 secmem_term()
8344 {
8345 if( !pool_okay )
8346 return;
8347
8348 wipememory2( pool, 0xff, poolsize);
8349 wipememory2( pool, 0xaa, poolsize);
8350 wipememory2( pool, 0x55, poolsize);
8351 wipememory2( pool, 0x00, poolsize);
8352 #ifdef HAVE_MMAP
8353 if( pool_is_mmapped )
8354 munmap( pool, poolsize );
8355 #endif
8356 pool = NULL;
8357 pool_okay = 0;
8358 poolsize=0;
8359 poollen=0;
8360 unused_blocks=NULL;
8361 }
8362
8363
8364 void
8365 secmem_dump_stats()
8366 {
8367 if( disable_secmem )
8368 return;
8369 fprintf(stderr,
8370 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
8371 cur_alloced, max_alloced, cur_blocks, max_blocks,
8372 (ulong)poollen, (ulong)poolsize );
8373 }