Secure-memory initialization leaves Linux capabilities active
In USE_CAPABILITIES builds, the only capability-clearing code is in the zero-size secure-memory branch. The documented, normal GCRYCTL_INIT_SECMEM call uses a nonzero pool size, locks the pool, and returns without dropping capabilities. A file- or ambient-capability process whose real and effective UIDs are equal therefore retains all effective and permitted kernel authority.
Vulnerable code
src/secmem.c, _gcry_secmem_init_internal:
c
if (!n)
{
#ifdef USE_CAPABILITIES
/* drop all capabilities */
if (!no_priv_drop)
{
cap_t cap;
cap = cap_from_text ("all-eip");
cap_set_proc (cap);
cap_free (cap);
}The ordinary path never reaches that block:
c
else
{
if (n < MINIMUM_POOL_SIZE)
n = MINIMUM_POOL_SIZE;
if (! pool->okay)
{
init_pool (pool, n);
lock_pool_pages (pool->mem, n);
}Why it matters
lock_pool_pages only performs a UID drop for the classic uid != 0 && geteuid() == 0 case. It does nothing to capability sets when real and effective UIDs match. Code running after initialization thus keeps not only CAP_IPC_LOCK, but any unrelated capabilities granted to the process, increasing the impact of a later memory-safety or command-execution flaw. The issue requires the optional --with-capabilities build and a capability-bearing application; it does not grant privileges to an otherwise unprivileged process.
Proposed fix
After the pool is locked on the nonzero path, clear effective, permitted, and inheritable capability sets unless GCRYCTL_DISABLE_PRIV_DROP was explicitly used. Check cap_from_text, cap_set_proc, and post-drop state, and fail initialization if dropping fails. Add a Linux namespace integration test that starts with a harmless capability, performs nonzero secure-memory initialization, and verifies empty CapEff, CapPrm, and CapInh sets afterward.