diff mbox series

[bpf] bpf, sockmap: Fix map type error in sock_map_del_link

Message ID 20230728105649.3978774-1-xukuohai@huaweicloud.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series [bpf] bpf, sockmap: Fix map type error in sock_map_del_link | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1344 this patch: 1344
netdev/cc_maintainers fail 1 blamed authors not CCed: ast@kernel.org; 1 maintainers not CCed: ast@kernel.org
netdev/build_clang success Errors and warnings before: 1365 this patch: 1365
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 1367 this patch: 1367
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 18 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-PR success PR summary
bpf/vmtest-bpf-VM_Test-8 success Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-VM_Test-5 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-11 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-13 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-15 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-VM_Test-12 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-VM_Test-16 fail Logs for test_progs_no_alu32 on s390x with gcc

Commit Message

Xu Kuohai July 28, 2023, 10:56 a.m. UTC
From: Xu Kuohai <xukuohai@huawei.com>

sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although
both types have member named "progs", the offset of "progs" member in
these two types is different, so "progs" should be accessed with the
real map type.

Fixes: 604326b41a6f ("bpf, sockmap: convert to generic sk_msg interface")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 net/core/sock_map.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

Comments

Martin KaFai Lau Aug. 1, 2023, 1:19 a.m. UTC | #1
On 7/28/23 3:56 AM, Xu Kuohai wrote:
> sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although
> both types have member named "progs", the offset of "progs" member in
> these two types is different, so "progs" should be accessed with the
> real map type.

The patch makes sense to me. Can a test be written to trigger it?

John, please review.
Xu Kuohai Aug. 1, 2023, 2:24 a.m. UTC | #2
On 8/1/2023 9:19 AM, Martin KaFai Lau wrote:
> On 7/28/23 3:56 AM, Xu Kuohai wrote:
>> sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although
>> both types have member named "progs", the offset of "progs" member in
>> these two types is different, so "progs" should be accessed with the
>> real map type.
> 
> The patch makes sense to me. Can a test be written to trigger it?
> 

Thank you for the review. I have a messy prog that triggers memleak
caused by this issue. I'll try to simplify it to a test.

> John, please review.
> 
> 
> .
John Fastabend Aug. 1, 2023, 3:47 a.m. UTC | #3
Xu Kuohai wrote:
> On 8/1/2023 9:19 AM, Martin KaFai Lau wrote:
> > On 7/28/23 3:56 AM, Xu Kuohai wrote:
> >> sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although
> >> both types have member named "progs", the offset of "progs" member in
> >> these two types is different, so "progs" should be accessed with the
> >> real map type.
> > 
> > The patch makes sense to me. Can a test be written to trigger it?
> > 
> 
> Thank you for the review. I have a messy prog that triggers memleak
> caused by this issue. I'll try to simplify it to a test.
> 
> > John, please review.
> > 
> > 
> > .
> 
> 

Thanks good catch. One thing I don't see any tests for is deleting a
socket from a sockmap and then trying to use it? My guess is almost
no one deletes sockets from a map except on sock close. Maybe to
reproduce,

 1. connect a bunch of sockets to sockhash with verdict prog
 2. remove the sockets
 3. remove the sockhash
 4. that should leak the bpf ref cnt so we could check for the
    prog still existing?

Reviewed-by: John Fastabend <john.fastabend@gmail.com>
Xu Kuohai Aug. 3, 2023, 2:47 a.m. UTC | #4
On 8/1/2023 11:47 AM, John Fastabend wrote:
> Xu Kuohai wrote:
>> On 8/1/2023 9:19 AM, Martin KaFai Lau wrote:
>>> On 7/28/23 3:56 AM, Xu Kuohai wrote:
>>>> sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although
>>>> both types have member named "progs", the offset of "progs" member in
>>>> these two types is different, so "progs" should be accessed with the
>>>> real map type.
>>>
>>> The patch makes sense to me. Can a test be written to trigger it?
>>>
>>
>> Thank you for the review. I have a messy prog that triggers memleak
>> caused by this issue. I'll try to simplify it to a test.
>>
>>> John, please review.
>>>
>>>
>>> .
>>
>>
> 
> Thanks good catch. One thing I don't see any tests for is deleting a
> socket from a sockmap and then trying to use it? My guess is almost
> no one deletes sockets from a map except on sock close. Maybe to
> reproduce,
> 
>   1. connect a bunch of sockets to sockhash with verdict prog
>   2. remove the sockets
>   3. remove the sockhash
>   4. that should leak the bpf ref cnt so we could check for the
>      prog still existing?
> 

