From 0d67b00ff9db48c5555e8ae11daff9a469c770b0 Mon Sep 17 00:00:00 2001 From: Ben Kaduk Date: Wed, 27 Mar 2013 17:02:55 -0400 Subject: [PATCH] Export heimdal's rand-fortuna PRNG to the kernel 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 Tested-by: BuildBot Reviewed-by: Jeffrey Altman --- src/afs/afs_call.c | 25 ++++++++++ src/afsd/Makefile.in | 2 +- src/afsd/afsd.c | 12 +++++ src/config/afs_args.h | 1 + src/crypto/hcrypto/kernel/config.h | 33 ++++++++++++++ src/crypto/hcrypto/kernel/heim_threads.h | 12 +++++ src/crypto/hcrypto/kernel/rand-timer.c | 58 ++++++++++++++++++++++++ src/crypto/hcrypto/kernel/rand.c | 27 +++++++++++ src/crypto/hcrypto/kernel/strcasecmp.c | 32 +++++++++++++ src/libafs/Makefile.common.in | 29 ++++++++++++ src/libafs/MakefileProto.LINUX.in | 4 ++ 11 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 src/crypto/hcrypto/kernel/heim_threads.h create mode 100644 src/crypto/hcrypto/kernel/rand-timer.c create mode 100644 src/crypto/hcrypto/kernel/strcasecmp.c diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 4e3c4c43e..f3448ed84 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -33,6 +33,12 @@ #include "h/ksynch.h" #include "h/sunddi.h" #endif +#include + +/* 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; } diff --git a/src/afsd/Makefile.in b/src/afsd/Makefile.in index 954ad4998..c1dd92b8b 100644 --- a/src/afsd/Makefile.in +++ b/src/afsd/Makefile.in @@ -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) diff --git a/src/afsd/afsd.c b/src/afsd/afsd.c index 0fb524a72..3097610aa 100644 --- a/src/afsd/afsd.c +++ b/src/afsd/afsd.c @@ -79,6 +79,7 @@ #include #include +#include /* 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); diff --git a/src/config/afs_args.h b/src/config/afs_args.h index 296cf96e1..01bdac53e 100644 --- a/src/config/afs_args.h +++ b/src/config/afs_args.h @@ -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 diff --git a/src/crypto/hcrypto/kernel/config.h b/src/crypto/hcrypto/kernel/config.h index d9c58c5a3..c7b22d936 100644 --- a/src/crypto/hcrypto/kernel/config.h +++ b/src/crypto/hcrypto/kernel/config.h @@ -36,6 +36,20 @@ #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 index 000000000..cc0940fc7 --- /dev/null +++ b/src/crypto/hcrypto/kernel/heim_threads.h @@ -0,0 +1,12 @@ +#include +#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 index 000000000..3a7023555 --- /dev/null +++ b/src/crypto/hcrypto/kernel/rand-timer.c @@ -0,0 +1,58 @@ +/* + * Stub rand-timer "implementation" so that rand-fortuna is linkable + * into the kernel. + * + * Contains no copyrightable content. + */ +#include + +#include +#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; +} diff --git a/src/crypto/hcrypto/kernel/rand.c b/src/crypto/hcrypto/kernel/rand.c index b0254f334..81064863b 100644 --- a/src/crypto/hcrypto/kernel/rand.c +++ b/src/crypto/hcrypto/kernel/rand.c @@ -6,13 +6,40 @@ #include #include #include +#include + +/* + * 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 index 000000000..4a5acf213 --- /dev/null +++ b/src/crypto/hcrypto/kernel/strcasecmp.c @@ -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 diff --git a/src/libafs/Makefile.common.in b/src/libafs/Makefile.common.in index e70c7dfcc..325863f10 100644 --- a/src/libafs/Makefile.common.in +++ b/src/libafs/Makefile.common.in @@ -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 diff --git a/src/libafs/MakefileProto.LINUX.in b/src/libafs/MakefileProto.LINUX.in index 1213e4e9b..b7801aee1 100644 --- a/src/libafs/MakefileProto.LINUX.in +++ b/src/libafs/MakefileProto.LINUX.in @@ -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 -- 2.39.5