* [PATCH v2 0/2] tracing/user_events: Fix non-spaced field matching
@ 2024-04-23 16:23 Beau Belgrave
2024-04-23 16:23 ` [PATCH v2 1/2] " Beau Belgrave
2024-04-23 16:23 ` [PATCH v2 2/2] selftests/user_events: Add non-spacing separator check Beau Belgrave
0 siblings, 2 replies; 7+ messages in thread
From: Beau Belgrave @ 2024-04-23 16:23 UTC (permalink / raw)
To: rostedt, mhiramat, mathieu.desnoyers
Cc: linux-kernel, linux-trace-kernel, dcook
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.
I could not find an existing function to accomplish this, so I had to
hand code a copy with this logic. If there is a better way to achieve
this, I'm all ears.
This series also adds a selftest to ensure this doesn't break again.
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
V2 changes:
Renamed fix_semis_no_space() to insert_space_after_semis().
Have user_event_argv_split() return fast in no-split case.
Pulled in Masami's shorter loop in insert_space_after_semis().
Beau Belgrave (2):
tracing/user_events: Fix non-spaced field matching
selftests/user_events: Add non-spacing separator check
kernel/trace/trace_events_user.c | 76 ++++++++++++++++++-
.../selftests/user_events/ftrace_test.c | 8 ++
2 files changed, 83 insertions(+), 1 deletion(-)
base-commit: 0bbac3facb5d6cc0171c45c9873a2dc96bea9680
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v2 1/2] tracing/user_events: Fix non-spaced field matching 2024-04-23 16:23 [PATCH v2 0/2] tracing/user_events: Fix non-spaced field matching Beau Belgrave @ 2024-04-23 16:23 ` Beau Belgrave 2024-05-02 21:16 ` Steven Rostedt 2024-04-23 16:23 ` [PATCH v2 2/2] selftests/user_events: Add non-spacing separator check Beau Belgrave 1 sibling, 1 reply; 7+ messages in thread From: Beau Belgrave @ 2024-04-23 16:23 UTC (permalink / raw) To: rostedt, mhiramat, mathieu.desnoyers Cc: linux-kernel, linux-trace-kernel, dcook 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 Fixes: ba470eebc2f6 ("tracing/user_events: Prevent same name but different args event") Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> --- kernel/trace/trace_events_user.c | 76 +++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c index 70d428c394b6..82b191f33a28 100644 --- a/kernel/trace/trace_events_user.c +++ b/kernel/trace/trace_events_user.c @@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user) return 0; } +/* + * Counts how many ';' without a trailing space are in the args. + */ +static int count_semis_no_space(char *args) +{ + int count = 0; + + while ((args = strchr(args, ';'))) { + args++; + + if (!isspace(*args)) + count++; + } + + return count; +} + +/* + * Copies the arguments while ensuring all ';' have a trailing space. + */ +static char *insert_space_after_semis(char *args, int count) +{ + char *fixed, *pos; + int len; + + len = strlen(args) + count; + fixed = kmalloc(len + 1, GFP_KERNEL); + + if (!fixed) + return NULL; + + pos = fixed; + + /* Insert a space after ';' if there is no trailing space. */ + while (*args) { + *pos = *args++; + + if (*pos++ == ';' && !isspace(*args)) + *pos++ = ' '; + } + + *pos = '\0'; + + return fixed; +} + +static char **user_event_argv_split(char *args, int *argc) +{ + char **split; + char *fixed; + int count; + + /* Count how many ';' without a trailing space */ + count = count_semis_no_space(args); + + /* No fixup is required */ + if (!count) + return argv_split(GFP_KERNEL, args, argc); + + /* We must fixup 'field;field' to 'field; field' */ + fixed = insert_space_after_semis(args, count); + + if (!fixed) + return NULL; + + /* We do a normal split afterwards */ + split = argv_split(GFP_KERNEL, fixed, argc); + + /* We can free since argv_split makes a copy */ + kfree(fixed); + + return split; +} + /* * Parses the event name, arguments and flags then registers if successful. * 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, return -EPERM; if (args) { - argv = argv_split(GFP_KERNEL, args, &argc); + argv = user_event_argv_split(args, &argc); if (!argv) return -ENOMEM; -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] tracing/user_events: Fix non-spaced field matching 2024-04-23 16:23 ` [PATCH v2 1/2] " Beau Belgrave @ 2024-05-02 21:16 ` Steven Rostedt 2024-05-02 22:58 ` Beau Belgrave 0 siblings, 1 reply; 7+ messages in thread From: Steven Rostedt @ 2024-05-02 21:16 UTC (permalink / raw) To: Beau Belgrave Cc: mhiramat, mathieu.desnoyers, linux-kernel, linux-trace-kernel, dcook On Tue, 23 Apr 2024 16:23:37 +0000 Beau Belgrave <beaub@linux.microsoft.com> wrote: > 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 I'm curious, what happens if you have: "u8 field1; u8 field2;" ? Do you care? As you will then create "u8 field1; u8 field2; " but I'm guessing the extra whitespace at the end doesn't affect anything. > > Fixes: ba470eebc2f6 ("tracing/user_events: Prevent same name but different args event") > Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> > --- > kernel/trace/trace_events_user.c | 76 +++++++++++++++++++++++++++++++- > 1 file changed, 75 insertions(+), 1 deletion(-) > > diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c > index 70d428c394b6..82b191f33a28 100644 > --- a/kernel/trace/trace_events_user.c > +++ b/kernel/trace/trace_events_user.c > @@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user) > return 0; > } > > +/* > + * Counts how many ';' without a trailing space are in the args. > + */ > +static int count_semis_no_space(char *args) > +{ > + int count = 0; > + > + while ((args = strchr(args, ';'))) { > + args++; > + > + if (!isspace(*args)) > + count++; This will count that "..;" This is most likely not an issue, but since I didn't see this case anywhere, I figured I bring it up just to confirm that it's not an issue. -- Steve > + } > + > + return count; > +} > + > +/* > + * Copies the arguments while ensuring all ';' have a trailing space. > + */ > +static char *insert_space_after_semis(char *args, int count) > +{ > + char *fixed, *pos; > + int len; > + > + len = strlen(args) + count; > + fixed = kmalloc(len + 1, GFP_KERNEL); > + > + if (!fixed) > + return NULL; > + > + pos = fixed; > + > + /* Insert a space after ';' if there is no trailing space. */ > + while (*args) { > + *pos = *args++; > + > + if (*pos++ == ';' && !isspace(*args)) > + *pos++ = ' '; > + } > + > + *pos = '\0'; > + > + return fixed; > +} > + ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] tracing/user_events: Fix non-spaced field matching 2024-05-02 21:16 ` Steven Rostedt @ 2024-05-02 22:58 ` Beau Belgrave 2024-05-02 23:11 ` Steven Rostedt 0 siblings, 1 reply; 7+ messages in thread From: Beau Belgrave @ 2024-05-02 22:58 UTC (permalink / raw) To: Steven Rostedt Cc: mhiramat, mathieu.desnoyers, linux-kernel, linux-trace-kernel, dcook On Thu, May 02, 2024 at 05:16:34PM -0400, Steven Rostedt wrote: > On Tue, 23 Apr 2024 16:23:37 +0000 > Beau Belgrave <beaub@linux.microsoft.com> wrote: > > > 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 > > I'm curious, what happens if you have: "u8 field1; u8 field2;" ? > You'll get an extra whitespace during the copy, assuming it was really: "u8 field1;u8 field2" If it had spaces, this code wouldn't run. > Do you care? As you will then create "u8 field1; u8 field2; " > > but I'm guessing the extra whitespace at the end doesn't affect anything. > Right, you get an extra byte allocated, but the argv_split() with ignore it. The compare will work correctly (I've verified this just now to double check). IE these all match: "Test u8 a; u8 b; " "Test u8 a; u8 b;" "Test u8 a; u8 b" > > > > > Fixes: ba470eebc2f6 ("tracing/user_events: Prevent same name but different args event") > > Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> > > --- > > kernel/trace/trace_events_user.c | 76 +++++++++++++++++++++++++++++++- > > 1 file changed, 75 insertions(+), 1 deletion(-) > > > > diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c > > index 70d428c394b6..82b191f33a28 100644 > > --- a/kernel/trace/trace_events_user.c > > +++ b/kernel/trace/trace_events_user.c > > @@ -1989,6 +1989,80 @@ static int user_event_set_tp_name(struct user_event *user) > > return 0; > > } > > > > +/* > > + * Counts how many ';' without a trailing space are in the args. > > + */ > > +static int count_semis_no_space(char *args) > > +{ > > + int count = 0; > > + > > + while ((args = strchr(args, ';'))) { > > + args++; > > + > > + if (!isspace(*args)) > > + count++; > > This will count that "..;" > > This is most likely not an issue, but since I didn't see this case > anywhere, I figured I bring it up just to confirm that it's not an issue. > It's not an issue on the matching/logic. However, you do get an extra byte alloc (which doesn't bother me in this edge case). Thanks, -Beau > -- Steve > > > > + } > > + > > + return count; > > +} > > + > > +/* > > + * Copies the arguments while ensuring all ';' have a trailing space. > > + */ > > +static char *insert_space_after_semis(char *args, int count) > > +{ > > + char *fixed, *pos; > > + int len; > > + > > + len = strlen(args) + count; > > + fixed = kmalloc(len + 1, GFP_KERNEL); > > + > > + if (!fixed) > > + return NULL; > > + > > + pos = fixed; > > + > > + /* Insert a space after ';' if there is no trailing space. */ > > + while (*args) { > > + *pos = *args++; > > + > > + if (*pos++ == ';' && !isspace(*args)) > > + *pos++ = ' '; > > + } > > + > > + *pos = '\0'; > > + > > + return fixed; > > +} > > + ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] tracing/user_events: Fix non-spaced field matching 2024-05-02 22:58 ` Beau Belgrave @ 2024-05-02 23:11 ` Steven Rostedt 0 siblings, 0 replies; 7+ messages in thread From: Steven Rostedt @ 2024-05-02 23:11 UTC (permalink / raw) To: Beau Belgrave Cc: mhiramat, mathieu.desnoyers, linux-kernel, linux-trace-kernel, dcook On Thu, 2 May 2024 15:58:53 -0700 Beau Belgrave <beaub@linux.microsoft.com> wrote: > It's not an issue on the matching/logic. However, you do get an extra > byte alloc (which doesn't bother me in this edge case). Figured as much, but since there was no mention of it, I decided to bring it up. I'll take this as-is then. -- Steve ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] selftests/user_events: Add non-spacing separator check 2024-04-23 16:23 [PATCH v2 0/2] tracing/user_events: Fix non-spaced field matching Beau Belgrave 2024-04-23 16:23 ` [PATCH v2 1/2] " Beau Belgrave @ 2024-04-23 16:23 ` Beau Belgrave 2024-05-28 2:08 ` Masami Hiramatsu 1 sibling, 1 reply; 7+ messages in thread From: Beau Belgrave @ 2024-04-23 16:23 UTC (permalink / raw) To: rostedt, mhiramat, mathieu.desnoyers Cc: linux-kernel, linux-trace-kernel, dcook The ABI documentation indicates that field separators do not need a space between them, only a ';'. When no spacing is used, the register must work. Any subsequent register, with or without spaces, must match and not return -EADDRINUSE. Add a non-spacing separator case to our self-test register case to ensure it works going forward. Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> --- tools/testing/selftests/user_events/ftrace_test.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c index dcd7509fe2e0..0bb46793dcd4 100644 --- a/tools/testing/selftests/user_events/ftrace_test.c +++ b/tools/testing/selftests/user_events/ftrace_test.c @@ -261,6 +261,12 @@ TEST_F(user, register_events) { ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); ASSERT_EQ(0, reg.write_index); + /* Register without separator spacing should still match */ + reg.enable_bit = 29; + reg.name_args = (__u64)"__test_event u32 field1;u32 field2"; + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); + ASSERT_EQ(0, reg.write_index); + /* Multiple registers to same name but different args should fail */ reg.enable_bit = 29; reg.name_args = (__u64)"__test_event u32 field1;"; @@ -288,6 +294,8 @@ TEST_F(user, register_events) { ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); unreg.disable_bit = 30; ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); + unreg.disable_bit = 29; + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); /* Delete should have been auto-done after close and unregister */ close(self->data_fd); -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] selftests/user_events: Add non-spacing separator check 2024-04-23 16:23 ` [PATCH v2 2/2] selftests/user_events: Add non-spacing separator check Beau Belgrave @ 2024-05-28 2:08 ` Masami Hiramatsu 0 siblings, 0 replies; 7+ messages in thread From: Masami Hiramatsu @ 2024-05-28 2:08 UTC (permalink / raw) To: Beau Belgrave Cc: rostedt, mathieu.desnoyers, linux-kernel, linux-trace-kernel, dcook On Tue, 23 Apr 2024 16:23:38 +0000 Beau Belgrave <beaub@linux.microsoft.com> wrote: > The ABI documentation indicates that field separators do not need a > space between them, only a ';'. When no spacing is used, the register > must work. Any subsequent register, with or without spaces, must match > and not return -EADDRINUSE. > > Add a non-spacing separator case to our self-test register case to ensure > it works going forward. > Looks good to me. Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Thanks! > Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> > --- > tools/testing/selftests/user_events/ftrace_test.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c > index dcd7509fe2e0..0bb46793dcd4 100644 > --- a/tools/testing/selftests/user_events/ftrace_test.c > +++ b/tools/testing/selftests/user_events/ftrace_test.c > @@ -261,6 +261,12 @@ TEST_F(user, register_events) { > ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); > ASSERT_EQ(0, reg.write_index); > > + /* Register without separator spacing should still match */ > + reg.enable_bit = 29; > + reg.name_args = (__u64)"__test_event u32 field1;u32 field2"; > + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); > + ASSERT_EQ(0, reg.write_index); > + > /* Multiple registers to same name but different args should fail */ > reg.enable_bit = 29; > reg.name_args = (__u64)"__test_event u32 field1;"; > @@ -288,6 +294,8 @@ TEST_F(user, register_events) { > ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); > unreg.disable_bit = 30; > ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); > + unreg.disable_bit = 29; > + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg)); > > /* Delete should have been auto-done after close and unregister */ > close(self->data_fd); > -- > 2.34.1 > -- Masami Hiramatsu (Google) <mhiramat@kernel.org> ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-05-28 2:08 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-04-23 16:23 [PATCH v2 0/2] tracing/user_events: Fix non-spaced field matching Beau Belgrave 2024-04-23 16:23 ` [PATCH v2 1/2] " Beau Belgrave 2024-05-02 21:16 ` Steven Rostedt 2024-05-02 22:58 ` Beau Belgrave 2024-05-02 23:11 ` Steven Rostedt 2024-04-23 16:23 ` [PATCH v2 2/2] selftests/user_events: Add non-spacing separator check Beau Belgrave 2024-05-28 2:08 ` Masami Hiramatsu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).