mirror of
https://github.com/netblue30/firejail.git
synced 2026-05-21 06:45:29 -06:00
Merge pull request #4374 from smitsohu/euid
fs_home.c: run more code with euid of the user
This commit is contained in:
commit
99e533580b
6 changed files with 77 additions and 44 deletions
|
|
@ -508,7 +508,7 @@ void logargs(int argc, char **argv) ;
|
|||
void logerr(const char *msg);
|
||||
void set_nice(int inc);
|
||||
int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode);
|
||||
void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode);
|
||||
void copy_file_as_user(const char *srcname, const char *destname, mode_t mode);
|
||||
void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode);
|
||||
void touch_file_as_user(const char *fname, mode_t mode);
|
||||
int is_dir(const char *fname);
|
||||
|
|
|
|||
|
|
@ -34,12 +34,13 @@
|
|||
#define O_PATH 010000000
|
||||
#endif
|
||||
|
||||
static void skel(const char *homedir, uid_t u, gid_t g) {
|
||||
char *fname;
|
||||
static void skel(const char *homedir) {
|
||||
EUID_ASSERT();
|
||||
|
||||
// zsh
|
||||
if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) {
|
||||
// copy skel files
|
||||
char *fname;
|
||||
if (asprintf(&fname, "%s/.zshrc", homedir) == -1)
|
||||
errExit("asprintf");
|
||||
// don't copy it if we already have the file
|
||||
|
|
@ -50,7 +51,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
|
|||
exit(1);
|
||||
}
|
||||
if (access("/etc/skel/.zshrc", R_OK) == 0) {
|
||||
copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user
|
||||
copy_file_as_user("/etc/skel/.zshrc", fname, 0644); // regular user
|
||||
fs_logger("clone /etc/skel/.zshrc");
|
||||
fs_logger2("clone", fname);
|
||||
}
|
||||
|
|
@ -64,6 +65,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
|
|||
// csh
|
||||
else if (!arg_shell_none && strcmp(cfg.shell,"/bin/csh") == 0) {
|
||||
// copy skel files
|
||||
char *fname;
|
||||
if (asprintf(&fname, "%s/.cshrc", homedir) == -1)
|
||||
errExit("asprintf");
|
||||
// don't copy it if we already have the file
|
||||
|
|
@ -74,7 +76,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
|
|||
exit(1);
|
||||
}
|
||||
if (access("/etc/skel/.cshrc", R_OK) == 0) {
|
||||
copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user
|
||||
copy_file_as_user("/etc/skel/.cshrc", fname, 0644); // regular user
|
||||
fs_logger("clone /etc/skel/.cshrc");
|
||||
fs_logger2("clone", fname);
|
||||
}
|
||||
|
|
@ -88,6 +90,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
|
|||
// bash etc.
|
||||
else {
|
||||
// copy skel files
|
||||
char *fname;
|
||||
if (asprintf(&fname, "%s/.bashrc", homedir) == -1)
|
||||
errExit("asprintf");
|
||||
// don't copy it if we already have the file
|
||||
|
|
@ -98,7 +101,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
|
|||
exit(1);
|
||||
}
|
||||
if (access("/etc/skel/.bashrc", R_OK) == 0) {
|
||||
copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user
|
||||
copy_file_as_user("/etc/skel/.bashrc", fname, 0644); // regular user
|
||||
fs_logger("clone /etc/skel/.bashrc");
|
||||
fs_logger2("clone", fname);
|
||||
}
|
||||
|
|
@ -108,6 +111,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
|
|||
}
|
||||
|
||||
static int store_xauthority(void) {
|
||||
EUID_ASSERT();
|
||||
if (arg_x11_block)
|
||||
return 0;
|
||||
|
||||
|
|
@ -118,7 +122,7 @@ static int store_xauthority(void) {
|
|||
errExit("asprintf");
|
||||
|
||||
struct stat s;
|
||||
if (lstat_as_user(src, &s) == 0) {
|
||||
if (lstat(src, &s) == 0) {
|
||||
if (S_ISLNK(s.st_mode)) {
|
||||
fwarning("invalid .Xauthority file\n");
|
||||
free(src);
|
||||
|
|
@ -126,6 +130,7 @@ static int store_xauthority(void) {
|
|||
}
|
||||
|
||||
// create an empty file as root, and change ownership to user
|
||||
EUID_ROOT();
|
||||
FILE *fp = fopen(dest, "we");
|
||||
if (fp) {
|
||||
fprintf(fp, "\n");
|
||||
|
|
@ -134,10 +139,11 @@ static int store_xauthority(void) {
|
|||
}
|
||||
else
|
||||
errExit("fopen");
|
||||
EUID_USER();
|
||||
|
||||
copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user
|
||||
fs_logger2("clone", dest);
|
||||
copy_file_as_user(src, dest, 0600); // regular user
|
||||
selinux_relabel_path(dest, src);
|
||||
fs_logger2("clone", dest);
|
||||
free(src);
|
||||
return 1; // file copied
|
||||
}
|
||||
|
|
@ -147,6 +153,7 @@ static int store_xauthority(void) {
|
|||
}
|
||||
|
||||
static int store_asoundrc(void) {
|
||||
EUID_ASSERT();
|
||||
if (arg_nosound)
|
||||
return 0;
|
||||
|
||||
|
|
@ -157,11 +164,11 @@ static int store_asoundrc(void) {
|
|||
errExit("asprintf");
|
||||
|
||||
struct stat s;
|
||||
if (lstat_as_user(src, &s) == 0) {
|
||||
if (lstat(src, &s) == 0) {
|
||||
if (S_ISLNK(s.st_mode)) {
|
||||
// make sure the real path of the file is inside the home directory
|
||||
/* coverity[toctou] */
|
||||
char *rp = realpath_as_user(src);
|
||||
char *rp = realpath(src, NULL);
|
||||
if (!rp) {
|
||||
fprintf(stderr, "Error: Cannot access %s\n", src);
|
||||
exit(1);
|
||||
|
|
@ -174,6 +181,7 @@ static int store_asoundrc(void) {
|
|||
}
|
||||
|
||||
// create an empty file as root, and change ownership to user
|
||||
EUID_ROOT();
|
||||
FILE *fp = fopen(dest, "we");
|
||||
if (fp) {
|
||||
fprintf(fp, "\n");
|
||||
|
|
@ -182,10 +190,11 @@ static int store_asoundrc(void) {
|
|||
}
|
||||
else
|
||||
errExit("fopen");
|
||||
EUID_USER();
|
||||
|
||||
copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user
|
||||
selinux_relabel_path(dest, src);
|
||||
copy_file_as_user(src, dest, 0644); // regular user
|
||||
fs_logger2("clone", dest);
|
||||
selinux_relabel_path(dest, src);
|
||||
free(src);
|
||||
return 1; // file copied
|
||||
}
|
||||
|
|
@ -195,6 +204,7 @@ static int store_asoundrc(void) {
|
|||
}
|
||||
|
||||
static void copy_xauthority(void) {
|
||||
EUID_ASSERT();
|
||||
// copy XAUTHORITY_FILE in the new home directory
|
||||
char *src = RUN_XAUTHORITY_FILE ;
|
||||
char *dest;
|
||||
|
|
@ -207,16 +217,18 @@ static void copy_xauthority(void) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
|
||||
selinux_relabel_path(dest, src);
|
||||
copy_file_as_user(src, dest, S_IRUSR | S_IWUSR); // regular user
|
||||
fs_logger2("clone", dest);
|
||||
selinux_relabel_path(dest, dest);
|
||||
free(dest);
|
||||
|
||||
// delete the temporary file
|
||||
unlink(src);
|
||||
EUID_ROOT();
|
||||
unlink(src); // delete the temporary file
|
||||
EUID_USER();
|
||||
}
|
||||
|
||||
static void copy_asoundrc(void) {
|
||||
EUID_ASSERT();
|
||||
// copy ASOUNDRC_FILE in the new home directory
|
||||
char *src = RUN_ASOUNDRC_FILE ;
|
||||
char *dest;
|
||||
|
|
@ -229,13 +241,14 @@ static void copy_asoundrc(void) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
|
||||
selinux_relabel_path(dest, src);
|
||||
copy_file_as_user(src, dest, S_IRUSR | S_IWUSR); // regular user
|
||||
fs_logger2("clone", dest);
|
||||
selinux_relabel_path(dest, dest);
|
||||
free(dest);
|
||||
|
||||
// delete the temporary file
|
||||
unlink(src);
|
||||
EUID_ROOT();
|
||||
unlink(src); // delete the temporary file
|
||||
EUID_USER();
|
||||
}
|
||||
|
||||
// private mode (--private=homedir):
|
||||
|
|
@ -248,18 +261,18 @@ void fs_private_homedir(void) {
|
|||
char *private_homedir = cfg.home_private;
|
||||
assert(homedir);
|
||||
assert(private_homedir);
|
||||
EUID_ASSERT();
|
||||
|
||||
uid_t u = getuid();
|
||||
// gid_t g = getgid();
|
||||
|
||||
int xflag = store_xauthority();
|
||||
int aflag = store_asoundrc();
|
||||
|
||||
uid_t u = getuid();
|
||||
gid_t g = getgid();
|
||||
|
||||
// mount bind private_homedir on top of homedir
|
||||
if (arg_debug)
|
||||
printf("Mount-bind %s on top of %s\n", private_homedir, homedir);
|
||||
// get file descriptors for homedir and private_homedir, fails if there is any symlink
|
||||
EUID_USER();
|
||||
int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
|
||||
if (src == -1)
|
||||
errExit("opening private directory");
|
||||
|
|
@ -287,6 +300,7 @@ void fs_private_homedir(void) {
|
|||
EUID_ROOT();
|
||||
if (bind_mount_by_fd(src, dst))
|
||||
errExit("mount bind");
|
||||
EUID_USER();
|
||||
|
||||
// check /proc/self/mountinfo to confirm the mount is ok
|
||||
MountData *mptr = get_last_mount();
|
||||
|
|
@ -305,6 +319,7 @@ void fs_private_homedir(void) {
|
|||
// if (chmod(homedir, s.st_mode) == -1)
|
||||
// errExit("mount-bind chmod");
|
||||
|
||||
EUID_ROOT();
|
||||
if (u != 0) {
|
||||
// mask /root
|
||||
if (arg_debug)
|
||||
|
|
@ -323,8 +338,9 @@ void fs_private_homedir(void) {
|
|||
selinux_relabel_path("/home", "/home");
|
||||
fs_logger("tmpfs /home");
|
||||
}
|
||||
EUID_USER();
|
||||
|
||||
skel(homedir, u, g);
|
||||
skel(homedir);
|
||||
if (xflag)
|
||||
copy_xauthority();
|
||||
if (aflag)
|
||||
|
|
@ -339,12 +355,15 @@ void fs_private_homedir(void) {
|
|||
void fs_private(void) {
|
||||
char *homedir = cfg.homedir;
|
||||
assert(homedir);
|
||||
EUID_ASSERT();
|
||||
|
||||
uid_t u = getuid();
|
||||
gid_t g = getgid();
|
||||
|
||||
int xflag = store_xauthority();
|
||||
int aflag = store_asoundrc();
|
||||
|
||||
EUID_ROOT();
|
||||
// mask /root
|
||||
if (arg_debug)
|
||||
printf("Mounting a new /root directory\n");
|
||||
|
|
@ -387,8 +406,9 @@ void fs_private(void) {
|
|||
|
||||
selinux_relabel_path(homedir, homedir);
|
||||
}
|
||||
EUID_USER();
|
||||
|
||||
skel(homedir, u, g);
|
||||
skel(homedir);
|
||||
if (xflag)
|
||||
copy_xauthority();
|
||||
if (aflag)
|
||||
|
|
@ -530,26 +550,29 @@ static void duplicate(char *name) {
|
|||
// set skel files,
|
||||
// restore .Xauthority
|
||||
void fs_private_home_list(void) {
|
||||
timetrace_start();
|
||||
|
||||
char *homedir = cfg.homedir;
|
||||
char *private_list = cfg.home_private_keep;
|
||||
assert(homedir);
|
||||
assert(private_list);
|
||||
EUID_ASSERT();
|
||||
|
||||
int xflag = store_xauthority();
|
||||
int aflag = store_asoundrc();
|
||||
timetrace_start();
|
||||
|
||||
uid_t uid = getuid();
|
||||
gid_t gid = getgid();
|
||||
|
||||
int xflag = store_xauthority();
|
||||
int aflag = store_asoundrc();
|
||||
|
||||
// create /run/firejail/mnt/home directory
|
||||
EUID_ROOT();
|
||||
mkdir_attr(RUN_HOME_DIR, 0755, uid, gid);
|
||||
selinux_relabel_path(RUN_HOME_DIR, homedir);
|
||||
|
||||
fs_logger_print(); // save the current log
|
||||
EUID_USER();
|
||||
|
||||
// copy the list of files in the new home directory
|
||||
EUID_USER();
|
||||
if (arg_debug)
|
||||
printf("Copying files in the new home:\n");
|
||||
char *dlist = strdup(cfg.home_private_keep);
|
||||
|
|
@ -588,6 +611,7 @@ void fs_private_home_list(void) {
|
|||
if (bind_mount_path_to_fd(RUN_HOME_DIR, fd))
|
||||
errExit("mount bind");
|
||||
close(fd);
|
||||
EUID_USER();
|
||||
|
||||
// check /proc/self/mountinfo to confirm the mount is ok
|
||||
MountData *mptr = get_last_mount();
|
||||
|
|
@ -595,11 +619,7 @@ void fs_private_home_list(void) {
|
|||
errLogExit("invalid private-home mount");
|
||||
fs_logger2("tmpfs", homedir);
|
||||
|
||||
// mask RUN_HOME_DIR, it is writable and not noexec
|
||||
if (mount("tmpfs", RUN_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
|
||||
errExit("mounting tmpfs");
|
||||
fs_logger2("tmpfs", RUN_HOME_DIR);
|
||||
|
||||
EUID_ROOT();
|
||||
if (uid != 0) {
|
||||
// mask /root
|
||||
if (arg_debug)
|
||||
|
|
@ -619,7 +639,12 @@ void fs_private_home_list(void) {
|
|||
fs_logger("tmpfs /home");
|
||||
}
|
||||
|
||||
skel(homedir, uid, gid);
|
||||
// mask RUN_HOME_DIR, it is writable and not noexec
|
||||
if (mount("tmpfs", RUN_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
|
||||
errExit("mounting tmpfs");
|
||||
EUID_USER();
|
||||
|
||||
skel(homedir);
|
||||
if (xflag)
|
||||
copy_xauthority();
|
||||
if (aflag)
|
||||
|
|
|
|||
|
|
@ -374,9 +374,12 @@ static void tmpfs_topdirs(const TopDir *topdirs) {
|
|||
}
|
||||
|
||||
// user home directory
|
||||
if (tmpfs_home)
|
||||
if (tmpfs_home) {
|
||||
// checks owner if outside /home
|
||||
EUID_USER();
|
||||
fs_private();
|
||||
EUID_ROOT();
|
||||
}
|
||||
|
||||
// /run/user/$UID directory
|
||||
if (tmpfs_runuser) {
|
||||
|
|
|
|||
|
|
@ -840,6 +840,7 @@ int sandbox(void* sandbox_arg) {
|
|||
// private mode
|
||||
//****************************
|
||||
if (arg_private) {
|
||||
EUID_USER();
|
||||
if (cfg.home_private) { // --private=
|
||||
if (cfg.chrootdir)
|
||||
fwarning("private=directory feature is disabled in chroot\n");
|
||||
|
|
@ -858,6 +859,7 @@ int sandbox(void* sandbox_arg) {
|
|||
}
|
||||
else // --private
|
||||
fs_private();
|
||||
EUID_ROOT();
|
||||
}
|
||||
|
||||
if (arg_private_dev)
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
|
|||
}
|
||||
|
||||
// return -1 if error, 0 if no error
|
||||
void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) {
|
||||
void copy_file_as_user(const char *srcname, const char *destname, mode_t mode) {
|
||||
pid_t child = fork();
|
||||
if (child < 0)
|
||||
errExit("fork");
|
||||
|
|
@ -378,8 +378,8 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid
|
|||
// drop privileges
|
||||
drop_privs(0);
|
||||
|
||||
// copy, set permissions and ownership
|
||||
int rv = copy_file(srcname, destname, uid, gid, mode); // already a regular user
|
||||
// copy, set permissions
|
||||
int rv = copy_file(srcname, destname, -1, -1, mode); // already a regular user
|
||||
if (rv)
|
||||
fwarning("cannot copy %s\n", srcname);
|
||||
#ifdef HAVE_GCOV
|
||||
|
|
@ -1231,6 +1231,7 @@ unsigned extract_timeout(const char *str) {
|
|||
}
|
||||
|
||||
void disable_file_or_dir(const char *fname) {
|
||||
assert(geteuid() == 0);
|
||||
assert(fname);
|
||||
|
||||
EUID_USER();
|
||||
|
|
|
|||
|
|
@ -1290,9 +1290,11 @@ void x11_xorg(void) {
|
|||
if (envar) {
|
||||
char *rp = realpath(envar, NULL);
|
||||
if (rp) {
|
||||
if (strcmp(rp, dest) != 0)
|
||||
// disable_file_or_dir returns with EUID 0
|
||||
if (strcmp(rp, dest) != 0) {
|
||||
EUID_ROOT();
|
||||
disable_file_or_dir(rp);
|
||||
EUID_USER();
|
||||
}
|
||||
free(rp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue