@@ -802,6 +802,50 @@ static void test_chmod_and_chown(void) {
802802 assert_se (S_ISLNK (st .st_mode ));
803803}
804804
805+ static void test_chmod_and_chown_unsafe (void ) {
806+ _cleanup_ (rm_rf_physical_and_freep ) char * d = NULL ;
807+ _unused_ _cleanup_umask_ mode_t u = umask (0000 );
808+ struct stat st ;
809+ const char * p ;
810+
811+ if (geteuid () != 0 )
812+ return ;
813+
814+ log_info ("/* %s */" , __func__ );
815+
816+ assert_se (mkdtemp_malloc (NULL , & d ) >= 0 );
817+
818+ p = strjoina (d , "/reg" );
819+ assert_se (mknod (p , S_IFREG | 0123 , 0 ) >= 0 );
820+
821+ assert_se (chmod_and_chown_unsafe (p , S_IFREG | 0321 , 1 , 2 ) >= 0 );
822+ assert_se (chmod_and_chown_unsafe (p , S_IFDIR | 0555 , 3 , 4 ) == - EINVAL );
823+
824+ assert_se (lstat (p , & st ) >= 0 );
825+ assert_se (S_ISREG (st .st_mode ));
826+ assert_se ((st .st_mode & 07777 ) == 0321 );
827+
828+ p = strjoina (d , "/dir" );
829+ assert_se (mkdir (p , 0123 ) >= 0 );
830+
831+ assert_se (chmod_and_chown_unsafe (p , S_IFDIR | 0321 , 1 , 2 ) >= 0 );
832+ assert_se (chmod_and_chown_unsafe (p , S_IFREG | 0555 , 3 , 4 ) == - EINVAL );
833+
834+ assert_se (lstat (p , & st ) >= 0 );
835+ assert_se (S_ISDIR (st .st_mode ));
836+ assert_se ((st .st_mode & 07777 ) == 0321 );
837+
838+ p = strjoina (d , "/lnk" );
839+ assert_se (symlink ("idontexist" , p ) >= 0 );
840+
841+ assert_se (chmod_and_chown_unsafe (p , S_IFLNK | 0321 , 1 , 2 ) >= 0 );
842+ assert_se (chmod_and_chown_unsafe (p , S_IFREG | 0555 , 3 , 4 ) == - EINVAL );
843+ assert_se (chmod_and_chown_unsafe (p , S_IFDIR | 0555 , 3 , 4 ) == - EINVAL );
844+
845+ assert_se (lstat (p , & st ) >= 0 );
846+ assert_se (S_ISLNK (st .st_mode ));
847+ }
848+
805849int main (int argc , char * argv []) {
806850 test_setup_logging (LOG_INFO );
807851
@@ -819,6 +863,7 @@ int main(int argc, char *argv[]) {
819863 test_fsync_directory_of_file ();
820864 test_rename_noreplace ();
821865 test_chmod_and_chown ();
866+ test_chmod_and_chown_unsafe ();
822867
823868 return 0 ;
824869}
0 commit comments