2023-12-19 09:12:56

by lee bruce

[permalink] [raw]
Subject: memory leak in unix_create1/copy_process/security_prepare_creds

Hello I found a bug in net/af_unix in the lastest upstream linux
6.7.rc5 and comfired in lastest net/net-next/bpf/bpf-next tree.
Titled "TITLE: memory leak in unix_create1” and I also upload the
repro.c and repro.txt.

If you fix this issue, please add the following tag to the commit:
Reported-by: xingwei Lee <[email protected]>

lastest net tree: 979e90173af8d2f52f671d988189aab98c6d1be6
Kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=8c4e4700f1727d30

in the lastest net tree, the crash like:
Linux syzkaller 6.7.0-rc5-00172-g979e90173af8 #4 SMP PREEMPT_DYNAMIC
Tue Dec 19 11:03:58 HKT 2023 x86_4

TITLE: memory leak in security_prepare_creds
[<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
[<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
[<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
BUG: memory leak
unreferenced object 0xffff8881408b9390 (size 16):
comm "cd01", pid 8363, jiffies 4296754700 (age 12.260s)
hex dump (first 16 bytes):
00 00 00 00 00 00 00 00 00 4b 99 00 81 88 ff ff .........K......
backtrace:
[<ffffffff816340fd>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
[<ffffffff8157f42b>] __do_kmalloc_node mm/slab_common.c:1006 [inline]
[<ffffffff8157f42b>] __kmalloc+0x4b/0x150 mm/slab_common.c:1020
[<ffffffff823695b1>] kmalloc include/linux/slab.h:604 [inline]
[<ffffffff823695b1>] kzalloc include/linux/slab.h:721 [inline]
[<ffffffff823695b1>] lsm_cred_alloc security/security.c:577 [inline]
[<ffffffff823695b1>] security_prepare_creds+0x121/0x140
security/security.c:2950
[<ffffffff812e1189>] prepare_creds+0x329/0x4e0 kernel/cred.c:300
[<ffffffff812e18f4>] copy_creds+0x44/0x280 kernel/cred.c:373
[<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
[<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
[<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff888147c26b40 (size 112):
comm "cd01", pid 8363, jiffies 4296754700 (age 12.260s)
hex dump (first 32 bytes):
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<ffffffff81631578>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
[<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
[<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
[<ffffffff812d30ca>] alloc_pid+0x6a/0x570 kernel/pid.c:183
[<ffffffff81293ab8>] copy_process+0x1848/0x25c0 kernel/fork.c:2518
[<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
[<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff88810813d040 (size 1088):
comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 8a 00 00 00 00 00 00 00 ................
01 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
backtrace:
[<ffffffff81631578>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
[<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
[<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
[<ffffffff83ecc0ce>] sk_prot_alloc+0x3e/0x1b0 net/core/sock.c:2069
[<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
[<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
[<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
[<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
[<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
[<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
[<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
[<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
[<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff88811701bd10 (size 16):
comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
hex dump (first 16 bytes):
00 4b 99 00 81 88 ff ff 00 00 00 00 00 00 00 00 .K..............
backtrace:
[<ffffffff816340fd>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
[<ffffffff8157ed85>] kmalloc_trace+0x25/0x90 mm/slab_common.c:1098
[<ffffffff823a75c2>] kmalloc include/linux/slab.h:600 [inline]
[<ffffffff823a75c2>] kzalloc include/linux/slab.h:721 [inline]
[<ffffffff823a75c2>] apparmor_sk_alloc_security+0x52/0xd0
security/apparmor/lsm.c:997
[<ffffffff8236b407>] security_sk_alloc+0x47/0x80 security/security.c:4411
[<ffffffff83ecc11f>] sk_prot_alloc+0x8f/0x1b0 net/core/sock.c:2078
[<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
[<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
[<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
[<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
[<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
[<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
[<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
[<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
[<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b



TITLE: memory leak in copy_process
[<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
[<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
[<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
BUG: memory leak
unreferenced object 0xffff888147c26b40 (size 112):
comm "cd01", pid 8363, jiffies 4296754700 (age 12.260s)
hex dump (first 32 bytes):
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<ffffffff81631578>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
[<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
[<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
[<ffffffff812d30ca>] alloc_pid+0x6a/0x570 kernel/pid.c:183
[<ffffffff81293ab8>] copy_process+0x1848/0x25c0 kernel/fork.c:2518
[<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
[<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff88810813d040 (size 1088):
comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 8a 00 00 00 00 00 00 00 ................
01 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
backtrace:
[<ffffffff81631578>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
[<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
[<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
[<ffffffff83ecc0ce>] sk_prot_alloc+0x3e/0x1b0 net/core/sock.c:2069
[<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
[<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
[<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
[<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
[<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
[<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
[<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
[<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
[<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff88811701bd10 (size 16):
comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
hex dump (first 16 bytes):
00 4b 99 00 81 88 ff ff 00 00 00 00 00 00 00 00 .K..............
backtrace:
[<ffffffff816340fd>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
[<ffffffff8157ed85>] kmalloc_trace+0x25/0x90 mm/slab_common.c:1098
[<ffffffff823a75c2>] kmalloc include/linux/slab.h:600 [inline]
[<ffffffff823a75c2>] kzalloc include/linux/slab.h:721 [inline]
[<ffffffff823a75c2>] apparmor_sk_alloc_security+0x52/0xd0
security/apparmor/lsm.c:997
[<ffffffff8236b407>] security_sk_alloc+0x47/0x80 security/security.c:4411
[<ffffffff83ecc11f>] sk_prot_alloc+0x8f/0x1b0 net/core/sock.c:2078
[<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
[<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
[<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
[<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
[<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
[<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
[<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
[<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
[<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

TITLE: memory leak in unix_create1
[<ffffffff81293ab8>] copy_process+0x1848/0x25c0 kernel/fork.c:2518
[<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
[<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
BUG: memory leak
unreferenced object 0xffff88810813d040 (size 1088):
comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 8a 00 00 00 00 00 00 00 ................
01 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
backtrace:
[<ffffffff81631578>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
[<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
[<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
[<ffffffff83ecc0ce>] sk_prot_alloc+0x3e/0x1b0 net/core/sock.c:2069
[<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
[<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
[<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
[<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
[<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
[<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
[<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
[<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
[<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff88811701bd10 (size 16):
comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
hex dump (first 16 bytes):
00 4b 99 00 81 88 ff ff 00 00 00 00 00 00 00 00 .K..............
backtrace:
[<ffffffff816340fd>] kmemleak_alloc_recursive
include/linux/kmemleak.h:42 [inline]
[<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
[<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
[<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
[<ffffffff8157ed85>] kmalloc_trace+0x25/0x90 mm/slab_common.c:1098
[<ffffffff823a75c2>] kmalloc include/linux/slab.h:600 [inline]
[<ffffffff823a75c2>] kzalloc include/linux/slab.h:721 [inline]
[<ffffffff823a75c2>] apparmor_sk_alloc_security+0x52/0xd0
security/apparmor/lsm.c:997
[<ffffffff8236b407>] security_sk_alloc+0x47/0x80 security/security.c:4411
[<ffffffff83ecc11f>] sk_prot_alloc+0x8f/0x1b0 net/core/sock.c:2078
[<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
[<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
[<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
[<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
[<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
[<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
[<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
[<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
[<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
[<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
[<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
[<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

=* repro.c =*
// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#ifndef __NR_bpf
#define __NR_bpf 321
#endif

static void sleep_ms(uint64_t ms) { usleep(ms * 1000); }

static uint64_t current_time_ms(void) {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts)) exit(1);
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}

static bool write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1) return false;
if (write(fd, buf, len) != len) {
int err = errno;
close(fd);
errno = err;
return false;
}
close(fd);
return true;
}

static void kill_and_wait(int pid, int* status) {
kill(-pid, SIGKILL);
kill(pid, SIGKILL);
for (int i = 0; i < 100; i++) {
if (waitpid(-1, status, WNOHANG | __WALL) == pid) return;
usleep(1000);
}
DIR* dir = opendir("/sys/fs/fuse/connections");
if (dir) {
for (;;) {
struct dirent* ent = readdir(dir);
if (!ent) break;
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
continue;
char abort[300];
snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
ent->d_name);
int fd = open(abort, O_WRONLY);
if (fd == -1) {
continue;
}
if (write(fd, abort, 1) < 0) {
}
close(fd);
}
closedir(dir);
} else {
}
while (waitpid(-1, status, __WALL) != pid) {
}
}

static void setup_test() {
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
write_file("/proc/self/oom_score_adj", "1000");
}

#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"

static void setup_leak() {
if (!write_file(KMEMLEAK_FILE, "scan")) exit(1);
sleep(5);
if (!write_file(KMEMLEAK_FILE, "scan")) exit(1);
if (!write_file(KMEMLEAK_FILE, "clear")) exit(1);
}

static void check_leaks(void) {
int fd = open(KMEMLEAK_FILE, O_RDWR);
if (fd == -1) exit(1);
uint64_t start = current_time_ms();
if (write(fd, "scan", 4) != 4) exit(1);
sleep(1);
while (current_time_ms() - start < 4 * 1000) sleep(1);
if (write(fd, "scan", 4) != 4) exit(1);
static char buf[128 << 10];
ssize_t n = read(fd, buf, sizeof(buf) - 1);
if (n < 0) exit(1);
int nleaks = 0;
if (n != 0) {
sleep(1);
if (write(fd, "scan", 4) != 4) exit(1);
if (lseek(fd, 0, SEEK_SET) < 0) exit(1);
n = read(fd, buf, sizeof(buf) - 1);
if (n < 0) exit(1);
buf[n] = 0;
char* pos = buf;
char* end = buf + n;
while (pos < end) {
char* next = strstr(pos + 1, "unreferenced object");
if (!next) next = end;
char prev = *next;
*next = 0;
fprintf(stderr, "BUG: memory leak\n%s\n", pos);
*next = prev;
pos = next;
nleaks++;
}
}
if (write(fd, "clear", 5) != 5) exit(1);
close(fd);
if (nleaks) exit(1);
}

static void execute_one(void);

#define WAIT_FLAGS __WALL

static void loop(void) {
int iter = 0;
for (;; iter++) {
int pid = fork();
if (pid < 0) exit(1);
if (pid == 0) {
setup_test();
execute_one();
exit(0);
}
int status = 0;
uint64_t start = current_time_ms();
for (;;) {
if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) break;
sleep_ms(1);
if (current_time_ms() - start < 5000) continue;
kill_and_wait(pid, &status);
break;
}
check_leaks();
}
}

uint64_t r[1] = {0xffffffffffffffff};

void execute_one(void) {
intptr_t res = 0;
syscall(__NR_socketpair, /*domain=*/1ul, /*type=*/1ul, /*proto=*/0,
/*fds=*/0x20000000ul);
*(uint32_t*)0x200000c0 = 0x12;
*(uint32_t*)0x200000c4 = 2;
*(uint32_t*)0x200000c8 = 4;
*(uint32_t*)0x200000cc = 1;
*(uint32_t*)0x200000d0 = 0;
*(uint32_t*)0x200000d4 = -1;
*(uint32_t*)0x200000d8 = 0;
memset((void*)0x200000dc, 0, 16);
*(uint32_t*)0x200000ec = 0;
*(uint32_t*)0x200000f0 = -1;
*(uint32_t*)0x200000f4 = 0;
*(uint32_t*)0x200000f8 = 0;
*(uint32_t*)0x200000fc = 0;
*(uint64_t*)0x20000100 = 0;
res = syscall(__NR_bpf, /*cmd=*/0ul, /*arg=*/0x200000c0ul, /*size=*/0x48ul);
if (res != -1) r[0] = res;
*(uint32_t*)0x200003c0 = r[0];
*(uint64_t*)0x200003c8 = 0x20000040;
*(uint64_t*)0x200003d0 = 0x20000000;
*(uint64_t*)0x200003d8 = 0;
syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);
*(uint32_t*)0x200003c0 = r[0];
*(uint64_t*)0x200003c8 = 0x20000040;
*(uint64_t*)0x200003d0 = 0x20000000;
*(uint64_t*)0x200003d8 = 0;
syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);
}
int main(void) {
syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
/*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
/*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
setup_leak();
loop();
return 0;
}



=* repro.txt =*
socketpair(0x1, 0x1, 0x0, &(0x7f0000000000))
r0 = bpf$MAP_CREATE(0x0, &(0x7f00000000c0)=@base={0x12, 0x2, 0x4, 0x1}, 0x48)
bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
0x20000000}, 0x20)
bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
0x20000000}, 0x20)


Please see also
https://gist.github.com/xrivendell7/80fc686da1e9223cf49ec87ad8e2ebfc

I do not analysis it deeply but looks like it might be related to the
bpf module so I aslo CC bpf maintainers.
Hope it helps.
Best regards.
xingwei Lee


2023-12-19 15:51:29

by Kuniyuki Iwashima

[permalink] [raw]
Subject: Re: memory leak in unix_create1/copy_process/security_prepare_creds

From: xingwei lee <[email protected]>
Date: Tue, 19 Dec 2023 17:12:25 +0800
> Hello I found a bug in net/af_unix in the lastest upstream linux
> 6.7.rc5 and comfired in lastest net/net-next/bpf/bpf-next tree.
> Titled "TITLE: memory leak in unix_create1” and I also upload the
> repro.c and repro.txt.
>
> If you fix this issue, please add the following tag to the commit:
> Reported-by: xingwei Lee <[email protected]>

Thanks for reporting!

It seems 8866730aed510 forgot to add sock_put().
I've confirmed that the diff below silenced kmemleak but will check
more before posting a patch.

---8<---
diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c
index 7ea7c3a0d0d0..32daba9e7f8b 100644
--- a/net/unix/unix_bpf.c
+++ b/net/unix/unix_bpf.c
@@ -164,6 +164,7 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r
if (restore) {
sk->sk_write_space = psock->saved_write_space;
sock_replace_proto(sk, psock->sk_proto);
+ sock_put(psock->sk_pair);
return 0;
}

---8<---

Thanks!


>
> lastest net tree: 979e90173af8d2f52f671d988189aab98c6d1be6
> Kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=8c4e4700f1727d30
>
> in the lastest net tree, the crash like:
> Linux syzkaller 6.7.0-rc5-00172-g979e90173af8 #4 SMP PREEMPT_DYNAMIC
> Tue Dec 19 11:03:58 HKT 2023 x86_4
>
> TITLE: memory leak in security_prepare_creds
> [<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
> [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
> BUG: memory leak
> unreferenced object 0xffff8881408b9390 (size 16):
> comm "cd01", pid 8363, jiffies 4296754700 (age 12.260s)
> hex dump (first 16 bytes):
> 00 00 00 00 00 00 00 00 00 4b 99 00 81 88 ff ff .........K......
> backtrace:
> [<ffffffff816340fd>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
> [<ffffffff8157f42b>] __do_kmalloc_node mm/slab_common.c:1006 [inline]
> [<ffffffff8157f42b>] __kmalloc+0x4b/0x150 mm/slab_common.c:1020
> [<ffffffff823695b1>] kmalloc include/linux/slab.h:604 [inline]
> [<ffffffff823695b1>] kzalloc include/linux/slab.h:721 [inline]
> [<ffffffff823695b1>] lsm_cred_alloc security/security.c:577 [inline]
> [<ffffffff823695b1>] security_prepare_creds+0x121/0x140
> security/security.c:2950
> [<ffffffff812e1189>] prepare_creds+0x329/0x4e0 kernel/cred.c:300
> [<ffffffff812e18f4>] copy_creds+0x44/0x280 kernel/cred.c:373
> [<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
> [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> BUG: memory leak
> unreferenced object 0xffff888147c26b40 (size 112):
> comm "cd01", pid 8363, jiffies 4296754700 (age 12.260s)
> hex dump (first 32 bytes):
> 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> backtrace:
> [<ffffffff81631578>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
> [<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
> [<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
> [<ffffffff812d30ca>] alloc_pid+0x6a/0x570 kernel/pid.c:183
> [<ffffffff81293ab8>] copy_process+0x1848/0x25c0 kernel/fork.c:2518
> [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> BUG: memory leak
> unreferenced object 0xffff88810813d040 (size 1088):
> comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
> hex dump (first 32 bytes):
> 00 00 00 00 00 00 00 00 8a 00 00 00 00 00 00 00 ................
> 01 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
> backtrace:
> [<ffffffff81631578>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
> [<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
> [<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
> [<ffffffff83ecc0ce>] sk_prot_alloc+0x3e/0x1b0 net/core/sock.c:2069
> [<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
> [<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
> [<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
> [<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
> [<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
> [<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
> [<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
> [<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
> [<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> BUG: memory leak
> unreferenced object 0xffff88811701bd10 (size 16):
> comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
> hex dump (first 16 bytes):
> 00 4b 99 00 81 88 ff ff 00 00 00 00 00 00 00 00 .K..............
> backtrace:
> [<ffffffff816340fd>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
> [<ffffffff8157ed85>] kmalloc_trace+0x25/0x90 mm/slab_common.c:1098
> [<ffffffff823a75c2>] kmalloc include/linux/slab.h:600 [inline]
> [<ffffffff823a75c2>] kzalloc include/linux/slab.h:721 [inline]
> [<ffffffff823a75c2>] apparmor_sk_alloc_security+0x52/0xd0
> security/apparmor/lsm.c:997
> [<ffffffff8236b407>] security_sk_alloc+0x47/0x80 security/security.c:4411
> [<ffffffff83ecc11f>] sk_prot_alloc+0x8f/0x1b0 net/core/sock.c:2078
> [<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
> [<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
> [<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
> [<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
> [<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
> [<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
> [<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
> [<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
> [<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
>
>
> TITLE: memory leak in copy_process
> [<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
> [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
> BUG: memory leak
> unreferenced object 0xffff888147c26b40 (size 112):
> comm "cd01", pid 8363, jiffies 4296754700 (age 12.260s)
> hex dump (first 32 bytes):
> 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> backtrace:
> [<ffffffff81631578>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
> [<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
> [<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
> [<ffffffff812d30ca>] alloc_pid+0x6a/0x570 kernel/pid.c:183
> [<ffffffff81293ab8>] copy_process+0x1848/0x25c0 kernel/fork.c:2518
> [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> BUG: memory leak
> unreferenced object 0xffff88810813d040 (size 1088):
> comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
> hex dump (first 32 bytes):
> 00 00 00 00 00 00 00 00 8a 00 00 00 00 00 00 00 ................
> 01 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
> backtrace:
> [<ffffffff81631578>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
> [<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
> [<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
> [<ffffffff83ecc0ce>] sk_prot_alloc+0x3e/0x1b0 net/core/sock.c:2069
> [<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
> [<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
> [<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
> [<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
> [<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
> [<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
> [<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
> [<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
> [<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> BUG: memory leak
> unreferenced object 0xffff88811701bd10 (size 16):
> comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
> hex dump (first 16 bytes):
> 00 4b 99 00 81 88 ff ff 00 00 00 00 00 00 00 00 .K..............
> backtrace:
> [<ffffffff816340fd>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
> [<ffffffff8157ed85>] kmalloc_trace+0x25/0x90 mm/slab_common.c:1098
> [<ffffffff823a75c2>] kmalloc include/linux/slab.h:600 [inline]
> [<ffffffff823a75c2>] kzalloc include/linux/slab.h:721 [inline]
> [<ffffffff823a75c2>] apparmor_sk_alloc_security+0x52/0xd0
> security/apparmor/lsm.c:997
> [<ffffffff8236b407>] security_sk_alloc+0x47/0x80 security/security.c:4411
> [<ffffffff83ecc11f>] sk_prot_alloc+0x8f/0x1b0 net/core/sock.c:2078
> [<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
> [<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
> [<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
> [<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
> [<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
> [<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
> [<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
> [<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
> [<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> TITLE: memory leak in unix_create1
> [<ffffffff81293ab8>] copy_process+0x1848/0x25c0 kernel/fork.c:2518
> [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
> BUG: memory leak
> unreferenced object 0xffff88810813d040 (size 1088):
> comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
> hex dump (first 32 bytes):
> 00 00 00 00 00 00 00 00 8a 00 00 00 00 00 00 00 ................
> 01 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
> backtrace:
> [<ffffffff81631578>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff81631578>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff81631578>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff81631578>] slab_alloc mm/slub.c:3486 [inline]
> [<ffffffff81631578>] __kmem_cache_alloc_lru mm/slub.c:3493 [inline]
> [<ffffffff81631578>] kmem_cache_alloc+0x298/0x430 mm/slub.c:3502
> [<ffffffff83ecc0ce>] sk_prot_alloc+0x3e/0x1b0 net/core/sock.c:2069
> [<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
> [<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
> [<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
> [<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
> [<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
> [<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
> [<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
> [<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
> [<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> BUG: memory leak
> unreferenced object 0xffff88811701bd10 (size 16):
> comm "cd01", pid 8365, jiffies 4296754700 (age 12.260s)
> hex dump (first 16 bytes):
> 00 4b 99 00 81 88 ff ff 00 00 00 00 00 00 00 00 .K..............
> backtrace:
> [<ffffffff816340fd>] kmemleak_alloc_recursive
> include/linux/kmemleak.h:42 [inline]
> [<ffffffff816340fd>] slab_post_alloc_hook mm/slab.h:766 [inline]
> [<ffffffff816340fd>] slab_alloc_node mm/slub.c:3478 [inline]
> [<ffffffff816340fd>] __kmem_cache_alloc_node+0x2dd/0x3f0 mm/slub.c:3517
> [<ffffffff8157ed85>] kmalloc_trace+0x25/0x90 mm/slab_common.c:1098
> [<ffffffff823a75c2>] kmalloc include/linux/slab.h:600 [inline]
> [<ffffffff823a75c2>] kzalloc include/linux/slab.h:721 [inline]
> [<ffffffff823a75c2>] apparmor_sk_alloc_security+0x52/0xd0
> security/apparmor/lsm.c:997
> [<ffffffff8236b407>] security_sk_alloc+0x47/0x80 security/security.c:4411
> [<ffffffff83ecc11f>] sk_prot_alloc+0x8f/0x1b0 net/core/sock.c:2078
> [<ffffffff83ecf506>] sk_alloc+0x36/0x2f0 net/core/sock.c:2128
> [<ffffffff84371e34>] unix_create1+0x84/0x320 net/unix/af_unix.c:982
> [<ffffffff84372168>] unix_create+0x98/0x130 net/unix/af_unix.c:1049
> [<ffffffff83ec493f>] __sock_create+0x19f/0x2e0 net/socket.c:1569
> [<ffffffff83ec8440>] sock_create net/socket.c:1620 [inline]
> [<ffffffff83ec8440>] __sys_socketpair+0x160/0x370 net/socket.c:1771
> [<ffffffff83ec866f>] __do_sys_socketpair net/socket.c:1820 [inline]
> [<ffffffff83ec866f>] __se_sys_socketpair net/socket.c:1817 [inline]
> [<ffffffff83ec866f>] __x64_sys_socketpair+0x1f/0x30 net/socket.c:1817
> [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> =* repro.c =*
> // autogenerated by syzkaller (https://github.com/google/syzkaller)
>
> #define _GNU_SOURCE
>
> #include <dirent.h>
> #include <endian.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <signal.h>
> #include <stdarg.h>
> #include <stdbool.h>
> #include <stdint.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <sys/prctl.h>
> #include <sys/stat.h>
> #include <sys/syscall.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <time.h>
> #include <unistd.h>
>
> #ifndef __NR_bpf
> #define __NR_bpf 321
> #endif
>
> static void sleep_ms(uint64_t ms) { usleep(ms * 1000); }
>
> static uint64_t current_time_ms(void) {
> struct timespec ts;
> if (clock_gettime(CLOCK_MONOTONIC, &ts)) exit(1);
> return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
> }
>
> static bool write_file(const char* file, const char* what, ...) {
> char buf[1024];
> va_list args;
> va_start(args, what);
> vsnprintf(buf, sizeof(buf), what, args);
> va_end(args);
> buf[sizeof(buf) - 1] = 0;
> int len = strlen(buf);
> int fd = open(file, O_WRONLY | O_CLOEXEC);
> if (fd == -1) return false;
> if (write(fd, buf, len) != len) {
> int err = errno;
> close(fd);
> errno = err;
> return false;
> }
> close(fd);
> return true;
> }
>
> static void kill_and_wait(int pid, int* status) {
> kill(-pid, SIGKILL);
> kill(pid, SIGKILL);
> for (int i = 0; i < 100; i++) {
> if (waitpid(-1, status, WNOHANG | __WALL) == pid) return;
> usleep(1000);
> }
> DIR* dir = opendir("/sys/fs/fuse/connections");
> if (dir) {
> for (;;) {
> struct dirent* ent = readdir(dir);
> if (!ent) break;
> if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
> continue;
> char abort[300];
> snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
> ent->d_name);
> int fd = open(abort, O_WRONLY);
> if (fd == -1) {
> continue;
> }
> if (write(fd, abort, 1) < 0) {
> }
> close(fd);
> }
> closedir(dir);
> } else {
> }
> while (waitpid(-1, status, __WALL) != pid) {
> }
> }
>
> static void setup_test() {
> prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
> setpgrp();
> write_file("/proc/self/oom_score_adj", "1000");
> }
>
> #define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak"
>
> static void setup_leak() {
> if (!write_file(KMEMLEAK_FILE, "scan")) exit(1);
> sleep(5);
> if (!write_file(KMEMLEAK_FILE, "scan")) exit(1);
> if (!write_file(KMEMLEAK_FILE, "clear")) exit(1);
> }
>
> static void check_leaks(void) {
> int fd = open(KMEMLEAK_FILE, O_RDWR);
> if (fd == -1) exit(1);
> uint64_t start = current_time_ms();
> if (write(fd, "scan", 4) != 4) exit(1);
> sleep(1);
> while (current_time_ms() - start < 4 * 1000) sleep(1);
> if (write(fd, "scan", 4) != 4) exit(1);
> static char buf[128 << 10];
> ssize_t n = read(fd, buf, sizeof(buf) - 1);
> if (n < 0) exit(1);
> int nleaks = 0;
> if (n != 0) {
> sleep(1);
> if (write(fd, "scan", 4) != 4) exit(1);
> if (lseek(fd, 0, SEEK_SET) < 0) exit(1);
> n = read(fd, buf, sizeof(buf) - 1);
> if (n < 0) exit(1);
> buf[n] = 0;
> char* pos = buf;
> char* end = buf + n;
> while (pos < end) {
> char* next = strstr(pos + 1, "unreferenced object");
> if (!next) next = end;
> char prev = *next;
> *next = 0;
> fprintf(stderr, "BUG: memory leak\n%s\n", pos);
> *next = prev;
> pos = next;
> nleaks++;
> }
> }
> if (write(fd, "clear", 5) != 5) exit(1);
> close(fd);
> if (nleaks) exit(1);
> }
>
> static void execute_one(void);
>
> #define WAIT_FLAGS __WALL
>
> static void loop(void) {
> int iter = 0;
> for (;; iter++) {
> int pid = fork();
> if (pid < 0) exit(1);
> if (pid == 0) {
> setup_test();
> execute_one();
> exit(0);
> }
> int status = 0;
> uint64_t start = current_time_ms();
> for (;;) {
> if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) break;
> sleep_ms(1);
> if (current_time_ms() - start < 5000) continue;
> kill_and_wait(pid, &status);
> break;
> }
> check_leaks();
> }
> }
>
> uint64_t r[1] = {0xffffffffffffffff};
>
> void execute_one(void) {
> intptr_t res = 0;
> syscall(__NR_socketpair, /*domain=*/1ul, /*type=*/1ul, /*proto=*/0,
> /*fds=*/0x20000000ul);
> *(uint32_t*)0x200000c0 = 0x12;
> *(uint32_t*)0x200000c4 = 2;
> *(uint32_t*)0x200000c8 = 4;
> *(uint32_t*)0x200000cc = 1;
> *(uint32_t*)0x200000d0 = 0;
> *(uint32_t*)0x200000d4 = -1;
> *(uint32_t*)0x200000d8 = 0;
> memset((void*)0x200000dc, 0, 16);
> *(uint32_t*)0x200000ec = 0;
> *(uint32_t*)0x200000f0 = -1;
> *(uint32_t*)0x200000f4 = 0;
> *(uint32_t*)0x200000f8 = 0;
> *(uint32_t*)0x200000fc = 0;
> *(uint64_t*)0x20000100 = 0;
> res = syscall(__NR_bpf, /*cmd=*/0ul, /*arg=*/0x200000c0ul, /*size=*/0x48ul);
> if (res != -1) r[0] = res;
> *(uint32_t*)0x200003c0 = r[0];
> *(uint64_t*)0x200003c8 = 0x20000040;
> *(uint64_t*)0x200003d0 = 0x20000000;
> *(uint64_t*)0x200003d8 = 0;
> syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);
> *(uint32_t*)0x200003c0 = r[0];
> *(uint64_t*)0x200003c8 = 0x20000040;
> *(uint64_t*)0x200003d0 = 0x20000000;
> *(uint64_t*)0x200003d8 = 0;
> syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);
> }
> int main(void) {
> syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
> /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> setup_leak();
> loop();
> return 0;
> }
>
>
>
> =* repro.txt =*
> socketpair(0x1, 0x1, 0x0, &(0x7f0000000000))
> r0 = bpf$MAP_CREATE(0x0, &(0x7f00000000c0)=@base={0x12, 0x2, 0x4, 0x1}, 0x48)
> bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
> 0x20000000}, 0x20)
> bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
> 0x20000000}, 0x20)
>
>
> Please see also
> https://gist.github.com/xrivendell7/80fc686da1e9223cf49ec87ad8e2ebfc
>
> I do not analysis it deeply but looks like it might be related to the
> bpf module so I aslo CC bpf maintainers.
> Hope it helps.
> Best regards.
> xingwei Lee

2023-12-19 19:55:08

by John Fastabend

[permalink] [raw]
Subject: Re: memory leak in unix_create1/copy_process/security_prepare_creds

Kuniyuki Iwashima wrote:
> From: xingwei lee <[email protected]>
> Date: Tue, 19 Dec 2023 17:12:25 +0800
> > Hello I found a bug in net/af_unix in the lastest upstream linux
> > 6.7.rc5 and comfired in lastest net/net-next/bpf/bpf-next tree.
> > Titled "TITLE: memory leak in unix_create1” and I also upload the
> > repro.c and repro.txt.
> >
> > If you fix this issue, please add the following tag to the commit:
> > Reported-by: xingwei Lee <[email protected]>
>
> Thanks for reporting!
>
> It seems 8866730aed510 forgot to add sock_put().
> I've confirmed that the diff below silenced kmemleak but will check
> more before posting a patch.

Did it really silence the memleak?

>
> ---8<---
> diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c
> index 7ea7c3a0d0d0..32daba9e7f8b 100644
> --- a/net/unix/unix_bpf.c
> +++ b/net/unix/unix_bpf.c
> @@ -164,6 +164,7 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r
> if (restore) {
> sk->sk_write_space = psock->saved_write_space;
> sock_replace_proto(sk, psock->sk_proto);
> + sock_put(psock->sk_pair);
> return 0;

The reason the sock_put is not in this routine but in the sk_psock_destory
is because we need to wait a RCU grace period for any pending queued
BPF sends to also be flushed.

> }
>
> ---8<---
>
> Thanks!
>
>

I'm also trying to understand how this adds up to
unix_stream_bpf_update_proto() issue. The reproduce has a map_create
followed by two map_delete() calls. I can't see how the unix socket
ever got added to the BPF map and the deletes should be empty?

> >
> > lastest net tree: 979e90173af8d2f52f671d988189aab98c6d1be6
> > Kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=8c4e4700f1727d30
> >
> > in the lastest net tree, the crash like:
> > Linux syzkaller 6.7.0-rc5-00172-g979e90173af8 #4 SMP PREEMPT_DYNAMIC
> > Tue Dec 19 11:03:58 HKT 2023 x86_4
> >
> > TITLE: memory leak in security_prepare_creds
> > [<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
> > [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> > [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> > [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> > [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> > [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

...

> > uint64_t r[1] = {0xffffffffffffffff};
> >
> > void execute_one(void) {
> > intptr_t res = 0;
> > syscall(__NR_socketpair, /*domain=*/1ul, /*type=*/1ul, /*proto=*/0,
> > /*fds=*/0x20000000ul);
> > *(uint32_t*)0x200000c0 = 0x12;
> > *(uint32_t*)0x200000c4 = 2;
> > *(uint32_t*)0x200000c8 = 4;
> > *(uint32_t*)0x200000cc = 1;
> > *(uint32_t*)0x200000d0 = 0;
> > *(uint32_t*)0x200000d4 = -1;
> > *(uint32_t*)0x200000d8 = 0;


> > memset((void*)0x200000dc, 0, 16);
> > *(uint32_t*)0x200000ec = 0;
> > *(uint32_t*)0x200000f0 = -1;
> > *(uint32_t*)0x200000f4 = 0;
> > *(uint32_t*)0x200000f8 = 0;
> > *(uint32_t*)0x200000fc = 0;
> > *(uint64_t*)0x20000100 = 0;
> > res = syscall(__NR_bpf, /*cmd=*/0ul, /*arg=*/0x200000c0ul, /*size=*/0x48ul);

mapfd = map_create( bpf_attr { SOCKHASH, 1 entry, 0 flags, ...} )

> > if (res != -1) r[0] = res;
> > *(uint32_t*)0x200003c0 = r[0];
> > *(uint64_t*)0x200003c8 = 0x20000040;
> > *(uint64_t*)0x200003d0 = 0x20000000;
> > *(uint64_t*)0x200003d8 = 0;
> > syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);

map_delete(mapfd, key=0x20000040, value=0x20000000, flags = 0)

> > *(uint32_t*)0x200003c0 = r[0];
> > *(uint64_t*)0x200003c8 = 0x20000040;
> > *(uint64_t*)0x200003d0 = 0x20000000;
> > *(uint64_t*)0x200003d8 = 0;
> > syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);

map_delete(mapfd, key=0x20000040, value=0x20000000, flags = 0)

so same as repro.txt below makes sense. But, if the sockets are
never added to the sockhash then we never touched the proto from
BPF side. And both of these deletes should return errors.

> > }
> > int main(void) {
> > syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> > /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> > syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
> > /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> > syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> > /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> > setup_leak();
> > loop();
> > return 0;
> > }
> >
> >
> >
> > =* repro.txt =*
> > socketpair(0x1, 0x1, 0x0, &(0x7f0000000000))
> > r0 = bpf$MAP_CREATE(0x0, &(0x7f00000000c0)=@base={0x12, 0x2, 0x4, 0x1}, 0x48)
> > bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
> > 0x20000000}, 0x20)
> > bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
> > 0x20000000}, 0x20)

So not making sense to me how we got to blaming the proto delete
logic here. It doesn't look like we ever added the psock and
configured the proto?

Did a bisect really blame the mentioned patch? I can likely try here
as well.

Thanks,
John

2023-12-19 20:36:30

by John Fastabend

[permalink] [raw]
Subject: Re: memory leak in unix_create1/copy_process/security_prepare_creds

John Fastabend wrote:
> Kuniyuki Iwashima wrote:
> > From: xingwei lee <[email protected]>
> > Date: Tue, 19 Dec 2023 17:12:25 +0800
> > > Hello I found a bug in net/af_unix in the lastest upstream linux
> > > 6.7.rc5 and comfired in lastest net/net-next/bpf/bpf-next tree.
> > > Titled "TITLE: memory leak in unix_create1” and I also upload the
> > > repro.c and repro.txt.
> > >
> > > If you fix this issue, please add the following tag to the commit:
> > > Reported-by: xingwei Lee <[email protected]>
> >
> > Thanks for reporting!
> >
> > It seems 8866730aed510 forgot to add sock_put().
> > I've confirmed that the diff below silenced kmemleak but will check
> > more before posting a patch.
>
> Did it really silence the memleak?

Yes reverting the patch fixed the issue for me.

>
> >
> > ---8<---
> > diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c
> > index 7ea7c3a0d0d0..32daba9e7f8b 100644
> > --- a/net/unix/unix_bpf.c
> > +++ b/net/unix/unix_bpf.c
> > @@ -164,6 +164,7 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r
> > if (restore) {
> > sk->sk_write_space = psock->saved_write_space;
> > sock_replace_proto(sk, psock->sk_proto);
> > + sock_put(psock->sk_pair);
> > return 0;
>
> The reason the sock_put is not in this routine but in the sk_psock_destory
> is because we need to wait a RCU grace period for any pending queued
> BPF sends to also be flushed.

So we need a different fix here. I'll look into it.

>
> > }
> >
> > ---8<---
> >
> > Thanks!
> >
> >
>
> I'm also trying to understand how this adds up to
> unix_stream_bpf_update_proto() issue. The reproduce has a map_create
> followed by two map_delete() calls. I can't see how the unix socket
> ever got added to the BPF map and the deletes should be empty?
>
> > >
> > > lastest net tree: 979e90173af8d2f52f671d988189aab98c6d1be6
> > > Kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=8c4e4700f1727d30
> > >
> > > in the lastest net tree, the crash like:
> > > Linux syzkaller 6.7.0-rc5-00172-g979e90173af8 #4 SMP PREEMPT_DYNAMIC
> > > Tue Dec 19 11:03:58 HKT 2023 x86_4
> > >
> > > TITLE: memory leak in security_prepare_creds
> > > [<ffffffff8129291a>] copy_process+0x6aa/0x25c0 kernel/fork.c:2366
> > > [<ffffffff812949db>] kernel_clone+0x11b/0x690 kernel/fork.c:2907
> > > [<ffffffff81294fcc>] __do_sys_clone+0x7c/0xb0 kernel/fork.c:3050
> > > [<ffffffff84b70dcf>] do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> > > [<ffffffff84b70dcf>] do_syscall_64+0x3f/0x110 arch/x86/entry/common.c:83
> > > [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b
>
> ...
>
> > > uint64_t r[1] = {0xffffffffffffffff};
> > >
> > > void execute_one(void) {
> > > intptr_t res = 0;
> > > syscall(__NR_socketpair, /*domain=*/1ul, /*type=*/1ul, /*proto=*/0,
> > > /*fds=*/0x20000000ul);
> > > *(uint32_t*)0x200000c0 = 0x12;
> > > *(uint32_t*)0x200000c4 = 2;
> > > *(uint32_t*)0x200000c8 = 4;
> > > *(uint32_t*)0x200000cc = 1;
> > > *(uint32_t*)0x200000d0 = 0;
> > > *(uint32_t*)0x200000d4 = -1;
> > > *(uint32_t*)0x200000d8 = 0;
>
>
> > > memset((void*)0x200000dc, 0, 16);
> > > *(uint32_t*)0x200000ec = 0;
> > > *(uint32_t*)0x200000f0 = -1;
> > > *(uint32_t*)0x200000f4 = 0;
> > > *(uint32_t*)0x200000f8 = 0;
> > > *(uint32_t*)0x200000fc = 0;
> > > *(uint64_t*)0x20000100 = 0;
> > > res = syscall(__NR_bpf, /*cmd=*/0ul, /*arg=*/0x200000c0ul, /*size=*/0x48ul);
>
> mapfd = map_create( bpf_attr { SOCKHASH, 1 entry, 0 flags, ...} )
>
> > > if (res != -1) r[0] = res;
> > > *(uint32_t*)0x200003c0 = r[0];
> > > *(uint64_t*)0x200003c8 = 0x20000040;
> > > *(uint64_t*)0x200003d0 = 0x20000000;
> > > *(uint64_t*)0x200003d8 = 0;
> > > syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);
>
> map_delete(mapfd, key=0x20000040, value=0x20000000, flags = 0)
>
> > > *(uint32_t*)0x200003c0 = r[0];
> > > *(uint64_t*)0x200003c8 = 0x20000040;
> > > *(uint64_t*)0x200003d0 = 0x20000000;
> > > *(uint64_t*)0x200003d8 = 0;
> > > syscall(__NR_bpf, /*cmd=*/2ul, /*arg=*/0x200003c0ul, /*size=*/0x20ul);
>
> map_delete(mapfd, key=0x20000040, value=0x20000000, flags = 0)

cmd=2 is update so this splat makes more sense.

>
> so same as repro.txt below makes sense. But, if the sockets are
> never added to the sockhash then we never touched the proto from
> BPF side. And both of these deletes should return errors.
>
> > > }
> > > int main(void) {
> > > syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> > > /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> > > syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
> > > /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> > > syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> > > /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> > > setup_leak();
> > > loop();
> > > return 0;
> > > }
> > >
> > >
> > >
> > > =* repro.txt =*
> > > socketpair(0x1, 0x1, 0x0, &(0x7f0000000000))
> > > r0 = bpf$MAP_CREATE(0x0, &(0x7f00000000c0)=@base={0x12, 0x2, 0x4, 0x1}, 0x48)
> > > bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
> > > 0x20000000}, 0x20)
> > > bpf$MAP_DELETE_ELEM(0x2, &(0x7f00000003c0)={r0, &(0x7f0000000040),
> > > 0x20000000}, 0x20)
>
> So not making sense to me how we got to blaming the proto delete
> logic here. It doesn't look like we ever added the psock and
> configured the proto?

Not sure why these is delete cmd=0x2.

#define ___BPF_FUNC_MAPPER(FN, ctx...) \
FN(unspec, 0, ##ctx) \
FN(map_lookup_elem, 1, ##ctx) \
FN(map_update_elem, 2, ##ctx) \


>
> Did a bisect really blame the mentioned patch? I can likely try here
> as well.

Seems so.

>
> Thanks,
> John



2023-12-19 22:14:25

by John Fastabend

[permalink] [raw]
Subject: Re: memory leak in unix_create1/copy_process/security_prepare_creds

John Fastabend wrote:
> John Fastabend wrote:
> > Kuniyuki Iwashima wrote:
> > > From: xingwei lee <[email protected]>
> > > Date: Tue, 19 Dec 2023 17:12:25 +0800
> > > > Hello I found a bug in net/af_unix in the lastest upstream linux
> > > > 6.7.rc5 and comfired in lastest net/net-next/bpf/bpf-next tree.
> > > > Titled "TITLE: memory leak in unix_create1” and I also upload the
> > > > repro.c and repro.txt.
> > > >
> > > > If you fix this issue, please add the following tag to the commit:
> > > > Reported-by: xingwei Lee <[email protected]>
> > >
> > > Thanks for reporting!
> > >
> > > It seems 8866730aed510 forgot to add sock_put().
> > > I've confirmed that the diff below silenced kmemleak but will check
> > > more before posting a patch.
> >
> > Did it really silence the memleak?
>
> Yes reverting the patch fixed the issue for me.

The problem is we call proto update twice that bumps the refcnt
when adding a the same element to the map in the same slot. I'll fix
this on sockmap side so we can keep the current af_unix logic. Should
be able to push a fix tomorrow.

We probably never noticed for other socket types because its an
unusal replace to do same sock/same slot, but af_unix has this
side effect of incrementing the refcnt that doesn't exist elsewhere.

Thanks,
John