[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