summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--shlibs/mount/src/context_mount.c2
-rw-r--r--shlibs/mount/src/context_umount.c41
-rw-r--r--shlibs/mount/src/mountP.h1
-rw-r--r--shlibs/mount/src/utils.c73
4 files changed, 114 insertions, 3 deletions
diff --git a/shlibs/mount/src/context_mount.c b/shlibs/mount/src/context_mount.c
index eaba33c05..58c3ec10e 100644
--- a/shlibs/mount/src/context_mount.c
+++ b/shlibs/mount/src/context_mount.c
@@ -392,7 +392,7 @@ static int do_mount(struct libmnt_context *cxt, const char *try_type)
DBG(CXT, mnt_debug_h(cxt, "%smount(2) "
"[source=%s, target=%s, type=%s, "
- " mountflags=%08lx, mountdata=%s]",
+ " mountflags=0x%08lx, mountdata=%s]",
(cxt->flags & MNT_FL_FAKE) ? "(FAKE) " : "",
src, target, type,
flags, cxt->mountdata ? "yes" : "<none>"));
diff --git a/shlibs/mount/src/context_umount.c b/shlibs/mount/src/context_umount.c
index cdf919854..0e69fe5f9 100644
--- a/shlibs/mount/src/context_umount.c
+++ b/shlibs/mount/src/context_umount.c
@@ -424,10 +424,25 @@ int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg)
return rc;
}
+/* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
+static int umount_nofollow_support(void)
+{
+ int res = umount2("", UMOUNT_UNUSED);
+ if (res != -1 || errno != EINVAL)
+ return 0;
+
+ res = umount2("", UMOUNT_NOFOLLOW);
+ if (res != -1 || errno != ENOENT)
+ return 0;
+
+ return 1;
+}
+
static int do_umount(struct libmnt_context *cxt)
{
int rc = 0, flags = 0;
const char *src, *target;
+ char *tgtbuf = NULL;
assert(cxt);
assert(cxt->fs);
@@ -446,16 +461,38 @@ static int do_umount(struct libmnt_context *cxt)
if (cxt->flags & MNT_FL_FAKE)
return 0;
+ DBG(CXT, mnt_debug_h(cxt, "do umount"));
+
+ if (cxt->restricted) {
+ /*
+ * extra paranoa for non-root users
+ * -- chdir to the parent of the mountpoint and use NOFOLLOW
+ * flag to avoid races and symlink attacks.
+ */
+ if (umount_nofollow_support())
+ flags |= UMOUNT_NOFOLLOW;
+
+ rc = mnt_chdir_to_parent(target, &tgtbuf);
+ if (rc)
+ return rc;
+ target = tgtbuf;
+ }
+
if (cxt->flags & MNT_FL_LAZY)
flags |= MNT_DETACH;
else if (cxt->flags & MNT_FL_FORCE)
flags |= MNT_FORCE;
- rc = flasg ? umount2(target, flags) : umount(target);
+ DBG(CXT, mnt_debug_h(cxt, "umount(2) [target='%s', flags=0x%08x]",
+ target, flags));
+
+ rc = flags ? umount2(target, flags) : umount(target);
if (rc < 0)
cxt->syscall_status = -errno;
+ free(tgtbuf);
+
/*
* try remount read-only
*/
@@ -468,7 +505,7 @@ static int do_umount(struct libmnt_context *cxt)
"umount(2) failed [errno=%d] -- tring remount read-only",
-cxt->syscall_status));
- rc = mount(src, target, NULL,
+ rc = mount(src, mnt_fs_get_target(cxt->fs), NULL,
MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
if (rc < 0) {
cxt->syscall_status = -errno;
diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h
index 0d773ba0a..abaa6b2c6 100644
--- a/shlibs/mount/src/mountP.h
+++ b/shlibs/mount/src/mountP.h
@@ -111,6 +111,7 @@ extern int mnt_run_test(struct libmnt_test *tests, int argc, char *argv[]);
extern int endswith(const char *s, const char *sx);
extern int startswith(const char *s, const char *sx);
+extern int mnt_chdir_to_parent(const char *target, char **filename);
extern char *mnt_get_username(const uid_t uid);
extern int mnt_get_uid(const char *username, uid_t *uid);
extern int mnt_get_gid(const char *groupname, gid_t *gid);
diff --git a/shlibs/mount/src/utils.c b/shlibs/mount/src/utils.c
index b02b6fe4d..1261a2934 100644
--- a/shlibs/mount/src/utils.c
+++ b/shlibs/mount/src/utils.c
@@ -71,6 +71,58 @@ static char *stripoff_last_component(char *path)
return ++p;
}
+/* Note that the @target has to be absolute path (so at least "/")
+ */
+int mnt_chdir_to_parent(const char *target, char **filename)
+{
+ char *path, *last = NULL;
+ char cwd[PATH_MAX];
+ int rc = -EINVAL;
+
+ if (!target || *target != '/')
+ return -EINVAL;
+
+ path = strdup(target);
+ if (!path)
+ return -ENOMEM;
+
+ if (*(path + 1) != '\0') {
+ last = stripoff_last_component(path);
+ if (!last)
+ goto err;
+ }
+ if (!*path)
+ *path = '/'; /* root */
+
+ if (chdir(path) == -1) {
+ DBG(UTILS, mnt_debug("failed to chdir to %s: %m", path));
+ rc = -errno;
+ goto err;
+ }
+ if (!getcwd(cwd, sizeof(cwd))) {
+ DBG(UTILS, mnt_debug("failed to obtain current directory: %m"));
+ rc = -errno;
+ goto err;
+ }
+ if (strcmp(cwd, path) != 0) {
+ DBG(UTILS, mnt_debug("path moved (%s -> %s)", path, cwd));
+ goto err;
+ }
+
+ DBG(CXT, mnt_debug("current directory moved to %s", path));
+
+ *filename = path;
+
+ if (!last || !*last)
+ memcpy(*filename, ".", 2);
+ else
+ memcpy(*filename, last, strlen(last) + 1);
+ return 0;
+err:
+ free(path);
+ return rc;
+}
+
/**
* mnt_mangle:
* @str: string
@@ -800,6 +852,26 @@ int test_filesystems(struct libmnt_test *ts, int argc, char *argv[])
return rc;
}
+int test_chdir(struct libmnt_test *ts, int argc, char *argv[])
+{
+ int rc;
+ char *path = canonicalize_path(argv[1]),
+ *last = NULL;
+
+ if (!path)
+ return -errno;
+
+ rc = mnt_chdir_to_parent(path, &last);
+ if (!rc) {
+ printf("path='%s', abs='%s', last='%s'\n",
+ argv[1], path, last);
+ }
+ free(path);
+ free(last);
+ return rc;
+}
+
+
int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
@@ -810,6 +882,7 @@ int main(int argc, char *argv[])
{ "--ends-with", test_endswith, "<string> <prefix>" },
{ "--mountpoint", test_mountpoint, "<path>" },
{ "--fs-root", test_fsroot, "<path>" },
+ { "--cd-parent", test_chdir, "<path>" },
{ NULL }
};