Skip to content

Commit

Permalink
Merge pull request #4590 from smitsohu/mountid
Browse files Browse the repository at this point in the history
Read mount id also on legacy kernels
  • Loading branch information
smitsohu committed Oct 6, 2021
2 parents 32fb5ed + a78d014 commit f02a218
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ typedef struct {

// mountinfo.c
MountData *get_last_mount(void);
int get_mount_id(const char *path);
int get_mount_id(int fd);
char **build_mount_array(const int mount_id, const char *path);

// fs_var.c
Expand Down
38 changes: 17 additions & 21 deletions src/firejail/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -633,34 +633,30 @@ static void fs_remount_simple(const char *path, OPERATION op) {
}

// remount recursively; requires a resolved path
static void fs_remount_rec(const char *dir, OPERATION op) {
static void fs_remount_rec(const char *path, OPERATION op) {
EUID_ASSERT();
assert(dir);
assert(op < OPERATION_MAX);
assert(path);

struct stat s;
if (stat(dir, &s) != 0)
return;
if (!S_ISDIR(s.st_mode)) {
// no need to search in /proc/self/mountinfo for submounts if not a directory
fs_remount_simple(dir, op);
// no need to search /proc/self/mountinfo for submounts if not a directory
int fd = open(path, O_PATH|O_DIRECTORY|O_|O_CLOEXEC);
if (fd < 0) {
fs_remount_simple(path, op);
return;
}
// get mount point of the directory
int mountid = get_mount_id(dir);
if (mountid == -1)
return;
if (mountid == -2) {
// falling back to a simple remount on old kernels
static int mount_warning = 0;
if (!mount_warning) {
fwarning("read-only, read-write and noexec options are not applied recursively\n");
mount_warning = 1;
}
fs_remount_simple(dir, op);

// get mount id of the directory
int mountid = get_mount_id(fd);
close(fd);
if (mountid < 0) {
// falling back to a simple remount
fwarning("%s %s not applied recursively\n", opstr[op], path);
fs_remount_simple(path, op);
return;
}

// build array with all mount points that need to get remounted
char **arr = build_mount_array(mountid, dir);
char **arr = build_mount_array(mountid, path);
assert(arr);
// remount
char **tmp = arr;
Expand Down
71 changes: 45 additions & 26 deletions src/firejail/mountinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include "firejail.h"
#include <errno.h>

#include <fcntl.h>
#ifndef O_PATH
Expand Down Expand Up @@ -151,53 +152,71 @@ MountData *get_last_mount(void) {
return &mdata;
}

// Extract the mount id from /proc/self/fdinfo and return it.
int get_mount_id(const char *path) {
// Returns mount id, or -1 if fd refers to a procfs or sysfs file
static int get_mount_id_from_handle(int fd) {
EUID_ASSERT();
assert(path);

int fd = open(path, O_PATH|O_CLOEXEC);
if (fd == -1)
return -1;
char *proc;
if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
errExit("asprintf");
struct file_handle *fh = malloc(sizeof *fh);
if (!fh)
errExit("malloc");
fh->handle_bytes = 0;

int rv = -1;
int tmp;
if (name_to_handle_at(-1, proc, fh, &tmp, AT_SYMLINK_FOLLOW) != -1) {
fprintf(stderr, "Error: unexpected result from name_to_handle_at\n");
exit(1);
}
if (errno == EOVERFLOW && fh->handle_bytes)
rv = tmp;

free(proc);
free(fh);
return rv;
}

// Returns mount id, or -1 on kernels < 3.15
static int get_mount_id_from_fdinfo(int fd) {
EUID_ASSERT();
int rv = -1;

char *fdinfo;
if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1)
char *proc;
if (asprintf(&proc, "/proc/self/fdinfo/%d", fd) == -1)
errExit("asprintf");
EUID_ROOT();
FILE *fp = fopen(fdinfo, "re");
FILE *fp = fopen(proc, "re");
EUID_USER();
free(fdinfo);
if (!fp)
goto errexit;

// read the file
char buf[MAX_BUF];
if (fgets(buf, MAX_BUF, fp) == NULL)
goto errexit;
do {
while (fgets(buf, MAX_BUF, fp)) {
if (strncmp(buf, "mnt_id:", 7) == 0) {
char *ptr = buf + 7;
while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
ptr++;
}
if (*ptr == '\0')
if (sscanf(buf + 7, "%d", &rv) != 1)
goto errexit;
fclose(fp);
close(fd);
return atoi(ptr);
break;
}
} while (fgets(buf, MAX_BUF, fp));
}

// fallback, kernels older than 3.15 don't expose the mount id in this place
free(proc);
fclose(fp);
close(fd);
return -2;
return rv;

errexit:
fprintf(stderr, "Error: cannot read proc file\n");
exit(1);
}

int get_mount_id(int fd) {
int rv = get_mount_id_from_fdinfo(fd);
if (rv < 0)
rv = get_mount_id_from_handle(fd);
return rv;
}

// Check /proc/self/mountinfo if path contains any mounts points.
// Returns an array that can be iterated over for recursive remounting.
char **build_mount_array(const int mount_id, const char *path) {
Expand Down

0 comments on commit f02a218

Please sign in to comment.