From: Lennart Poettering Date: Wed, 20 Aug 2025 09:39:41 +0000 (+0200) Subject: rm-rf: make sure we can safely remove dirs we have no access to via rm_rf_at() X-Git-Tag: v259-rc1~239^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=502f7a2b804370d32adb373e661831f583565075;p=thirdparty%2Fsystemd.git rm-rf: make sure we can safely remove dirs we have no access to via rm_rf_at() Previously, we'd first empty a dir, and then remove it. This works fine as long as we have access to a dir. But in some cases (like for example a foreign owned container tree) we might not have access to the dir, but are still able to remove it (because it is empty, and in a dir we own). Hence let's try that first. If it works, we do not need to enter the dir (and thus fail). --- diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index 1b3ecf07901..9d917e95971 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -449,12 +449,18 @@ int rm_rf_at(int dir_fd, const char *path, RemoveFlags flags) { if (FLAGS_SET(flags, REMOVE_MISSING_OK) && r == -ENOENT) return 0; - if (!IN_SET(r, -ENOTTY, -EINVAL, -ENOTDIR)) + if (!IN_SET(r, -ENOTTY, -EINVAL, -ENOTDIR, -EPERM, -EACCES)) return r; - /* Not btrfs or not a subvolume */ + /* Not btrfs or not a subvolume, or permissions are not available (but might if we go via unlinkat()) */ } + /* In the next step we'll try to open the directory in order to enumerate its contents. This might + * not work due to perms, but we might still be able to delete it, hence let's try that first. */ + if (FLAGS_SET(flags, REMOVE_ROOT | REMOVE_PHYSICAL)) + if (unlinkat(dir_fd, path, AT_REMOVEDIR) >= 0) + return 0; + fd = openat_harder(dir_fd, path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, flags, &old_mode); if (fd >= 0) { /* We have a dir */