mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
cp: Fix issues with destination directory mode.
Ensure that we are able to enter the destination directory after we
create it, even if the current umask would normally prevent it, and
that it has the expected permissions once we are done, even if we had
to tweak them to be able to enter it.
Fixes: 82fc0d09e8
Sponsored by: Klara, Inc.
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D50266
This commit is contained in:
parent
be7839151c
commit
48578dcb6b
2 changed files with 52 additions and 4 deletions
33
bin/cp/cp.c
33
bin/cp/cp.c
|
|
@ -331,10 +331,18 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
|||
assert(to.dir < 0);
|
||||
assert(root_stat == NULL);
|
||||
mode = curr_stat->st_mode | S_IRWXU;
|
||||
/*
|
||||
* Will our umask prevent us from entering
|
||||
* the directory after we create it?
|
||||
*/
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask & ~S_IRWXU);
|
||||
if (mkdir(to.base, mode) != 0) {
|
||||
warn("%s", to.base);
|
||||
fts_set(ftsp, curr, FTS_SKIP);
|
||||
badcp = rval = 1;
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask);
|
||||
continue;
|
||||
}
|
||||
to.dir = open(to.base, O_DIRECTORY | O_SEARCH);
|
||||
|
|
@ -343,6 +351,8 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
|||
(void)rmdir(to.base);
|
||||
fts_set(ftsp, curr, FTS_SKIP);
|
||||
badcp = rval = 1;
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask);
|
||||
continue;
|
||||
}
|
||||
if (fstat(to.dir, &created_root_stat) != 0) {
|
||||
|
|
@ -352,9 +362,14 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
|||
fts_set(ftsp, curr, FTS_SKIP);
|
||||
to.dir = -1;
|
||||
badcp = rval = 1;
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask);
|
||||
continue;
|
||||
}
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask);
|
||||
root_stat = &created_root_stat;
|
||||
curr->fts_number = 1;
|
||||
} else {
|
||||
/* entering a directory; append its name to to.path */
|
||||
len = snprintf(to.end, END(to.path) - to.end, "%s%s",
|
||||
|
|
@ -432,9 +447,7 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
|||
} else if (curr->fts_number) {
|
||||
const char *path = *to.path ? to.path : dot;
|
||||
mode = curr_stat->st_mode;
|
||||
if (((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
|
||||
((mode | S_IRWXU) & mask) != (mode & mask)) &&
|
||||
fchmodat(to.dir, path, mode & mask, 0) != 0) {
|
||||
if (fchmodat(to.dir, path, mode & mask, 0) != 0) {
|
||||
warn("chmod: %s/%s", to.base, to.path);
|
||||
rval = 1;
|
||||
}
|
||||
|
|
@ -538,12 +551,22 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
|||
*/
|
||||
if (dne) {
|
||||
mode = curr_stat->st_mode | S_IRWXU;
|
||||
/*
|
||||
* Will our umask prevent us from entering
|
||||
* the directory after we create it?
|
||||
*/
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask & ~S_IRWXU);
|
||||
if (mkdirat(to.dir, to.path, mode) != 0) {
|
||||
warn("%s/%s", to.base, to.path);
|
||||
fts_set(ftsp, curr, FTS_SKIP);
|
||||
badcp = rval = 1;
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask);
|
||||
break;
|
||||
}
|
||||
if (~mask & S_IRWXU)
|
||||
umask(~mask);
|
||||
} else if (!S_ISDIR(to_stat.st_mode)) {
|
||||
warnc(ENOTDIR, "%s/%s", to.base, to.path);
|
||||
fts_set(ftsp, curr, FTS_SKIP);
|
||||
|
|
@ -554,8 +577,10 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
|||
* Arrange to correct directory attributes later
|
||||
* (in the post-order phase) if this is a new
|
||||
* directory, or if the -p flag is in effect.
|
||||
* Note that fts_number may already be set if this
|
||||
* is the newly created destination directory.
|
||||
*/
|
||||
curr->fts_number = pflag || dne;
|
||||
curr->fts_number |= pflag || dne;
|
||||
break;
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
|
|
|
|||
|
|
@ -557,6 +557,28 @@ to_link_outside_body()
|
|||
cp -r dir dst
|
||||
}
|
||||
|
||||
atf_test_case dstmode
|
||||
dstmode_body()
|
||||
{
|
||||
mkdir -m 0755 dir
|
||||
echo "foo" >dir/file
|
||||
umask 0177
|
||||
#atf_check cp -R dir dst
|
||||
#begin
|
||||
# atf-check stupidly refuses to work if the current umask is
|
||||
# weird, instead of just dealing with the situation
|
||||
cp -R dir dst >stdout 2>stderr
|
||||
rc=$?
|
||||
umask 022
|
||||
atf_check_equal 0 $rc
|
||||
atf_check cat stdout
|
||||
atf_check cat stderr
|
||||
#end
|
||||
atf_check -o inline:"40600\n" stat -f%p dst
|
||||
atf_check chmod 0750 dst
|
||||
atf_check cmp dir/file dst/file
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case basic
|
||||
|
|
@ -593,4 +615,5 @@ atf_init_test_cases()
|
|||
atf_add_test_case to_dirlink
|
||||
atf_add_test_case to_deaddirlink
|
||||
atf_add_test_case to_link_outside
|
||||
atf_add_test_case dstmode
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue