Fix synthetic event "strcat" overrun

New synthetic event code used strcat() and miscalculated the ending, causing
 the concatenation to write beyond the allocated memory.
 
 Instead of using strncat(), the code is switched over to seq_buf which has
 all the mechanisms in place to protect against writing more than what is
 allocated, and cleans up the code a bit.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCX5lZkBQccm9zdGVkdEBn
 b29kbWlzLm9yZwAKCRAp5XQQmuv6qu8+AQDfg1UM12HUIs1XRhbXBxf9g3kjwrJh
 nuoMilEZZstSCgD8DDQiPckOS9NfrdkyCPQ86tIKoOsGPowoA21sNOHPvQQ=
 =+V+S
 -----END PGP SIGNATURE-----

Merge tag 'trace-v5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fix from Steven Rostedt:
 "Fix synthetic event "strcat" overrun

  New synthetic event code used strcat() and miscalculated the ending,
  causing the concatenation to write beyond the allocated memory.

  Instead of using strncat(), the code is switched over to seq_buf which
  has all the mechanisms in place to protect against writing more than
  what is allocated, and cleans up the code a bit"

* tag 'trace-v5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracing, synthetic events: Replace buggy strcat() with seq_buf operations
This commit is contained in:
Linus Torvalds 2020-10-28 12:05:14 -07:00
commit 23859ae444

View File

@ -585,6 +585,7 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,
struct synth_field *field;
const char *prefix = NULL, *field_type = argv[0], *field_name, *array;
int len, ret = 0;
struct seq_buf s;
ssize_t size;
if (field_type[0] == ';')
@ -630,13 +631,9 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,
field_type++;
len = strlen(field_type) + 1;
if (array) {
int l = strlen(array);
if (array)
len += strlen(array);
if (l && array[l - 1] == ';')
l--;
len += l;
}
if (prefix)
len += strlen(prefix);
@ -645,14 +642,18 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,
ret = -ENOMEM;
goto free;
}
seq_buf_init(&s, field->type, len);
if (prefix)
strcat(field->type, prefix);
strcat(field->type, field_type);
seq_buf_puts(&s, prefix);
seq_buf_puts(&s, field_type);
if (array) {
strcat(field->type, array);
if (field->type[len - 1] == ';')
field->type[len - 1] = '\0';
seq_buf_puts(&s, array);
if (s.buffer[s.len - 1] == ';')
s.len--;
}
if (WARN_ON_ONCE(!seq_buf_buffer_left(&s)))
goto free;
s.buffer[s.len] = '\0';
size = synth_field_size(field->type);
if (size < 0) {
@ -663,14 +664,21 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,
if (synth_field_is_string(field->type)) {
char *type;
type = kzalloc(sizeof("__data_loc ") + strlen(field->type) + 1, GFP_KERNEL);
len = sizeof("__data_loc ") + strlen(field->type) + 1;
type = kzalloc(len, GFP_KERNEL);
if (!type) {
ret = -ENOMEM;
goto free;
}
strcat(type, "__data_loc ");
strcat(type, field->type);
seq_buf_init(&s, type, len);
seq_buf_puts(&s, "__data_loc ");
seq_buf_puts(&s, field->type);
if (WARN_ON_ONCE(!seq_buf_buffer_left(&s)))
goto free;
s.buffer[s.len] = '\0';
kfree(field->type);
field->type = type;