public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>
Cc: passt-dev@passt.top
Subject: Re: [PATCH 0/6] Fix bug 215 and some related issues with fd handling
Date: Thu, 16 Jul 2026 15:25:08 +1000	[thread overview]
Message-ID: <alhrKtgMp4mBvcAl@zatzit> (raw)
In-Reply-To: <20260715183946.6121580a@elisabeth>

[-- Attachment #1: Type: text/plain, Size: 8420 bytes --]

On Wed, Jul 15, 2026 at 06:39:47PM +0200, Stefano Brivio wrote:
> On Tue, 14 Jul 2026 19:29:20 +1000
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
> > Stefano, you called it correctly.  While working on bug 215, as usual,
> > I found a bunch of adjacent things to clean up.
> 
> So, I finally finished reviewing the series.
> 
> Other than 1/6 and 2/6 on which I already commented (long story short,
> I think we should avoid 1/6, and about 2/6, it would be nice to parse -F
> just once in general but I think we shouldn't "force" it like that...
> maybe just parse / get it outside conf()?),

Hm, I'm not entirely sure of the distinction you're drawing between
the two cases.

> I don't see any substantial
> issue with the other patches, but I have some general comments about the
> approach.
> 
> As a detail, though, I would recommend Cc'ing everybody who might be
> interested or affected by this (reporter of bug #215, Rich as he fixed
> the original https://github.com/libguestfs/libguestfs/issues/360, and
> Alyssa as author of aa1cc8922867 ("conf: allow --fd 0").

Ah, good point, I'll do that for the next spin.

> > I did start by attempting the appoach you suggested for bug 215 -
> > remembering which of the low fds were standard streams and avoiding
> > closing them in __daemon().  It is indeed shorter, but only by 1-2
> > lines.  Looking at possible interactions with other things, I became
> > more and more convinced that leaving anything other than the standard
> > streams in fds 0-2 was an accident waiting to happen.
> 
> It did actually happen, see c66f0341d94d ("log: Don't report syslog
> failures to stderr after initialisation"). I didn't consider that,
> and it's indeed a strong argument in favour of this approach.
> 
> I still have some remarks and doubts about it though:
> 
> 1. we might have users passing a given file descriptor with the
>    expectation that it won't change its number as seen from procfs
>    (and dup2() changes that, right?), even just for debugging, and 4/6
>    breaks that. It's not a very legitimate expectation maybe but it
>    might be one, we simply don't know

That... really seems like taking bug for bug compatibility too far to
me.

> 
> 2. the reason behind my proposal (check if file descriptors are open
>    when we start and avoid closing them) was simplicity and avoiding
>    the risk of a number of side effects (more below).
> 
>    Yes, it's just a bit shorter (depending on how we count), but this
>    diff (build tested only) should be equivalent to patches 4/6 and 5/6,
>    which look considerably more complicated to me (even though the
>    simplification in close_open_files() is significant... but we could
>    get the same outcome also with just 4/6):
> 
> ---
> diff --git a/passt.c b/passt.c
> index 65a07d7..e2ea613 100644
> --- a/passt.c
> +++ b/passt.c
> @@ -330,8 +330,9 @@ 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];
> +	bool close_low_fd[STDERR_FILENO + 1];
> +	int nfds, devnull_fd = -1, i;
>  	struct ctx *c = &passt_ctx;
> -	int nfds, devnull_fd = -1;
>  	struct rlimit limit;
>  	struct timespec now;
>  	struct sigaction sa;
> @@ -339,6 +340,9 @@ int main(int argc, char **argv)
>  	if (clock_gettime(CLOCK_MONOTONIC, &log_start))
>  		die_perror("Failed to get CLOCK_MONOTONIC time");
>  
> +	for (i = STDIN_FILENO; i <= STDERR_FILENO; i++)
> +		close_low_fd[i] = !fcntl(i, F_GETFD);

Nit: needs to have a >= 0, F_GETFD returns flags, not 0 on success.

> +
>  	arch_avx2_exec(argv);
>  
>  	isolate_initial(argc, argv);
> @@ -419,7 +423,10 @@ int main(int argc, char **argv)
>  		die("Failed to sandbox process, exiting");
>  
>  	if (!c->foreground) {
> -		__daemon(c->pidfile_fd, devnull_fd);
> +		if (c->fd_tap != -1 && c->fd_tap < STDERR_FILENO)
> +			close_low_fd[c->fd_tap] = false;
> +
> +		__daemon(close_low_fd, c->pidfile_fd, devnull_fd);
>  		close(c->pidfile_fd);
>  		c->pidfile_fd = -1;
>  		log_stderr = false;
> diff --git a/util.c b/util.c
> index 4bc5d6f..57d42e1 100644
> --- a/util.c
> +++ b/util.c
> @@ -501,13 +501,14 @@ int output_file_open(const char *path, int flags)
>  
>  /**
>   * __daemon() - daemon()-like function writing PID file before parent exits
> + * @close_fd:	Standard stream descriptors numbers to close
>   * @pidfile_fd:	Open PID file descriptor
>   * @devnull_fd:	Open file descriptor for /dev/null
>   *
>   * Return: 0 in the child process on success. The parent process exits.
>   * 	   Does not return in either process on failure (calls _exit).
>   */
> -int __daemon(int pidfile_fd, int devnull_fd)
> +int __daemon(bool close_fd[STDERR_FILENO + 1], int pidfile_fd, int devnull_fd)
>  {
>  	pid_t pid = fork();
>  
> @@ -522,9 +523,9 @@ 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_fd[STDIN_FILENO]  && dup2(devnull_fd, STDIN_FILENO)  < 0) ||
> +	    (close_fd[STDOUT_FILENO] && dup2(devnull_fd, STDOUT_FILENO)	< 0) ||
> +	    (close_fd[STDERR_FILENO] && dup2(devnull_fd, STDERR_FILENO)	< 0) ||
>  	    close(devnull_fd))
>  		passt_exit(EXIT_FAILURE);
>  
> diff --git a/util.h b/util.h
> index 90e8a20..246ac67 100644
> --- a/util.h
> +++ b/util.h
> @@ -160,7 +160,7 @@ bool ns_is_init(void);
>  int open_in_ns(const struct ctx *c, const char *path, int flags);
>  int output_file_open(const char *path, int flags);
>  void pidfile_write(int fd, pid_t pid);
> -int __daemon(int pidfile_fd, int devnull_fd);
> +int __daemon(bool close_fd[STDERR_FILENO + 1], int pidfile_fd, int devnull_fd);
>  int fls(unsigned long x);
>  int ilog2(unsigned long x);
>  int write_file(const char *path, const char *buf);
> ---

Yes, that will do the job.  I still think avoiding anything but the
standard streams in 0-2 is worthwhile.

> 3. I have a generic worry that LSMs might get in the way. This would be solved
>    by testing your series against current AppArmor and SELinux policies but I
>    didn't get the chance yet (it would be nice if you could...)

That seems really far-fetched to me.  I assume you're meaning they
would block the dup2()?  That would break nearly anything that spawns
child processes.

> 4. if the concern is a misused fprintf() or printf(), shouldn't we prevent
>    direct usage anyway with, say:
> 
> #define printf(x) @ "Don't call printf() directly, use err() / warn() / debug() etc."
> 
>    and similar for fprintf(), that could only be called directly from
>    FPRINTF() and wherever we really need it? At that point I'm not sure
>    we would have any remaining concern about risks of using standard
>    streams by mistake

I guess.  I feel like that's even uglier than what I've proposed.

> 5. assuming we go with both 4/6 and 5/6: can we finally assume that sockets
>    will never be numbered 0 and save a lot of initialisations to -1 and
>    related checks, at that point? If we can achieve that as side effect,
>    that would be another argument in favour of it in my eyes

Huh, interesting, I guess it would allow that.

> 
> > Much of the
> > rest of the series is, for example, dealing with the possibility of
> > --fd [012].
> 
> ...well, yes, but the possibility of --fd [12] was introduced by the
> series itself. :)

Well, true, but dealing with -fd [12] was basically free while dealing
with --fd 0.

> Anyway, summing up my feedback, *maybe* other advantages outweigh 1. (I
> haven't checked what happens in procfs though), and once we check that
> 3. is not a problem, I'm fine with this approach (even though still a
> bit reluctant because we're adding substantial changes for a problem
> that doesn't even exist anymore as it's already fixed in libguestfs).

Hm, ok.  Well I have some ideas that might mitigate at least some of
your concerns, so I'll apply those, respin and see what you think.

-- 
David Gibson (he or they)	| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you, not the other way
				| around.
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2026-07-16  5:45 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14  9:29 David Gibson
2026-07-14  9:29 ` [PATCH 1/6] isolation, util: Fold close_open_files() into isolate_initial() David Gibson
2026-07-15  7:12   ` Stefano Brivio
2026-07-16  5:06     ` David Gibson
2026-07-14  9:29 ` [PATCH 2/6] isolation, conf: Set c->fd_tap from eary parse of --fd David Gibson
2026-07-15  7:12   ` Stefano Brivio
2026-07-16  5:12     ` David Gibson
2026-07-14  9:29 ` [PATCH 3/6] conf: Make conf_tap_fd() operate more like conf_mode() David Gibson
2026-07-14  9:29 ` [PATCH 4/6] isolation: Move --fd descriptor to a number of our choosing David Gibson
2026-07-14  9:29 ` [PATCH 5/6] main: Ensure fds 0-2 are populated David Gibson
2026-07-14  9:29 ` [PATCH 6/6] passt: *Always* close pidfile_fd, not just when daemonizing David Gibson
2026-07-15 16:39 ` [PATCH 0/6] Fix bug 215 and some related issues with fd handling Stefano Brivio
2026-07-16  5:25   ` David Gibson [this message]
2026-07-16  7:22     ` Stefano Brivio
2026-07-16  7:49       ` David Gibson
2026-07-16  8:02         ` Stefano Brivio

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alhrKtgMp4mBvcAl@zatzit \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).