lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <AS8PR03MB9626D86E2025129C178927E2E5E0A@AS8PR03MB9626.eurprd03.prod.outlook.com>
Date:   Mon, 28 Aug 2023 12:30:45 +0000
From:   Fröhling, Maximilian 
        <Maximilian.Froehling@...ta.de>
To:     Bagas Sanjaya <bagasdotme@...il.com>,
        Ingo Molnar <mingo@...nel.org>,
        Masami Hiramatsu <mhiramat@...nel.org>,
        "Steven Rostedt (Google)" <rostedt@...dmis.org>
CC:     Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
        Linux BPF <bpf@...r.kernel.org>,
        Linux Memory Management List <linux-mm@...ck.org>
Subject: RE: bpf: bpf_probe_read_user_str() returns 0 for empty strings

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@...il.com> 
Sent: Sunday, July 23, 2023 3:53 AM
To: Ingo Molnar <mingo@...nel.org>; Masami Hiramatsu <mhiramat@...nel.org>; Steven Rostedt (Google) <rostedt@...dmis.org>; Fröhling, Maximilian <Maximilian.Froehling@...ta.de>
Cc: Linux Kernel Mailing List <linux-kernel@...r.kernel.org>; Linux BPF <bpf@...r.kernel.org>; Linux Memory Management List <linux-mm@...ck.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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