mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-26 18:43:33 -05:00
lib/vsprintf.c: improve standard conformance of sscanf()
Xen's pciback points out a couple of deficiencies with vsscanf()'s standard conformance: - Trailing character matching cannot be checked by the caller: With a format string of "(%x:%x.%x) %n" absence of the closing parenthesis cannot be checked, as input of "(00:00.0)" doesn't cause the %n to be evaluated (because of the code not skipping white space before the trailing %n). - The parameter corresponding to a trailing %n could get filled even if there was a matching error: With a format string of "(%x:%x.%x)%n", input of "(00:00.0]" would still fill the respective variable pointed to (and hence again make the mismatch non-detectable by the caller). This patch aims at fixing those, but leaves other non-conforming aspects of it untouched, among them these possibly relevant ones: - improper handling of the assignment suppression character '*' (blindly discarding all succeeding non-white space from the format and input strings), - not honoring conversion specifiers for %n, - not recognizing the C99 conversion specifier 't' (recognized by vsprintf()). Signed-off-by: Jan Beulich <jbeulich@suse.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
214f766ea0
commit
da99075c1d
1 changed files with 14 additions and 19 deletions
|
@ -2017,7 +2017,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
|
||||||
s16 field_width;
|
s16 field_width;
|
||||||
bool is_sign;
|
bool is_sign;
|
||||||
|
|
||||||
while (*fmt && *str) {
|
while (*fmt) {
|
||||||
/* skip any white space in format */
|
/* skip any white space in format */
|
||||||
/* white space in format matchs any amount of
|
/* white space in format matchs any amount of
|
||||||
* white space, including none, in the input.
|
* white space, including none, in the input.
|
||||||
|
@ -2042,6 +2042,8 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
|
||||||
* advance both strings to next white space
|
* advance both strings to next white space
|
||||||
*/
|
*/
|
||||||
if (*fmt == '*') {
|
if (*fmt == '*') {
|
||||||
|
if (!*str)
|
||||||
|
break;
|
||||||
while (!isspace(*fmt) && *fmt != '%' && *fmt)
|
while (!isspace(*fmt) && *fmt != '%' && *fmt)
|
||||||
fmt++;
|
fmt++;
|
||||||
while (!isspace(*str) && *str)
|
while (!isspace(*str) && *str)
|
||||||
|
@ -2070,7 +2072,17 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*fmt || !*str)
|
if (!*fmt)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*fmt == 'n') {
|
||||||
|
/* return number of characters read so far */
|
||||||
|
*va_arg(args, int *) = str - buf;
|
||||||
|
++fmt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*str)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
base = 10;
|
base = 10;
|
||||||
|
@ -2103,13 +2115,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case 'n':
|
|
||||||
/* return number of characters read so far */
|
|
||||||
{
|
|
||||||
int *i = (int *)va_arg(args, int*);
|
|
||||||
*i = str - buf;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
case 'o':
|
case 'o':
|
||||||
base = 8;
|
base = 8;
|
||||||
break;
|
break;
|
||||||
|
@ -2210,16 +2215,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
|
||||||
str = next;
|
str = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Now we've come all the way through so either the input string or the
|
|
||||||
* format ended. In the former case, there can be a %n at the current
|
|
||||||
* position in the format that needs to be filled.
|
|
||||||
*/
|
|
||||||
if (*fmt == '%' && *(fmt + 1) == 'n') {
|
|
||||||
int *p = (int *)va_arg(args, int *);
|
|
||||||
*p = str - buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vsscanf);
|
EXPORT_SYMBOL(vsscanf);
|
||||||
|
|
Loading…
Add table
Reference in a new issue