]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Export heimdal's rand-fortuna PRNG to the kernel
authorBen Kaduk <kaduk@mit.edu>
Wed, 27 Mar 2013 21:02:55 +0000 (17:02 -0400)
committerJeffrey Altman <jaltman@your-file-system.com>
Wed, 10 Sep 2014 19:05:07 +0000 (15:05 -0400)
Some systems (e.g., AIX, SGI, DFBSD, HPUX) do not supply a useful
implementation of osi_readRandom(), in some cases because the kernel
does not expose a random-number interface to kernel modules.  We want
real random numbers on all systems, because we want to use the for
setting the RX epoch and connection ID in the kernel.

Build hcrypto's rand-fortuna PRNG into the rand-kernel interface we expose,
and implement RAND_bytes using rand-fortuna when osi_ReadRandom()
is not useful.

Add stub routines to config.h as needed, and add a heim_threads.h
with the necessary locking for rand-fortuna.  The rand-fortuna algorithm
requires some measure of time's passage, so provide a stub gettimeofday()
with single-second resolution.  We use a single (global) mutex for the
hcrypto kernel code, so that we can statically declare an initializer to
be the address of that mutex.  Otherwise the locking is taken essentially
wholesale from rx_kmutex.

rand-fortuna requires the sha256 code for its hashing, and also
requires a stub rand-fortuna to satisfy linker symbol visibility.

Since the rand-fortuna code does not have any actual sources of entropy
available to it during its initialization routines, we must explicitly
seed the in-kernel rand-fortuna using entropy passed in from userland.
(Userland will always have at least /dev/random available, so the
userland hcrypto should always have usable entropy.)  Be sure to do so
early in the afsd startup sequence, before any daemons are started, so
that entropy is available to the core rx code for generating the epoch
and cid -- the rand-fortuna code will (erroneously) always claim that
it has startup entropy even though in this case it may not actually
have any entropy.  The rand-fortuna code does not consider itself
fully seeded until it has 128 bytes of entropy, so be sure to pass
more than that in from userspace.

It is preferrable to always build this code into the kernel, even on
systems when it is not going to be used, to help prevent bitrot.  This
also avoids the possibility of a new system being supported that would
attempt to use the rand-fortuna code but fail to supply any seed entropy,
which would not necessarily be readily apparent.

Change-Id: I614d2bd9ac52803ec3b9572cc694cd836c8427dd
Reviewed-on: http://gerrit.openafs.org/10840
Reviewed-by: D Brashear <shadow@your-file-system.com>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>
src/afs/afs_call.c
src/afsd/Makefile.in
src/afsd/afsd.c
src/config/afs_args.h
src/crypto/hcrypto/kernel/config.h
src/crypto/hcrypto/kernel/heim_threads.h [new file with mode: 0644]
src/crypto/hcrypto/kernel/rand-timer.c [new file with mode: 0644]
src/crypto/hcrypto/kernel/rand.c
src/crypto/hcrypto/kernel/strcasecmp.c [new file with mode: 0644]
src/libafs/Makefile.common.in
src/libafs/MakefileProto.LINUX.in

index 4e3c4c43e1e96cc16e86ad16bf64e58c1fda8b4a..f3448ed84e3693ab0a3e1b74bc15040a2b430ece 100644 (file)
 #include "h/ksynch.h"
 #include "h/sunddi.h"
 #endif
+#include <hcrypto/rand.h>
+
+/* No hckernel-specific header for this prototype. */
+#ifndef UKERNEL
+extern void init_hckernel_mutex(void);
+#endif
 
 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_HPUX_ENV)
 #define        AFS_MINBUFFERS  100
@@ -101,6 +107,11 @@ afs_InitSetup(int preallocs)
     if (afs_InitSetup_done)
        return EAGAIN;
 
+    /* Initialize a lock for the kernel hcrypto bits. */
+#ifndef UKERNEL
+    init_hckernel_mutex();
+#endif
+
 #ifdef AFS_SUN510_ENV
     /* Initialize a RW lock for the ifinfo global array */
     rw_init(&afsifinfo_lock, NULL, RW_DRIVER, NULL);
