Skip to content

Commit bd125a0

Browse files
beaubelgraverostedt
authored andcommitted
tracing/user_events: Fix non-spaced field matching
When the ABI was updated to prevent same name w/different args, it missed an important corner case when fields don't end with a space. Typically, space is used for fields to help separate them, like "u8 field1; u8 field2". If no spaces are used, like "u8 field1;u8 field2", then the parsing works for the first time. However, the match check fails on a subsequent register, leading to confusion. This is because the match check uses argv_split() and assumes that all fields will be split upon the space. When spaces are used, we get back { "u8", "field1;" }, without spaces we get back { "u8", "field1;u8" }. This causes a mismatch, and the user program gets back -EADDRINUSE. Add a method to detect this case before calling argv_split(). If found force a space after the field separator character ';'. This ensures all cases work properly for matching. With this fix, the following are all treated as matching: u8 field1;u8 field2 u8 field1; u8 field2 u8 field1;\tu8 field2 u8 field1;\nu8 field2 Link: https://lore.kernel.org/linux-trace-kernel/20240423162338.292-2-beaub@linux.microsoft.com Fixes: ba470ee ("tracing/user_events: Prevent same name but different args event") Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent dd5a440 commit bd125a0

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

kernel/trace/trace_events_user.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user)
19891989
return 0;
19901990
}
19911991

1992+
/*
1993+
* Counts how many ';' without a trailing space are in the args.
1994+
*/
1995+
static int count_semis_no_space(char *args)
1996+
{
1997+
int count = 0;
1998+
1999+
while ((args = strchr(args, ';'))) {
2000+
args++;
2001+
2002+
if (!isspace(*args))
2003+
count++;
2004+
}
2005+
2006+
return count;
2007+
}
2008+
2009+
/*
2010+
* Copies the arguments while ensuring all ';' have a trailing space.
2011+
*/
2012+
static char *insert_space_after_semis(char *args, int count)
2013+
{
2014+
char *fixed, *pos;
2015+
int len;
2016+
2017+
len = strlen(args) + count;
2018+
fixed = kmalloc(len + 1, GFP_KERNEL);
2019+
2020+
if (!fixed)
2021+
return NULL;
2022+
2023+
pos = fixed;
2024+
2025+
/* Insert a space after ';' if there is no trailing space. */
2026+
while (*args) {
2027+
*pos = *args++;
2028+
2029+
if (*pos++ == ';' && !isspace(*args))
2030+
*pos++ = ' ';
2031+
}
2032+
2033+
*pos = '\0';
2034+
2035+
return fixed;
2036+
}
2037+
2038+
static char **user_event_argv_split(char *args, int *argc)
2039+
{
2040+
char **split;
2041+
char *fixed;
2042+
int count;
2043+
2044+
/* Count how many ';' without a trailing space */
2045+
count = count_semis_no_space(args);
2046+
2047+
/* No fixup is required */
2048+
if (!count)
2049+
return argv_split(GFP_KERNEL, args, argc);
2050+
2051+
/* We must fixup 'field;field' to 'field; field' */
2052+
fixed = insert_space_after_semis(args, count);
2053+
2054+
if (!fixed)
2055+
return NULL;
2056+
2057+
/* We do a normal split afterwards */
2058+
split = argv_split(GFP_KERNEL, fixed, argc);
2059+
2060+
/* We can free since argv_split makes a copy */
2061+
kfree(fixed);
2062+
2063+
return split;
2064+
}
2065+
19922066
/*
19932067
* Parses the event name, arguments and flags then registers if successful.
19942068
* The name buffer lifetime is owned by this method for success cases only.
@@ -2012,7 +2086,7 @@ static int user_event_parse(struct user_event_group *group, char *name,
20122086
return -EPERM;
20132087

20142088
if (args) {
2015-
argv = argv_split(GFP_KERNEL, args, &argc);
2089+
argv = user_event_argv_split(args, &argc);
20162090

20172091
if (!argv)
20182092
return -ENOMEM;

0 commit comments

Comments
 (0)