mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
s390/debug: Pass in and enforce output buffer size for format handlers
The s390dbf format handler rely on being passed an output buffer sized such that their output will always fit and then use plain sprintf() to write to it. While only supplied data from other kernel components this still potentially allows buffer overwrite if callers are not careful. Instead just pass in the size of the output buffer and use scnprintf() instead of sprintf() and strscpy() instead of strcpy(). The latter also allows us to get rid of a separate strlen() call. Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
3f020399e4
commit
897614f90f
@ -66,14 +66,15 @@ typedef int (debug_header_proc_t) (debug_info_t *id,
|
|||||||
struct debug_view *view,
|
struct debug_view *view,
|
||||||
int area,
|
int area,
|
||||||
debug_entry_t *entry,
|
debug_entry_t *entry,
|
||||||
char *out_buf);
|
char *out_buf, size_t out_buf_size);
|
||||||
|
|
||||||
typedef int (debug_format_proc_t) (debug_info_t *id,
|
typedef int (debug_format_proc_t) (debug_info_t *id,
|
||||||
struct debug_view *view, char *out_buf,
|
struct debug_view *view, char *out_buf,
|
||||||
|
size_t out_buf_size,
|
||||||
const char *in_buf);
|
const char *in_buf);
|
||||||
typedef int (debug_prolog_proc_t) (debug_info_t *id,
|
typedef int (debug_prolog_proc_t) (debug_info_t *id,
|
||||||
struct debug_view *view,
|
struct debug_view *view,
|
||||||
char *out_buf);
|
char *out_buf, size_t out_buf_size);
|
||||||
typedef int (debug_input_proc_t) (debug_info_t *id,
|
typedef int (debug_input_proc_t) (debug_info_t *id,
|
||||||
struct debug_view *view,
|
struct debug_view *view,
|
||||||
struct file *file,
|
struct file *file,
|
||||||
@ -81,7 +82,8 @@ typedef int (debug_input_proc_t) (debug_info_t *id,
|
|||||||
size_t in_buf_size, loff_t *offset);
|
size_t in_buf_size, loff_t *offset);
|
||||||
|
|
||||||
int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
|
int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
|
||||||
int area, debug_entry_t *entry, char *out_buf);
|
int area, debug_entry_t *entry,
|
||||||
|
char *out_buf, size_t out_buf_size);
|
||||||
|
|
||||||
struct debug_view {
|
struct debug_view {
|
||||||
char name[DEBUG_MAX_NAME_LEN];
|
char name[DEBUG_MAX_NAME_LEN];
|
||||||
|
@ -77,12 +77,14 @@ static debug_info_t *debug_info_create(const char *name, int pages_per_area,
|
|||||||
static void debug_info_get(debug_info_t *);
|
static void debug_info_get(debug_info_t *);
|
||||||
static void debug_info_put(debug_info_t *);
|
static void debug_info_put(debug_info_t *);
|
||||||
static int debug_prolog_level_fn(debug_info_t *id,
|
static int debug_prolog_level_fn(debug_info_t *id,
|
||||||
struct debug_view *view, char *out_buf);
|
struct debug_view *view, char *out_buf,
|
||||||
|
size_t out_buf_size);
|
||||||
static int debug_input_level_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_input_level_fn(debug_info_t *id, struct debug_view *view,
|
||||||
struct file *file, const char __user *user_buf,
|
struct file *file, const char __user *user_buf,
|
||||||
size_t user_buf_size, loff_t *offset);
|
size_t user_buf_size, loff_t *offset);
|
||||||
static int debug_prolog_pages_fn(debug_info_t *id,
|
static int debug_prolog_pages_fn(debug_info_t *id,
|
||||||
struct debug_view *view, char *out_buf);
|
struct debug_view *view, char *out_buf,
|
||||||
|
size_t out_buf_size);
|
||||||
static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view,
|
||||||
struct file *file, const char __user *user_buf,
|
struct file *file, const char __user *user_buf,
|
||||||
size_t user_buf_size, loff_t *offset);
|
size_t user_buf_size, loff_t *offset);
|
||||||
@ -90,9 +92,11 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
struct file *file, const char __user *user_buf,
|
struct file *file, const char __user *user_buf,
|
||||||
size_t user_buf_size, loff_t *offset);
|
size_t user_buf_size, loff_t *offset);
|
||||||
static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
|
||||||
char *out_buf, const char *in_buf);
|
char *out_buf, size_t out_buf_size,
|
||||||
|
const char *in_buf);
|
||||||
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
|
||||||
char *out_buf, const char *inbuf);
|
char *out_buf, size_t out_buf_size,
|
||||||
|
const char *inbuf);
|
||||||
static void debug_areas_swap(debug_info_t *a, debug_info_t *b);
|
static void debug_areas_swap(debug_info_t *a, debug_info_t *b);
|
||||||
static void debug_events_append(debug_info_t *dest, debug_info_t *src);
|
static void debug_events_append(debug_info_t *dest, debug_info_t *src);
|
||||||
|
|
||||||
@ -391,8 +395,10 @@ static int debug_format_entry(file_private_info_t *p_info)
|
|||||||
|
|
||||||
if (p_info->act_entry == DEBUG_PROLOG_ENTRY) {
|
if (p_info->act_entry == DEBUG_PROLOG_ENTRY) {
|
||||||
/* print prolog */
|
/* print prolog */
|
||||||
if (view->prolog_proc)
|
if (view->prolog_proc) {
|
||||||
len += view->prolog_proc(id_snap, view, p_info->temp_buf);
|
len += view->prolog_proc(id_snap, view, p_info->temp_buf,
|
||||||
|
sizeof(p_info->temp_buf));
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!id_snap->areas) /* this is true, if we have a prolog only view */
|
if (!id_snap->areas) /* this is true, if we have a prolog only view */
|
||||||
@ -402,12 +408,16 @@ static int debug_format_entry(file_private_info_t *p_info)
|
|||||||
|
|
||||||
if (act_entry->clock == 0LL)
|
if (act_entry->clock == 0LL)
|
||||||
goto out; /* empty entry */
|
goto out; /* empty entry */
|
||||||
if (view->header_proc)
|
if (view->header_proc) {
|
||||||
len += view->header_proc(id_snap, view, p_info->act_area,
|
len += view->header_proc(id_snap, view, p_info->act_area,
|
||||||
act_entry, p_info->temp_buf + len);
|
act_entry, p_info->temp_buf + len,
|
||||||
if (view->format_proc)
|
sizeof(p_info->temp_buf) - len);
|
||||||
|
}
|
||||||
|
if (view->format_proc) {
|
||||||
len += view->format_proc(id_snap, view, p_info->temp_buf + len,
|
len += view->format_proc(id_snap, view, p_info->temp_buf + len,
|
||||||
|
sizeof(p_info->temp_buf) - len,
|
||||||
DEBUG_DATA(act_entry));
|
DEBUG_DATA(act_entry));
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@ -1292,9 +1302,9 @@ static inline int debug_get_uint(char *buf)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int debug_prolog_pages_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_prolog_pages_fn(debug_info_t *id, struct debug_view *view,
|
||||||
char *out_buf)
|
char *out_buf, size_t out_buf_size)
|
||||||
{
|
{
|
||||||
return sprintf(out_buf, "%i\n", id->pages_per_area);
|
return scnprintf(out_buf, out_buf_size, "%i\n", id->pages_per_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1341,14 +1351,14 @@ static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
* prints out actual debug level
|
* prints out actual debug level
|
||||||
*/
|
*/
|
||||||
static int debug_prolog_level_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_prolog_level_fn(debug_info_t *id, struct debug_view *view,
|
||||||
char *out_buf)
|
char *out_buf, size_t out_buf_size)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (id->level == DEBUG_OFF_LEVEL)
|
if (id->level == DEBUG_OFF_LEVEL)
|
||||||
rc = sprintf(out_buf, "-\n");
|
rc = scnprintf(out_buf, out_buf_size, "-\n");
|
||||||
else
|
else
|
||||||
rc = sprintf(out_buf, "%i\n", id->level);
|
rc = scnprintf(out_buf, out_buf_size, "%i\n", id->level);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1465,22 +1475,24 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
* prints debug data in hex/ascii format
|
* prints debug data in hex/ascii format
|
||||||
*/
|
*/
|
||||||
static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
|
||||||
char *out_buf, const char *in_buf)
|
char *out_buf, size_t out_buf_size, const char *in_buf)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
|
|
||||||
for (i = 0; i < id->buf_size; i++)
|
for (i = 0; i < id->buf_size; i++) {
|
||||||
rc += sprintf(out_buf + rc, "%02x ", ((unsigned char *) in_buf)[i]);
|
rc += scnprintf(out_buf + rc, out_buf_size - rc,
|
||||||
rc += sprintf(out_buf + rc, "| ");
|
"%02x ", ((unsigned char *)in_buf)[i]);
|
||||||
|
}
|
||||||
|
rc += scnprintf(out_buf + rc, out_buf_size - rc, "| ");
|
||||||
for (i = 0; i < id->buf_size; i++) {
|
for (i = 0; i < id->buf_size; i++) {
|
||||||
unsigned char c = in_buf[i];
|
unsigned char c = in_buf[i];
|
||||||
|
|
||||||
if (isascii(c) && isprint(c))
|
if (isascii(c) && isprint(c))
|
||||||
rc += sprintf(out_buf + rc, "%c", c);
|
rc += scnprintf(out_buf + rc, out_buf_size - rc, "%c", c);
|
||||||
else
|
else
|
||||||
rc += sprintf(out_buf + rc, ".");
|
rc += scnprintf(out_buf + rc, out_buf_size - rc, ".");
|
||||||
}
|
}
|
||||||
rc += sprintf(out_buf + rc, "\n");
|
rc += scnprintf(out_buf + rc, out_buf_size - rc, "\n");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1488,7 +1500,8 @@ static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
* prints header for debug entry
|
* prints header for debug entry
|
||||||
*/
|
*/
|
||||||
int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
|
int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
|
||||||
int area, debug_entry_t *entry, char *out_buf)
|
int area, debug_entry_t *entry, char *out_buf,
|
||||||
|
size_t out_buf_size)
|
||||||
{
|
{
|
||||||
unsigned long sec, usec;
|
unsigned long sec, usec;
|
||||||
unsigned long caller;
|
unsigned long caller;
|
||||||
@ -1505,9 +1518,9 @@ int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
else
|
else
|
||||||
except_str = "-";
|
except_str = "-";
|
||||||
caller = (unsigned long) entry->caller;
|
caller = (unsigned long) entry->caller;
|
||||||
rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %04u %px ",
|
rc += scnprintf(out_buf, out_buf_size, "%02i %011ld:%06lu %1u %1s %04u %px ",
|
||||||
area, sec, usec, level, except_str,
|
area, sec, usec, level, except_str,
|
||||||
entry->cpu, (void *)caller);
|
entry->cpu, (void *)caller);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(debug_dflt_header_fn);
|
EXPORT_SYMBOL(debug_dflt_header_fn);
|
||||||
@ -1520,7 +1533,7 @@ EXPORT_SYMBOL(debug_dflt_header_fn);
|
|||||||
#define DEBUG_SPRINTF_MAX_ARGS 10
|
#define DEBUG_SPRINTF_MAX_ARGS 10
|
||||||
|
|
||||||
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
|
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
|
||||||
char *out_buf, const char *inbuf)
|
char *out_buf, size_t out_buf_size, const char *inbuf)
|
||||||
{
|
{
|
||||||
debug_sprintf_entry_t *curr_event = (debug_sprintf_entry_t *)inbuf;
|
debug_sprintf_entry_t *curr_event = (debug_sprintf_entry_t *)inbuf;
|
||||||
int num_longs, num_used_args = 0, i, rc = 0;
|
int num_longs, num_used_args = 0, i, rc = 0;
|
||||||
@ -1533,8 +1546,9 @@ static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
goto out; /* bufsize of entry too small */
|
goto out; /* bufsize of entry too small */
|
||||||
if (num_longs == 1) {
|
if (num_longs == 1) {
|
||||||
/* no args, we use only the string */
|
/* no args, we use only the string */
|
||||||
strcpy(out_buf, curr_event->string);
|
rc = strscpy(out_buf, curr_event->string, out_buf_size);
|
||||||
rc = strlen(curr_event->string);
|
if (rc == -E2BIG)
|
||||||
|
rc = out_buf_size;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1546,12 +1560,13 @@ static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
|
|||||||
for (i = 0; i < num_used_args; i++)
|
for (i = 0; i < num_used_args; i++)
|
||||||
index[i] = i;
|
index[i] = i;
|
||||||
|
|
||||||
rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
|
rc = scnprintf(out_buf, out_buf_size,
|
||||||
curr_event->args[index[1]], curr_event->args[index[2]],
|
curr_event->string, curr_event->args[index[0]],
|
||||||
curr_event->args[index[3]], curr_event->args[index[4]],
|
curr_event->args[index[1]], curr_event->args[index[2]],
|
||||||
curr_event->args[index[5]], curr_event->args[index[6]],
|
curr_event->args[index[3]], curr_event->args[index[4]],
|
||||||
curr_event->args[index[7]], curr_event->args[index[8]],
|
curr_event->args[index[5]], curr_event->args[index[6]],
|
||||||
curr_event->args[index[9]]);
|
curr_event->args[index[7]], curr_event->args[index[8]],
|
||||||
|
curr_event->args[index[9]]);
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user