[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
This commit is contained in:
parent
d4c1855578
commit
86c39754f2
|
@ -450,6 +450,7 @@ if 1:
|
|||
'strchr',
|
||||
'strdup',
|
||||
'strerror',
|
||||
'strerror_r',
|
||||
'strftime',
|
||||
'strstr',
|
||||
'strtol',
|
||||
|
|
|
@ -1516,6 +1516,7 @@ AC_CHECK_FUNCS([\
|
|||
sigaction \
|
||||
signal \
|
||||
srandom \
|
||||
strerror_r \
|
||||
timegm \
|
||||
writev \
|
||||
])
|
||||
|
|
|
@ -192,6 +192,7 @@ check_function_exists(sigaction HAVE_SIGACTION)
|
|||
check_function_exists(signal HAVE_SIGNAL)
|
||||
check_function_exists(sigtimedwait HAVE_SIGTIMEDWAIT)
|
||||
check_function_exists(srandom HAVE_SRANDOM)
|
||||
check_function_exists(strerror_r HAVE_STRERROR_R)
|
||||
check_function_exists(strptime HAVE_STRPTIME)
|
||||
check_function_exists(syslog HAVE_SYSLOG)
|
||||
check_function_exists(writev HAVE_WRITEV)
|
||||
|
@ -767,7 +768,7 @@ set(COMMON_SRC
|
|||
request.c
|
||||
sock_addr.c
|
||||
rand.c
|
||||
safe_memclear.c
|
||||
ck.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
|
|
@ -88,7 +88,7 @@ common_src=base64.c buffer.c burl.c log.c \
|
|||
rand.c \
|
||||
request.c \
|
||||
sock_addr.c \
|
||||
safe_memclear.c
|
||||
ck.c
|
||||
|
||||
src = server.c response.c connections.c h2.c reqpool.c \
|
||||
sock_addr_cache.c \
|
||||
|
|
|
@ -74,7 +74,7 @@ common_src = Split("base64.c buffer.c burl.c log.c \
|
|||
request.c \
|
||||
sock_addr.c \
|
||||
rand.c \
|
||||
safe_memclear.c \
|
||||
ck.c \
|
||||
")
|
||||
|
||||
src = Split("server.c response.c connections.c h2.c reqpool.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
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 INCLUDED_CK_H
|
||||
#define INCLUDED_CK_H
|
||||
#ifndef __STDC_WANT_LIB_EXT1__ /*(enable C11 Annex K ext1 *_s functions)*/
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#endif
|
||||
#include "first.h"
|
||||
#ifdef __FreeBSD__
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
#ifndef RSIZE_MAX
|
||||
#define RSIZE_MAX (SIZE_MAX >> 1)
|
||||
typedef size_t rsize_t;
|
||||
typedef int errno_t;
|
||||
#endif
|
||||
|
||||
|
||||
errno_t ck_getenv_s (size_t * restrict len, char * restrict value, rsize_t maxsize, const char * restrict name);
|
||||
|
||||
/*(ck_memclear_s() is not from C11 Annex K
|
||||
* ck_memclear_s() is similar to memset_s() using constant byte 0 for fill)*/
|
||||
errno_t ck_memclear_s (void *s, rsize_t smax, rsize_t n);
|
||||
|
||||
/*(ck_memzero() is not from C11 Annex K
|
||||
* ck_memzero() is a convenience wrapper around ck_memclear_s())*/
|
||||
static inline errno_t ck_memzero(void *s, rsize_t n);
|
||||
static inline errno_t ck_memzero(void *s, rsize_t n) {
|
||||
return ck_memclear_s(s, n, n);
|
||||
}
|
||||
|
||||
errno_t ck_strerror_s (char *s, rsize_t maxsize, errno_t errnum);
|
||||
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
||||
#endif
|
|
@ -144,6 +144,7 @@
|
|||
#cmakedefine HAVE_SIGACTION
|
||||
#cmakedefine HAVE_SIGNAL
|
||||
#cmakedefine HAVE_SIGTIMEDWAIT
|
||||
#cmakedefine HAVE_STRERROR_R
|
||||
#cmakedefine HAVE_STRPTIME
|
||||
#cmakedefine HAVE_SYSLOG
|
||||
#cmakedefine HAVE_TIMEGM
|
||||
|
|
|
@ -142,6 +142,7 @@ conf_data.set('HAVE_SIGACTION', compiler.has_function('sigaction', args: defs))
|
|||
conf_data.set('HAVE_SIGNAL', compiler.has_function('signal', args: defs))
|
||||
conf_data.set('HAVE_SIGTIMEDWAIT', compiler.has_function('sigtimedwait', args: defs))
|
||||
conf_data.set('HAVE_SRANDOM', compiler.has_function('srandom', args: defs))
|
||||
conf_data.set('HAVE_STRERROR_R', compiler.has_function('strerror_r', args: defs))
|
||||
conf_data.set('HAVE_STRPTIME', compiler.has_function('strptime', args: defs))
|
||||
conf_data.set('HAVE_SYSLOG', compiler.has_function('syslog', args: defs))
|
||||
conf_data.set('HAVE_TIMEGM', compiler.has_function('timegm', args: defs))
|
||||
|
@ -739,7 +740,7 @@ common_src = [
|
|||
'plugin.c',
|
||||
'rand.c',
|
||||
'request.c',
|
||||
'safe_memclear.c',
|
||||
'ck.c',
|
||||
'sock_addr.c',
|
||||
'stat_cache.c',
|
||||
'vector.c',
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#include "first.h"
|
||||
|
||||
#include "safe_memclear.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include <WinBase.h>
|
||||
/*(Windows XP and later provide SecureZeroMemory())*/
|
||||
#define HAVE_SECUREZEROMEMORY
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_MEMSET_S) \
|
||||
&& !defined(HAVE_EXPLICIT_BZERO) \
|
||||
&& !defined(HAVE_EXPLICIT_MEMSET) \
|
||||
&& !defined(HAVE_SECUREZEROMEMORY)
|
||||
|
||||
typedef void *(*safe_memclear_func_t)(void *, int, size_t);
|
||||
extern volatile safe_memclear_func_t safe_memclear_func;
|
||||
volatile safe_memclear_func_t safe_memclear_func = memset;
|
||||
|
||||
# if defined(HAVE_WEAK_SYMBOLS)
|
||||
/* it seems weak functions are never inlined, even for static builds */
|
||||
__attribute__((weak)) void __li_safe_memset_hook(void *buf, size_t len);
|
||||
|
||||
void __li_safe_memset_hook(void *buf, size_t len)
|
||||
{
|
||||
UNUSED(buf);
|
||||
UNUSED(len);
|
||||
}
|
||||
# endif /* HAVE_WEAK_SYMBOLS */
|
||||
|
||||
static void* safe_memset(void *s, int c, size_t n)
|
||||
{
|
||||
if (n > 0) {
|
||||
volatile unsigned volatile_zero = 0;
|
||||
volatile unsigned char *vs = (volatile unsigned char*)s;
|
||||
|
||||
do {
|
||||
safe_memclear_func(s, c, n);
|
||||
} while (vs[volatile_zero] != (unsigned char)c);
|
||||
# if defined(HAVE_WEAK_SYMBOLS)
|
||||
__li_safe_memset_hook(s, n);
|
||||
# endif /* HAVE_WEAK_SYMBOLS */
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void safe_memclear(void *s, size_t n) {
|
||||
#if defined(HAVE_MEMSET_S)
|
||||
memset_s(s, n, 0, n);
|
||||
#elif 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
|
||||
safe_memset(s, 0, n);
|
||||
#endif
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#define _SAFE_MEMCLEAR_H_
|
||||
#include "first.h"
|
||||
|
||||
void safe_memclear(void *s, size_t n);
|
||||
#include "ck.h"
|
||||
#define safe_memclear ck_memzero
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue