{"uuid": "eeea1d39-2102-4e2c-bf7f-42510e37beec", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-31431", "type": "seen", "source": "https://gist.github.com/spynika/e452783668ff5a7a3dc4cc036d3f9463", "content": "/* SPDX-License-Identifier: LGPL-2.1-or-later OR MIT */\n/*\n * Copy Fail -- CVE-2026-31431\n * Vulnerability checker.\n *\n * Detects whether the running kernel is susceptible to the AF_ALG/splice\n * page-cache mutation primitive used by exploit.c and exploit-passwd.c,\n * without touching any system file. Creates a local \"testfile\" in the\n * working directory containing the string \"init\", then runs the same\n * patch_chunk() primitive against its page cache to attempt to overwrite\n * the bytes with \"vulnerable\". Reads back to confirm whether the\n * mutation took.\n *\n * The on-disk inode is never modified; the testfile is removed on exit,\n * and the page-cache mutation evaporates with it. Runs unprivileged.\n *\n * Exit codes:\n *   100 - kernel is vulnerable\n *   0   - kernel is not vulnerable (primitive ran but mutation did not take)\n *   2   - AF_ALG socket family or authencesn template is unavailable;\n *         patch state cannot be determined from this test\n *   1   - other runtime error\n */\n\n#define _GNU_SOURCE\n#include \n#include \n#include \n#include \n#include \n#include \n\n#include \n\n#include \"utils.h\"\n\nstatic const char PAYLOAD[] = \"vulnerable\";\n#define PAYLOAD_LEN (sizeof PAYLOAD - 1)\n\nstatic int check_file(const char *filename) {\n    int fd = open(filename, O_RDONLY);\n    if (fd &lt; 0) return 0;\n    printf(\"content of %s fd=%d ---\\n\", filename, fd);\n    char buf[256];\n    ssize_t total = read(fd, buf, sizeof buf);\n    if (total &gt; 0)\n        write(STDOUT_FILENO, buf, total);\n    close(fd);\n    printf(\"\\n---\\n\");\n    return total &gt;= (ssize_t)PAYLOAD_LEN &amp;&amp;\n           memcmp(buf, PAYLOAD, PAYLOAD_LEN) == 0;\n}\n\nstatic void init_file(const char *filename) {\n    static const char init_buf[32] = \"init\";\n    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);\n    if (fd &lt; 0) {\n        fprintf(stderr, \"open(%s): %s\\n\", filename, strerror(errno));\n        exit(1);\n    }\n    write(fd, init_buf, sizeof init_buf);\n    close(fd);\n}\n\nint main(int argc, char **argv) {\n    (void)argc; (void)argv;\n    const char *target = \"testfile\";\n\n    init_file(target);\n    sync();\n    check_file(target);\n\n    int file_fd = open(target, O_RDONLY);\n    if (file_fd &lt; 0) {\n        fprintf(stderr, \"open(%s): %s\\n\", target, strerror(errno));\n        unlink(target);\n        return 1;\n    }\n\n    size_t iters = (PAYLOAD_LEN + 3) / 4;\n\n    fprintf(stderr, \"[+] target:    %s\\n\", target);\n    fprintf(stderr, \"[+] payload:   %zu bytes (%zu iterations)\\n\",\n            PAYLOAD_LEN, iters);\n\n    /* Walk the payload in 4-byte windows. window[] is 5 bytes so the\n     * trailing zero acts as a NUL terminator for the %s log below. */\n    for (off_t off = 0; (size_t)off &lt; PAYLOAD_LEN; off += 4) {\n        unsigned char window[5] = { 0, 0, 0, 0, 0 };\n        size_t take = (PAYLOAD_LEN - (size_t)off &gt;= 4)\n                      ? 4 : PAYLOAD_LEN - (size_t)off;\n        memcpy(window, PAYLOAD + off, take);\n\n        fprintf(stderr, \"[+] patch fd=%d off=%lld bytes=\\\"%s\\\"\\n\",\n                file_fd, (long long)off, window);\n        if (patch_chunk(file_fd, off, window) &lt; 0) {\n            int ret;\n            if (errno == EAFNOSUPPORT) {\n                fprintf(stderr,\n                        \"[?] AF_ALG socket family unavailable; kernel patch \"\n                        \"state cannot be determined from this test\\n\");\n                ret = 2;\n            } else if (errno == ENOENT) {\n                fprintf(stderr,\n                        \"[?] AF_ALG authencesn template not registered; \"\n                        \"kernel patch state cannot be determined from this \"\n                        \"test\\n\");\n                ret = 2;\n            } else {\n                fprintf(stderr, \"[-] patch_chunk failed at offset %lld\\n\",\n                        (long long)off);\n                ret = 1;\n            }\n\n            close(file_fd);\n            unlink(target);\n            return ret;\n        }\n        fprintf(stderr, \"[+] patch ok\\n\");\n    }\n\n    close(file_fd);\n\n    fprintf(stderr, \"[+] page cache mutated\\n\");\n\n    int vulnerable = check_file(target);\n    unlink(target);\n\n    if (vulnerable) {\n        fprintf(stderr, \"[!] VULNERABLE\\n\");\n        return 100;\n    }\n\n    fprintf(stderr, \"[+] not vulnerable :)\\n\");\n    return 0;\n}", "creation_timestamp": "2026-06-04T07:22:41.000000Z"}