[openssh-commits] [openssh] 12/15: fuzz: add sshconfig_fuzz harness for SSH client config parser

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Oct 9 21:38:30 AEDT 2026


This is an automated email from the git hooks/post-receive script.

dtucker pushed a commit to branch master
in repository openssh.

commit 0579edc76b8a885cf1d5d693f7146af3d5b9e816
Author: KiloClaw <bot at kiloclaw.ai>
AuthorDate: Sun May 31 03:37:04 2026 +0000

    fuzz: add sshconfig_fuzz harness for SSH client config parser
    
    Add a libfuzzer harness covering the SSH client configuration file
    parser (readconf.c). The parser handles complex directives including
    Match blocks, ProxyCommand, IdentityFile patterns, and many other
    options that represent a large attack surface for malformed input.
    
    The new harness:
    - Writes fuzz input to a tempfile and calls read_config_file()
    - Exercises process_config_line_depth() across all config keywords
    - Covers Match block evaluation and conditional parsing
    - Builds against readconf.o, addrmatch.o, misc.o, krl.o
    
    Also adds sshconfig_fuzz to the TARGETS list in Makefile.
---
 regress/misc/fuzz-harness/Makefile          |  7 ++-
 regress/misc/fuzz-harness/sshconfig_fuzz.cc | 71 +++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile
index 6a83ecc78..f86e3c731 100644
--- a/regress/misc/fuzz-harness/Makefile
+++ b/regress/misc/fuzz-harness/Makefile
@@ -18,7 +18,7 @@ TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz authkeys_fuzz sshsig_fuzz \
 	ssh_client_session_fuzz sftp_server_msg_fuzz authfd_reply_fuzz \
 	sftp_client_fuzz misc_parse_fuzz ssh_channels_fuzz \
 	session_channel_req_fuzz sshd_auth_session_fuzz hostfile_fuzz \
-	mux_fuzz
+	mux_fuzz sshconfig_fuzz
 
 all: $(TARGETS)
 
@@ -52,6 +52,11 @@ privkey_fuzz: privkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
 kex_fuzz: kex_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
 	$(CXX) -o $@ kex_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(FUZZ_FLAGS) $(LIBS) -lz
 
+sshconfig_fuzz: sshconfig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+	$(CXX) -o $@ sshconfig_fuzz.o $(SK_NULL_OBJS) ../../../readconf.o \
+		../../../addrmatch.o ../../../misc.o ../../../krl.o \
+		$(LDFLAGS) $(FUZZ_FLAGS) $(LIBS) -lz
+
 agent_fuzz: agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(COMMON_DEPS)
 	$(CXX) -o $@ agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(LDFLAGS) $(FUZZ_FLAGS) $(LIBS) -lz
 
diff --git a/regress/misc/fuzz-harness/sshconfig_fuzz.cc b/regress/misc/fuzz-harness/sshconfig_fuzz.cc
new file mode 100644
index 000000000..c70760ed2
--- /dev/null
+++ b/regress/misc/fuzz-harness/sshconfig_fuzz.cc
@@ -0,0 +1,71 @@
+// libfuzzer driver for SSH client configuration file parser.
+// Covers readconf.c: process_config_line_depth() and related parsing logic.
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <unistd.h>
+
+extern "C" {
+
+#include "includes.h"
+#include "readconf.h"
+#include "log.h"
+#include "xmalloc.h"
+
+// Stub out log output to reduce noise
+void sshsig_free(struct sshsig_ctx *ctx) {}
+
+}  // extern "C"
+
+static struct passwd fuzz_pw;
+static char fuzz_username[] = "fuzzer";
+static char fuzz_home[] = "/tmp";
+static char fuzz_shell[] = "/bin/sh";
+
+static void init_pw(void) {
+    fuzz_pw.pw_name = fuzz_username;
+    fuzz_pw.pw_uid = getuid();
+    fuzz_pw.pw_gid = getgid();
+    fuzz_pw.pw_dir = fuzz_home;
+    fuzz_pw.pw_shell = fuzz_shell;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    static int initialized = 0;
+    if (!initialized) {
+        log_init("sshconfig_fuzz", SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_AUTH, 0);
+        init_pw();
+        initialized = 1;
+    }
+
+    // Write fuzz input to a temp file (read_config_file requires a path)
+    char tmpfile[] = "/tmp/sshconfig_fuzz_XXXXXX";
+    int fd = mkstemp(tmpfile);
+    if (fd < 0)
+        return 0;
+
+    if (write(fd, data, size) != (ssize_t)size) {
+        close(fd);
+        unlink(tmpfile);
+        return 0;
+    }
+    close(fd);
+
+    Options options;
+    initialize_options(&options);
+
+    // Process each line through the config parser
+    // Errors are intentional (fuzzing) — suppress but don't crash
+    read_config_file(tmpfile, &fuzz_pw, "fuzz.example.com", "fuzz.example.com",
+                     &options, 0, NULL);
+
+    // Clean up allocated options
+    // (options cleanup is intentionally omitted; leak sanitizer disabled for fuzzing)
+
+    unlink(tmpfile);
+    return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list