From bb7ffdd7966c044361e86be1663b459fd0f6274c Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 30 Oct 2026 08:23:58 +0000 Subject: [PATCH] upstream: check for errors when writing known_hosts files and refuse to replace if the replacement is incomplete. Anthropic ANT-2026-SZY2YGUM OpenBSD-Commit-ID: 6d2137c4db55664397ba1ecb4cd4dc29d21eefe5 --- hostfile.c | 20 ++++++++++++++++---- ssh-keygen.c | 10 +++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/hostfile.c b/hostfile.c index c02662601..6b0e084eb 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.101 2026/10/30 07:48:23 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.102 2026/10/30 08:23:58 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -592,7 +592,8 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx) if (!sshkey_equal(ctx->keys[i], l->key)) continue; ctx->match_keys[i] |= l->match; - fprintf(ctx->out, "%s\n", l->line); + if (fprintf(ctx->out, "%s\n", l->line) < 0) + return SSH_ERR_SYSTEM_ERROR; debug3_f("%s key already at %s:%ld", sshkey_type(l->key), l->path, l->linenum); return 0; @@ -614,7 +615,8 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx) ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "", l->path, l->linenum); } - fprintf(ctx->out, "%s\n", l->line); + if (fprintf(ctx->out, "%s\n", l->line) < 0) + return SSH_ERR_SYSTEM_ERROR; return 0; } @@ -717,8 +719,15 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip, fp = NULL; ctx.modified = 1; } - fclose(ctx.out); + /* Don't replace the original with an incompletely-written copy */ + r = fclose(ctx.out); ctx.out = NULL; + if (r != 0) { + oerrno = errno; + error_f("fclose \"%s\": %s", temp, strerror(oerrno)); + r = SSH_ERR_SYSTEM_ERROR; + goto fail; + } if (ctx.modified) { /* Backup the original file and replace it with the temporary */ @@ -955,6 +964,9 @@ hostkeys_foreach_file(const char *path, FILE *f, hostkeys_foreach_fn *callback, if ((r = callback(&lineinfo, ctx)) != 0) break; } + /* A read error must not be mistaken for the end of the file */ + if (r == 0 && ferror(f)) + r = SSH_ERR_SYSTEM_ERROR; sshkey_free(lineinfo.key); free(lineinfo.line); free(line); diff --git a/ssh-keygen.c b/ssh-keygen.c index 2980cc27a..22ed27ea8 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.499 2026/10/30 03:47:56 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.500 2026/10/30 08:23:58 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -1350,8 +1350,12 @@ do_known_hosts(struct passwd *pw, const char *name, int find_host, fatal_fr(r, "hostkeys_foreach"); } - if (inplace) - fclose(ctx.out); + /* Don't replace the original with an incompletely-written copy */ + if (inplace && (ferror(ctx.out) || fclose(ctx.out) != 0)) { + oerrno = errno; + unlink(tmp); + fatal("write %s: %s", tmp, strerror(oerrno)); + } if (ctx.invalid) { error("%s is not a valid known_hosts file.", identity_file);