aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJan Beulich <JBeulich@suse.com>2012-12-17 19:01:31 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-17 20:15:18 -0500
commit53809751ac230a3611b5cdd375f3389f3207d471 (patch)
tree8555da83945aaba9291f0d9ff09d271043e36263 /lib
parent375da3a76dc49f10c35e243ebef62df12e3adf4e (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.c96
1 files changed, 53 insertions, 43 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 41da0741a66..292fcb174a3 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++;