diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-05-21 22:22:45 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-08-27 02:16:41 -0400 |
commit | 86c39754f215ec00186a649c09cf0b2eea21c872 (patch) | |
tree | 6e3341a6657e2dabd4811393883752d125eb069f /src/ck.c | |
parent | d4c18555780432718558833ccd7ae4870fd6845e (diff) | |
download | lighttpd-git-86c39754f215ec00186a649c09cf0b2eea21c872.tar.gz |
[core] ck.[ch] - C11 Annex K wrappers
(selected functions; not complete)
(import from one of my development branches from 2016)
define safe_memclear() -> ck_memzero() for transition
Diffstat (limited to 'src/ck.c')
-rw-r--r-- | src/ck.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/ck.c b/src/ck.c new file mode 100644 index 00000000..5bdc4b01 --- /dev/null +++ b/src/ck.c @@ -0,0 +1,256 @@ +/* + * ck - C11 Annex K wrappers (selected functions; not complete) + * + * ck is also an abbreviation for "check". + * These are validating, checking functions. + * + * Copyright(c) 2016 Glenn Strauss gstrauss()gluelogic.com All rights reserved + * License: BSD 3-clause (same as lighttpd) + */ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 +#endif +#ifndef _NETBSD_SOURCE +#define _NETBSD_SOURCE +#endif +#include "first.h" + +#include "ck.h" + +#include <stdlib.h> /* getenv() getenv_s() */ +#include <string.h> /* memcpy() memset() memset_s() explicit_bzero() + * strerror() strerror_r() strerror_s() strlen() */ + +#ifdef __STDC_LIB_EXT1__ +#ifndef HAVE_MEMSET_S +#define HAVE_MEMSET_S +#endif +#else +#include <errno.h> +#include <stdio.h> /* snprintf() */ +#endif + +#ifndef HAVE_MEMSET_S + +#ifdef _WIN32 +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN +#include <windows.h> /* SecureZeroMemory() */ +/*(Windows XP and later provide SecureZeroMemory())*/ +#define HAVE_SECUREZEROMEMORY +#else /* !_WIN32 */ +#ifdef HAVE_SIGNAL +#include <signal.h> /* sig_atomic_t */ +#else +typedef int sig_atomic_t; +#endif +/*#include <plasma/plasma_membar.h>*/ /* plasma_membar_ccfence() */ +#endif + +#endif /* !HAVE_MEMSET_S */ + + +#if !defined(HAVE_MEMSET_S) \ + && !defined(HAVE_EXPLICIT_BZERO) \ + && !defined(HAVE_EXPLICIT_MEMSET) \ + && !defined(HAVE_SECUREZEROMEMORY) + +typedef void *(*ck_memclear_func_t)(void *, int, size_t); +extern volatile ck_memclear_func_t ck_memclear_func; +volatile ck_memclear_func_t ck_memclear_func = memset; + +#ifdef HAVE_WEAK_SYMBOLS +/* it seems weak functions are never inlined, even for static builds */ +__attribute__((__weak__)) +void ck_memclear_s_hook (void *buf, rsize_t len); +void ck_memclear_s_hook (void *buf __attribute_unused__, + rsize_t len __attribute_unused__) +{ + /*(application might define func to call OPENSSL_cleanse(), if available)*/ + (void)(buf); /* UNUSED */ + (void)(len); /* UNUSED */ +} +#endif /* HAVE_WEAK_SYMBOLS */ + +static void * +ck_memset_compat(void *s, int c, size_t n) +{ + /* attempt to inhibit compiler/linker heuristics which might elide memset() + * - insert compiler optimization fences around memset() + * - access s through volatile pointer at volatile index after memset() + * - pass s to weak (overridable) func to create additional data dependency + */ + + if (0 == n) /*(must check n > 0 since s[0] will be accessed)*/ + return s; + + static volatile sig_atomic_t vzero; + volatile unsigned char *vs = (volatile unsigned char *)s; + do { + /*plasma_membar_ccfence();*/ + ck_memclear_func(s, c, n); + /*plasma_membar_ccfence();*/ + } while (vs[vzero] != c); + + #ifdef HAVE_WEAK_SYMBOLS + ck_memclear_s_hook(s, n); + #endif + + return s; +} + +#endif + + +errno_t +ck_memclear_s (void * const s, const rsize_t smax, rsize_t n) +{ + #ifdef HAVE_MEMSET_S + + return memset_s(s, smax, 0, n); + + #else + + if (NULL == s) + /* runtime constraint violation */ + return EINVAL; + if (RSIZE_MAX < smax) + /* runtime constraint violation */ + return E2BIG; + + errno_t rc = 0; + if (RSIZE_MAX < n) { + /* runtime constraint violation */ + rc = EINVAL; + n = smax; + } + if (smax < n) { + /* runtime constraint violation */ + rc = EOVERFLOW; + n = smax; + } + + #if defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(s, n); + #elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(s, 0, n); + #elif defined(HAVE_SECUREZEROMEMORY) + SecureZeroMemory(s, n); + #else + ck_memset_compat(s, 0, n); + #endif + + return rc; + + #endif +} + + +errno_t +ck_getenv_s (size_t * const restrict len, + char * const restrict value, const rsize_t maxsize, + const char * const restrict name) +{ + #ifdef __STDC_LIB_EXT1__ + + return getenv_s(len, value, maxsize, name); + + #else + + if (NULL == name || RSIZE_MAX < maxsize || (0 != maxsize && NULL == value)){ + /* runtime constraint violation */ + if (NULL != len) + *len = 0; + if (NULL != value && maxsize) + *value = '\0'; + return EINVAL; + } + + const char * const v = getenv(name); + if (NULL != v) { + const size_t vlen = strlen(v); + if (NULL != len) + *len = vlen; + if (vlen < maxsize) { + memcpy(value, v, vlen+1); + return 0; + } + else { + if (maxsize) + *value = '\0'; + return ERANGE; + } + } + else { + if (NULL != len) + *len = 0; + if (maxsize) + *value = '\0'; + #ifdef ENODATA + return ENODATA; + #else + return ENOENT; + #endif + } + + #endif +} + + +errno_t +ck_strerror_s (char * const s, const rsize_t maxsize, const errno_t errnum) +{ + #ifdef __STDC_LIB_EXT1__ + + return strerror_s(s, maxsize, errnum); + + #else + + if (NULL == s || 0 == maxsize || RSIZE_MAX < maxsize) { + /* runtime constraint violation */ + return EINVAL; + } + + /*(HAVE_STRERROR_R defined after tests by configure.ac or SConstruct)*/ + #if !defined(HAVE_STRERROR_R) && !defined(HAVE_CONFIG_H) + #define HAVE_STRERROR_R 1 + #endif /*(assume strerror_r() available if no config.h)*/ + + #ifdef HAVE_STRERROR_R + char buf[1024]; + #if defined(_GNU_SOURCE) && defined(__GLIBC__) + const char *errstr = strerror_r(errnum,buf,sizeof(buf)); + #else /* XSI-compliant strerror_r() */ + const char *errstr = (0 == strerror_r(errnum,buf,sizeof(buf))) ? buf : NULL; + #endif + #else /* !HAVE_STRERROR_R */ + const char *errstr = strerror(errnum); + #endif + if (NULL != errstr) { + const size_t errlen = strlen(errstr); + if (errlen < maxsize) { + memcpy(s, errstr, errlen+1); + return 0; + } + else { + memcpy(s, errstr, maxsize-1); + s[maxsize-1] = '\0'; + /*(fall through; not enough space to store entire error string)*/ + } + } + else { + if ((rsize_t)snprintf(s, maxsize, "Unknown error %d", errnum) < maxsize) + return 0; + /*(else fall through; not enough space to store entire error string)*/ + } + + /*(not enough space to store entire error string)*/ + if (maxsize > 3) + memcpy(s+maxsize-4, "...", 3); + return ERANGE; + + #endif +} |