Repository navigation
Prevent mutating the global environment pointer in CommandExt::exec and opt to use execve and resolve path manually
#157144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
asder8215
wants to merge
11
commits into
rust-lang:main
Choose a base branch
from
asder8215:commandext_exec_bug_fix
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
a8b72e0
Prevent mutating the global environment pointer in CommandExt::exec a…
asder8215 db368d4
Perform all memory allocations necessary for do_exec before forking; …
asder8215 f8894f5
Pre-allocate a buffer with the maximum path length that we'll have fr…
asder8215 09f496d
Search for PATH environment variable from maybe_envp/environ() once, …
asder8215 fc53d39
Account for paths with separator byte at the end and added further do…
asder8215 32aa0fd
Update documentation on confstr to refer to Issue 8 instead of Issue …
asder8215 45e2ed2
Refactor exec code from do_exec into an internal execvpe function
asder8215 4359483
Use confstr(_CS_PATH) on linux with a gnu target env and _PATH_DEFPAT…
asder8215 07cf726
Refactor setting default_path field and shell_argv buffer population …
asder8215 c6475f9
Change confstr(...) function to return a CString instead of an OsStri…
asder8215 1a70ae0
Add default fallback path for AIX + shell path fallback on ENOEXEC ex…
asder8215 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Apologies for the repeat ping, previous message is label outdated due to new commits)
@joboet see my comment earlier #157144 (comment)
Unresolved question here is should we just directly use
":/bin:/usr/bin"for uclibc's execvp default fallback path? This is different from its_PATH_DEFPATHvalue which is"/usr/bin:/bin"View changes since the review
View changes since the review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@psumbera for Solaris, @xingxue-ibm for AIX: Do these platforms have constants like
_PATH_DEFPATHthat are used byexecvpwhen noPATHis available? Or is there a better way to emulateexecvpbehavior?Probably doing a libc release in 1-2 weeks, as a heads up if there's something to add there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AIX's
paths.hdefines_PATH_BSHELLbut not_PATH_DEFPATH. I opened PR rust-lang/libc#5676 to add_PATH_BSHELLto libc for AIX.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xingxue-ibm does AIX invoke the shell (e.g. if not i.e.
_PATH_BSHELL) onENOEXECin theirexecvpimplementation? (something similar to what glibc does here) Follow up question I have is doesposix_spawn(or equivalent name) forward toexecvpe? If it does, I would like to put up a FIXME comment in those areas.(To note for reviewers, if
_PATH_BSHELLor some equivalent path is used inENOEXECbehavior or if_PATH_DEFPATHis used, we can put up a different/future PR to add these behaviors in since the code is written in a way that you can easily insert the correct behavior inCommand::get_shell_argvorget_default_path)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked the current Solaris ON libc sources.
Solaris defines
_PATH_BSHELLin<paths.h>as"/usr/bin/sh", but it does not define_PATH_DEFPATH.When
PATHis unset, Solarisexecvpdoes not use a fixed fallback constant. Itsget_PATH()helper callsconfstr(_CS_PATH)and then:":/usr/sbin"when either the real or effective UID is 0;":", causing the current directory to be searched last.Therefore, the closest emulation is to obtain
_CS_PATHbefore the fork and implement the UID-dependent suffix, rather than hard-coding a_PATH_DEFPATH. The suffix should be selected after any requested credential change has been applied.Solaris does handle
ENOEXECby invoking a shell. The executable is_PATH_BSHELL(/usr/bin/sh) normally, or/usr/xpg4/bin/shfor an XPG4-mode caller; itsargv[0]is"sh".posix_spawnp()uses the same path and shell helpers.For
rust-lang/libc, it would be useful to add both Solaris_PATH_BSHELLand_CS_PATH(65). One caveat: the existing Rust Solarisconfstrbinding links to__confstr_xpg7, whereas Solarisexecvpuses the mode-sensitive baseconfstr. Thus simply adding Solaris to the existinglibc::confstrbranch would select the XPG7 path and would not exactly reproduce currentexecvpbehavior.Oracle's documentation also confirms that the
ENOEXECshell depends on the caller's conformance mode:execvp(2)andstandards(7).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have access to the AIX system source code, but I checked on AIX 7.2 by running tests and disassembling some routines. Here are my findings:
•
ENOEXEC:execvpandexecvperunexecv("/usr/bin/sh", {"sh", "--", <script>, <args...>}). The shell path is the literal/usr/bin/sh, not_PATH_BSHELL, which AIX defines as/usr/bin/bshin/usr/include/paths.h.• No
PATH: The fallback is:/bin:/usr/bin, with the current directory searched first (the same string you found foruClibc). AIX'spaths.hhas no_PATH_DEFPATH.•
posix_spawnp: It forwards toexecvpe. It forks, and the child callsexecvpe(orexecvpifenvpisNULL).A FIXME in both places works for me, with the AIX handling in a follow-up PR.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xingxue-ibm Got you and thank you for testing
execvp/posix_spawnpbehavior on AIX!If there's no reliance on
_PATH_BSHELL(as well as no existence of_PATH_DEFPATH) and AIX forwards posix_spawnp to execvpe, then I'll hardcode the values here (should be self explanatory since it would be cfg gated on AIX). Will update the PR in the morning once I get some rest.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I am not suggesting removing the existing
#[link_name = "__confstr_xpg7"]fromrust-lang/libc. That mapping fromlibc#4035is intentional and should remain.On Solaris, when C code is compiled with
_XOPEN_SOURCE=700,<unistd.h>redirects the source-level nameconfstrto the ELF symbol__confstr_xpg7. The libc test configuration uses_XOPEN_SOURCE=700, which is why the Rustlibc::confstrdeclaration needs thatlink_nameto represent the XPG7-facing API correctly.This is separate from what the already-compiled Solaris libc implementation of
execvpdoes internally. Its path is effectively:The base
confstrsymbol is itself mode-sensitive: it reads the process's__xpg4/__xpg6state and returns the corresponding path. Therefore, Rust does not need a new compile-time cfg analogous to a musl-version cfg, and it does not need to determine the XPG mode itself.To preserve the behavior of the old
execvpcall,stdcan keep the publiclibc::confstrbinding unchanged and declare a separate private Solaris-only binding with a different Rust name:That private function and
libc::confstrrefer to two different Solaris ELF symbols, so there is no conflict and no breaking change torust-lang/libc.The shell choice is a separate issue. For an ordinary Rust process, where
__xpg4remains at its default value of 0,_PATH_BSHELL(/usr/bin/sh) matchesexecvp. If exact behavior for a process explicitly linked into XPG mode is also required, the shell must likewise be selected from that process mode; globally replacing_PATH_BSHELLwith/usr/xpg4/bin/shwould instead break the default mode.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I think I understand how this would work, and thank you for taking the time to clarify this with me!
In regards to this:
I suppose here, would we do something similar as done for
confstrfor__xpg4? Like:From reading illumos' code, I'm assuming
__xpg4is also anint/i32on Solaris. Is__xpg4something I could retrieve on all the current Solaris targets that Rust supports?Or is there a better/correct approach than the above?
To kinda recap how I think it would work in my head, I would modify
library/std/src/sys/conf.rsto contain Solaris' mode-sensitiveconfstrand then expand + modify our currentconfstrfor apple/linux on gnu target envs to solaris (and illumos). I would maybe put the__xpg4extern value in this file as well.The
get_default_path()function inlibrary/std/src/sys/process/unix/common.rswould just expand theconfstrcalling branch to Solaris, and then inlast_execvpe_errorinlibrary/std/src/sys/process/unix/unix.rs, I would have a separate branch for Solaris that would check on__xpg4to determine whether we'd use_PATH_BSHELLor/usr/xpg4/bin/shfor the first argument in ourlibc::execvecall. Inget_shell_argv()since both Solaris and AIX put "sh" asargv[0], I'd just cfg gate it for both to set shell_argv[0] to "sh".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, for Solaris, reading
__xpg4is the correct way to reproduce the shell selection made byexecvp.I checked the current Solaris 11.4 ON sources.
__xpg4is anint, and it is exported bylibc.so.1in theSUNW_0.8symbol version with size 4 and theNODIRECTflag. The same libc mapfile is used for both currently supported Solaris targets,sparcv9-sun-solarisandx86_64-pc-solaris. The illumos ABI has the same definition in its libc mapfile.NODIRECTis important here: the normal definition in libc is 0, whilevalues-xpg4.o(andvalues-xpg6.o) can interpose a definition that enables the conforming mode for the whole process. Consequently, a privatestdbinding observes the same value as libc'sexecvp. I would uselibc::c_intrather than spelling the Rust representation asi32, for example:This can remain a private Solaris implementation detail in
std; I do not think it needs to be added to the publicrust-lang/libcAPI.There are a few details I would change in the proposed layout:
The mode-dependent shell is Solaris-specific. Current Solaris uses
_PATH_BSHELLwhen__xpg4 == 0and/usr/xpg4/bin/shotherwise. The illumosexecvpimplementation you linked, however, always uses_PATH_BSHELLforENOEXEC; it uses__xpg4only when constructing the fallbackPATH.The executable pathname and
argv[0]need to remain separate. On Solaris the call is conceptually:where
shell_pathis selected using__xpg4. The current code usesshell_argv[0]both as the pathname passed toexecveand asargv[0], so supporting Solaris/AIX's"sh"value requires carrying the shell pathname separately from the argument vector.For Solaris, calling the private base
confstris only the first part of the fallback path.execvpthen appends:/usr/sbinwhen either the real or effective UID is 0, and otherwise appends:so that the current directory is searched last. The UID test must reflect the credentials afterCommand::uidand anypre_execcallback have run. Since allocation is not allowed there, the root and non-root variants could be prepared beforeforkand selected afterwards.Illumos should not simply share the Solaris
confstr(_CS_PATH)branch. In the linked illumos implementation,confstr(_CS_PATH)returns the XPG path, whereasexecvpchooses among separate__xpg4/UID-dependent paths. Illumos therefore needs its own fallback-path handling if the goal is to preserve its nativeexecvpbehavior exactly.So the
__xpg4binding itself is fine for Solaris, but I would keep the Solaris and illumos path/shell cases separate rather than treating them as oneconfstrimplementation.