I tried this and found no bpf prog leaks. The debugging shows that
the stream_parser and stream_verdict progs are released as follows:

sock_map_unref

   sock_map_del_link

     struct bpf_stab *stab = container_of(map, struct bpf_stab, map);

     if (psock->saved_data_ready && stab->progs.stream_parser)
       strp_stop = true; // (1) not executed, since stab->progs.stream_parser
                         //     is actually shtab->progs.msg_parser, which is
                         //     NULL, so the if condition is false.

     if (psock->saved_data_ready && stab->progs.stream_verdict)
       verdict_stop = true;  // (2) executed, so verdict_stop is set to true

     if (strp_stop) // (3) condition is false since strp_stop is false
       sk_psock_stop_strp(sk, psock)

     if (verdict_stop) // (4) condition pass, so stream_verdict prog refcnt
                       //     is released by sk_psock_stop_verdict
       sk_psock_stop_verdict(sk, psock)
         psock_set_prog(&pock->progs.stream_verdict, NULL)
           bpf_prog_put // (5) release refcnt of stream_verdict prog


   sk_psock_put
       sk_psock_drop(sk, psock)
         sk_psock_stop_strp(sk, psock)
           sk_psock_stop_strp(&psock->progs.stream_parser, NULL)
             bpf_prog_put // (6) release refcnt of stream_parser prog



However, this issue triggers a WARNING in strp_done:

sock_map_unref
   sock_map_del_link

     struct bpf_stab *stab = container_of(map, struct bpf_stab, map);

     if (psock->saved_data_ready && stab->progs.stream_verdict)
       verdict_stop = true;  // (1) verdict_stop is set to true


     if (verdict_stop) // (2) condition pass
       sk_psock_stop_verdict(sk, psock)
         psock_set_prog(&pock->progs.stream_verdict, NULL)
           bpf_prog_put
         psock->saved_data_ready = NULL;  // (3) psock->saved_data_ready is
                                          //     set to NULL

   sk_psock_put
       sk_psock_drop(sk, psock)

         sk_psock_stop_strp(sk, psock)

           if (!psock->saved_data_ready) return; // (4) sk_psock_stop_strp returns

           strp_stop(&psock->strp) // (5) so strp_stop can not be called
             strp->stopped = 1; // (6) so strp->stopped is **NOT** set to 1

         sk_psock_destroy
           sk_psock_done_strp
             strp_done
               WARN_ON(!strp->stopped); // (7) WARNING triggered


Now I'm convinced the memleak I observed was caused by strp_done not
being called, I'll send a test for it.


> Reviewed-by: John Fastabend <john.fastabend@gmail.com>
> 
> 
> .
Jakub Sitnicki Aug. 5, 2023, 11:41 a.m. UTC | #5
On Fri, Jul 28, 2023 at 06:56 AM -04, Xu Kuohai wrote:
> From: Xu Kuohai <xukuohai@huawei.com>
>
> sock_map_del_link() operates on both SOCKMAP and SOCKHASH, although
> both types have member named "progs", the offset of "progs" member in
> these two types is different, so "progs" should be accessed with the
> real map type.
>
> Fixes: 604326b41a6f ("bpf, sockmap: convert to generic sk_msg interface")
> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> ---

Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
diff mbox series

Patch

diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 19538d628714..936c5cabe9f3 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -148,13 +148,13 @@  static void sock_map_del_link(struct sock *sk,
 	list_for_each_entry_safe(link, tmp, &psock->link, list) {
 		if (link->link_raw == link_raw) {
 			struct bpf_map *map = link->map;
-			struct bpf_stab *stab = container_of(map, struct bpf_stab,
-							     map);
-			if (psock->saved_data_ready && stab->progs.stream_parser)
+			struct sk_psock_progs *progs = sock_map_progs(map);
+
+			if (psock->saved_data_ready && progs->stream_parser)
 				strp_stop = true;
-			if (psock->saved_data_ready && stab->progs.stream_verdict)
+			if (psock->saved_data_ready && progs->stream_verdict)
 				verdict_stop = true;
-			if (psock->saved_data_ready && stab->progs.skb_verdict)
+			if (psock->saved_data_ready && progs->skb_verdict)
 				verdict_stop = true;
 			list_del(&link->list);
 			sk_psock_free_link(link);