[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] libc: Verhindern von Über- und Unterläufe in Scanf
! Scanf limitiert die maximale Größe einer eingelesener Zahl abhängig
von der Variablengröße. Dieser Commit implementiert dieses Verhalten.
Signed-off-by: Nico Mayer <mayerNico@xxxxxxxxxx>
---
src/lib/string.c | 15 +++++++++++----
src/modules/lib/stdlibc/scanf.c | 31 ++++++++++++++++++++++++++++++-
2 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/src/lib/string.c b/src/lib/string.c
index 98861869..6eb90e98 100644
--- a/src/lib/string.c
+++ b/src/lib/string.c
@@ -67,7 +67,9 @@ void itoa(unsigned int n, char *s, unsigned int base)
s[y] = '\0';
}
-unsigned long long int strtoull(const char *nptr, char **endptr, int base)
+unsigned long long int do_strtoull(const char *nptr, char **endptr, int base,
+ unsigned long long max_val,
+ unsigned long long min_val)
{
unsigned long long int result = 0;
int neg = 0;
@@ -145,7 +147,7 @@ unsigned long long int strtoull(const char *nptr, char **endptr, int base)
goto out;
}
- if (result > (ULLONG_MAX - digit) / base) {
+ if (result > (max_val - digit) / base) {
overflow = true;
}
result = result * base + digit;
@@ -159,15 +161,20 @@ out:
}
if (overflow) {
- return ULLONG_MAX;
+ return neg ? min_val : max_val;
}
return neg ? - result : result;
}
+unsigned long long int strtoull(const char *nptr, char **endptr, int base)
+{
+ return do_strtoull(nptr, endptr, base, ULLONG_MAX, ULLONG_MAX);
+}
+
unsigned long int strtoul(const char *nptr, char **endptr, int base)
{
- return (unsigned long int) strtoull(nptr, endptr, base);
+ return (unsigned long int) do_strtoull(nptr, endptr, base, ULONG_MAX, ULLONG_MAX);
}
diff --git a/src/modules/lib/stdlibc/scanf.c b/src/modules/lib/stdlibc/scanf.c
index 0f978606..c4d0082d 100644
--- a/src/modules/lib/stdlibc/scanf.c
+++ b/src/modules/lib/stdlibc/scanf.c
@@ -33,6 +33,12 @@
#include <stddef.h>
#include <string.h>
#include <ctype.h>
+#include <limits.h>
+
+
+unsigned long long int do_strtoull(const char *nptr, char **endptr, int base,
+ unsigned long long max_val,
+ unsigned long long min_val);
typedef int (*jscanf_getc)(void* state);
typedef void (*jscanf_ungetc)(void* state, char c);
@@ -185,6 +191,7 @@ static int jscanf(const char* fmt, va_list ap,
int c;
char* endptr;
uint64_t value;
+ int non_negative = 0;
// 64 Bit oktal = 22 Zeichen, führende 0, Vorzeichen und \0
char buf[25];
@@ -282,22 +289,30 @@ static int jscanf(const char* fmt, va_list ap,
// %p - Pointer (strtoul mit Basis 16)
case 'i':
base = 0;
+ non_negative = 0;
goto convert_number;
case 'o':
base = 8;
+ non_negative = 1;
goto convert_number;
case 'x':
case 'X':
+ non_negative = 1;
base = 16;
goto convert_number;
case 'p':
base = 16;
size = sizeof(void*);
+ non_negative = 1;
len = 0;
goto convert_number;
case 'd':
+ base = 10;
+ non_negative = 0;
+ goto convert_number;
case 'u':
base = 10;
+ non_negative = 1;
convert_number:
if (len == 0 || len >= sizeof(buf)) {
len = sizeof(buf) - 1;
@@ -305,7 +320,20 @@ static int jscanf(const char* fmt, va_list ap,
len = jscanf_read_number(buf, len, jgetc, jungetc,
state, base, &eof);
- value = strtoull(buf, &endptr, base);
+ if (size == sizeof(int)) {
+ if (non_negative) {
+ value = do_strtoull(buf, &endptr, base, ULONG_MAX, ULONG_MAX);
+ } else {
+ value = do_strtoull(buf, &endptr, base, LONG_MAX, LONG_MIN);
+ }
+ } else {
+ if (non_negative) {
+ value = do_strtoull(buf, &endptr, base, ULLONG_MAX, ULLONG_MAX);
+ } else {
+ value = do_strtoull(buf, &endptr, base, LLONG_MAX, LLONG_MIN);
+ }
+ }
+
if ((endptr != buf + len) || (len == 0)) {
if ((len == 0) && eof) {
goto input_error;
@@ -320,6 +348,7 @@ static int jscanf(const char* fmt, va_list ap,
}
break;
+
// %n - Anzahl der bisher gelesenen Zeichen
case 'n':
if (assign) {
--
2.29.2