libmount: improve X-mount.mkdir for non-root users
Since v2.35 mount(8) drops suid on -EPERM and repeat necessary actions before mount(2) syscall. This patch also improves this behavior for X-mount.mkdir too. mount(8): * return -EPERM on sanitize_paths() rather than call err() * call suid_drop() on failed sanitize_paths() * update man page libmount: * mnt_context_prepare_target() refactoring * return -EPERM when in restricted mode for X-mount.mkdir Fixed version: /home/kzak/mnt-foo sr.net.home:/home/kzak fuse.sshfs noauto,X-mount.mkdir $ mount /home/kzak/mnt-foo kzak@sr.net.home's password: $ /home/projects/util-linux/util-linux findmnt /home/kzak/mnt-foo TARGET SOURCE FSTYPE OPTIONS /home/kzak/mnt-foo sr.net.home:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 Addresses: https://github.com/systemd/systemd/issues/14418 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
d0c4300682
commit
6b0094d0c1
|
@ -1903,7 +1903,6 @@ static int mkdir_target(const char *tgt, struct libmnt_fs *fs)
|
|||
int mnt_context_prepare_target(struct libmnt_context *cxt)
|
||||
{
|
||||
const char *tgt, *prefix;
|
||||
struct libmnt_cache *cache;
|
||||
int rc = 0;
|
||||
struct libmnt_ns *ns_old;
|
||||
|
||||
|
@ -1944,37 +1943,35 @@ int mnt_context_prepare_target(struct libmnt_context *cxt)
|
|||
if (!ns_old)
|
||||
return -MNT_ERR_NAMESPACE;
|
||||
|
||||
/* mkdir target */
|
||||
/* X-mount.mkdir target */
|
||||
if (cxt->action == MNT_ACT_MOUNT
|
||||
&& !mnt_context_is_restricted(cxt)
|
||||
&& (cxt->user_mountflags & MNT_MS_XCOMMENT ||
|
||||
cxt->user_mountflags & MNT_MS_XFSTABCOMM)) {
|
||||
|
||||
/* supported only for root or non-suid mount(8) */
|
||||
if (!mnt_context_is_restricted(cxt))
|
||||
rc = mkdir_target(tgt, cxt->fs);
|
||||
if (rc) {
|
||||
if (!mnt_context_switch_ns(cxt, ns_old))
|
||||
return -MNT_ERR_NAMESPACE;
|
||||
return rc; /* mkdir or parse error */
|
||||
}
|
||||
else
|
||||
rc = -EPERM;
|
||||
}
|
||||
|
||||
/* canonicalize the path */
|
||||
cache = mnt_context_get_cache(cxt);
|
||||
if (rc == 0) {
|
||||
struct libmnt_cache *cache = mnt_context_get_cache(cxt);
|
||||
|
||||
if (cache) {
|
||||
char *path = mnt_resolve_path(tgt, cache);
|
||||
if (path && strcmp(path, tgt) != 0)
|
||||
rc = mnt_fs_set_target(cxt->fs, path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mnt_context_switch_ns(cxt, ns_old))
|
||||
return -MNT_ERR_NAMESPACE;
|
||||
|
||||
if (rc)
|
||||
DBG(CXT, ul_debugobj(cxt, "failed to prepare target '%s'", tgt));
|
||||
else
|
||||
DBG(CXT, ul_debugobj(cxt, "final target '%s'",
|
||||
mnt_fs_get_target(cxt->fs)));
|
||||
return 0;
|
||||
DBG(CXT, ul_debugobj(cxt, "final target '%s' [rc=%d]",
|
||||
mnt_fs_get_target(cxt->fs), rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Guess type, but not set to cxt->fs, always use free() for the result. It's
|
||||
|
|
|
@ -992,10 +992,10 @@ int mnt_context_prepare_mount(struct libmnt_context *cxt)
|
|||
rc = fix_optstr(cxt);
|
||||
if (!rc)
|
||||
rc = mnt_context_prepare_srcpath(cxt);
|
||||
if (!rc)
|
||||
rc = mnt_context_prepare_target(cxt);
|
||||
if (!rc)
|
||||
rc = mnt_context_guess_fstype(cxt);
|
||||
if (!rc)
|
||||
rc = mnt_context_prepare_target(cxt);
|
||||
if (!rc)
|
||||
rc = mnt_context_prepare_helper(cxt, "mount", NULL);
|
||||
if (rc) {
|
||||
|
|
|
@ -1311,8 +1311,9 @@ Allow to make a target directory (mountpoint). The optional argument
|
|||
specifies the filesystem access mode used for
|
||||
.BR mkdir (2)
|
||||
in octal notation. The default mode is 0755. This functionality is supported
|
||||
only for root users. The option is also supported as x-mount.mkdir, this notation
|
||||
is deprecated for mount.mkdir since v2.30.
|
||||
only for root users or when mount executed without suid permissions. The option
|
||||
is also supported as x-mount.mkdir, this notation is deprecated for mount.mkdir
|
||||
since v2.30.
|
||||
|
||||
.SH "FILESYSTEM-SPECIFIC MOUNT OPTIONS"
|
||||
You should consult the respective man page for the filesystem first.
|
||||
|
|
|
@ -384,19 +384,19 @@ static struct libmnt_table *append_fstab(struct libmnt_context *cxt,
|
|||
* Check source and target paths -- non-root user should not be able to
|
||||
* resolve paths which are unreadable for him.
|
||||
*/
|
||||
static void sanitize_paths(struct libmnt_context *cxt)
|
||||
static int sanitize_paths(struct libmnt_context *cxt)
|
||||
{
|
||||
const char *p;
|
||||
struct libmnt_fs *fs = mnt_context_get_fs(cxt);
|
||||
|
||||
if (!fs)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
p = mnt_fs_get_target(fs);
|
||||
if (p) {
|
||||
char *np = canonicalize_path_restricted(p);
|
||||
if (!np)
|
||||
err(MNT_EX_USAGE, "%s", p);
|
||||
return -EPERM;
|
||||
mnt_fs_set_target(fs, np);
|
||||
free(np);
|
||||
}
|
||||
|
@ -405,10 +405,11 @@ static void sanitize_paths(struct libmnt_context *cxt)
|
|||
if (p) {
|
||||
char *np = canonicalize_path_restricted(p);
|
||||
if (!np)
|
||||
err(MNT_EX_USAGE, "%s", p);
|
||||
return -EPERM;
|
||||
mnt_fs_set_source(fs, np);
|
||||
free(np);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void append_option(struct libmnt_context *cxt, const char *opt)
|
||||
|
@ -952,8 +953,8 @@ int main(int argc, char **argv)
|
|||
errtryhelp(MNT_EX_USAGE);
|
||||
}
|
||||
|
||||
if (mnt_context_is_restricted(cxt))
|
||||
sanitize_paths(cxt);
|
||||
if (mnt_context_is_restricted(cxt) && sanitize_paths(cxt) != 0)
|
||||
suid_drop(cxt);
|
||||
|
||||
if (is_move)
|
||||
/* "move" as option string is not supported by libmount */
|
||||
|
|
Loading…
Reference in New Issue