From: Karel Zak Date: Thu, 18 Aug 2022 07:51:57 +0000 (+0200) Subject: libmount: (mount) use optlist from options processing X-Git-Tag: v2.39-rc1~315 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=afee6db1863d36ac1df998c0bc475b81fcdd664b;p=thirdparty%2Futil-linux.git libmount: (mount) use optlist from options processing Signed-off-by: Karel Zak --- diff --git a/libmount/src/context.c b/libmount/src/context.c index 8115ffc18f..c104002181 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -1175,7 +1175,7 @@ const char *mnt_context_get_options(struct libmnt_context *cxt) if (!ls) return NULL; - mnt_optlist_get_optstr(ls, &str, NULL); + mnt_optlist_get_optstr(ls, &str, NULL, 0); return str; } @@ -1709,7 +1709,7 @@ int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags) return -ENOMEM; return mnt_optlist_get_flags(ls, flags, - mnt_get_builtin_optmap(MNT_LINUX_MAP)); + mnt_get_builtin_optmap(MNT_LINUX_MAP), 0); } /** @@ -1752,7 +1752,7 @@ int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags return -ENOMEM; return mnt_optlist_get_flags(ls, flags, - mnt_get_builtin_optmap(MNT_USERSPACE_MAP)); + mnt_get_builtin_optmap(MNT_USERSPACE_MAP), 0); } /** diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index 7772d39e05..1275862a26 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -29,25 +29,14 @@ #include "strutils.h" #if defined(HAVE_LIBSELINUX) || defined(HAVE_SMACK) -struct libmnt_optname { - const char *name; - size_t namesz; -}; - -#define DEF_OPTNAME(n) { .name = n, .namesz = sizeof(n) - 1 } -#define DEF_OPTNAME_LAST { .name = NULL } - -static int is_option(const char *name, size_t namesz, - const struct libmnt_optname *names) +static int is_option(const char *name, const char **names) { - const struct libmnt_optname *p; + const char **p; - for (p = names; p && p->name; p++) { - if (p->namesz == namesz - && strncmp(name, p->name, namesz) == 0) + for (p = names; p && *p; p++) { + if (strcmp(name, *p) == 0) return 1; } - return 0; } #endif /* HAVE_LIBSELINUX || HAVE_SMACK */ @@ -57,98 +46,89 @@ static int is_option(const char *name, size_t namesz, */ static int fix_optstr(struct libmnt_context *cxt) { - int rc = 0; + struct libmnt_optlist *ol; + struct libmnt_opt *opt; struct libmnt_ns *ns_old; - char *next; - char *name, *val; - size_t namesz, valsz; struct libmnt_fs *fs; + const char *val; + int rc = 0; #ifdef HAVE_LIBSELINUX int se_fix = 0, se_rem = 0; - static const struct libmnt_optname selinux_options[] = { - DEF_OPTNAME("context"), - DEF_OPTNAME("fscontext"), - DEF_OPTNAME("defcontext"), - DEF_OPTNAME("rootcontext"), - DEF_OPTNAME("seclabel"), - DEF_OPTNAME_LAST - }; -#endif -#ifdef HAVE_SMACK - int sm_rem = 0; - static const struct libmnt_optname smack_options[] = { - DEF_OPTNAME("smackfsdef"), - DEF_OPTNAME("smackfsfloor"), - DEF_OPTNAME("smackfshat"), - DEF_OPTNAME("smackfsroot"), - DEF_OPTNAME("smackfstransmute"), - DEF_OPTNAME_LAST - }; #endif assert(cxt); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); - if (!cxt->fs || (cxt->flags & MNT_FL_MOUNTOPTS_FIXED)) + if (cxt->flags & MNT_FL_MOUNTOPTS_FIXED) return 0; - DBG(CXT, ul_debugobj(cxt, "-->: preparing mount options")); - fs = cxt->fs; - DBG(CXT, ul_debugobj(cxt, " current options" - "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'", - fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr)); + DBG(CXT, ul_debugobj(cxt, "--> preparing options")); - /* - * The "user" options is our business (so we can modify the option), - * the exception is command line for /sbin/mount. helpers. Let's - * save the original user= to call the helpers with an unchanged - * "user" setting. - */ - if (cxt->user_mountflags & MNT_MS_USER) { - if (!mnt_optstr_get_option(fs->user_optstr, - "user", &val, &valsz) && val) { - cxt->orig_user = strndup(val, valsz); - if (!cxt->orig_user) { + ol = mnt_context_get_optlist(cxt); + if (!ol) + return -EINVAL; + + ns_old = mnt_context_switch_origin_ns(cxt); + if (!ns_old) + return -MNT_ERR_NAMESPACE; + + /* Fix user (convert "user" to "user=username") */ + if (mnt_context_is_restricted(cxt)) { + const struct libmnt_optmap *map = mnt_get_builtin_optmap(MNT_USERSPACE_MAP); + assert(map); + + opt = mnt_optlist_get_opt(ol, MNT_MS_USER, map); + if (opt) { + char *name = mnt_get_username(getuid()); + + if (!name) rc = -ENOMEM; + else + rc = mnt_opt_set_value(opt, name); + if (rc) goto done; - } } - cxt->flags |= MNT_FL_SAVED_USER; } - /* - * Sync mount options with mount flags - */ - DBG(CXT, ul_debugobj(cxt, " fixing vfs optstr")); - rc = mnt_optstr_apply_flags(&fs->vfs_optstr, cxt->mountflags, - mnt_get_builtin_optmap(MNT_LINUX_MAP)); - if (rc) - goto done; - - DBG(CXT, ul_debugobj(cxt, " fixing user optstr")); - rc = mnt_optstr_apply_flags(&fs->user_optstr, cxt->user_mountflags, - mnt_get_builtin_optmap(MNT_USERSPACE_MAP)); - if (rc) - goto done; + /* Fix UID */ + opt = mnt_optlist_get_named(ol, "uid", NULL); + if (opt && (val = mnt_opt_get_value(opt)) && !isdigit_string(val)) { + uid_t id; - if (fs->vfs_optstr && *fs->vfs_optstr == '\0') { - free(fs->vfs_optstr); - fs->vfs_optstr = NULL; - } - if (fs->user_optstr && *fs->user_optstr == '\0') { - free(fs->user_optstr); - fs->user_optstr = NULL; + if (strcmp(val, "useruid") == 0) /* UID of the current user */ + id = getuid(); + else + rc = mnt_get_uid(val, &id); /* UID for the username */ + if (!rc) + rc = mnt_opt_set_u64value(opt, id); + if (rc) + goto done; } + /* Fix GID */ + opt = mnt_optlist_get_named(ol, "gid", NULL); + if (opt && (val = mnt_opt_get_value(opt)) && !isdigit_string(val)) { + gid_t id; - next = fs->fs_optstr; + if (strcmp(val, "usergid") == 0) /* UID of the current user */ + id = getgid(); + else + rc = mnt_get_gid(val, &id); /* UID for the groupname */ + if (!rc) + rc = mnt_opt_set_u64value(opt, id); + if (rc) + goto done; + } + + if (!mnt_context_switch_ns(cxt, ns_old)) + return -MNT_ERR_NAMESPACE; #ifdef HAVE_LIBSELINUX if (!is_selinux_enabled()) /* Always remove SELinux garbage if SELinux disabled */ se_rem = 1; - else if (cxt->mountflags & MS_REMOUNT) + else if (mnt_optlist_is_remount(ol)) /* * Linux kernel < 2.6.39 does not support remount operation * with any selinux specific mount options. @@ -163,77 +143,101 @@ static int fix_optstr(struct libmnt_context *cxt) /* For normal mount, contexts are translated */ se_fix = 1; - if (!se_rem) { - /* de-duplicate SELinux options */ - const struct libmnt_optname *p; - for (p = selinux_options; p && p->name; p++) - mnt_optstr_deduplicate_option(&fs->fs_optstr, p->name); - } -#endif -#ifdef HAVE_SMACK - if (access("/sys/fs/smackfs", F_OK) != 0) - sm_rem = 1; -#endif - while (!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) { + /* Fix SELinux contexts */ + if (se_rem || se_fix) { + static const char *selinux_options[] = { + "context", + "fscontext", + "defcontext", + "rootcontext", + "seclabel", + NULL + }; + struct libmnt_iter itr; - if (namesz == 3 && !strncmp(name, "uid", 3)) - rc = mnt_optstr_fix_uid(&fs->fs_optstr, val, valsz, &next); - else if (namesz == 3 && !strncmp(name, "gid", 3)) - rc = mnt_optstr_fix_gid(&fs->fs_optstr, val, valsz, &next); -#ifdef HAVE_LIBSELINUX - else if ((se_rem || se_fix) - && is_option(name, namesz, selinux_options)) { - - if (se_rem) { - /* remove context= option */ - next = name; - rc = mnt_optstr_remove_option_at(&fs->fs_optstr, - name, - val ? val + valsz : - name + namesz); - } else if (se_fix && val && valsz) - /* translate selinux contexts */ - rc = mnt_optstr_fix_secontext(&fs->fs_optstr, - val, valsz, &next); + mnt_reset_iter(&itr, MNT_ITER_FORWARD); + + while (mnt_optlist_next_opt(ol, &itr, &opt) == 0) { + if (!is_option(mnt_opt_get_name(opt), selinux_options)) + continue; + if (se_rem) + rc = mnt_optlist_remove_opt(ol, opt); + else if (se_fix && mnt_opt_has_value(opt)) { + const char *val = mnt_opt_get_value(opt); + char *raw = NULL; + + rc = selinux_trans_to_raw_context(val, &raw); + if (rc == -1 || !raw) + rc = -EINVAL; + if (!rc) + rc = mnt_opt_set_quoted_value(opt, raw); + if (raw) + freecon(raw); + } + if (rc) + goto done; } + } #endif + #ifdef HAVE_SMACK - else if (sm_rem && is_option(name, namesz, smack_options)) { + /* Fix Smack */ + if (access("/sys/fs/smackfs", F_OK) != 0) { + struct libmnt_iter itr; - next = name; - rc = mnt_optstr_remove_option_at(&fs->fs_optstr, - name, - val ? val + valsz : name + namesz); + static const char *smack_options[] = { + "smackfsdef", + "smackfsfloor", + "smackfshat", + "smackfsroot", + "smackfstransmute", + NULL, + }; + mnt_reset_iter(&itr, MNT_ITER_FORWARD); + + while (mnt_optlist_next_opt(ol, &itr, &opt) == 0) { + if (!is_option(mnt_opt_get_name(opt), smack_options)) + continue; + rc = mnt_optlist_remove_opt(ol, opt); + if (rc) + goto done; } -#endif - if (rc) - goto done; } +#endif + mnt_context_call_hooks(cxt, MNT_STAGE_PREP_OPTIONS); - if (!rc && mnt_context_is_restricted(cxt) && (cxt->user_mountflags & MNT_MS_USER)) { - ns_old = mnt_context_switch_origin_ns(cxt); - if (!ns_old) - return -MNT_ERR_NAMESPACE; + /* For backward compatinility update context fs mount options */ + if (fs) { + const struct libmnt_optmap *map; + const char *p; - rc = mnt_optstr_fix_user(&fs->user_optstr); + /* All options */ + mnt_optlist_get_optstr(ol, &p, NULL, 0); + strdup_to_struct_member(fs, optstr, p); - if (!mnt_context_switch_ns(cxt, ns_old)) - return -MNT_ERR_NAMESPACE; - } + /* FS options */ + mnt_optlist_get_optstr(ol, &p, NULL, MNT_OPTLIST_UNKNOWN); + strdup_to_struct_member(fs, fs_optstr, p); - mnt_context_call_hooks(cxt, MNT_STAGE_PREP_OPTIONS); + /* VFS options */ + map = mnt_get_builtin_optmap(MNT_LINUX_MAP); + mnt_optlist_get_optstr(ol, &p, map, 0); + strdup_to_struct_member(fs, vfs_optstr, p); + + /* Userspace options */ + map = mnt_get_builtin_optmap(MNT_USERSPACE_MAP); + mnt_optlist_get_optstr(ol, &p, map, 0); + strdup_to_struct_member(fs, user_optstr, p); + + DBG(CXT, ul_debugobj(cxt, " fixed options: " + "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'", + fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr)); + } - /* refresh merged optstr */ - free(fs->optstr); - fs->optstr = NULL; - fs->optstr = mnt_fs_strdup_options(fs); done: + DBG(CXT, ul_debugobj(cxt, "<-- preparing options done [rc=%d]", rc)); cxt->flags |= MNT_FL_MOUNTOPTS_FIXED; - DBG(CXT, ul_debugobj(cxt, " fixed options [rc=%d]: " - "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'", rc, - fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr)); - if (rc) rc = -MNT_ERR_MOUNTOPT; return rc; @@ -345,7 +349,7 @@ static int evaluate_permissions(struct libmnt_context *cxt) assert(user_map); /* get userspace mount flags (user[=] etc.*/ - rc = mnt_optlist_get_flags(ol, &user_flags, user_map); + rc = mnt_optlist_get_flags(ol, &user_flags, user_map, 0); if (rc) return rc; @@ -383,6 +387,8 @@ static int evaluate_permissions(struct libmnt_context *cxt) && mnt_opt_has_value(opt)) { DBG(CXT, ul_debugobj(cxt, "perms: user= detected, ignore")); + cxt->flags |= MNT_FL_SAVED_USER; + mnt_opt_set_external(opt, 1); user_flags &= ~MNT_MS_USER; } @@ -1874,17 +1880,18 @@ static int test_perms(struct libmnt_test *ts, int argc, char *argv[]) int rc; cxt = mnt_new_context(); - if (!cxt) return -ENOMEM; cxt->restricted = 1; /* emulate suid mount(8) */ mnt_context_get_fs(cxt); /* due to assert() in evaluate_permissions() */ - if (argc != 2) { + if (argc < 2) { warn("missing fstab options"); return -EPERM; } + if (argc == 3 && strcmp(argv[2], "--root") == 0) + cxt->restricted = 0; ls = mnt_context_get_optlist(cxt); if (!ls) @@ -1909,10 +1916,65 @@ static int test_perms(struct libmnt_test *ts, int argc, char *argv[]) return 0; } +static int test_fixopts(struct libmnt_test *ts, int argc, char *argv[]) +{ + struct libmnt_context *cxt; + struct libmnt_optlist *ls; + const char *p; + int rc; + + cxt = mnt_new_context(); + if (!cxt) + return -ENOMEM; + + cxt->restricted = 1; /* emulate suid mount(8) */ + mnt_context_get_fs(cxt); /* to fill fs->*_optstr */ + + if (argc < 2) { + warn("missing fstab options"); + return -EPERM; + } + if (argc == 3 && strcmp(argv[2], "--root") == 0) + cxt->restricted = 0; + + ls = mnt_context_get_optlist(cxt); + if (!ls) + return -ENOMEM; + rc = mnt_optlist_set_optstr(ls, argv[1], NULL); + if (rc) { + warn("cannot apply fstab options"); + return rc; + } + cxt->flags |= MNT_FL_TAB_APPLIED; /* emulate mnt_context_apply_fstab() */ + + mnt_context_merge_mflags(cxt); + + rc = evaluate_permissions(cxt); + if (rc) { + warn("evaluate permission failed [rc=%d]", rc); + return rc; + } + rc = fix_optstr(cxt); + if (rc) { + warn("fix options failed [rc=%d]", rc); + return rc; + } + mnt_optlist_get_optstr(ls, &p, NULL, 0); + printf("options (dfl): '%s'\n", p); + + mnt_optlist_get_optstr(ls, &p, NULL, MNT_OPTLIST_EXTERNAL); + printf("options (ex.): '%s'\n", p); + + mnt_free_context(cxt); + return 0; +} + int main(int argc, char *argv[]) { struct libmnt_test tss[] = { - { "--perms", test_perms, "" }, + { "--perms", test_perms, " [--root]" }, + { "--fix-options", test_fixopts, " [--root]" }, + { NULL }}; return mnt_run_test(tss, argc, argv);