/* Full initialization of this module. */ static void initialize(void) { /* Although the basic initialization should have happened already, we call it here to make sure that all prerequisites are met. */ initialize_basics (); /* Now we can look the pool and complete the initialization if necessary. */ lock_pool (); if (!rndpool) { /* The data buffer is allocated somewhat larger, so that we can use this extra space (which is allocated in secure memory) as a temporary hash buffer */ rndpool = (secure_alloc ? xcalloc_secure (1, POOLSIZE + BLOCKLEN) : xcalloc (1, POOLSIZE + BLOCKLEN)); keypool = (secure_alloc ? xcalloc_secure (1, POOLSIZE + BLOCKLEN) : xcalloc (1, POOLSIZE + BLOCKLEN)); /* Setup the slow entropy gathering function. The code requires that this function exists. */ slow_gather_fnc = getfnc_gather_random (); /* Setup the fast entropy gathering function. */ fast_gather_fnc = getfnc_fast_random_poll (); } unlock_pool (); }
/* ---------------------------------------------------------------------- * allocate an object from the pool. if there are free objects in * the pool, the allocation will happen immediately. otherwise, we * will sleep for up to 'timeout' microseconds waiting for an object * to be released. * * timeout of 0xffffffff means 'wait forever'; 0 means 'do not wait'. * * returns (opaque) pointer to the newly allocated object, or NULL on * failure (ie. even after 'timeout' there were still no free objects) * * a newly allocated object will have its reference count initialised * to 1. * -------------------------------------------------------------------- */ VC_POOL_OBJECT_T * vc_pool_alloc( VC_POOL_T *pool, size_t size, uint32_t timeout ) { VC_POOL_OBJECT_T *object; vcos_assert( pool->magic == POOL_MAGIC ); // wait for an object to become free for (;;) { lock_pool( pool ); object = alloc_object( pool, size ); unlock_pool( pool ); if ( object ) break; if ( wait_event(pool,timeout) ) { pool->alloc_fails++; return NULL; // timed out } } pool_object_logging( __FUNCTION__, object ); return object; }
/* Try to close the FDs of the random gather module. This is currently only implemented for rndlinux. */ void _gcry_rngcsprng_close_fds (void) { lock_pool (); #if USE_RNDLINUX _gcry_rndlinux_gather_random (NULL, 0, 0, 0); pool_filled = 0; /* Force re-open on next use. */ #endif unlock_pool (); }
/* ---------------------------------------------------------------------- * increase the refcount of a pool object * * return the new refcount * -------------------------------------------------------------------- */ int vc_pool_acquire( VC_POOL_OBJECT_T *object ) { vcos_assert( object->magic == OBJECT_MAGIC ); lock_pool( object->pool ); int refcount = ++object->refcount; pool_object_logging( __FUNCTION__, object ); unlock_pool( object->pool ); return refcount; }
/* Public function to fill the buffer with LENGTH bytes of cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is not very strong, GCRY_STRONG_RANDOM is strong enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but may be very slow. */ void _gcry_rngcsprng_randomize (void *buffer, size_t length, enum gcry_random_level level) { unsigned char *p; /* Make sure we are initialized. */ initialize (); /* Handle our hack used for regression tests of Libgcrypt. */ if ( quick_test && level > GCRY_STRONG_RANDOM ) level = GCRY_STRONG_RANDOM; /* Make sure the level is okay. */ level &= 3; #ifdef USE_RANDOM_DAEMON if (allow_daemon && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level)) return; /* The daemon succeeded. */ allow_daemon = 0; /* Daemon failed - switch off. */ #endif /*USE_RANDOM_DAEMON*/ /* Acquire the pool lock. */ lock_pool (); /* Update the statistics. */ if (level >= GCRY_VERY_STRONG_RANDOM) { rndstats.getbytes2 += length; rndstats.ngetbytes2++; } else { rndstats.getbytes1 += length; rndstats.ngetbytes1++; } /* Read the random into the provided buffer. */ for (p = buffer; length > 0;) { size_t n; n = length > POOLSIZE? POOLSIZE : length; read_pool (p, n, level); length -= n; p += n; } /* Release the pool lock. */ unlock_pool (); }
/* The fast random pool function as called at some places in libgcrypt. This is merely a wrapper to make sure that this module is initalized and to look the pool. Note, that this function is a NOP unless a random function has been used or _gcry_initialize (1) has been used. We use this hack so that the internal use of this function in cipher_open and md_open won't start filling up the random pool, even if no random will be required by the process. */ void _gcry_rngcsprng_fast_poll (void) { initialize_basics (); lock_pool (); if (rndpool) { /* Yes, we are fully initialized. */ do_fast_random_poll (); } unlock_pool (); }
/** * Delete a queue. * * Free a whole queue. * @param queue - The queue to free. */ void queue_delete(T_QUEUE queue, OS_ERR_TYPE* err) { OS_ERR_TYPE _err; queue_impl_t * q = (queue_impl_t*) queue; T_EXEC_LEVEL execLvl = _getExecLevel(); uint32_t data; T_QUEUE_MESSAGE p_msg = &data; /* check execution level */ if ((E_EXEC_LVL_FIBER == execLvl) || (E_EXEC_LVL_TASK == execLvl)) { lock_pool(); if (queue_used(q) && q->sema != NULL) { /* first empty the queue before to delete it to free all the elements */ do{ queue_get_message(q, &p_msg, OS_NO_WAIT, &_err); }while(_err == E_OS_OK); if(_err == E_OS_ERR_EMPTY) { semaphore_delete(q->sema, &_err); q->sema = NULL; if( _err == E_OS_OK) { queue_free(q); error_management (err, E_OS_OK); } else { panic(E_OS_ERR_UNKNOWN); // Panic because we should never reach this point. } } else { error_management (err, E_OS_ERR); } } else { error_management (err, E_OS_ERR); } unlock_pool(); } else { error_management (err, E_OS_ERR_NOT_ALLOWED); } return; }
/* ---------------------------------------------------------------------- * decrease the refcount of a pool object. if the refcount hits 0, * the object is treated as being returned to the pool as free; update * pool struct accordingly (and potentially wakeup any sleepers) * * return the new refcount * -------------------------------------------------------------------- */ int vc_pool_release( VC_POOL_OBJECT_T *object ) { vcos_assert( object->magic == OBJECT_MAGIC ); lock_pool( object->pool ); int refcount = --object->refcount; pool_object_logging( __FUNCTION__, object ); if ( refcount == 0 ) { free_object( object ); signal_event( object->pool ); } unlock_pool( object->pool ); return refcount; }
/** * @brief Get a buffer from the pool * * @param bphp Pointer to buffer pool handle structure. * @return Pointer to a buffer reference structure. * */ BPCF_BUFFER_REF* mmpool_getbuff(BPOOL_HANDLE* bphp) { BPCF_BUFFER_REF* buff_refp = NULL; BPOOL_INDEX bpx; lock_pool(bphp); if (!dq_rtd(&bphp->bpmf_recp->dq_inpool, &bpx)) { // Get reference to the buffer buff_refp = mmpool_buffx2refp(bphp, bpx); // Add the buffer to the out of pool deque dq_abd(&bphp->bpmf_recp->dq_outpool, &bpx); bphp->bpmf_recp->stats.remaining--; } unlock_pool(bphp); return buff_refp; }
/* ---------------------------------------------------------------------- * destroy a pool of objects. if none of the pool objects are in use, * the destroy will happen immediately. otherwise, we will sleep for * up to 'timeout' microseconds waiting for the objects to be released. * * timeout of 0xffffffff means 'wait forever'; 0 means 'do not wait'. * * returns 0 on success, -1 on error (ie. even after 'timeout' there * were still objects in use) * -------------------------------------------------------------------- */ int32_t vc_pool_destroy( VC_POOL_T *pool, uint32_t timeout ) { int i; vcos_assert( pool->magic == POOL_MAGIC ); // wait for all objects to become free for (;;) { lock_pool( pool ); if ( pool->allocated == 0 ) break; unlock_pool( pool ); if ( wait_event(pool,timeout) ) return -1; // timed out } if ( pool->mem != MEM_INVALID_HANDLE ) { // just a single memory object to free mem_release( pool->mem ); } else { // release individual pool entries back to mempool for (i=0; i<pool->nobjects; i++) mem_release( pool->object[i].mem ); } // remove from the global list rtos_latch_get(&pool_list_latch); VC_POOL_T **pp = &vc_pool_list; while (*pp != pool) { pp = &((*pp)->next); } vcos_assert(*pp); *pp = pool->next; rtos_latch_put(&pool_list_latch); // kill the pool struct pool->magic = 0; destroy_event( pool ); rtos_priorityfree( pool ); return 0; }
/** * @brief Return a buffer to the pool. * * @param bphp Pointer to buffer pool handle structure. * @param buffp Pointer to buffer reference structure of buffer to return * @return Pointer to a buffer reference structure. * @return 0 if successful, non-zero error code otherwise. */ int mmpool_putbuff(BPOOL_HANDLE* bphp, BPCF_BUFFER_REF* buffp) { int error = 0; lock_pool(bphp); /* * Search the out of pool deque for the item. */ if (search_deque(&bphp->bpmf_recp->dq_outpool, buffp->bpindex)) { // Found a match ... do the deallocation. dq_abd(&bphp->bpmf_recp->dq_inpool, &buffp->bpindex); bphp->bpmf_recp->stats.remaining++; } else { // The buffer pool index of the passed reference is NOT // in use ... this is an error condition error = 1; } unlock_pool(bphp); return error; }
/** * Create a message queue. * * Create a message queue. * This service may panic if err parameter is NULL and: * -# no queue is available, or * -# when called from an ISR. * * Authorized execution levels: task, fiber. * * As for semaphores and mutexes, queues are picked from a pool of * statically-allocated objects. * * @param maxSize: maximum number of messages in the queue. * (Rationale: queues only contain pointer to messages) * * @param err (out): execution status: * -# E_OS_OK : queue was created * -# E_OS_ERR: all queues from the pool are already being used * -# E_OS_ERR_NOT_ALLOWED: service cannot be executed from ISR context. * * @return Handler on the created queue. * NULL if all allocated queues are already being used. */ T_QUEUE queue_create(uint32_t max_size, OS_ERR_TYPE* err) { queue_impl_t * q = NULL; T_EXEC_LEVEL execLvl = _getExecLevel(); OS_ERR_TYPE _err; if(max_size==0 || max_size>QUEUE_ELEMENT_POOL_SIZE) { error_management (err, E_OS_ERR); return NULL; } /* check execution level */ if ((E_EXEC_LVL_FIBER == execLvl) || (E_EXEC_LVL_TASK == execLvl)) { /* Block concurrent accesses to the pool of queue_list */ lock_pool(); q = queue_alloc(); unlock_pool(); if (q != NULL) { list_init(&q->_list); // replace the following commented code q->current_size = 0; q->max_size = max_size; q->sema = semaphore_create(0, &_err); error_management (err, _err); } else { error_management (err, E_OS_ERR); } } else { error_management (err, E_OS_ERR_NOT_ALLOWED); } return (T_QUEUE)q; }
/* See _gcry_secmem_init. This function is expected to be called with the secmem lock held. */ static void secmem_init (size_t n) { if (!n) { #ifdef USE_CAPABILITIES /* drop all capabilities */ { cap_t cap; cap = cap_from_text ("all-eip"); cap_set_proc (cap); cap_free (cap); } #elif !defined(HAVE_DOSISH_SYSTEM) uid_t uid; disable_secmem = 1; uid = getuid (); if (uid != geteuid ()) { if (setuid (uid) || getuid () != geteuid () || !setuid (0)) log_fatal ("failed to drop setuid\n"); } #endif } else { if (n < MINIMUM_POOL_SIZE) n = MINIMUM_POOL_SIZE; if (! pool_okay) { init_pool (n); lock_pool (pool, n); } else log_error ("Oops, secure memory pool already initialized\n"); } }
/* Initialize the secure memory system. If running with the necessary privileges, the secure memory pool will be locked into the core in order to prevent page-outs of the data. Furthermore allocated secure memory will be wiped out when released. */ void _gcry_secmem_init (size_t n) { SECMEM_LOCK; if (!n) { #ifdef USE_CAPABILITIES /* drop all capabilities */ cap_set_proc (cap_from_text ("all-eip")); #elif !defined(HAVE_DOSISH_SYSTEM) uid_t uid; disable_secmem = 1; uid = getuid (); if (uid != geteuid ()) { if (setuid (uid) || getuid () != geteuid () || !setuid (0)) log_fatal ("failed to drop setuid\n"); } #endif } else { if (n < DEFAULT_POOL_SIZE) n = DEFAULT_POOL_SIZE; if (! pool_okay) { init_pool (n); lock_pool (pool, n); } else log_error ("Oops, secure memory pool already initialized\n"); } SECMEM_UNLOCK; }
/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY should be in the range of 0..100 to indicate the goodness of the entropy added, or -1 for goodness not known. */ gcry_error_t _gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, int quality) { size_t nbytes; const char *bufptr; if (quality == -1) quality = 35; else if (quality > 100) quality = 100; else if (quality < 0) quality = 0; if (!buf) return gpg_error (GPG_ERR_INV_ARG); if (!buflen || quality < 10) return 0; /* Take a shortcut. */ /* Because we don't increment the entropy estimation with FASTPOLL, we don't need to take lock that estimation while adding from an external source. This limited entropy estimation also means that we can't take QUALITY into account. */ initialize_basics (); bufptr = buf; while (buflen) { nbytes = buflen > POOLSIZE? POOLSIZE : buflen; lock_pool (); if (rndpool) add_randomness (bufptr, nbytes, RANDOM_ORIGIN_EXTERNAL); unlock_pool (); bufptr += nbytes; buflen -= nbytes; } return 0; }
static void init_pool( size_t n) { long int pgsize_val; size_t pgsize; poolsize = n; if( disable_secmem ) log_bug("secure memory is disabled"); #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) pgsize_val = sysconf (_SC_PAGESIZE); #elif defined(HAVE_GETPAGESIZE) pgsize_val = getpagesize (); #else pgsize_val = -1; #endif pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096; #ifdef HAVE_MMAP poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1); #ifdef MAP_ANONYMOUS pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); #else /* map /dev/zero instead */ { int fd; fd = open("/dev/zero", O_RDWR); if( fd == -1 ) { log_error("can't open /dev/zero: %s\n", strerror(errno) ); pool = (void*)-1; } else { pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); close (fd); } } #endif if( pool == (void*)-1 ) log_info("can't mmap pool of %u bytes: %s - using malloc\n", (unsigned)poolsize, strerror(errno)); else { pool_is_mmapped = 1; pool_okay = 1; } #endif if( !pool_okay ) { pool = malloc( poolsize ); if( !pool ) log_fatal("can't allocate memory pool of %u bytes\n", (unsigned)poolsize); else pool_okay = 1; } lock_pool( pool, poolsize ); poollen = 0; }
void _gcry_rngcsprng_update_seed_file (void) { unsigned long *sp, *dp; int fd, i; /* We do only a basic initialization so that we can lock the pool. This is required to cope with the case that this function is called by some cleanup code at a point where the RNG has never been initialized. */ initialize_basics (); lock_pool (); if ( !seed_file_name || !rndpool || !pool_filled ) { unlock_pool (); return; } if ( !allow_seed_file_update ) { unlock_pool (); log_info(_("note: random_seed file not updated\n")); return; } /* At this point we know that there is something in the pool and thus we can conclude that the pool has been fully initialized. */ /* Copy the entropy pool to a scratch pool and mix both of them. */ for (i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool; i < POOLWORDS; i++, dp++, sp++ ) { *dp = *sp + ADD_VALUE; } mix_pool(rndpool); rndstats.mixrnd++; mix_pool(keypool); rndstats.mixkey++; #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__) fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR ); #else # if LOCK_SEED_FILE fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR ); # else fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR ); # endif #endif if (fd == -1 ) log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) ); else if (lock_seed_file (fd, seed_file_name, 1)) { close (fd); } #if LOCK_SEED_FILE else if (ftruncate (fd, 0)) { log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno)); close (fd); } #endif /*LOCK_SEED_FILE*/ else { do { i = write (fd, keypool, POOLSIZE ); } while (i == -1 && errno == EINTR); if (i != POOLSIZE) log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno)); if (close(fd)) log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno)); } unlock_pool (); }