* src/install.c (initial_umask): New variable.
(strip): Set the umask to initial_umask before invoking 'strip' and then
reset it to zero after the child is created.
(main): Save the initial umask when setting it to zero.
* tests/install/strip-program.sh: Add a few invocations to test the
behavior.
* NEWS: Mention the bug fix.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-39LQ2UOD.
---
NEWS | 4 ++++
src/install.c | 14 +++++++++++++-
tests/install/strip-program.sh | 11 +++++++++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index 64f6b0bfc..a20815642 100644
--- a/NEWS
+++ b/NEWS
@@ -67,6 +67,10 @@ GNU coreutils NEWS -*-
outline -*-
after a tab character are accounted for correctly.
[bugs introduced in coreutils-9.8]
+ 'install --strip' sets the umask to the initial umask specified by the user
+ before invoking 'strip' instead of using a umask of zero.
+ [This bug was present in "the beginning".]
+
'ls' no longer omits ACL indicators or capability coloring for subsequent
files on the same file system after an unsupported security context
lookup on a file without an ACL.
diff --git a/src/install.c b/src/install.c
index 1eae1a5ff..ffe2aee27 100644
--- a/src/install.c
+++ b/src/install.c
@@ -102,6 +102,9 @@ static bool dir_arg;
/* Program used to strip binaries, "strip" is default */
static char const *strip_program = "strip";
+/* The umask specified the user before we set it to zero. */
+static mode_t initial_umask;
+
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
@@ -509,11 +512,20 @@ strip (char const *name)
safe_name = concat_name = file_name_concat (".", name, NULL);
char const *const argv[] = { strip_program, safe_name, NULL };
+ /* Reset the umask to the one specified by the user, since some
+ 'strip' implementations create files that can be read and/or
+ written to by other users. */
+ umask (initial_umask);
+
/* Run 'strip'. */
pid_t pid;
int result = posix_spawnp (&pid, strip_program, NULL, attrp,
(char * const *) argv, environ);
+ /* Restore the umask to zero now that the child process has
+ inherited the initial umask. */
+ umask (0);
+
bool ok = false;
if (result != 0)
{
@@ -863,7 +875,7 @@ main (int argc, char **argv)
cp_option_init (&x);
- umask (0);
+ initial_umask = umask (0);
int optc;
while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options,
diff --git a/tests/install/strip-program.sh b/tests/install/strip-program.sh
index 08e6abb9b..e25c8399c 100755
--- a/tests/install/strip-program.sh
+++ b/tests/install/strip-program.sh
@@ -32,6 +32,17 @@ echo aBc > exp || framework_failure_
ginstall src dest -s --strip-program=./b || fail=1
compare exp dest || fail=1
+cat <<EOF >getumask || framework_failure_
+#!$SHELL
+umask > \$1
+EOF
+chmod a+x getumask || framework_failure_
+
+for u in 2 4 7 22 44 77; do
+ (umask $u && ginstall src dest -s --strip-program=./getumask) || fail=1
+ test "$(sed 's/^0*//' dest)" = $u || fail=1
+done
+
# Check that install cleans up properly if strip fails.
returns_ 1 ginstall src dest2 -s --strip-program=./FOO || fail=1
test -e dest2 && fail=1
--
2.56.0