Merge pull request #4374 from smitsohu/euid

fs_home.c: run more code with euid of the user
This commit is contained in:
smitsohu 2021-06-26 16:34:49 +02:00 committed by GitHub
commit 99e533580b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 44 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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) {

View file

@ -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)

View file

@ -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();

View file

@ -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);
}
}