Skip to content

cp -r creates directories with the source's mode, ignoring the umask #14549

Description

@sylvestre

cp -r gives every directory it creates the source's mode bits unmasked, where GNU applies the umask. Regular files in the same copy are masked correctly, so files and directories disagree and the directory branch wins.

$ mkdir -p src/dir && echo x > src/dir/f && chmod 777 src/dir && chmod 666 src/dir/f
$ (umask 077; cp -r src d)
$ stat -c '%a %n' d/dir d/dir/f
d/dir d/dir/f
uutils 0.11.0 / main 777 600
GNU 9.11 700 600

Under umask 022 uutils gives 777 where GNU gives 755. --no-preserve=mode gives 700, matching GNU, and -a gives 777 on both, which is correct because -a preserves.

Cause

copy_dir creates each directory through build_dir, which does apply the umask, and records it in dirs_needing_permissions (copydir.rs:520) for a final pass (copydir.rs:574). That pass calls copy_attributes, which promotes any freshly created directory to Preserve::Yes even when the attribute set is Attributes::NONE:

// cp.rs:1868
let mode = if !mode_explicitly_disabled && dest_is_freshly_created_dir {

and the preserving path then writes the source's unmasked mode at cp.rs:1943, overwriting what build_dir chose. Regular files take the other path and apply the umask explicitly.

Suggested fix

In that branch, when attributes.mode is Preserve::No, apply source_mode & !umask - the computation the file path already uses - instead of promoting to Preserve::Yes. The promotion presumably exists so a created directory ends up with the source's mode rather than build_dir's temporary one; masking keeps that and drops the widening.

Affected: 0.11.0 and main. Reported privately by Hongkai Chen (SEFCOM Lab, Arizona State University); handled as a normal bug rather than an advisory.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions