mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-27 18:55:09 +03:00
util: rm_rf() refuse cleaning non-memory file systems, as extra paranoia
This commit is contained in:
parent
825c6fe5eb
commit
f56d5db919
@ -3243,7 +3243,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
|
||||
int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
|
||||
DIR *d;
|
||||
int ret = 0;
|
||||
|
||||
@ -3335,14 +3335,43 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
|
||||
int fd;
|
||||
int r;
|
||||
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
|
||||
struct statfs s;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (fstatfs(fd, &s) < 0) {
|
||||
close_nointr_nofail(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* We refuse to clean disk file systems with this call. This
|
||||
* is extra paranoia just to be sure we never ever remove
|
||||
* non-state data */
|
||||
|
||||
if (s.f_type != TMPFS_MAGIC &&
|
||||
s.f_type != RAMFS_MAGIC) {
|
||||
log_error("Attempted to remove disk file system, and we can't allow that.");
|
||||
close_nointr_nofail(fd);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
|
||||
}
|
||||
|
||||
static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
|
||||
int fd, r;
|
||||
struct statfs s;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Be paranoid */
|
||||
assert(!streq(path, "/"));
|
||||
/* We refuse to clean the root file system with this
|
||||
* call. This is extra paranoia to never cause a really
|
||||
* seriously broken system. */
|
||||
if (path_equal(path, "/")) {
|
||||
log_error("Attempted to remove entire root file system, and we can't allow that.");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
|
||||
if (fd < 0) {
|
||||
@ -3350,6 +3379,17 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
|
||||
if (errno != ENOTDIR)
|
||||
return -errno;
|
||||
|
||||
if (!dangerous) {
|
||||
if (statfs(path, &s) < 0)
|
||||
return -errno;
|
||||
|
||||
if (s.f_type != TMPFS_MAGIC &&
|
||||
s.f_type != RAMFS_MAGIC) {
|
||||
log_error("Attempted to remove disk file system, and we can't allow that.");
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_root && !only_dirs)
|
||||
if (unlink(path) < 0 && errno != ENOENT)
|
||||
return -errno;
|
||||
@ -3357,8 +3397,21 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = rm_rf_children(fd, only_dirs, honour_sticky, NULL);
|
||||
if (!dangerous) {
|
||||
if (fstatfs(fd, &s) < 0) {
|
||||
close_nointr_nofail(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (s.f_type != TMPFS_MAGIC &&
|
||||
s.f_type != RAMFS_MAGIC) {
|
||||
log_error("Attempted to remove disk file system, and we can't allow that.");
|
||||
close_nointr_nofail(fd);
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL);
|
||||
if (delete_root) {
|
||||
|
||||
if (honour_sticky && file_is_priv_sticky(path) > 0)
|
||||
@ -3373,6 +3426,14 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
|
||||
return r;
|
||||
}
|
||||
|
||||
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
|
||||
return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false);
|
||||
}
|
||||
|
||||
int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
|
||||
return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true);
|
||||
}
|
||||
|
||||
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
assert(path);
|
||||
|
||||
|
@ -358,7 +358,9 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
|
||||
int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
|
||||
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
|
||||
int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
|
||||
|
||||
int pipe_eof(int fd);
|
||||
|
||||
|
@ -845,7 +845,7 @@ static int remove_item_instance(Item *i, const char *instance) {
|
||||
case RECURSIVE_REMOVE_PATH:
|
||||
/* FIXME: we probably should use dir_cleanup() here
|
||||
* instead of rm_rf() so that 'x' is honoured. */
|
||||
r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
|
||||
r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
|
||||
if (r < 0 && r != -ENOENT) {
|
||||
log_error("rm_rf(%s): %s", instance, strerror(-r));
|
||||
return r;
|
||||
|
Loading…
Reference in New Issue
Block a user