Add control commands to disable mlock and setuid dropping.
authorWerner Koch <wk@gnupg.org>
Thu, 18 Apr 2013 12:40:43 +0000 (14:40 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 22 May 2013 15:59:29 +0000 (17:59 +0200)
* src/gcrypt.h.in (GCRYCTL_DISABLE_LOCKED_SECMEM): New.
(GCRYCTL_DISABLE_PRIV_DROP): New.
* src/global.c (_gcry_vcontrol): Implement them.
* src/secmem.h (GCRY_SECMEM_FLAG_NO_MLOCK): New.
(GCRY_SECMEM_FLAG_NO_PRIV_DROP): New.
* src/secmem.c (no_mlock, no_priv_drop): New.
(_gcry_secmem_set_flags, _gcry_secmem_get_flags): Set and get them.
(lock_pool): Handle no_mlock and no_priv_drop.

Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
doc/gcrypt.texi
src/gcrypt.h.in
src/global.c
src/secmem.c
src/secmem.h

diff --git a/NEWS b/NEWS
index 5dea552..ac60993 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -68,6 +68,8 @@ Noteworthy changes in version 1.6.0 (unreleased)
  GCRYPT_VERSION_NUMBER           NEW.
  GCRY_KDF_SCRYPT                 NEW.
  gcry_pubkey_get_sexp            NEW.
+ GCRYCTL_DISABLE_LOCKED_SECMEM   NEW.
+ GCRYCTL_DISABLE_PRIV_DROP       NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
index d4c4194..4d24475 100644 (file)
@@ -679,6 +679,24 @@ Many applications do not require secure memory, so they should disable
 it right away.  This command should be executed right after
 @code{gcry_check_version}.
 
+@item GCRYCTL_DISABLE_LOCKED_SECMEM; Arguments: none
+This command disables the use of the mlock call for secure memory.
+Disabling the use of mlock may for example be done if an encrypted
+swap space is in use.  This command should be executed right after
+@code{gcry_check_version}.
+
+@item GCRYCTL_DISABLE_PRIV_DROP; Arguments: none
+This command sets a global flag to tell the secure memory subsystem
+that it shall not drop privileges after secure memory has been
+allocated.  This command is commonly used right after
+@code{gcry_check_version} but may also be used right away at program
+startup.  It won't have an effect after the secure memory pool has
+been initialized.  WARNING: A process running setuid(root) is a severe
+security risk.  Processes making use of Libgcrypt or other complex
+code should drop these extra privileges as soon as possible.  If this
+command has been used the caller is responsible for dropping the
+privileges.
+
 @item GCRYCTL_INIT_SECMEM; Arguments: int nbytes
 This command is used to allocate a pool of secure memory and thus
 enabling the use of secure memory.  It also drops all extra privileges
index f472b02..27a29ec 100644 (file)
@@ -302,7 +302,9 @@ enum gcry_ctl_cmds
     GCRYCTL_DISABLE_HWF = 63,
     GCRYCTL_SET_ENFORCED_FIPS_FLAG = 64,
     GCRYCTL_SET_PREFERRED_RNG_TYPE = 65,
-    GCRYCTL_GET_CURRENT_RNG_TYPE = 66
+    GCRYCTL_GET_CURRENT_RNG_TYPE = 66,
+    GCRYCTL_DISABLE_LOCKED_SECMEM = 67,
+    GCRYCTL_DISABLE_PRIV_DROP = 68
   };
 
 /* Perform various operations defined by CMD. */
index f873897..a6fe980 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
  *               2004, 2005, 2006, 2008, 2011,
  *               2012  Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -687,6 +688,18 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       }
       break;
 
+    case GCRYCTL_DISABLE_LOCKED_SECMEM:
+      _gcry_set_preferred_rng_type (0);
+      _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
+                              | GCRY_SECMEM_FLAG_NO_MLOCK));
+      break;
+
+    case GCRYCTL_DISABLE_PRIV_DROP:
+      _gcry_set_preferred_rng_type (0);
+      _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
+                              | GCRY_SECMEM_FLAG_NO_PRIV_DROP));
+      break;
+
     default:
       _gcry_set_preferred_rng_type (0);
       err = GPG_ERR_INV_OP;
