aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2019-12-03 15:23:53 +0100
committerKarel Zak <kzak@redhat.com>2019-12-03 15:23:53 +0100
commit3861c371f673625a1ca9c8e203d800ddbaa99a67 (patch)
tree9f71d6f234fbfc568c37ec18c4b63aa28165a76c
parentac0391cc4f22e0892f2129f32285dcdfc542cfe0 (diff)
parent6497f2d99e9cabee3531e644ba4dcffd14532200 (diff)
downloadutil-linux-3861c371f673625a1ca9c8e203d800ddbaa99a67.tar.gz
Merge branch 'mount-eperm'
* mount-eperm: mount: no exit on EPERM, continue without suid
-rw-r--r--libmount/docs/libmount-sections.txt1
-rw-r--r--libmount/src/context.c25
-rw-r--r--libmount/src/libmount.h.in1
-rw-r--r--libmount/src/libmount.sym1
-rw-r--r--sys-utils/mount.86
-rw-r--r--sys-utils/mount.c43
-rw-r--r--sys-utils/umount.819
-rw-r--r--sys-utils/umount.c37
8 files changed, 102 insertions, 31 deletions
diff --git a/libmount/docs/libmount-sections.txt b/libmount/docs/libmount-sections.txt
index 990c0394f2..0bba9f8356 100644
--- a/libmount/docs/libmount-sections.txt
+++ b/libmount/docs/libmount-sections.txt
@@ -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
diff --git a/libmount/src/context.c b/libmount/src/context.c
index bfba39c4bd..7b94aa9fcc 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -427,6 +427,31 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
}
/**
+ * 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
* @mode: MNT_OMODE_* flags
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index 19d4c5b53c..ba54cf25da 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -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);
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index b9a4c0d22d..792d11753e 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -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;
diff --git a/sys-utils/mount.8 b/sys-utils/mount.8
index 9d31d8245b..a6231c7c1c 100644
--- a/sys-utils/mount.8
+++ b/sys-utils/mount.8
@@ -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.
diff --git a/sys-utils/mount.c b/sys-utils/mount.c
index 08da9e6a54..5842bc2ecc 100644
--- a/sys-utils/mount.c
+++ b/sys-utils/mount.c
@@ -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))
diff --git a/sys-utils/umount.8 b/sys-utils/umount.8
index f94d2f41f4..9bec521e7f 100644
--- a/sys-utils/umount.8
+++ b/sys-utils/umount.8
@@ -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
diff --git a/sys-utils/umount.c b/sys-utils/umount.c
index 397e0ebfc5..74d87d671b 100644
--- a/sys-utils/umount.c
+++ b/sys-utils/umount.c
@@ -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);