On Fri, 4 Jul 2025, Jeremy Drake via Cygwin-patches wrote:

> On Fri, 4 Jul 2025, Corinna Vinschen wrote:
>
> > On Jul  3 12:03, Jeremy Drake via Cygwin-patches wrote:
> > > On Thu, 3 Jul 2025, Jeremy Drake via Cygwin-patches wrote:
> > > >
> > > > https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addclose.html
> > > >
> > > > > A spawn file actions object, when passed to posix_spawn() or
> > > > > posix_spawnp(), shall specify how the set of open file descriptors in
> > > > > the calling process is transformed into a set of potentially open file
> > > > > descriptors for the spawned process. This transformation shall be as 
> > > > > if
> > > > > the specified sequence of actions was performed exactly once, in the
> > > > > context of the spawned process (prior to execution of the new process
> > > > > image), in the order in which the actions were added to the object;
> >
> > I see what you mean.  The question of questions is if "as if" only
> > covers the "performed exactly once" requirement, or if the "as if"
> > really encompasses all three requirements, i.e.
> >
> > - as if the specified sequence of actions was performed exactly once
> >
> > - exactly in the context of the spawned process (prior to execution of the 
> > new
> >   process image)
> >
> > - exactly in the order in which the actions were added to the object
> >
> > in contrast to
> >
> > - as if the specified sequence of actions was performed exactly once
> >
> > - as if in the context of the spawned process (prior to execution of the new
> >   process image)
> >
> > - as if in the order in which the actions were added to the object
> >
> > My understanding (as a non-native speaker) is that "as if" only
> > covers the "performed exactly once" requirement.  Applying "as if"
> > to the order requirement doesn't make much sense to me.  And applying "as 
> > if"
> > implicitely to the second requirement, but not to the third, doesn't
> > make much sense to me either.
>
> The "as if" performed exactly once doesn't make a whole lot of sense to me
> either... To me, the only case where "as if" adds flexibility is the
> context of the child process.
>
> > On top of that you'd have the problem that the man pages of
> > osix_spawn_file_actions_addclose and posix_spawn_file_actions_addchdir
> > contradict each other.  This, of course, is always possible.  Only an
> > RFC to the Austin Group could clarify this.  Maybe we should really do
> > that.
>
> The parts you quoted are in a section labeled "The following sections are
> informative.".  But there does seem to be some confusion over whether the
> actions *must* be performed in the child, or only *as if* they were
> performed in the child.  Maybe they could clarify.  I interpreted the
> posix_spawn rationale applying to the Windows model, whereas maybe they
> only meant systems lacking fork due to their embedded-ness (lacking mmu
> etc).  I don't see why they would preclude this though.  I'm kind of
> considering the Cygwin dll as the "kernel" in this context.
>
> > > > > How do you run, say,
> > > > >
> > > > >   addopen (42, "dir", O_SEARCH|O_DIRECTORY)
> > > > >
> > > > > without potentially disrupting the actions of another parallel thread,
> > > > > just reading data from a file attached to fd 42?
> > > >
> > > > First, I wouldn't be rushing to optimize the case of file descriptors
> > > > greater than 2, because I don't see that as a common case.  However, if
> > > > necessary, I'd do it much the same way as for 0 through 2:
> > > >
> > > > hold the lock_process lock
> > > > perform the open, and assign the returned file descriptor into a mapping
> > > > of file descriptors for the child.
> > > > for a Win32 child, implement the lpReserved2 used by msvcrt to specify
> > > > the fd to handle mapping
> > > > for a Cygwin child, change the stdin/stdout/stderr child_info_spawn to
> > > > some mapping structure for move_fd operations to perform in 
> > > > handle_spawn.
> > >
> > > I get the idea that "some mapping structure" in child_info_spawn could
> > > just be the file actions and attributes from posix_spawn, and instead of
> > > move_fd process the actions and attributes in handle_spawn.  Why I am
> > > resisting this is that I don't want to have to do this twice: once in the
> > > parent as I do now, which must continue to exist for win32 processes AND
> > > to find the directory to which a relative program path is relative; and do
> > > it again during Cygwin process startup.  I'm really struggling to see why
> > > the added complexity of a special path for Cygwin children is necessary
> > > here.
> >
> > Yeah, ok, I get that.  I understand that you're frustrated.  Please keep
> > in mind that, to me, Cygwin processes are the first class citizens,
> > native processes are second class.  Therefore it would be great to be
> > able to do it right for Cygwin processes in the first place.
> >
> > I'm not trying to be unreasonable and inclined to go with your patchset
> > for a start.  But, to me, considering the Issue 8 descriptions, it
> > seems we could do more, better for Cygwin processes.
> >
> > Or maybe not!  But that will probably require more tedious discussions
> > like this one and throwing ideas back and forth.  It would be a bit
> > disappointing to be stuck with this and not trying to come up with
> > funny ideas to workaround obstacles like O_CLOEXEC, POSIX_SPAWN_RESETIDS,
> > etc.
>
> I'm sorry if I'm sounding frustrated.  I am just trying to debate to find
> the best implementation.  I think that having two versions of processing
> the file actions is asking for inconsistencies and bugs.  As you point
> out, non-Cygwin processes are second-class citizens to Cygwin but are more
> important to MSYS2 and Git for Windows, so I can see bugs in the
> non-Cygwin case going undiscovered until after a Cygwin release, when
> MSYS2 and Git for Windows try to integrate it and exercise the case of a
> Cygwin GNU make running mingw gcc, or Cygwin bash running mingw git
> running Cygwin ssh, or any other bizarre combination.
>
> I'd be happy to consider a counter implementation.  I think this would
> have to:
> 1. exist inside child_info_spawn::worker, because path_conv.iscygexec ()
> wouldn't be reliable until after av::setup has run and set it based in
> hook_or_detect_cygwin.
> 2. process the file actions in the parent to compute the child's cwd, so
> that a relative program is found relative to the correct cwd.  This has
> a certain amount of chicken-and-egg because av::setup needs to use this
> cwd to find relative paths in the #! at least.
> 3. the malloc/strdup/free in newlib posix_spawn.c needs to be swapped out
> for cmalloc-based ones so the structures remain available in the child.
> 4. the posix_spawnattrs_t and posix_spawn_file_actions_t need to be passed
> to the child (child_info_spawn or the moreinfo member)
> 5. the process_spawnattr and process_file_actions in newlib posix_spawn.c
> need to be called from dcrt0.c (probably handle_spawn).

6. any existing file descriptors referenced by the file_actions_t (dup2,
fchdir) need to be made available to the child while they are processed,
but closed before the child actually runs if they were FD_CLOEXEC.

Also, I didn't mean to imply that there was any issue with RESETIDS - I
just didn't feel like it was important to figure out the security
implications vs just letting fork/exec do its thing.  I'm pretty sure it
could just deimpersonate & refrain from using CreateProcessAsUserW path.
I didn't look into it.

Reply via email to