Commit 60db772a authored by Benjamin LaHaise's avatar Benjamin LaHaise Committed by Linus Torvalds

[PATCH] vsnprintf returns incorrect length

In conjunction with some of the earlier problems found in /proc code,
now it turns out that snprintf doesn't work correctly in the kernel...
Without the following patch, snprintf can return lengths greater than
the size argument passed.  The net effect is that code using the return
value from snprintf can still buffer overrun.  This is fixed by not
updating the pointer in the buffer unless there is actually space.
parent 70abe157
...@@ -172,50 +172,41 @@ static char * number(char * buf, char * end, long long num, int base, int size, ...@@ -172,50 +172,41 @@ static char * number(char * buf, char * end, long long num, int base, int size,
if (!(type&(ZEROPAD+LEFT))) { if (!(type&(ZEROPAD+LEFT))) {
while(size-->0) { while(size-->0) {
if (buf <= end) if (buf <= end)
*buf = ' '; *buf++ = ' ';
++buf;
} }
} }
if (sign) { if (sign) {
if (buf <= end) if (buf <= end)
*buf = sign; *buf++ = sign;
++buf;
} }
if (type & SPECIAL) { if (type & SPECIAL) {
if (base==8) { if (base==8) {
if (buf <= end) if (buf <= end)
*buf = '0'; *buf++ = '0';
++buf;
} else if (base==16) { } else if (base==16) {
if (buf <= end) if (buf <= end)
*buf = '0'; *buf++ = '0';
++buf;
if (buf <= end) if (buf <= end)
*buf = digits[33]; *buf++ = digits[33];
++buf;
} }
} }
if (!(type & LEFT)) { if (!(type & LEFT)) {
while (size-- > 0) { while (size-- > 0) {
if (buf <= end) if (buf <= end)
*buf = c; *buf++ = c;
++buf;
} }
} }
while (i < precision--) { while (i < precision--) {
if (buf <= end) if (buf <= end)
*buf = '0'; *buf++ = '0';
++buf;
} }
while (i-- > 0) { while (i-- > 0) {
if (buf <= end) if (buf <= end)
*buf = tmp[i]; *buf++ = tmp[i];
++buf;
} }
while (size-- > 0) { while (size-- > 0) {
if (buf <= end) if (buf <= end)
*buf = ' '; *buf++ = ' ';
++buf;
} }
return buf; return buf;
} }
...@@ -247,6 +238,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ...@@ -247,6 +238,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
/* 'z' support added 23/7/1999 S.H. */ /* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */ /* 'z' changed to 'Z' --davidm 1/25/99 */
/* Enforce absolute minimum size: one character + the trailing 0 */
if (size < 2)
return 0;
str = buf; str = buf;
end = buf + size - 1; end = buf + size - 1;
...@@ -258,8 +253,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ...@@ -258,8 +253,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
for (; *fmt ; ++fmt) { for (; *fmt ; ++fmt) {
if (*fmt != '%') { if (*fmt != '%') {
if (str <= end) if (str <= end)
*str = *fmt; *str++ = *fmt;
++str;
continue; continue;
} }
...@@ -323,18 +317,15 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ...@@ -323,18 +317,15 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
if (!(flags & LEFT)) { if (!(flags & LEFT)) {
while (--field_width > 0) { while (--field_width > 0) {
if (str <= end) if (str <= end)
*str = ' '; *str++ = ' ';
++str;
} }
} }
c = (unsigned char) va_arg(args, int); c = (unsigned char) va_arg(args, int);
if (str <= end) if (str <= end)
*str = c; *str++ = c;
++str;
while (--field_width > 0) { while (--field_width > 0) {
if (str <= end) if (str <= end)
*str = ' '; *str++ = ' ';
++str;
} }
continue; continue;
...@@ -348,19 +339,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ...@@ -348,19 +339,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
if (!(flags & LEFT)) { if (!(flags & LEFT)) {
while (len < field_width--) { while (len < field_width--) {
if (str <= end) if (str <= end)
*str = ' '; *str++ = ' ';
++str;
} }
} }
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
if (str <= end) if (str <= end)
*str = *s; *str++ = *s++;
++str; ++s;
} }
while (len < field_width--) { while (len < field_width--) {
if (str <= end) if (str <= end)
*str = ' '; *str++ = ' ';
++str;
} }
continue; continue;
...@@ -392,8 +380,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ...@@ -392,8 +380,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
case '%': case '%':
if (str <= end) if (str <= end)
*str = '%'; *str++ = '%';
++str;
continue; continue;
/* integer number formats - set up the flags and "break" */ /* integer number formats - set up the flags and "break" */
...@@ -415,12 +402,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ...@@ -415,12 +402,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
default: default:
if (str <= end) if (str <= end)
*str = '%'; *str++ = '%';
++str;
if (*fmt) { if (*fmt) {
if (str <= end) if (str <= end)
*str = *fmt; *str++ = *fmt;
++str;
} else { } else {
--fmt; --fmt;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment