diff options
author | Jan Beulich <JBeulich@suse.com> | 2012-12-17 19:01:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-17 20:15:18 -0500 |
commit | 53809751ac230a3611b5cdd375f3389f3207d471 (patch) | |
tree | 8555da83945aaba9291f0d9ff09d271043e36263 /lib | |
parent | 375da3a76dc49f10c35e243ebef62df12e3adf4e (diff) |
sscanf: don't ignore field widths for numeric conversions
This is another step towards better standard conformance. Rather than
adding a local buffer to store the specified portion of the string (with
the need to enforce an arbitrary maximum supported width to limit the
buffer size), do a maximum width conversion and then drop as much of it as
is necessary to meet the caller's request.
Also fail on negative field widths.
Uses the deprecated simple_strto*() functions because kstrtoXX() fail on
non-zero terminated strings.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/vsprintf.c | 96 |
1 files changed, 53 insertions, 43 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 41da0741a663..292fcb174a32 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -23,12 +23,12 @@ | |||
23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/kallsyms.h> | 25 | #include <linux/kallsyms.h> |
26 | #include <linux/math64.h> | ||
26 | #include <linux/uaccess.h> | 27 | #include <linux/uaccess.h> |
27 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
28 | #include <net/addrconf.h> | 29 | #include <net/addrconf.h> |
29 | 30 | ||
30 | #include <asm/page.h> /* for PAGE_SIZE */ | 31 | #include <asm/page.h> /* for PAGE_SIZE */ |
31 | #include <asm/div64.h> | ||
32 | #include <asm/sections.h> /* for dereference_function_descriptor() */ | 32 | #include <asm/sections.h> /* for dereference_function_descriptor() */ |
33 | 33 | ||
34 | #include "kstrtox.h" | 34 | #include "kstrtox.h" |
@@ -2016,7 +2016,11 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2016 | char digit; | 2016 | char digit; |
2017 | int num = 0; | 2017 | int num = 0; |
2018 | u8 qualifier; | 2018 | u8 qualifier; |
2019 | u8 base; | 2019 | unsigned int base; |
2020 | union { | ||
2021 | long long s; | ||
2022 | unsigned long long u; | ||
2023 | } val; | ||
2020 | s16 field_width; | 2024 | s16 field_width; |
2021 | bool is_sign; | 2025 | bool is_sign; |
2022 | 2026 | ||
@@ -2056,8 +2060,11 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2056 | 2060 | ||
2057 | /* get field width */ | 2061 | /* get field width */ |
2058 | field_width = -1; | 2062 | field_width = -1; |
2059 | if (isdigit(*fmt)) | 2063 | if (isdigit(*fmt)) { |
2060 | field_width = skip_atoi(&fmt); | 2064 | field_width = skip_atoi(&fmt); |
2065 | if (field_width <= 0) | ||
2066 | break; | ||
2067 | } | ||
2061 | 2068 | ||
2062 | /* get conversion qualifier */ | 2069 | /* get conversion qualifier */ |
2063 | qualifier = -1; | 2070 | qualifier = -1; |
@@ -2157,58 +2164,61 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2157 | || (base == 0 && !isdigit(digit))) | 2164 | || (base == 0 && !isdigit(digit))) |
2158 | break; | 2165 | break; |
2159 | 2166 | ||
2167 | if (is_sign) | ||
2168 | val.s = qualifier != 'L' ? | ||
2169 | simple_strtol(str, &next, base) : | ||
2170 | simple_strtoll(str, &next, base); | ||
2171 | else | ||
2172 | val.u = qualifier != 'L' ? | ||
2173 | simple_strtoul(str, &next, base) : | ||
2174 | simple_strtoull(str, &next, base); | ||
2175 | |||
2176 | if (field_width > 0 && next - str > field_width) { | ||
2177 | if (base == 0) | ||
2178 | _parse_integer_fixup_radix(str, &base); | ||
2179 | while (next - str > field_width) { | ||
2180 | if (is_sign) | ||
2181 | val.s = div_s64(val.s, base); | ||
2182 | else | ||
2183 | val.u = div_u64(val.u, base); | ||
2184 | --next; | ||
2185 | } | ||
2186 | } | ||
2187 | |||
2160 | switch (qualifier) { | 2188 | switch (qualifier) { |
2161 | case 'H': /* that's 'hh' in format */ | 2189 | case 'H': /* that's 'hh' in format */ |
2162 | if (is_sign) { | 2190 | if (is_sign) |
2163 | signed char *s = (signed char *)va_arg(args, signed char *); | 2191 | *va_arg(args, signed char *) = val.s; |
2164 | *s = (signed char)simple_strtol(str, &next, base); | 2192 | else |
2165 | } else { | 2193 | *va_arg(args, unsigned char *) = val.u; |
2166 | unsigned char *s = (unsigned char *)va_arg(args, unsigned char *); | ||
2167 | *s = (unsigned char)simple_strtoul(str, &next, base); | ||
2168 | } | ||
2169 | break; | 2194 | break; |
2170 | case 'h': | 2195 | case 'h': |
2171 | if (is_sign) { | 2196 | if (is_sign) |
2172 | short *s = (short *)va_arg(args, short *); | 2197 | *va_arg(args, short *) = val.s; |
2173 | *s = (short)simple_strtol(str, &next, base); | 2198 | else |
2174 | } else { | 2199 | *va_arg(args, unsigned short *) = val.u; |
2175 | unsigned short *s = (unsigned short *)va_arg(args, unsigned short *); | ||
2176 | *s = (unsigned short)simple_strtoul(str, &next, base); | ||
2177 | } | ||
2178 | break; | 2200 | break; |
2179 | case 'l': | 2201 | case 'l': |
2180 | if (is_sign) { | 2202 | if (is_sign) |
2181 | long *l = (long *)va_arg(args, long *); | 2203 | *va_arg(args, long *) = val.s; |
2182 | *l = simple_strtol(str, &next, base); | 2204 | else |
2183 | } else { | 2205 | *va_arg(args, unsigned long *) = val.u; |
2184 | unsigned long *l = (unsigned long *)va_arg(args, unsigned long *); | ||
2185 | *l = simple_strtoul(str, &next, base); | ||
2186 | } | ||
2187 | break; | 2206 | break; |
2188 | case 'L': | 2207 | case 'L': |
2189 | if (is_sign) { | 2208 | if (is_sign) |
2190 | long long *l = (long long *)va_arg(args, long long *); | 2209 | *va_arg(args, long long *) = val.s; |
2191 | *l = simple_strtoll(str, &next, base); | 2210 | else |
2192 | } else { | 2211 | *va_arg(args, unsigned long long *) = val.u; |
2193 | unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *); | ||
2194 | *l = simple_strtoull(str, &next, base); | ||
2195 | } | ||
2196 | break; | 2212 | break; |
2197 | case 'Z': | 2213 | case 'Z': |
2198 | case 'z': | 2214 | case 'z': |
2199 | { | 2215 | *va_arg(args, size_t *) = val.u; |
2200 | size_t *s = (size_t *)va_arg(args, size_t *); | 2216 | break; |
2201 | *s = (size_t)simple_strtoul(str, &next, base); | ||
2202 | } | ||
2203 | break; | ||
2204 | default: | 2217 | default: |
2205 | if (is_sign) { | 2218 | if (is_sign) |
2206 | int *i = (int *)va_arg(args, int *); | 2219 | *va_arg(args, int *) = val.s; |
2207 | *i = (int)simple_strtol(str, &next, base); | 2220 | else |
2208 | } else { | 2221 | *va_arg(args, unsigned int *) = val.u; |
2209 | unsigned int *i = (unsigned int *)va_arg(args, unsigned int*); | ||
2210 | *i = (unsigned int)simple_strtoul(str, &next, base); | ||
2211 | } | ||
2212 | break; | 2222 | break; |
2213 | } | 2223 | } |
2214 | num++; | 2224 | num++; |