| // SPDX-License-Identifier: GPL-2.0-or-later | |
| /* | |
| * Copyright (c) 2025 Andrea Cervesato <[email protected]> | |
| */ | |
| /*\ | |
| * Test for CVE-2025-21756 fixed in kernel v6.14: | |
| * fcdd2242c023 vsock: Keep the binding until socket destruction | |
| * | |
| * Reproducer based on: | |
| * https://lore.kernel.org/all/[email protected]/ | |
| * | |
| * Beware, this test will crash the system. | |
| */ | |
| #include "tst_test.h" | |
| #include "lapi/vm_sockets.h" | |
| #define MAX_PORT_RETRIES 24 | |
| #define VMADDR_CID_NONEXISTING 42 | |
| static int vsock_bind(unsigned int cid, unsigned int port, int type) | |
| { | |
| int sock; | |
| struct sockaddr_vm sa = { | |
| .svm_family = AF_VSOCK, | |
| .svm_cid = cid, | |
| .svm_port = port, | |
| }; | |
| sock = SAFE_SOCKET(AF_VSOCK, type, 0); | |
| if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == -1) { | |
| if (errno == EINVAL) | |
| tst_brk(TCONF, "VM socket is not supported"); | |
| tst_brk(TBROK | TERRNO, "bind() error"); | |
| } | |
| return sock; | |
| } | |
| static void run(void) | |
| { | |
| int sockets[MAX_PORT_RETRIES]; | |
| struct sockaddr_vm addr; | |
| int socket, sock_count; | |
| socklen_t alen; | |
| socket = vsock_bind(VMADDR_CID_LOCAL, VMADDR_PORT_ANY, SOCK_SEQPACKET); | |
| alen = sizeof(addr); | |
| SAFE_GETSOCKNAME(socket, (struct sockaddr *)&addr, &alen); | |
| for (sock_count = 0; sock_count < MAX_PORT_RETRIES; ++sock_count) { | |
| sockets[sock_count] = vsock_bind(VMADDR_CID_ANY, | |
| ++addr.svm_port, SOCK_SEQPACKET); | |
| } | |
| SAFE_CLOSE(socket); | |
| socket = SAFE_SOCKET(AF_VSOCK, SOCK_SEQPACKET, 0); | |
| if (!connect(socket, (struct sockaddr *)&addr, alen)) | |
| tst_brk(TBROK, "Unexpected connect() #1 success"); | |
| addr.svm_cid = VMADDR_CID_NONEXISTING; | |
| if (!connect(socket, (struct sockaddr *)&addr, alen)) | |
| tst_brk(TBROK, "Unexpected connect() #2 success"); | |
| addr.svm_cid = VMADDR_CID_LOCAL; | |
| addr.svm_port = VMADDR_PORT_ANY; | |
| /* Vulnerable system may crash now. */ | |
| SAFE_BIND(socket, (struct sockaddr *)&addr, alen); | |
| SAFE_CLOSE(socket); | |
| if (tst_taint_check()) | |
| tst_res(TFAIL, "Kernel is vulnerable"); | |
| else | |
| tst_res(TPASS, "Kernel survived after socket unbinding"); | |
| while (sock_count--) | |
| SAFE_CLOSE(sockets[sock_count]); | |
| } | |
| static struct tst_test test = { | |
| .test_all = run, | |
| .taint_check = TST_TAINT_W | TST_TAINT_D, | |
| .tags = (const struct tst_tag[]) { | |
| {"linux-git", "fcdd2242c0231032fc84e1404315c245ae56322a"}, | |
| {"CVE", "2025-21756"}, | |
| {} | |
| }, | |
| }; |