@@ -1314,6 +1325,20 @@ afs_syscall_call(long parm, long parm2, long parm3,
     } else if (parm == AFSOP_SET_RMTSYS_FLAG) {
        afs_rmtsys_enable = parm2;
        code = 0;
+#ifndef UKERNEL
+    } else if (parm == AFSOP_SEED_ENTROPY) {
+       unsigned char *seedbuf;
+
+       if (parm3 > 4096) {
+           code = EFAULT;
+       } else {
+           seedbuf = afs_osi_Alloc(parm3);
+           AFS_COPYIN(AFSKPTR(parm2), seedbuf, parm3, code);
+           RAND_seed(seedbuf, parm3);
+           memset(seedbuf, 0, parm3);
+           afs_osi_Free(seedbuf, parm3);
+       }
+#endif
     } else {
        code = EINVAL;
     }
index 954ad49983f54783b5d66ea9b97bc63410330f7b..c1dd92b8b23ed63c1d6c1d30958469c53f3f698e 100644 (file)
@@ -37,7 +37,7 @@ FUSE_LIBS=@FUSE_LIBS@
 LDFLAGS_afsd = $(AFSD_LDFLAGS)
 afsd: afsd.o afsd_kernel.o $(AFSLIBS) $(AFSD_LIBS)
        $(LT_LDRULE_static) afsd.o afsd_kernel.o $(NON_SHARED) \
-               $(AFSLIBS) ${AFSD_LIBS} $(LIB_roken) $(MT_LIBS) $(XLIBS)
+               $(AFSLIBS) ${AFSD_LIBS} $(LIB_hcrypto) $(LIB_roken) $(MT_LIBS) $(XLIBS)
 
 LDFLAGS_afsd.fuse = $(AFSD_LDFLAGS)
 afsd.fuse: afsd_fuse.o $(UAFSLIBS) $(AFSD_LIBS)
index 0fb524a72d2b7999f49dd054ada9c64c9331dad7..3097610aa4596d216655d4d4a7bf633150032618 100644 (file)
@@ -79,6 +79,7 @@
 
 #include <sys/file.h>
 #include <sys/wait.h>
+#include <hcrypto/rand.h>
 
 /* darwin dirent.h doesn't give us the prototypes we want if KERNEL is
  * defined */
