From 13fac76a71f25631d7415ba457bdab267d0950d4 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 4 Aug 2020 14:49:21 +0200 Subject: ctype: use non-locale-specific ctype.h We also make these constant time, even though we're never distinguishing between bits of a secret using them. From that perspective, though, this is markedly better than the locale-specific table lookups in glibc, even though base64 characters span two cache lines and valid private keys must hit both. Co-authored-by: Samuel Neves Signed-off-by: Jason A. Donenfeld Signed-off-by: Samuel Neves --- src/config.c | 14 +++++++------- src/ctype.h | 29 +++++++++++++++++++++++++++++ src/ipc-uapi.h | 6 +++--- src/pubkey.c | 4 ++-- src/terminal.c | 4 ++-- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 src/ctype.h diff --git a/src/config.c b/src/config.c index b8394a5..e0b4b7c 100644 --- a/src/config.c +++ b/src/config.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include "containers.h" #include "ipc.h" #include "encoding.h" +#include "ctype.h" #define COMMENT_CHAR '#' @@ -86,7 +86,7 @@ static inline bool parse_fwmark(uint32_t *fwmark, uint32_t *flags, const char *v return true; } - if (!isdigit(value[0])) + if (!char_is_digit(value[0])) goto err; if (strlen(value) > 2 && value[0] == '0' && value[1] == 'x') @@ -141,7 +141,7 @@ static bool parse_keyfile(uint8_t key[static WG_KEY_LEN], const char *path) dst[WG_KEY_LEN_BASE64 - 1] = '\0'; while ((c = getc(f)) != EOF) { - if (!isspace(c)) { + if (!char_is_space(c)) { fprintf(stderr, "Found trailing character in key file: `%c'\n", c); goto out; } @@ -290,7 +290,7 @@ static inline bool parse_persistent_keepalive(uint16_t *interval, uint32_t *flag return true; } - if (!isdigit(value[0])) + if (!char_is_digit(value[0])) goto err; ret = strtoul(value, &end, 10); @@ -375,7 +375,7 @@ static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **la } if (mask) { - if (!isdigit(mask[0])) + if (!char_is_digit(mask[0])) goto err; cidr = strtoul(mask, &end, 10); if (*end || (cidr > 32 && new_allowedip->family == AF_INET) || (cidr > 128 && new_allowedip->family == AF_INET6)) @@ -501,7 +501,7 @@ bool config_read_line(struct config_ctx *ctx, const char *input) } for (size_t i = 0; i < len; ++i) { - if (!isspace(input[i])) + if (!char_is_space(input[i])) line[cleaned_len++] = input[i]; } if (!cleaned_len) @@ -555,7 +555,7 @@ static char *strip_spaces(const char *in) return NULL; } for (i = 0, l = 0; i < t; ++i) { - if (!isspace(in[i])) + if (!char_is_space(in[i])) out[l++] = in[i]; } return out; diff --git a/src/ctype.h b/src/ctype.h new file mode 100644 index 0000000..98b2283 --- /dev/null +++ b/src/ctype.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2015-2020 Jason A. Donenfeld . All Rights Reserved. + * + * Specialized constant-time ctype.h reimplementations that aren't locale-specific. + */ + +#ifndef CTYPE_H +#define CTYPE_H + +#include + +static inline bool char_is_space(int c) +{ + unsigned char d = c - 9; + return (0x80001FU >> (d & 31)) & (1U >> (d >> 5)); +} + +static inline bool char_is_digit(int c) +{ + return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1); +} + +static inline bool char_is_alpha(int c) +{ + return (unsigned int)(('a' - 1 - (c | 32)) & ((c | 32) - ('z' + 1))) >> (sizeof(c) * 8 - 1); +} + +#endif diff --git a/src/ipc-uapi.h b/src/ipc-uapi.h index 3b1fff3..f464be7 100644 --- a/src/ipc-uapi.h +++ b/src/ipc-uapi.h @@ -4,7 +4,6 @@ */ #include -#include #include #include #include @@ -17,6 +16,7 @@ #include "containers.h" #include "curve25519.h" #include "encoding.h" +#include "ctype.h" #ifdef _WIN32 #include "ipc-uapi-windows.h" @@ -102,7 +102,7 @@ static int userspace_set_device(struct wgdevice *dev) #define NUM(max) ({ \ unsigned long long num; \ char *end; \ - if (!isdigit(value[0])) \ + if (!char_is_digit(value[0])) \ break; \ num = strtoull(value, &end, 10); \ if (*end || num > max) \ @@ -223,7 +223,7 @@ static int userspace_get_device(struct wgdevice **out, const char *iface) struct wgallowedip *new_allowedip; char *end, *mask = value, *ip = strsep(&mask, "/"); - if (!mask || !isdigit(mask[0])) + if (!mask || !char_is_digit(mask[0])) break; new_allowedip = calloc(1, sizeof(*new_allowedip)); if (!new_allowedip) { diff --git a/src/pubkey.c b/src/pubkey.c index a78fe11..b4478dc 100644 --- a/src/pubkey.c +++ b/src/pubkey.c @@ -5,11 +5,11 @@ #include #include -#include #include "curve25519.h" #include "encoding.h" #include "subcommands.h" +#include "ctype.h" int pubkey_main(int argc, char *argv[]) { @@ -31,7 +31,7 @@ int pubkey_main(int argc, char *argv[]) for (;;) { trailing_char = getc(stdin); - if (!trailing_char || isspace(trailing_char)) + if (!trailing_char || char_is_space(trailing_char)) continue; if (trailing_char == EOF) break; diff --git a/src/terminal.c b/src/terminal.c index bea27ba..7c293cd 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -3,7 +3,6 @@ * Copyright (C) 2015-2020 Jason A. Donenfeld . All Rights Reserved. */ -#include #include #include #include @@ -11,6 +10,7 @@ #include #include #include +#include "ctype.h" static bool color_mode(void) { @@ -46,7 +46,7 @@ static void filter_ansi(const char *fmt, va_list args) if (str[i] == '\x1b' && str[i + 1] == '[') { str[i] = str[i + 1] = '\0'; for (j = i + 2; j < len; ++j) { - if (isalpha(str[j])) + if (char_is_alpha(str[j])) break; str[j] = '\0'; } -- cgit v1.2.3-59-g8ed1b