libmount: use chdir() and NOFOLLOW umount flag for umount operation
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
a2c90d998e
commit
66bb826710
|
@ -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>"));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue