From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202606 header.b=obx+2jY8; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id CBE825A061E for ; Tue, 14 Jul 2026 11:29:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202606; t=1784021369; bh=vQXo3MaqZjbrixK6biIcFKRq1r/+6JLIPMQzi2M6DSk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=obx+2jY81qpqaghCHKJvyVME5GeRdgoXgEVVABV6Z8NDZa1wFUt58tDdlybjtyOhR FLUkAtxXOR+Qz1sKE8zz0Q6qdMVhZeQOI/i2NzNEAeIj029gppqeJi/CWE6LzAHh2R 4WvJF0Lx/GASIICyL5qborMmhKxPk3j7odf8Jdh7ZljKcJQKuFRKbkHHTiLVAYJbsc P2i4La7teRKTNsCag+H16lpeynfkBoSJrqJd9bNvlF1e9DlUtUMoZL+bB9O4AdaYen ogWBgwl6zIc5yBzD6FuqjFNbwx2VT7s2s8XMIC0bbDPaqFoETirAGjfEvbZz/gSpzO v3hvRVE0RfodA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4gzvCF725Qz4wCJ; Tue, 14 Jul 2026 19:29:29 +1000 (AEST) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH 5/6] main: Ensure fds 0-2 are populated Date: Tue, 14 Jul 2026 19:29:25 +1000 Message-ID: <20260714092926.2881848-6-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260714092926.2881848-1-david@gibson.dropbear.id.au> References: <20260714092926.2881848-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: FQTFNWD5OCUO4KAMYIINTAUGCEHUNRWN X-Message-ID-Hash: FQTFNWD5OCUO4KAMYIINTAUGCEHUNRWN X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Usually fds 0-2 are stdin, stdout and stderr. However, certain things which might invoke passt can close some of those standard fds. If so, anything we open might be placed in one of the standard slots. For the handful of things we open early enough, this can be a problem because we close fds 0-2 in __daemon(), replacing them with dupes of /dev/null. We could avoid closing those fds in __daemon() if they're not standard streams. However, leaving things other than the standard streams in fds 0-2 is a footgun: a stray printf() that occurs in a circumstance it shouldn't could send harmful garbage to a device or socket. It's also likely to be confusing if debugging with strace or similar. To avoid this, fill any missing standard streams with a dupe of /dev/null, right after isolate_initial(). Since open()ing /dev/null itself could land in one of those fd 0-2 slots, we need to be careful when we close it not to leave a new gap. Link: https://bugs.passt.top/show_bug.cgi?id=215 Signed-off-by: David Gibson --- passt.c | 19 +++++++++++++------ util.c | 3 +-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/passt.c b/passt.c index b99e5998..663a1005 100644 --- a/passt.c +++ b/passt.c @@ -330,8 +330,8 @@ static void passt_worker(void *opaque, int nfds, struct epoll_event *events) int main(int argc, char **argv) { struct epoll_event events[NUM_EPOLL_EVENTS]; + int nfds, devnull_fd = -1, fd; struct ctx *c = &passt_ctx; - int nfds, devnull_fd = -1; struct rlimit limit; struct timespec now; struct sigaction sa; @@ -343,6 +343,15 @@ int main(int argc, char **argv) c->fd_tap = isolate_initial(argc, argv); + if ((devnull_fd = open("/dev/null", O_RDWR | O_CLOEXEC)) < 0) + die_perror("Failed to open /dev/null"); + /* Ensure fds 0-2 are populated */ + for (fd = 0; fd <= STDERR_FILENO; fd++) { + if (fcntl(fd, F_GETFD) < 0 && + dup2(devnull_fd, fd) < 0) + die_perror("Failed to populate fd %d", fd); + } + sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = exit_handler; @@ -410,11 +419,6 @@ int main(int argc, char **argv) fwd_neigh_table_init(c); nl_neigh_notify_init(c); - if (!c->foreground) { - if ((devnull_fd = open("/dev/null", O_RDWR | O_CLOEXEC)) < 0) - die_perror("Failed to open /dev/null"); - } - if (isolate_prefork(c)) die("Failed to sandbox process, exiting"); @@ -428,6 +432,9 @@ int main(int argc, char **argv) c->pidfile_fd = -1; } + if (devnull_fd > STDERR_FILENO) + close(devnull_fd); + if (pasta_child_pid) { kill(pasta_child_pid, SIGUSR1); log_stderr = false; diff --git a/util.c b/util.c index ce5021a9..bd4c6caa 100644 --- a/util.c +++ b/util.c @@ -522,8 +522,7 @@ int __daemon(int pidfile_fd, int devnull_fd) if (setsid() < 0 || dup2(devnull_fd, STDIN_FILENO) < 0 || dup2(devnull_fd, STDOUT_FILENO) < 0 || - dup2(devnull_fd, STDERR_FILENO) < 0 || - close(devnull_fd)) + dup2(devnull_fd, STDERR_FILENO) < 0) passt_exit(EXIT_FAILURE); return 0; -- 2.55.0