aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2023-07-16 20:01:42 -0500
committerDenis Kenzior <denkenz@gmail.com>2023-07-16 20:01:42 -0500
commitbc58765e81f040a2ea15c14970b6bd7b9cd39788 (patch)
treeced23af5caebe8baef545a1f2c465f2d588a96e9
parent104d49638e3668bcc2935099a59f2ab2caf6b27f (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.c82
-rw-r--r--ell/util.h5
2 files changed, 87 insertions, 0 deletions
diff --git a/ell/util.c b/ell/util.c
index 2829a330..34b4224b 100644
--- a/ell/util.c
+++ b/ell/util.c
@@ -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);
+}
diff --git a/ell/util.h b/ell/util.h
index 19987203..589121a2 100644
--- a/ell/util.h
+++ b/ell/util.h
@@ -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