Skip to content

Commit

Permalink
Only mark regular files and /lost+found immutable
Browse files Browse the repository at this point in the history
Marking other directories as immutable is too risky.
  • Loading branch information
DemiMarie committed Jan 11, 2022
1 parent a9c159e commit 3825161
Showing 1 changed file with 27 additions and 25 deletions.
52 changes: 27 additions & 25 deletions genfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
#include <ext2fs.h>
#include <com_err.h>

static int real_main(const char *filesystem, const char *uname);
static int real_main(const char *filesystem, const char *uname,
bool mark_immutable);

static void process_dirent(ext2_filsys const fs,
const char *const path,
ext2_ino_t const inode,
int const name_len,
const char *const name,
const char *const selinux_label,
bool immutable);
bool force_mutable);

static int dir_iterate_callback(ext2_ino_t dir __attribute__((unused)),
int entry __attribute__((unused)),
Expand Down Expand Up @@ -68,14 +69,14 @@ static errcode_t qubes_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
return ext2fs_read_inode_full(fs, ino, ext2fs_inode(inode), sizeof *inode);
}

static bool mark_immutable;
static const char *const label_modules_object = "system_u:object_r:modules_object_t:s0";
static const char *const label_modules_dep = "system_u:object_r:modules_dep_t:s0";
static const char *const label_usr = "system_u:object_r:usr_t:s0";
static const char *const label_lib = "system_u:object_r:lib_t:s0";

