From c30113f3511c7e8c580c354b2b71be3ee585b633 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 30 Oct 2026 08:07:36 +0000 Subject: [PATCH] upstream: set a glob(3) error callback when globbing Include files to allow discrimination between missing files/directories and failure to open a file or directory. Avoids possible (though unlikely) situation where a local attacker could cause an Include'd file from being processed by doing tricks like hitting fd limits at the right time. Anthropic ANT-2026-NF7CR4JX OpenBSD-Commit-ID: 561568f92b71cda06f47070c31a533995d652a70 --- misc.c | 17 ++++++++++++++++- misc.h | 3 ++- readconf.c | 4 ++-- servconf.c | 5 +++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/misc.c b/misc.c index bc83e39fc..fb3ec2bee 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.222 2026/10/30 01:16:44 djm Exp $ */ +/* $OpenBSD: misc.c,v 1.223 2026/10/30 08:07:36 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -2686,6 +2686,21 @@ path_absolute(const char *path) return (*path == '/') ? 1 : 0; } +/* + * glob(3) error callback for configuration file Include directives. + * A directory that doesn't exist matches no files, but a failure to read + * one that does must not be mistaken for that: abort the glob instead. + */ +int +include_glob_error(const char *path, int errnum) +{ + if (errnum == ENOENT || errnum == ENOTDIR) + return 0; + error("Include: unable to read directory %s: %s", path, + strerror(errnum)); + return 1; +} + void skip_space(char **cpp) { diff --git a/misc.h b/misc.h index 0784f379b..cfb9d50a4 100644 --- a/misc.h +++ b/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.120 2026/09/16 06:23:16 djm Exp $ */ +/* $OpenBSD: misc.h,v 1.121 2026/10/30 08:07:36 djm Exp $ */ /* * Author: Tatu Ylonen @@ -111,6 +111,7 @@ int parse_absolute_time(const char *, uint64_t *); void format_absolute_time(uint64_t, char *, size_t); int parse_pattern_interval(const char *, char **, double *); int path_absolute(const char *); +int include_glob_error(const char *, int); int stdfd_devnull(int, int, int); int lib_contains_symbol(const char *, const char *); char *get_homedir(void); diff --git a/readconf.c b/readconf.c index cf9baa988..80788df85 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.421 2026/10/30 06:40:58 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.422 2026/10/30 08:07:36 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2150,7 +2150,7 @@ parse_pubkey_algos: } free(p); memset(&gl, 0, sizeof(gl)); - r = glob(arg2, GLOB_TILDE, NULL, &gl); + r = glob(arg2, GLOB_TILDE, include_glob_error, &gl); if (r == GLOB_NOMATCH) { debug("%.200s line %d: include %s matched no " "files",filename, linenum, arg2); diff --git a/servconf.c b/servconf.c index 70842a076..d40750a87 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.461 2026/10/30 03:28:03 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.462 2026/10/30 08:07:36 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -2226,7 +2226,8 @@ process_server_config_line_depth(ServerOptions *options, char *line, /* requested glob was not in cache */ debug2("%s line %d: new include %s", filename, linenum, arg); - if ((r = glob(arg, 0, NULL, &gbuf)) != 0) { + if ((r = glob(arg, 0, include_glob_error, + &gbuf)) != 0) { if (r != GLOB_NOMATCH) { fatal("%s line %d: include \"%s\" glob " "failed", filename, linenum, arg);