summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArvind Sankar <nivedita@alum.mit.edu>2020-05-18 22:07:08 +0300
committerArd Biesheuvel <ardb@kernel.org>2020-05-19 11:32:04 +0300
commit8fb331e10b63888e944a8a0dcf79b17e93b475ba (patch)
tree36be9c5f83b1096e6d427084d39694986b1d37ad
parentf97ca2c816748e3b7dee58775632f9e9269071e6 (diff)
downloadlinux-8fb331e10b63888e944a8a0dcf79b17e93b475ba.tar.xz
efi/printf: Turn vsprintf into vsnprintf
Implement vsnprintf instead of vsprintf to avoid the possibility of a buffer overflow. Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu> Link: https://lore.kernel.org/r/20200518190716.751506-17-nivedita@alum.mit.edu Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c6
-rw-r--r--drivers/firmware/efi/libstub/vsprintf.c42
2 files changed, 30 insertions, 18 deletions
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 56b3b84fd3bd..5ecafc57619a 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -60,10 +60,14 @@ int efi_printk(const char *fmt, ...)
int printed;
va_start(args, fmt);
- printed = vsprintf(printf_buf, fmt, args);
+ printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
va_end(args);
efi_puts(printf_buf);
+ if (printed >= sizeof(printf_buf)) {
+ efi_puts("[Message truncated]\n");
+ return -1;
+ }
return printed;
}
diff --git a/drivers/firmware/efi/libstub/vsprintf.c b/drivers/firmware/efi/libstub/vsprintf.c
index cca6b802b028..a3265a81adca 100644
--- a/drivers/firmware/efi/libstub/vsprintf.c
+++ b/drivers/firmware/efi/libstub/vsprintf.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/string.h>
+#include <linux/types.h>
static
int skip_atoi(const char **s)
@@ -237,16 +238,22 @@ char get_sign(long long *num, int flags)
return 0;
}
-int vsprintf(char *buf, const char *fmt, va_list ap)
+#define PUTC(c) \
+do { \
+ if (pos < size) \
+ buf[pos] = (c); \
+ ++pos; \
+} while (0);
+
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
{
/* The maximum space required is to print a 64-bit number in octal */
char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
long long num;
int base;
- char *str;
const char *s;
- int len;
+ size_t len, pos;
char sign;
int flags; /* flags to number() */
@@ -274,9 +281,9 @@ int vsprintf(char *buf, const char *fmt, va_list ap)
*/
va_copy(args, ap);
- for (str = buf; *fmt; ++fmt) {
+ for (pos = 0; *fmt; ++fmt) {
if (*fmt != '%' || *++fmt == '%') {
- *str++ = *fmt;
+ PUTC(*fmt);
continue;
}
@@ -416,40 +423,41 @@ output:
/* Leading padding with ' ' */
if (!(flags & LEFT))
while (field_width-- > 0)
- *str++ = ' ';
+ PUTC(' ');
/* sign */
if (sign)
- *str++ = sign;
+ PUTC(sign);
/* 0x/0X for hexadecimal */
if (flags & SPECIAL) {
- *str++ = '0';
- *str++ = 'X' | (flags & SMALL);
+ PUTC('0');
+ PUTC( 'X' | (flags & SMALL));
}
/* Zero padding and excess precision */
while (precision-- > len)
- *str++ = '0';
+ PUTC('0');
/* Actual output */
while (len-- > 0)
- *str++ = *s++;
+ PUTC(*s++);
/* Trailing padding with ' ' */
while (field_width-- > 0)
- *str++ = ' ';
+ PUTC(' ');
}
fail:
- *str = '\0';
-
va_end(args);
- return str - buf;
+ if (size)
+ buf[min(pos, size-1)] = '\0';
+
+ return pos;
}
-int sprintf(char *buf, const char *fmt, ...)
+int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
- i = vsprintf(buf, fmt, args);
+ i = vsnprintf(buf, size, fmt, args);
va_end(args);
return i;
}