int main(int argc, char **argv) {
initialize_ext2_error_table();
bool mark_immutable = false;
if (argc == 4) {
if (!strcmp("immutable=yes", argv[3]))
mark_immutable = true;
Expand All @@ -84,7 +85,7 @@ int main(int argc, char **argv) {
} else if (argc != 2)
errx(1, "Usage: genfs FILESYSTEM [UNAME immutable=[yes|no]]");
const char *const filesystem = argv[1], *const uname = argv[2];
return real_main(filesystem, uname);
return real_main(filesystem, uname, mark_immutable);
}

struct qubes_genfs_data {
Expand All @@ -111,10 +112,8 @@ static int root_iterate_callback(ext2_ino_t dir __attribute__((unused)),
int const name_len = ext2fs_dirent_name_len(dirent);
errcode_t err;
const char *label = label_modules_object;
bool mark_this_node_immutable = mark_immutable;
assert(name_len >= 0);
if ((name_len == 1 && dirent->name[0] == '.') ||
(name_len == 2 && dirent->name[0] == '.' && dirent->name[1] == '.')) {
if (name_len <= 2 && !memcmp(dirent->name, "..", name_len)) {
return 0;
} else if (memchr(dirent->name, '\0', (size_t)name_len)) {
errx(1, "Inode %" PRIx64 " has a NUL in its name", (uint64_t)dirent->inode);
Expand All @@ -129,15 +128,14 @@ static int root_iterate_callback(ext2_ino_t dir __attribute__((unused)),
} else if (!strncmp(dirent->name, data->uname_or_label, (size_t)name_len)) {
if ((err = ext2fs_dir_iterate2(data->fs, dirent->inode, 0, NULL, dir_iterate_callback, data)))
genfs_err(err, "processing %s", data->uname_or_label);
mark_this_node_immutable = false;
} else if (strncmp(dirent->name, "vmlinuz", (size_t)name_len) &&
strncmp(dirent->name, "lost+found", (size_t)name_len) &&
strncmp(dirent->name, "initramfs", (size_t)name_len)) {
errx(1, "Unexpected inode %.*s found in root of file system", name_len, dirent->name);
}

process_dirent(data->fs, "", dirent->inode, name_len, dirent->name,
label, mark_this_node_immutable);
process_dirent(data->fs, "", dirent->inode, name_len, dirent->name, label,
false);
return 0;
}

Expand All @@ -155,7 +153,7 @@ static int dir_iterate_callback(ext2_ino_t dir __attribute__((unused)),
if (ext2fs_dirent_file_type(dirent) != EXT2_FT_DIR)
errx(1, "File %s/%.*s is not a directory", data->uname_or_label, name_len, dirent->name);
process_dirent(data->fs, data->uname_or_label, dirent->inode, name_len, dirent->name,
label_usr, false);
label_usr, true);
struct qubes_genfs_data relabel_data = {
.fs = data->fs,
.uname_or_label = label_usr,
Expand All @@ -169,7 +167,7 @@ static int dir_iterate_callback(ext2_ino_t dir __attribute__((unused)),
errx(1, "File %s/%.*s is not a regular file", data->uname_or_label, name_len,
dirent->name);
process_dirent(data->fs, data->uname_or_label, dirent->inode, name_len, dirent->name,
label_modules_dep, false);
label_modules_dep, true);
}
return 0;
}
Expand All @@ -188,7 +186,7 @@ static int recursive_relabel(ext2_ino_t dir __attribute__((unused)),
if (name_len <= 2 && !memcmp(dirent->name, "..", name_len))
return 0;
process_dirent(data->fs, "", dirent->inode, name_len, dirent->name,
data->uname_or_label, mark_immutable);
data->uname_or_label, false);
errcode_t err;
if (ext2fs_dirent_file_type(dirent) == EXT2_FT_DIR &&
(err = ext2fs_dir_iterate2(data->fs, dirent->inode, 0, NULL,
Expand All @@ -203,18 +201,14 @@ static void process_dirent(ext2_filsys const fs,
int const name_len,
const char *const name,
const char *const selinux_label,
bool immutable) {
bool force_mutable) {
errcode_t err;
struct ext2_inode_large inode_contents;

if (selinux_label)
set_label(fs, path, inode, name_len, name, selinux_label);
set_label(fs, path, inode, name_len, name, selinux_label);
if ((err = qubes_read_inode_full(fs, inode, &inode_contents)))
genfs_err_inode(err, "reading inode", path, inode, name_len, name);
if (immutable &&
(LINUX_S_ISDIR(inode_contents.i_mode) || LINUX_S_ISREG(inode_contents.i_mode)))
inode_contents.i_flags |= EXT2_IMMUTABLE_FL;
else
if (force_mutable)
inode_contents.i_flags &= ~EXT2_IMMUTABLE_FL;
if ((err = qubes_write_inode_full(fs, inode, &inode_contents)))
genfs_err_inode(err, "writing inode", path, inode, name_len, name);
Expand Down Expand Up @@ -243,7 +237,8 @@ static void set_label(ext2_filsys const fs,
genfs_err_inode(err, "closing xattrs", path, inode, name_len, name);
}

static int real_main(const char *const filesystem, const char *const uname) {
static int real_main(const char *const filesystem, const char *const uname,
const bool mark_immutable) {
ext2_filsys fs = NULL;
errcode_t err;
const char *ptr = getenv("SOURCE_DATE_EPOCH");
Expand Down Expand Up @@ -317,6 +312,10 @@ static int real_main(const char *const filesystem, const char *const uname) {
if (!LINUX_S_ISLNK(inode.i_mode) && (inode.i_mode & (LINUX_S_IWGRP|LINUX_S_IWOTH)))
errx(1, "Inode %" PRIu32 " is not a symlink and is group- or "
"world- writable (mode 0%04o)", ino, (int)perms);

// /lost+found needs special handling
const bool is_lpf_ino = ino == fs->super->s_lpf_ino;

// Ensure all files have at least mode 0644 (read and write
// to owner, read for others). Since everything in this
// directory is public anyway (published online) trying to
Expand All @@ -325,14 +324,18 @@ static int real_main(const char *const filesystem, const char *const uname) {
//
// Exception: the lost+found inode is 0700 because of POLA.
if (LINUX_S_ISDIR(inode.i_mode))
inode.i_mode = ((ino == fs->super->s_lpf_ino) ? 0700 : 0755) | (inode.i_mode & ~0777);
inode.i_mode = (is_lpf_ino ? 0700 : 0755) | (inode.i_mode & ~0777);
else if (LINUX_S_ISREG(inode.i_mode) || LINUX_S_ISLNK(inode.i_mode))
inode.i_mode |= 0644;
else
errx(1, "Inode %" PRIu32 " is neither a regular file, "
"directory, or symbolic link (mode 0%06o)", ino, (int)inode.i_mode);
if (mark_immutable && LINUX_S_ISREG(inode.i_mode))
// If mark_immutable is set, mark regular files and /lost+found immutable
if (mark_immutable &&
(LINUX_S_ISREG(inode.i_mode) || (is_lpf_ino && LINUX_S_ISDIR(inode.i_mode))))
inode.i_flags |= EXT2_IMMUTABLE_FL;
else
inode.i_flags &= ~EXT2_IMMUTABLE_FL;
set_label(fs, "", ino, 0, "", label_modules_object);
inode.osd1.linux1.l_i_version = inode.i_generation = 0;
inode.i_version_hi = inode.i_projid = 0;
Expand All @@ -344,8 +347,7 @@ static int real_main(const char *const filesystem, const char *const uname) {
.fs = fs,
.uname_or_label = uname,
};
process_dirent(fs, "", EXT2_ROOT_INO, 0, "",
label_modules_object, false);
process_dirent(fs, "", EXT2_ROOT_INO, 0, "", label_modules_object, true);
if ((err = ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL,
root_iterate_callback, &data)))
genfs_err(err, "processing /");
Expand Down

0 comments on commit 3825161

Please sign in to comment.