index 107c662..c350bc9 100644 (file)
@@ -1,6 +1,7 @@
 /* secmem.c  - memory allocation from a secure heap
  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
  *               2003, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -78,6 +79,8 @@ static int show_warning;
 static int not_locked;
 static int no_warning;
 static int suspend_warning;
+static int no_mlock;
+static int no_priv_drop;
 
 /* Stats.  */
 static unsigned int cur_alloced, cur_blocks;
@@ -241,7 +244,7 @@ lock_pool (void *p, size_t n)
   int err;
 
   cap_set_proc (cap_from_text ("cap_ipc_lock+ep"));
-  err = mlock (p, n);
+  err = no_mlock? 0 : mlock (p, n);
   if (err && errno)
     err = errno;
   cap_set_proc (cap_from_text ("cap_ipc_lock+p"));
@@ -282,22 +285,27 @@ lock_pool (void *p, size_t n)
     }
   else
     {
-      err = mlock (p, n);
+      err = no_mlock? 0 : mlock (p, n);
       if (err && errno)
        err = errno;
     }
 #else /* !HAVE_BROKEN_MLOCK */
-  err = mlock (p, n);
+  err = no_mlock? 0 : mlock (p, n);
   if (err && errno)
     err = errno;
 #endif /* !HAVE_BROKEN_MLOCK */
 
+  /* Test whether we are running setuid(0).  */
   if (uid && ! geteuid ())
     {
-      /* check that we really dropped the privs.
-       * Note: setuid(0) should always fail */
-      if (setuid (uid) || getuid () != geteuid () || !setuid (0))
-       log_fatal ("failed to reset uid: %s\n", strerror (errno));
+      /* Yes, we are.  */
+      if (!no_priv_drop)
+        {
+          /* Check that we really dropped the privs.
+           * Note: setuid(0) should always fail */
+          if (setuid (uid) || getuid () != geteuid () || !setuid (0))
+            log_fatal ("failed to reset uid: %s\n", strerror (errno));
+        }
     }
 
   if (err)
@@ -339,7 +347,8 @@ lock_pool (void *p, size_t n)
 #else
   (void)p;
   (void)n;
-  log_info ("Please note that you don't have secure memory on this system\n");
+  if (!no_mlock)
+    log_info ("Please note that you don't have secure memory on this system\n");
 #endif
 }
 
@@ -424,6 +433,8 @@ _gcry_secmem_set_flags (unsigned flags)
   was_susp = suspend_warning;
   no_warning = flags & GCRY_SECMEM_FLAG_NO_WARNING;
   suspend_warning = flags & GCRY_SECMEM_FLAG_SUSPEND_WARNING;
+  no_mlock      = flags & GCRY_SECMEM_FLAG_NO_MLOCK;
+  no_priv_drop = flags & GCRY_SECMEM_FLAG_NO_PRIV_DROP;
 
   /* and now issue the warning if it is not longer suspended */
   if (was_susp && !suspend_warning && show_warning)
@@ -445,6 +456,8 @@ _gcry_secmem_get_flags (void)
   flags = no_warning ? GCRY_SECMEM_FLAG_NO_WARNING : 0;
   flags |= suspend_warning ? GCRY_SECMEM_FLAG_SUSPEND_WARNING : 0;
   flags |= not_locked ? GCRY_SECMEM_FLAG_NOT_LOCKED : 0;
+  flags |= no_mlock ? GCRY_SECMEM_FLAG_NO_MLOCK : 0;
+  flags |= no_priv_drop ? GCRY_SECMEM_FLAG_NO_PRIV_DROP : 0;
 
   SECMEM_UNLOCK;
 
index 29e151a..3577381 100644 (file)
@@ -35,5 +35,7 @@ int _gcry_private_is_secure (const void *p);
 #define GCRY_SECMEM_FLAG_NO_WARNING      (1 << 0)
 #define GCRY_SECMEM_FLAG_SUSPEND_WARNING (1 << 1)
 #define GCRY_SECMEM_FLAG_NOT_LOCKED      (1 << 2)
+#define GCRY_SECMEM_FLAG_NO_MLOCK        (1 << 3)
+#define GCRY_SECMEM_FLAG_NO_PRIV_DROP    (1 << 4)
 
 #endif /* G10_SECMEM_H */