diff options
author | Kees Cook <keescook@chromium.org> | 2013-11-14 17:31:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-14 19:32:20 -0500 |
commit | 9196436ab2f713b823a2ba2024cb69f40b2f54a5 (patch) | |
tree | d10e292c5e307d616edfa13345a6735ed3cc93c9 | |
parent | 652586df95e5d76b37d07a11839126dcfede1621 (diff) |
vsprintf: ignore %n again
This ignores %n in printf again, as was originally documented.
Implementing %n poses a greater security risk than utility, so it should
stay ignored. To help anyone attempting to use %n, a warning will be
emitted if it is encountered.
Based on an earlier patch by Joe Perches.
Because %n was designed to write to pointers on the stack, it has been
frequently used as an attack vector when bugs are found that leak
user-controlled strings into functions that ultimately process format
strings. While this class of bug can still be turned into an
information leak, removing %n eliminates the common method of elevating
such a bug into an arbitrary kernel memory writing primitive,
significantly reducing the danger of this class of bug.
For seq_file users that need to know the length of a written string for
padding, please see seq_setwidth() and seq_pad() instead.
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Joe Perches <joe@perches.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | lib/vsprintf.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 48586ac3a62e..10909c571494 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -1712,18 +1712,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
1712 | break; | 1712 | break; |
1713 | 1713 | ||
1714 | case FORMAT_TYPE_NRCHARS: { | 1714 | case FORMAT_TYPE_NRCHARS: { |
1715 | u8 qualifier = spec.qualifier; | 1715 | /* |
1716 | * Since %n poses a greater security risk than | ||
1717 | * utility, ignore %n and skip its argument. | ||
1718 | */ | ||
1719 | void *skip_arg; | ||
1716 | 1720 | ||
1717 | if (qualifier == 'l') { | 1721 | WARN_ONCE(1, "Please remove ignored %%n in '%s'\n", |
1718 | long *ip = va_arg(args, long *); | 1722 | old_fmt); |
1719 | *ip = (str - buf); | 1723 | |
1720 | } else if (_tolower(qualifier) == 'z') { | 1724 | skip_arg = va_arg(args, void *); |
1721 | size_t *ip = va_arg(args, size_t *); | ||
1722 | *ip = (str - buf); | ||
1723 | } else { | ||
1724 | int *ip = va_arg(args, int *); | ||
1725 | *ip = (str - buf); | ||
1726 | } | ||
1727 | break; | 1725 | break; |
1728 | } | 1726 | } |
1729 | 1727 | ||