@@ -7400,3 +7400,98 @@ fn test_cp_recurse_verbose_output_with_symlink_already_exists() {
74007400 . no_stderr ( )
74017401 . stdout_is ( output) ;
74027402}
7403+
7404+ #[ test]
7405+ #[ cfg( unix) ]
7406+ fn test_cp_strip_uid_gid_preserve_ownership_fails ( ) {
7407+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
7408+ let at = & scene. fixtures ;
7409+ let ucmd = & mut scene. ucmd ( ) ;
7410+
7411+ let src = "src" ;
7412+ let dest_dir = "dir" ;
7413+ let dest = "dir/dest" ;
7414+
7415+ // Test must be run as root (or with `sudo -E`)
7416+ if scene. cmd ( "whoami" ) . run ( ) . stdout_str ( ) != "root\n " {
7417+ return ;
7418+ }
7419+
7420+ at. touch ( src) ;
7421+ at. set_mode ( src, 0o6755 ) ;
7422+
7423+ at. mkdir ( dest_dir) ;
7424+ at. set_mode ( dest_dir, 0o777 ) ;
7425+
7426+ // Need to drop privileges for preserving ownership to fail
7427+ unsafe {
7428+ libc:: seteuid ( 1000 ) ;
7429+ }
7430+
7431+ ucmd. arg ( "-p" ) . arg ( src) . arg ( dest) . succeeds ( ) ;
7432+
7433+ // When preserving ownership fails, setuid and setgid bits should be stripped
7434+ let dest_metadata = at. metadata ( & dest) ;
7435+ assert_eq ! (
7436+ dest_metadata. mode( ) & 0o6755 ,
7437+ 0o755 ,
7438+ "setuid or setgid not stripped"
7439+ ) ;
7440+ }
7441+
7442+ #[ test]
7443+ #[ cfg( unix) ]
7444+ fn test_cp_strip_uid_gid_preserve_group_fails ( ) {
7445+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
7446+ let at = & scene. fixtures ;
7447+ let ucmd = & mut scene. ucmd ( ) ;
7448+
7449+ let dir = "dir" ;
7450+ let src = "dir/src" ;
7451+ let dest = "dir/dest" ;
7452+
7453+ // Test must be run as root (or with `sudo -E`)
7454+ if scene. cmd ( "whoami" ) . run ( ) . stdout_str ( ) != "root\n " {
7455+ return ;
7456+ }
7457+
7458+ at. mkdir ( dir) ;
7459+ at. set_mode ( dir, 0o777 ) ;
7460+
7461+ // Drop privileges before creating file
7462+ // Will need root to set group later
7463+ let orig_euid = unsafe { libc:: geteuid ( ) } ;
7464+ let orig_egid = unsafe { libc:: getegid ( ) } ;
7465+
7466+ unsafe {
7467+ libc:: seteuid ( 1000 ) ;
7468+ libc:: setegid ( 1000 ) ;
7469+ }
7470+
7471+ at. touch ( src) ;
7472+ at. set_mode ( src, 0o6755 ) ;
7473+
7474+ // Escalate privileges to set group
7475+ unsafe {
7476+ libc:: seteuid ( orig_euid) ;
7477+ libc:: setegid ( orig_egid) ;
7478+ }
7479+
7480+ scene. cmd ( "chgrp" ) . arg ( "0" ) . arg ( src) . succeeds ( ) ;
7481+
7482+ // Drop again before running cp
7483+ unsafe {
7484+ libc:: seteuid ( 1000 ) ;
7485+ libc:: setegid ( 1000 ) ;
7486+ }
7487+
7488+ ucmd. arg ( "-p" ) . arg ( src) . arg ( dest) . succeeds ( ) ;
7489+
7490+ // When preserving group fails, setuid and setgid bits should be stripped
7491+ let dest_metadata = at. metadata ( & dest) ;
7492+ assert_eq ! (
7493+ dest_metadata. mode( ) & 0o6755 ,
7494+ 0o755 ,
7495+ "setuid or setgid not stripped"
7496+ ) ;
7497+ }
0 commit comments