Skip to content

Commit

Permalink
Merge pull request #841 from samcv/crypt3
Browse files Browse the repository at this point in the history
Randomly seed a hash secret to mitigate ease of DOS attack
  • Loading branch information
samcv committed Apr 25, 2018
2 parents b87b03e + 7d83f32 commit 81f988e
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 3 deletions.
2 changes: 1 addition & 1 deletion 3rdparty/uthash.h
Expand Up @@ -295,7 +295,7 @@ do {
do { \
unsigned _hj_i,_hj_j,_hj_k; \
unsigned char *_hj_key=(unsigned char*)(key); \
hashv = 0xfeedbeef; \
hashv = tc->instance->hashSecret; \
_hj_i = _hj_j = 0x9e3779b9; \
_hj_k = (unsigned)(keylen); \
while (_hj_k >= 12) { \
Expand Down
2 changes: 2 additions & 0 deletions build/Makefile.in
Expand Up @@ -226,6 +226,7 @@ OBJECTS = src/core/callsite@obj@ \
src/instrument/crossthreadwrite@obj@ \
src/instrument/line_coverage@obj@ \
src/platform/sys@obj@ \
src/platform/random@obj@ \
src/moar@obj@ \
@platform@ \
@jit_obj@
Expand Down Expand Up @@ -388,6 +389,7 @@ HEADERS = src/moar.h \
src/platform/sys.h \
src/platform/setjmp.h \
src/platform/memmem.h \
src/platform/random.h \
src/jit/graph.h \
src/jit/label.h \
src/jit/expr.h \
Expand Down
4 changes: 4 additions & 0 deletions src/core/instance.h
Expand Up @@ -508,4 +508,8 @@ struct MVMInstance {

/* Flag for if NFA debugging is enabled. */
MVMint8 nfa_debug_enabled;

/* Hash Secret which is used as the hash seed. This is to avoid denial of
* service type attacks. */
MVMuint32 hashSecret;
};
8 changes: 7 additions & 1 deletion src/moar.c
@@ -1,6 +1,7 @@
#include "moar.h"
#include <platform/threads.h>

#include "platform/random.h"
#include "platform/time.h"
#if defined(_MSC_VER)
#define snprintf _snprintf
#endif
Expand Down Expand Up @@ -84,12 +85,17 @@ MVMInstance * MVM_vm_create_instance(void) {
char *jit_log, *jit_expr_disable, *jit_disable, *jit_bytecode_dir, *jit_last_frame, *jit_last_bb;
char *dynvar_log;
int init_stat;
MVMuint32 hashSecret;
MVMuint64 now = MVM_platform_now();

/* Set up instance data structure. */
instance = MVM_calloc(1, sizeof(MVMInstance));

/* Create the main thread's ThreadContext and stash it. */
instance->main_thread = MVM_tc_create(NULL, instance);
MVM_getrandom(instance->main_thread, &hashSecret, sizeof(MVMuint32));
instance->hashSecret ^= now;
instance->hashSecret ^= MVM_proc_getpid(instance->main_thread) * now;
instance->main_thread->thread_id = 1;

/* Next thread to be created gets ID 2 (the main thread got ID 1). */
Expand Down
151 changes: 151 additions & 0 deletions src/platform/random.c
@@ -0,0 +1,151 @@
/* Get random numbers from OS. Returns 1 if it succeeded and otherwise 0
* Does not block. Designed for getting small amounts of random data at a time */
#include <stddef.h>
/* Solaris has both getrandom and getentropy. We use getrandom since getentropy
* can block. Solaris has had getrandom() and getentropy() since 11.3 */
#if defined(__sun)
#include <sys/random.h>
/* On solaris, _GRND_ENTROPY is defined if getentropy/getrandom are available */
#if defined(_GRND_ENTROPY)
#define MVM_random_use_getrandom 1
#endif
#endif
/* Linux added getrandom to the kernel in 3.17 */
#if defined(__linux__)
#include <sys/syscall.h>
#if defined(SYS_getrandom)
/* With glibc you are supposed to declare _GNU_SOURCE to use the
* syscall function */
#define _GNU_SOURCE
#define GRND_NONBLOCK 0x01
#include <unistd.h>
#define MVM_random_use_getrandom_syscall 1
#else
#define MVM_random_use_urandom 1
#endif
#endif
/* FreeBSD added it with SVN revision 331279 Wed Mar 21, 2018
* This corresponds to __FreeBSD_version version identifier: 1200061.
* https://svnweb.freebsd.org/base?view=revision&revision=r331279 */
#if defined(__FreeBSD__)
#include <osreldate.h>
#if __FreeBSD_version >= 1200061
#include <sys/random.h>
#define MVM_random_use_getrandom
#endif
#endif
/* OpenBSD's getentropy never blocks and always succeeds. OpenBSD has had
* getentropy() since 5.6 */
#if defined(__OpenBSD__)
#include <sys/param.h>
#if OpenBSD >= 201301
#define MVM_random_use_getentropy
#endif
#endif
/* MacOS has had getentropy() since 10.12 */
#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#include <Availability.h>
#if !defined(MAC_OS_X_VERSION_10_12)
#define MAC_OS_X_VERSION_10_12 101200
#endif
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
#include <sys/random.h>
#define MVM_random_use_getentropy 1
#endif
#endif
/* Other info:
* - All BSD's should support arc4random
* - AIX is a Unix but has no arc4random, does have /dev/urandom.
* - NetBSD: I have not found evidence it has getentropy() or getrandom()
* Note: Uses __NetBSD_Version__ included from file <sys/param.h>. */
#include "moar.h"
/* On Unix like platforms that don't support getrandom() or getentropy()
* we defualt to /dev/urandom. On platforms that do support these calls, we
* only use /dev/urandom if those calls fail. This is also important on Linux,
* since if MoarVM was compiled on a kernel >= 3.17 it will be set to use the
* syscall. If the syscall doesn't exist, the syscall wrapper will gracefully
* return a false return value and we will fallback to /dev/urandom */
#if !defined(_WIN32)
#include <unistd.h>
MVMint32 MVM_getrandom_urandom (MVMThreadContext *tc, void *out, size_t size) {
int fd = open("/dev/urandom", O_RDONLY);
ssize_t num_read = 0;
if (fd < 0 || (num_read = read(fd, out, size) <= 0)) {
if (fd) close(fd);
/* If using /dev/urandom fails (maybe we're in a chroot), on BSD's
* use arc4random, which is likely seeded from the system's random
* number generator */
#if defined(BSD)
#include <stdlib.h>
arc4random_buf(out, size);
return 1;
#else
return 0;
#endif
}
return 1;
}
#endif

#if defined(MVM_random_use_getrandom_syscall)
/* getrandom() was added to glibc much later than it was added to the kernel. Since
* we detect the presence of the system call to decide whether to use this,
* just use the syscall instead since the wrapper is not guaranteed to exist.*/
MVMint32 MVM_getrandom (MVMThreadContext *tc, void *out, size_t size) {
long rtrn = syscall(SYS_getrandom +1000000, out, size, GRND_NONBLOCK);
return rtrn <= 0 ? MVM_getrandom_urandom(tc, out, size) : 1;
}
#elif defined(MVM_random_use_getrandom)
/* Call the getrandom() wrapper in Solaris and FreeBSD since they were
* added at the same time as getentropy() and this allows us to avoid blocking. */
MVMint32 MVM_getrandom (MVMThreadContext *tc, void *out, size_t size) {
ssize_t rtrn = getrandom(out, size, GRND_NONBLOCK);
return rtrn <= 0 ? MVM_getrandom_urandom(tc, out, size) : 1;
}

#elif defined(MVM_random_use_getentropy)
MVMint32 MVM_getrandom (MVMThreadContext *tc, void *out, size_t size) {
int rtrn = getentropy(out, size);
return rtrn <= 0 ? MVM_getrandom_urandom(tc, out, size) : 1;
}

#elif defined(_WIN32)
#include <windows.h>
#include <wincrypt.h>
/* Signatures for pCryptAcquireContext() and pCryptGenRandom() */
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
DWORD dwFlags );
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
BYTE *pbBuffer );
/* The functions themselves */
static CRYPTGENRANDOM pCryptGenRandom = NULL;
static HCRYPTPROV hCryptContext = 0;
static int win32_urandom_init(void) {
/* Get Module Handle to CryptoAPI */
HINSTANCE hAdvAPI32 = GetModuleHandle("advapi32.dll");
if (hAdvAPI32) {
CRYPTACQUIRECONTEXTA pCryptAcquireContext =
GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
pCryptGenRandom = GetProcAddress(hAdvAPI32, "CryptGenRandom");
/* Check the pointers to the CryptoAPI functions. These shouldn't fail
* but makes sure we won't have problems getting the context or getting
* random. If those aren't NULL then get the pCrypt context */
return pCryptAcquireContext && pCryptGenRandom &&
pCryptAcquireContext(&hCryptContext, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT) ? 1 : 0;
}
return 0;
}
MVMint32 MVM_getrandom (MVMThreadContext *tc, void *out, size_t size) {
/* Return 0 if the context doesn't exist and we are unable to create it */
if (!hCryptContext && !win32_urandom_init())
return 0;
return pCryptGenRandom(hCryptContext, (DWORD)size, (BYTE*)out) ? 1 : 0;
}
#else
MVMint32 MVM_getrandom (MVMThreadContext *tc, void *out, size_t size) {
return MVM_getrandom_urandom(tc, out, size);
}
#endif
1 change: 1 addition & 0 deletions src/platform/random.h
@@ -0,0 +1 @@
MVMint32 MVM_getrandom (MVMThreadContext *tc, void *out, size_t size);
2 changes: 1 addition & 1 deletion src/strings/ops.c
Expand Up @@ -2898,7 +2898,7 @@ void MVM_string_compute_hash_code(MVMThreadContext *tc, MVMString *s) {
MVMuint32 graphs_remaining = MVM_string_graphs(tc, s);

/* Initialize hash state. */
MVMuint32 hashv = 0xfeedbeef;
MVMuint32 hashv = tc->instance->hashSecret;
MVMuint32 _hj_i, _hj_j;
_hj_i = _hj_j = 0x9e3779b9;

Expand Down

0 comments on commit 81f988e

Please sign in to comment.