@@ -2128,6 +2129,13 @@ afsd_run(void)
 
     /* initialize the rx random number generator from user space */
     {
+       /* rand-fortuna wants at least 128 bytes of seed; be generous. */
+       unsigned char seedbuf[256];
+       if (RAND_bytes(seedbuf, sizeof(seedbuf)) != 1) {
+           printf("SEED_ENTROPY: Error retrieving seed entropy\n");
+       }
+       afsd_syscall(AFSOP_SEED_ENTROPY, seedbuf, sizeof(seedbuf));
+       memset(seedbuf, 0, sizeof(seedbuf));
        /* parse multihomed address files */
        afs_uint32 addrbuf[MAXIPADDRS], maskbuf[MAXIPADDRS],
            mtubuf[MAXIPADDRS];
@@ -2675,6 +2683,10 @@ afsd_syscall_populate(struct afsd_syscall_args *args, int syscall, va_list ap)
        params[0] = CAST_SYSCALL_PARAM((va_arg(ap, afs_uint32)));
 #endif
        break;
+    case AFSOP_SEED_ENTROPY:
+       params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
+       params[1] = CAST_SYSCALL_PARAM((va_arg(ap, afs_uint32)));
+       break;
     default:
        printf("Unknown syscall enountered: %d\n", syscall);
        opr_Assert(0);
index 296cf96e1ba294d6eec5944b78795343b8a214f3..01bdac53ea38e1102f6797f45dce86a8805c8335 100644 (file)
@@ -52,6 +52,7 @@
 #define AFSOP_BKG_HANDLER        41     /* userspace-capable Bkg daemon */
 #define AFSOP_SET_RXMAXFRAGS     43     /* set rxi_nSendFrags, rxi_nRecvFrags */
 #define AFSOP_SET_RMTSYS_FLAG    44     /* set flag if rmtsys is enabled */
+#define AFSOP_SEED_ENTROPY       45     /* Give the kernel hcrypto entropy */
 
 /* The range 20-30 is reserved for AFS system offsets in the afs_syscall */
 #define        AFSCALL_PIOCTL          20
index d9c58c5a3248c2e07958390d70afc8306029f23f..c7b22d9368146f3ece1010f4d61ed467ace35918 100644 (file)
 #endif
 #define assert osi_Assert
 
+/* Linux's current.h defines current to get_current(), conflicing with
+ * heimdal's rand-fortuna.c's local variable. */
+#if defined(current)
+#undef current
+#define current current
+#endif
+
+/* AIX and some Solaris (and others, presumably) still have a 'u' symbol for
+ * the user area.  rand-fortuna.c has a local variable of that name. */
+#if defined(u)
+#undef u
+#define u u
+#endif
+
 /* hcrypto uses "static inline", which isn't supported by some of our
  * compilers */
 #if !defined(inline) && !defined(__GNUC__)
@@ -64,3 +78,22 @@ void * _afscrypto_realloc(void *, size_t);
 /* osi_readRandom is also prototyped in afs_prototypes.h, but pulling that in
  * here creates loads of additional dependencies */
 extern int osi_readRandom(void *, afs_size_t);
+
+#if defined(getpid)
+/* On linux, getpid() is unfortunately declared in terms of current, which
+ * already gives us a namespace clash.  It was lousy entropy, anyway. */
+#undef getpid
+#define getpid()       1
+#else
+static_inline pid_t getpid(void) {return 1;};
+#endif
+static_inline int open(const char *path, int flags, ...) {return -1;}
+static_inline void abort(void) {osi_Panic("hckernel aborting\n");}
+static_inline void rk_cloexec(int fd) {}
+static_inline ssize_t read(int d, void *buf, size_t nbytes) {return -1;}
+static_inline int close(int d) {return -1;}
+#if defined(HAVE_GETUID)
+#undef HAVE_GETUID
+#endif
+static_inline int gettimeofday(struct timeval *tp, void *tzp)
+    {if (tp == NULL) return -1; tp->tv_sec = osi_Time(); tp->tv_usec = 0; return 0;}
diff --git a/src/crypto/hcrypto/kernel/heim_threads.h b/src/crypto/hcrypto/kernel/heim_threads.h
new file mode 100644 (file)
index 0000000..cc0940f
--- /dev/null
@@ -0,0 +1,12 @@
+#include <rx_kmutex.h>
+#define HEIMDAL_MUTEX afs_kmutex_t*
+extern afs_kmutex_t hckernel_mutex;
+#define HEIMDAL_MUTEX_INITIALIZER      &hckernel_mutex;
+#define HEIMDAL_MUTEX_init(m)          MUTEX_INIT(*m,0,0,0)
+#define HEIMDAL_MUTEX_lock(m)          MUTEX_ENTER(*m)
+#define HEIMDAL_MUTEX_unlock(m)                MUTEX_EXIT(*m)
+#define HEIMDAL_MUTEX_destroy(m)       MUTEX_DESTROY(*m)
+
+/* Tell rand-fortuna we don't have userspace things. */
+#define NO_RAND_UNIX_METHOD
+#define NO_RAND_EGD_METHOD
diff --git a/src/crypto/hcrypto/kernel/rand-timer.c b/src/crypto/hcrypto/kernel/rand-timer.c
new file mode 100644 (file)
index 0000000..3a70235
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Stub rand-timer "implementation" so that rand-fortuna is linkable
+ * into the kernel.
+ *
+ * Contains no copyrightable content.
+ */
+#include <config.h>
+
+#include <rand.h>
+#include "randi.h"
+
+static void
+timer_seed(const void *indata, int size)
+{
+}
+
+static int
+timer_bytes(unsigned char *outdata, int size)
+{
+    return 1;
+}
+
+static void
+timer_cleanup(void)
+{
+}
+
+static void
+timer_add(const void *indata, int size, double entropi)
+{
+}
+
+static int
+timer_pseudorand(unsigned char *outdata, int size)
+{
+    return 1;
+}
+
+static int
+timer_status(void)
+{
+    return 0;
+}
+
+const RAND_METHOD hc_rand_timer_method = {
+    timer_seed,
+    timer_bytes,
+    timer_cleanup,
+    timer_add,
+    timer_pseudorand,
+    timer_status
+};
+
+const RAND_METHOD *
+RAND_timer_method(void)
+{
+    return &hc_rand_timer_method;
+}
index b0254f334f9738c346e0e0444a3a672a1ee1aa55..81064863bca2b9b6abc8124498277fb21111e35d 100644 (file)
@@ -6,13 +6,40 @@
 #include <evp-hcrypto.h>
 #include <aes.h>
 #include <sha.h>
+#include <heim_threads.h>
+
+/*
+ * This mutex is used to synchronize hcrypto operations in the kernel.
+ * We cheat and assume that all access into hcrypto comes through routines
+ * in this file, so that we can ensure it is initialized before it is used.
+ */
+afs_kmutex_t hckernel_mutex;
+
+/* Called from osi_Init(); will only run once. */
+void
+init_hckernel_mutex(void)
+{
+    MUTEX_INIT(&hckernel_mutex, "hckernel", MUTEX_DEFAULT, 0);
+}
+
+void
+RAND_seed(const void *indata, size_t size)
+{
+    const RAND_METHOD *m = RAND_fortuna_method();
+    m->seed(indata, size);
+}
 
 int
 RAND_bytes(void *outdata, size_t size)
 {
     if (size == 0)
        return 0;
+#if defined(AFS_AIX_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SGI_ENV)
+    const RAND_METHOD *m = RAND_fortuna_method();
+    return m->bytes(outdata, size);
+#else
     if (osi_readRandom(outdata, size))
        return 0;
+#endif
     return 1;
 }
diff --git a/src/crypto/hcrypto/kernel/strcasecmp.c b/src/crypto/hcrypto/kernel/strcasecmp.c
new file mode 100644 (file)
index 0000000..4a5acf2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+const char hckernel_strcasecmp_placeholder[] =
+               "This is not an empty compilation unit.";
+
+#ifndef afs_strcasecmp
+int
+afs_strcasecmp(const char *s1, const char *s2)
+{
+    while (*s1 && *s2) {
+       char c1, c2;
+
+       c1 = *s1++;
+       c2 = *s2++;
+       if (c1 >= 'A' && c1 <= 'Z')
+           c1 += 0x20;
+       if (c2 >= 'A' && c2 <= 'Z')
+           c2 += 0x20;
+       if (c1 != c2)
+           return c1 - c2;
+    }
+
+    return *s1 - *s2;
+}
+#endif
index e70c7dfcc8b8347c909966ea075361a117557dac..325863f10a4f5398d60939a1493a1698298643f7 100644 (file)
@@ -71,6 +71,9 @@ single_destdir_libafs: dest_libafs
 depsrcs: 
 
 AFSAOBJS = \
+       sha256-kernel.o \
+       rand-fortuna-kernel.o \
+       rand-timer-kernel.o \
        afs_atomlist.o \
        afs_lhash.o \
        afs_analyze.o \
@@ -211,6 +214,17 @@ AFSNONFSOBJS = \
 
 # init daemons call pioctl
 AFSPAGOBJS = \
+       sha256-kernel.o \
+       rand-fortuna-kernel.o \
+       rand-timer-kernel.o \
+       md5.o           \
+       evp.o           \
+       evp-algs.o      \
+       rand-kernel.o   \
+       alloc-kernel.o  \
+       aes.o           \
+       rijndael-alg-fst.o \
+       sha.o           \
        afs_atomlist.o \
        afs_error.o \
        afs_icl.o \
@@ -250,6 +264,7 @@ AFSPAGOBJS = \
        rx_pag_packet.o \
        rx_multi.o      \
        rx_stats.o      \
+       strcasecmp_pag.o        \
        opr_rbtree.o    \
        xdr_rx.o        \
        xdr_mem.o       \
@@ -534,6 +549,8 @@ rx_pag_packet.o: $(TOP_SRC_RX)/rx_packet.c
        $(CRULE_NOOPT) $(TOP_SRC_RX)/rx_packet.c
 rx_pag_knet.o: $(TOP_SRC_RX)/${MKAFS_OSTYPE}/rx_knet.c
        $(CRULE_NOOPT) $(TOP_SRC_RX)/${MKAFS_OSTYPE}/rx_knet.c
+strcasecmp_pag.o: $(TOP_SRCDIR)/crypto/hcrypto/kernel/strcasecmp.c
+       $(CRULE_NOOPT) $(TOP_SRCDIR)/crypto/hcrypto/kernel/strcasecmp.c
 
 # Crypto
 md5.o: $(TOP_SRCDIR)/external/heimdal/hcrypto/md5.c
@@ -552,6 +569,18 @@ rand-kernel.o: $(TOP_SRCDIR)/crypto/hcrypto/kernel/rand.c
        $(CRULE_OPT) $(TOP_SRCDIR)/crypto/hcrypto/kernel/rand.c
 CFLAGS-rand-kernel.o = -I$(TOP_INCDIR)/hcrypto
 
+rand-fortuna-kernel.o: $(TOP_SRCDIR)/external/heimdal/hcrypto/rand-fortuna.c
+       $(CRULE_OPT) $(TOP_SRCDIR)/external/heimdal/hcrypto/rand-fortuna.c
+CFLAGS-rand-fortuna-kernel.o = -I$(TOP_INCDIR)/hcrypto
+
+rand-timer-kernel.o: $(TOP_SRCDIR)/crypto/hcrypto/kernel/rand-timer.c
+       $(CRULE_OPT) $(TOP_SRCDIR)/crypto/hcrypto/kernel/rand-timer.c
+CFLAGS-rand-timer-kernel.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
+
+sha256-kernel.o: $(TOP_SRCDIR)/external/heimdal/hcrypto/sha256.c
+       $(CRULE_OPT) $(TOP_SRCDIR)/external/heimdal/hcrypto/sha256.c
+CFLAGS-sha256-kernel.o = -I$(TOP_INCDIR)/hcrypto
+
 alloc-kernel.o: $(TOP_SRCDIR)/crypto/hcrypto/kernel/alloc.c
        $(CRULE_OPT) $(TOP_SRCDIR)/crypto/hcrypto/kernel/alloc.c
 
index 1213e4e9b1a25e283376be4ad970dd2f66b83945..b7801aee1f37107d0d682d57709b42a0c280de99 100644 (file)
@@ -57,6 +57,7 @@ AFS_OS_OBJS = \
 AFS_OS_PAGOBJS = \
        osi_alloc.o \
        osi_cred.o \
+       osi_crypto.o \
        osi_gcpags.o \
        osi_groups.o \
        osi_inode.o \
@@ -92,11 +93,14 @@ CFLAGS_evp.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto \
               -DHAVE_CONFIG_H
 CFLAGS_evp-algs.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
 CFLAGS_evp-kernel.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
+CFLAGS_rand-fortuna-kernel.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
+CFLAGS_rand-timer-kernel.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
 CFLAGS_rand-kernel.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
 CFLAGS_aes.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
 CFLAGS_rijndael-alg-fst.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto \
                            -DNO_CONFIG_H
 CFLAGS_sha.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
+CFLAGS_sha256-kernel.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
 CFLAGS_md5.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto
 CFLAGS_random.o = -I$(TOP_SRCDIR)/external/heimdal/hcrypto