mirror of
https://github.com/clearlinux/systemd-stable.git
synced 2026-09-07 06:03:51 +00:00
machined: use the FS_IMMUTABLE_FL file flag, if available, to implement a "read-only" concept for raw disk images, too
This commit is contained in:
@@ -120,6 +120,8 @@ static int image_make(
|
||||
(faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
unsigned file_attr = 0;
|
||||
|
||||
if (!ret)
|
||||
return 1;
|
||||
@@ -127,15 +129,14 @@ static int image_make(
|
||||
if (!pretty)
|
||||
pretty = filename;
|
||||
|
||||
fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
/* btrfs subvolumes have inode 256 */
|
||||
if (st.st_ino == 256) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
struct statfs sfs;
|
||||
|
||||
fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (fstatfs(fd, &sfs) < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -173,13 +174,17 @@ static int image_make(
|
||||
}
|
||||
}
|
||||
|
||||
/* It's just a normal directory. */
|
||||
/* If the IMMUTABLE bit is set, we consider the
|
||||
* directory read-only. Since the ioctl is not
|
||||
* supported everywhere we ignore failures. */
|
||||
(void) read_attr_fd(fd, &file_attr);
|
||||
|
||||
/* It's just a normal directory. */
|
||||
r = image_new(IMAGE_DIRECTORY,
|
||||
pretty,
|
||||
path,
|
||||
filename,
|
||||
read_only,
|
||||
read_only || (file_attr & FS_IMMUTABLE_FL),
|
||||
0,
|
||||
0,
|
||||
ret);
|
||||
@@ -347,6 +352,11 @@ int image_remove(Image *i) {
|
||||
return btrfs_subvol_remove(i->path);
|
||||
|
||||
case IMAGE_DIRECTORY:
|
||||
/* Allow deletion of read-only directories */
|
||||
(void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
|
||||
|
||||
/* fall through */
|
||||
|
||||
case IMAGE_GPT:
|
||||
return rm_rf_dangerous(i->path, false, true, false);
|
||||
|
||||
@@ -357,6 +367,7 @@ int image_remove(Image *i) {
|
||||
|
||||
int image_rename(Image *i, const char *new_name) {
|
||||
_cleanup_free_ char *new_path = NULL, *nn = NULL;
|
||||
unsigned file_attr = 0;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
@@ -376,8 +387,16 @@ int image_rename(Image *i, const char *new_name) {
|
||||
|
||||
switch (i->type) {
|
||||
|
||||
case IMAGE_SUBVOLUME:
|
||||
case IMAGE_DIRECTORY:
|
||||
/* Turn of the immutable bit while we rename the image, so that we can rename it */
|
||||
(void) read_attr_path(i->path, &file_attr);
|
||||
|
||||
if (file_attr & FS_IMMUTABLE_FL)
|
||||
(void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
|
||||
|
||||
/* fall through */
|
||||
|
||||
case IMAGE_SUBVOLUME:
|
||||
new_path = file_in_same_dir(i->path, new_name);
|
||||
break;
|
||||
|
||||
@@ -403,6 +422,10 @@ int image_rename(Image *i, const char *new_name) {
|
||||
if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, RENAME_NOREPLACE) < 0)
|
||||
return -errno;
|
||||
|
||||
/* Restore the immutable bit, if it was set before */
|
||||
if (file_attr & FS_IMMUTABLE_FL)
|
||||
(void) chattr_path(new_path, true, FS_IMMUTABLE_FL);
|
||||
|
||||
free(i->path);
|
||||
i->path = new_path;
|
||||
new_path = NULL;
|
||||
@@ -468,6 +491,22 @@ int image_read_only(Image *i, bool b) {
|
||||
r = btrfs_subvol_set_read_only(i->path, b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case IMAGE_DIRECTORY:
|
||||
/* For simple directory trees we cannot use the access
|
||||
mode of the top-level directory, since it has an
|
||||
effect on the container itself. However, we can
|
||||
use the "immutable" flag, to at least make the
|
||||
top-level directory read-only. It's not as good as
|
||||
a read-only subvolume, but at least something, and
|
||||
we can read the value back.*/
|
||||
|
||||
r = chattr_path(i->path, b, FS_IMMUTABLE_FL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case IMAGE_GPT: {
|
||||
@@ -487,7 +526,6 @@ int image_read_only(Image *i, bool b) {
|
||||
break;
|
||||
}
|
||||
|
||||
case IMAGE_DIRECTORY:
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
+23
-1
@@ -7791,9 +7791,31 @@ int chattr_path(const char *p, bool b, unsigned mask) {
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return chattr_fd(fd, b, mask);
|
||||
}
|
||||
|
||||
int read_attr_fd(int fd, unsigned *ret) {
|
||||
assert(fd >= 0);
|
||||
|
||||
if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_attr_path(const char *p, unsigned *ret) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return read_attr_fd(fd, ret);
|
||||
}
|
||||
|
||||
@@ -1077,4 +1077,7 @@ int same_fd(int a, int b);
|
||||
int chattr_fd(int fd, bool b, unsigned mask);
|
||||
int chattr_path(const char *p, bool b, unsigned mask);
|
||||
|
||||
int read_attr_fd(int fd, unsigned *ret);
|
||||
int read_attr_path(const char *p, unsigned *ret);
|
||||
|
||||
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
|
||||
|
||||
Reference in New Issue
Block a user