lib: sbi: Fix timing of clearing tbuf

A single scan of the format char may add multiple characters to the
tbuf, causing a buffer overflow. You should check if tbuf is full in
printc so that it does not cause a buffer overflow.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
Xiang W
2023-07-10 00:02:30 +08:00
committed by Anup Patel
parent cc89fa7b54
commit ff43168137

View File

@@ -121,6 +121,7 @@ unsigned long sbi_ngets(char *str, unsigned long len)
#define PAD_ZERO 2 #define PAD_ZERO 2
#define PAD_ALTERNATE 4 #define PAD_ALTERNATE 4
#define PAD_SIGN 8 #define PAD_SIGN 8
#define USE_TBUF 16
#define PRINT_BUF_LEN 64 #define PRINT_BUF_LEN 64
#define va_start(v, l) __builtin_va_start((v), l) #define va_start(v, l) __builtin_va_start((v), l)
@@ -128,7 +129,7 @@ unsigned long sbi_ngets(char *str, unsigned long len)
#define va_arg __builtin_va_arg #define va_arg __builtin_va_arg
typedef __builtin_va_list va_list; typedef __builtin_va_list va_list;
static void printc(char **out, u32 *out_len, char ch) static void printc(char **out, u32 *out_len, char ch, int flags)
{ {
if (!out) { if (!out) {
sbi_putc(ch); sbi_putc(ch);
@@ -142,8 +143,14 @@ static void printc(char **out, u32 *out_len, char ch)
if (!out_len || *out_len > 1) { if (!out_len || *out_len > 1) {
*(*out)++ = ch; *(*out)++ = ch;
**out = '\0'; **out = '\0';
if (out_len) if (out_len) {
--(*out_len); --(*out_len);
if ((flags & USE_TBUF) && *out_len == 1) {
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - *out_len);
*out = console_tbuf;
*out_len = CONSOLE_TBUF_MAX;
}
}
} }
} }
@@ -154,16 +161,16 @@ static int prints(char **out, u32 *out_len, const char *string, int width,
width -= sbi_strlen(string); width -= sbi_strlen(string);
if (!(flags & PAD_RIGHT)) { if (!(flags & PAD_RIGHT)) {
for (; width > 0; --width) { for (; width > 0; --width) {
printc(out, out_len, flags & PAD_ZERO ? '0' : ' '); printc(out, out_len, flags & PAD_ZERO ? '0' : ' ', flags);
++pc; ++pc;
} }
} }
for (; *string; ++string) { for (; *string; ++string) {
printc(out, out_len, *string); printc(out, out_len, *string, flags);
++pc; ++pc;
} }
for (; width > 0; --width) { for (; width > 0; --width) {
printc(out, out_len, ' '); printc(out, out_len, ' ', flags);
++pc; ++pc;
} }
@@ -215,18 +222,18 @@ static int printi(char **out, u32 *out_len, long long i,
if (flags & PAD_ZERO) { if (flags & PAD_ZERO) {
if (sign) { if (sign) {
printc(out, out_len, sign); printc(out, out_len, sign, flags);
++pc; ++pc;
--width; --width;
} }
if (i && (flags & PAD_ALTERNATE)) { if (i && (flags & PAD_ALTERNATE)) {
if (b == 16 || b == 8) { if (b == 16 || b == 8) {
printc(out, out_len, '0'); printc(out, out_len, '0', flags);
++pc; ++pc;
--width; --width;
} }
if (b == 16) { if (b == 16) {
printc(out, out_len, 'x' - 'a' + letbase); printc(out, out_len, 'x' - 'a' + letbase, flags);
++pc; ++pc;
--width; --width;
} }
@@ -265,15 +272,11 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
} }
for (; *format != 0; ++format) { for (; *format != 0; ++format) {
if (use_tbuf && !console_tbuf_len) { width = flags = 0;
nputs_all(console_tbuf, CONSOLE_TBUF_MAX); if (use_tbuf)
console_tbuf_len = CONSOLE_TBUF_MAX; flags |= USE_TBUF;
tout = console_tbuf;
}
if (*format == '%') { if (*format == '%') {
++format; ++format;
width = flags = 0;
if (*format == '\0') if (*format == '\0')
break; break;
if (*format == '%') if (*format == '%')
@@ -371,7 +374,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
} }
} else { } else {
literal: literal:
printc(out, out_len, *format); printc(out, out_len, *format, flags);
++pc; ++pc;
} }
} }