diff options
author | Denis Kenzior <denkenz@gmail.com> | 2023-07-16 20:01:42 -0500 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2023-07-16 20:01:42 -0500 |
commit | bc58765e81f040a2ea15c14970b6bd7b9cd39788 (patch) | |
tree | ced23af5caebe8baef545a1f2c465f2d588a96e9 | |
parent | 104d49638e3668bcc2935099a59f2ab2caf6b27f (diff) |
util: Add l_safe_atou32 & l_safe_atox{8,16,32} utilities
Useful for parsing data from sources that might not be trusted. Unlike
strtoul, leading whitespace is not allowed. Neither are '+' and '-'
characters. Leading zeros are not allowed by l_safe_atou32.
-rw-r--r-- | ell/util.c | 82 | ||||
-rw-r--r-- | ell/util.h | 5 |
2 files changed, 87 insertions, 0 deletions
@@ -28,6 +28,8 @@ #include <stdio.h> #include <stdlib.h> #include <limits.h> +#include <stdint.h> +#include <errno.h> #include "utf8.h" #include "util.h" @@ -745,3 +747,83 @@ LIB_EXPORT bool l_secure_memeq(const void *field, size_t size, uint8_t byte) { return __secure_memeq(field, size, byte) == 0 ? true : false; } + +static int safe_atou(const char *s, int base, unsigned int *out_u) +{ + unsigned long int r; + unsigned int t; + char *endp; + + errno = 0; + + t = r = strtoul(s, &endp, base); + if (unlikely(errno > 0)) + return -errno; + + if (endp == s || *endp != '\0') + return -EINVAL; + + if (unlikely(r != t)) + return -ERANGE; + + if (out_u) + *out_u = t; + + return 0; +} + +LIB_EXPORT int l_safe_atou32(const char *s, uint32_t *out_u) +{ + if (!l_ascii_isdigit(s[0])) + return -EINVAL; + + /* Don't allow leading zeros */ + if (s[0] == '0' && s[1] != '\0') + return -EINVAL; + + return safe_atou(s, 10, out_u); +} + +LIB_EXPORT int l_safe_atox8(const char *s, uint8_t *out_x) +{ + uint32_t x; + int r; + + r = l_safe_atox32(s, &x); + if (r < 0) + return r; + + if (x > UINT8_MAX) + return -ERANGE; + + if (out_x) + *out_x = x; + + return 0; +} + +LIB_EXPORT int l_safe_atox16(const char *s, uint16_t *out_x) +{ + uint32_t x; + int r; + + r = l_safe_atox32(s, &x); + if (r < 0) + return r; + + if (x > UINT16_MAX) + return -ERANGE; + + if (out_x) + *out_x = x; + + return 0; +} + +LIB_EXPORT int l_safe_atox32(const char *s, uint32_t *out_x) +{ + if (!l_ascii_isxdigit(s[0])) + return -EINVAL; + + return safe_atou(s, 16, out_x); +} @@ -427,6 +427,11 @@ static inline void l_secure_select(bool select_left, o[i] = r[i] ^ ((l[i] ^ r[i]) & mask); } +int l_safe_atou32(const char *s, uint32_t *out_u); +int l_safe_atox32(const char *s, uint32_t *out_u); +int l_safe_atox16(const char *s, uint16_t *out_u); +int l_safe_atox8(const char *s, uint8_t *out_u); + #ifdef __cplusplus } #endif |