Merge branch 'mount-eperm'
* mount-eperm: mount: no exit on EPERM, continue without suid
This commit is contained in:
commit
3861c371f6
|
@ -40,6 +40,7 @@ mnt_context_enable_rwonly_mount
|
|||
mnt_context_enable_sloppy
|
||||
mnt_context_enable_verbose
|
||||
mnt_context_forced_rdonly
|
||||
mnt_context_force_unrestricted
|
||||
mnt_context_get_cache
|
||||
mnt_context_get_excode
|
||||
mnt_context_get_fs
|
||||
|
|
|
@ -426,6 +426,31 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
|
|||
return cxt->restricted;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnt_context_force_unrestricted:
|
||||
* @cxt: mount context
|
||||
*
|
||||
* This function is DANGEROURS as it disables all security policies in libmount.
|
||||
* Don't use if not sure. It removes "restricted" flag from the context, so
|
||||
* libmount will use the current context as for root user.
|
||||
*
|
||||
* This function is designed for case you have no any suid permissions, so you
|
||||
* can depend on kernel.
|
||||
*
|
||||
* Returns: 0 on success, negative number in case of error.
|
||||
*
|
||||
* Since: 2.35
|
||||
*/
|
||||
int mnt_context_force_unrestricted(struct libmnt_context *cxt)
|
||||
{
|
||||
if (mnt_context_is_restricted(cxt)) {
|
||||
DBG(CXT, ul_debugobj(cxt, "force UNRESTRICTED"));
|
||||
cxt->restricted = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnt_context_set_optsmode
|
||||
* @cxt: mount context
|
||||
|
|
|
@ -705,6 +705,7 @@ extern void mnt_free_context(struct libmnt_context *cxt);
|
|||
extern int mnt_reset_context(struct libmnt_context *cxt);
|
||||
extern int mnt_context_is_restricted(struct libmnt_context *cxt)
|
||||
__ul_attribute__((nonnull));
|
||||
extern int mnt_context_force_unrestricted(struct libmnt_context *cxt);
|
||||
|
||||
extern int mnt_context_init_helper(struct libmnt_context *cxt,
|
||||
int action, int flags);
|
||||
|
|
|
@ -352,6 +352,7 @@ MOUNT_2.34 {
|
|||
} MOUNT_2.33;
|
||||
|
||||
MOUNT_2_35 {
|
||||
mnt_context_force_unrestricted;
|
||||
mnt_context_get_target_prefix;
|
||||
mnt_context_set_target_prefix;
|
||||
} MOUNT_2.34;
|
||||
|
|
|
@ -315,6 +315,12 @@ program is executed. It's strongly recommended to use a valid mountpoint to
|
|||
specify filesystem, otherwise \fBmount\fR may fail. For example it's bad idea
|
||||
to use NFS or CIFS source on command line.
|
||||
.PP
|
||||
Since version 2.35 \fBmount\fR command does not exit when user permissions are
|
||||
inadequate by internal libmount security rules. It drops suid permissions
|
||||
and continue as regular non-root user. It allows to support use-cases where
|
||||
root permissions are not necessary (e.g. fuse filesystems, user namespaces,
|
||||
etc).
|
||||
.PP
|
||||
For more details, see
|
||||
.BR fstab (5).
|
||||
Only the user that mounted a filesystem can unmount it again.
|
||||
|
|
|
@ -47,23 +47,24 @@
|
|||
|
||||
static int mk_exit_code(struct libmnt_context *cxt, int rc);
|
||||
|
||||
static void __attribute__((__noreturn__)) exit_non_root(const char *option)
|
||||
static void suid_drop(struct libmnt_context *cxt)
|
||||
{
|
||||
const uid_t ruid = getuid();
|
||||
const uid_t euid = geteuid();
|
||||
|
||||
if (ruid == 0 && euid != 0) {
|
||||
/* user is root, but setuid to non-root */
|
||||
if (option)
|
||||
errx(MNT_EX_USAGE, _("only root can use \"--%s\" option "
|
||||
"(effective UID is %u)"),
|
||||
option, euid);
|
||||
errx(MNT_EX_USAGE, _("only root can do that "
|
||||
"(effective UID is %u)"), euid);
|
||||
if (ruid != 0 && euid == 0) {
|
||||
if (setgid(getgid()) < 0)
|
||||
err(MNT_EX_FAIL, _("setgid() failed"));
|
||||
|
||||
if (setuid(getuid()) < 0)
|
||||
err(MNT_EX_FAIL, _("setuid() failed"));
|
||||
}
|
||||
if (option)
|
||||
errx(MNT_EX_USAGE, _("only root can use \"--%s\" option"), option);
|
||||
errx(MNT_EX_USAGE, _("only root can do that"));
|
||||
|
||||
/* be paranoid and check it, setuid(0) has to fail */
|
||||
if (ruid != 0 && setuid(0) == 0)
|
||||
errx(MNT_EX_FAIL, _("drop permissions failed."));
|
||||
|
||||
mnt_context_force_unrestricted(cxt);
|
||||
}
|
||||
|
||||
static void __attribute__((__noreturn__)) mount_print_version(void)
|
||||
|
@ -672,7 +673,7 @@ int main(int argc, char **argv)
|
|||
!strchr("hlLUVvrist", c) &&
|
||||
c != MOUNT_OPT_TARGET &&
|
||||
c != MOUNT_OPT_SOURCE)
|
||||
exit_non_root(option_to_longopt(c, longopts));
|
||||
suid_drop(cxt);
|
||||
|
||||
err_exclusive_options(c, longopts, excl, excl_st);
|
||||
|
||||
|
@ -872,7 +873,7 @@ int main(int argc, char **argv)
|
|||
/* Non-root users are allowed to use -t to print_all(),
|
||||
but not to mount */
|
||||
if (mnt_context_is_restricted(cxt) && types)
|
||||
exit_non_root("types");
|
||||
suid_drop(cxt);
|
||||
|
||||
if (oper && (types || all || mnt_context_get_source(cxt))) {
|
||||
warnx(_("bad usage"));
|
||||
|
@ -905,7 +906,7 @@ int main(int argc, char **argv)
|
|||
if (mnt_context_is_restricted(cxt) &&
|
||||
mnt_context_get_source(cxt) &&
|
||||
mnt_context_get_target(cxt))
|
||||
exit_non_root(NULL);
|
||||
suid_drop(cxt);
|
||||
|
||||
} else if (argc == 1 && (!mnt_context_get_source(cxt) ||
|
||||
!mnt_context_get_target(cxt))) {
|
||||
|
@ -933,7 +934,7 @@ int main(int argc, char **argv)
|
|||
if (mnt_context_is_restricted(cxt) &&
|
||||
mnt_context_get_source(cxt) &&
|
||||
mnt_context_get_target(cxt))
|
||||
exit_non_root(NULL);
|
||||
suid_drop(cxt);
|
||||
|
||||
} else if (argc == 2 && !mnt_context_get_source(cxt)
|
||||
&& !mnt_context_get_target(cxt)) {
|
||||
|
@ -941,7 +942,7 @@ int main(int argc, char **argv)
|
|||
* D) mount <source> <target>
|
||||
*/
|
||||
if (mnt_context_is_restricted(cxt))
|
||||
exit_non_root(NULL);
|
||||
suid_drop(cxt);
|
||||
|
||||
mnt_context_set_source(cxt, argv[0]);
|
||||
mnt_context_set_target(cxt, argv[1]);
|
||||
|
@ -963,6 +964,14 @@ int main(int argc, char **argv)
|
|||
mnt_context_set_optsmode(cxt, MNT_OMODE_NOTAB);
|
||||
|
||||
rc = mnt_context_mount(cxt);
|
||||
|
||||
if (rc == -EPERM
|
||||
&& mnt_context_is_restricted(cxt)
|
||||
&& !mnt_context_syscall_called(cxt)) {
|
||||
/* Try it again without permissions */
|
||||
suid_drop(cxt);
|
||||
rc = mnt_context_mount(cxt);
|
||||
}
|
||||
rc = mk_exit_code(cxt, rc);
|
||||
|
||||
if (rc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt))
|
||||
|
|
|
@ -190,6 +190,25 @@ Display version information and exit.
|
|||
.TP
|
||||
.BR \-h , " \-\-help"
|
||||
Display help text and exit.
|
||||
.SH "NON-SUPERUSER UMOUNTS"
|
||||
Normally, only the superuser can umount filesystems.
|
||||
However, when
|
||||
.I fstab
|
||||
contains the
|
||||
.B user
|
||||
option on a line, anybody can umount the corresponding filesystem. For more details see
|
||||
.BR mount (8)
|
||||
man page.
|
||||
.PP
|
||||
Since version 2.34 \fBumount\fR command allows to perform umount operation also
|
||||
for fuse filesystems if kernel mount table contains user's ID. In this case fstab
|
||||
user= mount option is not required.
|
||||
.PP
|
||||
Since version 2.35 \fBumount\fR command does not exit when user permissions are
|
||||
inadequate by internal libmount security rules. It drops suid permissions
|
||||
and continue as regular non-root user. It allows to support use-cases where
|
||||
root permissions are not necessary (e.g. fuse filesystems, user namespaces,
|
||||
etc).
|
||||
.SH "LOOP DEVICE"
|
||||
The
|
||||
.B umount
|
||||
|
|
|
@ -112,24 +112,24 @@ static void __attribute__((__noreturn__)) usage(void)
|
|||
exit(MNT_EX_SUCCESS);
|
||||
}
|
||||
|
||||
static void __attribute__((__noreturn__)) exit_non_root(const char *option)
|
||||
static void suid_drop(struct libmnt_context *cxt)
|
||||
{
|
||||
const uid_t ruid = getuid();
|
||||
const uid_t euid = geteuid();
|
||||
|
||||
if (ruid == 0 && euid != 0) {
|
||||
/* user is root, but setuid to non-root */
|
||||
if (option)
|
||||
errx(MNT_EX_USAGE,
|
||||
_("only root can use \"--%s\" option "
|
||||
"(effective UID is %u)"),
|
||||
option, euid);
|
||||
errx(MNT_EX_USAGE, _("only root can do that "
|
||||
"(effective UID is %u)"), euid);
|
||||
if (ruid != 0 && euid == 0) {
|
||||
if (setgid(getgid()) < 0)
|
||||
err(MNT_EX_FAIL, _("setgid() failed"));
|
||||
|
||||
if (setuid(getuid()) < 0)
|
||||
err(MNT_EX_FAIL, _("setuid() failed"));
|
||||
}
|
||||
if (option)
|
||||
errx(MNT_EX_USAGE, _("only root can use \"--%s\" option"), option);
|
||||
errx(MNT_EX_USAGE, _("only root can do that"));
|
||||
|
||||
/* be paranoid and check it, setuid(0) has to fail */
|
||||
if (ruid != 0 && setuid(0) == 0)
|
||||
errx(MNT_EX_FAIL, _("drop permissions failed."));
|
||||
|
||||
mnt_context_force_unrestricted(cxt);
|
||||
}
|
||||
|
||||
static void success_message(struct libmnt_context *cxt)
|
||||
|
@ -220,6 +220,15 @@ static int umount_one(struct libmnt_context *cxt, const char *spec)
|
|||
err(MNT_EX_SYSERR, _("failed to set umount target"));
|
||||
|
||||
rc = mnt_context_umount(cxt);
|
||||
|
||||
if (rc == -EPERM
|
||||
&& mnt_context_is_restricted(cxt)
|
||||
&& !mnt_context_syscall_called(cxt)) {
|
||||
/* Failed somewhere in libmount, drop perms and try it again */
|
||||
suid_drop(cxt);
|
||||
rc = mnt_context_umount(cxt);
|
||||
}
|
||||
|
||||
rc = mk_exit_code(cxt, rc);
|
||||
|
||||
if (rc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt))
|
||||
|
@ -494,7 +503,7 @@ int main(int argc, char **argv)
|
|||
|
||||
/* only few options are allowed for non-root users */
|
||||
if (mnt_context_is_restricted(cxt) && !strchr("hdilqVv", c))
|
||||
exit_non_root(option_to_longopt(c, longopts));
|
||||
suid_drop(cxt);
|
||||
|
||||
err_exclusive_options(c, longopts, excl, excl_st);
|
||||
|
||||
|
|
Loading…
Reference in New Issue