~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to util/secmem.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

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