summaryrefslogtreecommitdiff
path: root/src/ck.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2021-05-21 22:22:45 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2021-08-27 02:16:41 -0400
commit86c39754f215ec00186a649c09cf0b2eea21c872 (patch)
tree6e3341a6657e2dabd4811393883752d125eb069f /src/ck.c
parentd4c18555780432718558833ccd7ae4870fd6845e (diff)
downloadlighttpd-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.c256
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
+}