* Fwd: bpf: bpf_probe_read_user_str() returns 0 for empty strings
@ 2023-07-23 1:52 Bagas Sanjaya
2023-07-23 2:02 ` Alexei Starovoitov
2023-08-28 12:30 ` Fröhling, Maximilian
0 siblings, 2 replies; 3+ messages in thread
From: Bagas Sanjaya @ 2023-07-23 1:52 UTC (permalink / raw)
To: Ingo Molnar, Masami Hiramatsu, Steven Rostedt (Google),
Max Froehling
Cc: Linux Kernel Mailing List, Linux BPF,
Linux Memory Management List
Hi,
I notice a bug report on Bugzilla [1]. Quoting from it:
> Overview:
>
> From within eBPF, calling the helper function bpf_probe_read_user_str(void *dst, __u32 size, const void *unsafe_ptr returns 0 when the source string (void *unsafe_ptr) consists of a string containing only a single null-byte.
>
> This violates various functions documentations (the helper and various internal kernel functions), which all state:
>
>> On success, the strictly positive length of the output string,
>> including the trailing NUL character. On error, a negative value.
>
> To me, this states that the function should return 1 for char myString[] = ""; However, this is not the case. The function returns 0 instead.
>
> For non-empty strings, it works as expected. For example, char myString[] = "abc"; returns 4.
>
> Steps to Reproduce:
> * Write an eBPF program that calls bpf_probe_read_user_str(), using a userspace pointer pointing to an empty string.
> * Store the result value of that function
> * Do the same thing, but try out bpf_probe_read_kernel_str(), like this:
> char empty[] = "";
> char copy[5];
> long ret = bpf_probe_read_kernel_str(copy, 5, empty);
> * Compare the return value of bpf_probe_read_user_str() and bpf_probe_read_kernel_str()
>
> Expected Result:
>
> Both functions return 1 (because of the single NULL byte).
>
> Actual Result:
>
> bpf_probe_read_user_str() returns 0, while bpf_probe_read_kernel_str() returns 1.
>
> Additional Information:
>
> I believe I can see the bug on the current Linux kernel master branch.
>
> In the file/function mm/maccess.c::strncpy_from_user_nofault() the helper implementation calls strncpy_from_user(), which returns the length without trailing 0. Hence this function returns 0 for an empty string.
>
> However, in line 192 (as of commit fdf0eaf11452d72945af31804e2a1048ee1b574c) there is a check that only increments ret, if it is > 0. This appears to be the logic that adds the trailing null byte. Since the check only does this for a ret > 0, a ret of 0 remains at 0.
>
> This is a possible off-by-one error that might cause the behavior.
See Bugzilla for the full thread.
FYI, the culprit line is introduced by commit 3d7081822f7f9e ("uaccess: Add
non-pagefault user-space read functions"). I Cc: culprit SoB so that they
can look into this bug.
Thanks.
[1]: https://bugzilla.kernel.org/show_bug.cgi?id=217679
--
An old man doll... just what I always wanted! - Clara
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: bpf: bpf_probe_read_user_str() returns 0 for empty strings
2023-07-23 1:52 Fwd: bpf: bpf_probe_read_user_str() returns 0 for empty strings Bagas Sanjaya
@ 2023-07-23 2:02 ` Alexei Starovoitov
2023-08-28 12:30 ` Fröhling, Maximilian
1 sibling, 0 replies; 3+ messages in thread
From: Alexei Starovoitov @ 2023-07-23 2:02 UTC (permalink / raw)
To: Bagas Sanjaya
Cc: Ingo Molnar, Masami Hiramatsu, Steven Rostedt (Google),
Max Froehling, Linux Kernel Mailing List, Linux BPF,
Linux Memory Management List
On Sat, Jul 22, 2023 at 6:53 PM Bagas Sanjaya <bagasdotme@gmail.com> wrote:
>
> Hi,
>
> I notice a bug report on Bugzilla [1]. Quoting from it:
>
> > Overview:
> >
> > From within eBPF, calling the helper function bpf_probe_read_user_str(void *dst, __u32 size, const void *unsafe_ptr returns 0 when the source string (void *unsafe_ptr) consists of a string containing only a single null-byte.
> >
> > This violates various functions documentations (the helper and various internal kernel functions), which all state:
Sounds like the bugzilla author believes it's a documentation issue.
If so, please encourage the author to send the patch to fix the doc.
> >
> >> On success, the strictly positive length of the output string,
> >> including the trailing NUL character. On error, a negative value.
> >
> > To me, this states that the function should return 1 for char myString[] = ""; However, this is not the case. The function returns 0 instead.
> >
> > For non-empty strings, it works as expected. For example, char myString[] = "abc"; returns 4.
> >
> > Steps to Reproduce:
> > * Write an eBPF program that calls bpf_probe_read_user_str(), using a userspace pointer pointing to an empty string.
> > * Store the result value of that function
> > * Do the same thing, but try out bpf_probe_read_kernel_str(), like this:
> > char empty[] = "";
> > char copy[5];
> > long ret = bpf_probe_read_kernel_str(copy, 5, empty);
> > * Compare the return value of bpf_probe_read_user_str() and bpf_probe_read_kernel_str()
> >
> > Expected Result:
> >
> > Both functions return 1 (because of the single NULL byte).
> >
> > Actual Result:
> >
> > bpf_probe_read_user_str() returns 0, while bpf_probe_read_kernel_str() returns 1.
> >
> > Additional Information:
> >
> > I believe I can see the bug on the current Linux kernel master branch.
> >
> > In the file/function mm/maccess.c::strncpy_from_user_nofault() the helper implementation calls strncpy_from_user(), which returns the length without trailing 0. Hence this function returns 0 for an empty string.
> >
> > However, in line 192 (as of commit fdf0eaf11452d72945af31804e2a1048ee1b574c) there is a check that only increments ret, if it is > 0. This appears to be the logic that adds the trailing null byte. Since the check only does this for a ret > 0, a ret of 0 remains at 0.
> >
> > This is a possible off-by-one error that might cause the behavior.
>
> See Bugzilla for the full thread.
>
> FYI, the culprit line is introduced by commit 3d7081822f7f9e ("uaccess: Add
> non-pagefault user-space read functions"). I Cc: culprit SoB so that they
> can look into this bug.
>
> Thanks.
>
> [1]: https://bugzilla.kernel.org/show_bug.cgi?id=217679
>
> --
> An old man doll... just what I always wanted! - Clara
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* RE: bpf: bpf_probe_read_user_str() returns 0 for empty strings
2023-07-23 1:52 Fwd: bpf: bpf_probe_read_user_str() returns 0 for empty strings Bagas Sanjaya
2023-07-23 2:02 ` Alexei Starovoitov
@ 2023-08-28 12:30 ` Fröhling, Maximilian
1 sibling, 0 replies; 3+ messages in thread
From: Fröhling, Maximilian @ 2023-08-28 12:30 UTC (permalink / raw)
To: Bagas Sanjaya, Ingo Molnar, Masami Hiramatsu,
Steven Rostedt (Google)
Cc: Linux Kernel Mailing List, Linux BPF,
Linux Memory Management List
As a quick summary, just in case the original issue got misunderstood:
The root cause appears to be in mm/maccess.c::strncpy_from_user_nofault()
The function says it returns the length of the string "including the trailing NUL". It doesn't do that for empty strings: It returns 0 instead. This is causing issues for the upstream BPF function that calls it. There's a potential off-by-one error visible in the code.
strncpy_from_kernel_nofault() on the other hand works correctly: It returns 1 for an empty string.
Thanks,
Max
-----Original Message-----
From: Bagas Sanjaya <bagasdotme@gmail.com>
Sent: Sunday, July 23, 2023 3:53 AM
To: Ingo Molnar <mingo@kernel.org>; Masami Hiramatsu <mhiramat@kernel.org>; Steven Rostedt (Google) <rostedt@goodmis.org>; Fröhling, Maximilian <Maximilian.Froehling@gdata.de>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>; Linux BPF <bpf@vger.kernel.org>; Linux Memory Management List <linux-mm@kvack.org>
Subject: Fwd: bpf: bpf_probe_read_user_str() returns 0 for empty strings
Hi,
I notice a bug report on Bugzilla [1]. Quoting from it:
> Overview:
>
> From within eBPF, calling the helper function bpf_probe_read_user_str(void *dst, __u32 size, const void *unsafe_ptr returns 0 when the source string (void *unsafe_ptr) consists of a string containing only a single null-byte.
>
> This violates various functions documentations (the helper and various internal kernel functions), which all state:
>
>> On success, the strictly positive length of the output string,
>> including the trailing NUL character. On error, a negative value.
>
> To me, this states that the function should return 1 for char myString[] = ""; However, this is not the case. The function returns 0 instead.
>
> For non-empty strings, it works as expected. For example, char myString[] = "abc"; returns 4.
>
> Steps to Reproduce:
> * Write an eBPF program that calls bpf_probe_read_user_str(), using a userspace pointer pointing to an empty string.
> * Store the result value of that function
> * Do the same thing, but try out bpf_probe_read_kernel_str(), like this:
> char empty[] = "";
> char copy[5];
> long ret = bpf_probe_read_kernel_str(copy, 5, empty);
> * Compare the return value of bpf_probe_read_user_str() and
> bpf_probe_read_kernel_str()
>
> Expected Result:
>
> Both functions return 1 (because of the single NULL byte).
>
> Actual Result:
>
> bpf_probe_read_user_str() returns 0, while bpf_probe_read_kernel_str() returns 1.
>
> Additional Information:
>
> I believe I can see the bug on the current Linux kernel master branch.
>
> In the file/function mm/maccess.c::strncpy_from_user_nofault() the helper implementation calls strncpy_from_user(), which returns the length without trailing 0. Hence this function returns 0 for an empty string.
>
> However, in line 192 (as of commit fdf0eaf11452d72945af31804e2a1048ee1b574c) there is a check that only increments ret, if it is > 0. This appears to be the logic that adds the trailing null byte. Since the check only does this for a ret > 0, a ret of 0 remains at 0.
>
> This is a possible off-by-one error that might cause the behavior.
See Bugzilla for the full thread.
FYI, the culprit line is introduced by commit 3d7081822f7f9e ("uaccess: Add non-pagefault user-space read functions"). I Cc: culprit SoB so that they can look into this bug.
Thanks.
[1]: https://bugzilla.kernel.org/show_bug.cgi?id=217679
--
An old man doll... just what I always wanted! - Clara
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-08-28 12:30 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-23 1:52 Fwd: bpf: bpf_probe_read_user_str() returns 0 for empty strings Bagas Sanjaya
2023-07-23 2:02 ` Alexei Starovoitov
2023-08-28 12:30 ` Fröhling, Maximilian
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).