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++; |
