public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
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 10:02:38 +0200 (CEST)	[thread overview]
Message-ID: <20260716100237.4bc3c232@elisabeth> (raw)
In-Reply-To: <aliM94a9uAUtDVS5@zatzit>

On Thu, 16 Jul 2026 17:49:16 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:

> On Thu, Jul 16, 2026 at 09:22:30AM +0200, Stefano Brivio wrote:
> > On Thu, 16 Jul 2026 15:25:08 +1000
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >   
> > > 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.  
> > 
> > No, not dup2() specifically. AppArmor and SELinux don't operate (in
> > general) on specific system calls. I'm rather thinking of some issue
> > manipulating file descriptors that correspond to console devices.
> > 
> > For example, pasta's SELinux policy currently has:
> > 
> >   allow pasta_t console_device_t:chr_file { open write getattr ioctl };
> >   allow pasta_t user_devpts_t:chr_file { getattr read write ioctl };
> > 
> > are those sufficient if we call dup2() on those?  
> 
> Oh, I see.  Am I correct in thinking that those lavels are attached
> based on what the descriptor actually refers to, not based on the fd
> number?

Yes.

> If so, we don't call dup2() on console files.

Ah, oops, right, I mixed things up.

> We use it for 1) Moving
> the --fd descriptor out of the 0-2 range, so called on the --fd
> socket.  2) For filling up any empty slots in 0-2, so targeting a
> /dev/null handle.  In short, we never move the standard streams, we
> just move things around them.
> 
> Unless someone passes in an actual console descriptor with --fd, in
> which case SELinux blowing us up sounds like the correct outcome.

Right, good. I'll give things a quick try anyway once you re-spin.

-- 
Stefano


      reply	other threads:[~2026-07-16  8:02 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
2026-07-16  7:22     ` Stefano Brivio
2026-07-16  7:49       ` David Gibson
2026-07-16  8:02         ` Stefano Brivio [this message]

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=20260716100237.4bc3c232@elisabeth \
    --to=sbrivio@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    /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).