From: Karel Zak Date: Mon, 30 May 2022 09:47:32 +0000 (+0200) Subject: libmount: reimplement X-mount.{owner,group,mode}= by hooks X-Git-Tag: v2.39-rc1~340 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ee99f438b899c81f44aaf9f4cd90910cde9d712d;p=thirdparty%2Futil-linux.git libmount: reimplement X-mount.{owner,group,mode}= by hooks * "prepare-options hook" parses {owner,group,mode}= options * "mount-post hook" calls chmod/own Signed-off-by: Karel Zak --- diff --git a/libmount/meson.build b/libmount/meson.build index 011cd3783b..a1d4026595 100644 --- a/libmount/meson.build +++ b/libmount/meson.build @@ -46,6 +46,7 @@ if LINUX src/hook_mount_legacy.c src/hook_mkdir.c src/hook_subdir.c + src/hook_owner.c src/monitor.c '''.split() endif diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am index 90cc4ac266..ba229dace7 100644 --- a/libmount/src/Makemodule.am +++ b/libmount/src/Makemodule.am @@ -35,6 +35,7 @@ libmount_la_SOURCES += \ libmount/src/hook_mount_legacy.c \ libmount/src/hook_mkdir.c \ libmount/src/hook_subdir.c \ + libmount/src/hook_owner.c \ libmount/src/monitor.c if HAVE_BTRFS diff --git a/libmount/src/context.c b/libmount/src/context.c index 2c909b19e0..152704719f 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -56,10 +56,6 @@ struct libmnt_context *mnt_new_context(void) if (!cxt) return NULL; - cxt->tgt_owner = (uid_t) -1; - cxt->tgt_group = (gid_t) -1; - cxt->tgt_mode = (mode_t) -1; - ruid = getuid(); euid = geteuid(); @@ -159,10 +155,6 @@ int mnt_reset_context(struct libmnt_context *cxt) free(cxt->helper); free(cxt->orig_user); - cxt->tgt_owner = (uid_t) -1; - cxt->tgt_group = (gid_t) -1; - cxt->tgt_mode = (mode_t) -1; - cxt->fs = NULL; cxt->mountinfo = NULL; cxt->utab = NULL; diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index f986cf8ead..74cbc0452a 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -751,54 +751,6 @@ static int do_mount_by_pattern(struct libmnt_context *cxt, const char *pattern) return rc; } -/* - * Process X-mount.owner=, X-mount.group=, X-mount.mode=. - */ -static int parse_ownership_mode(struct libmnt_context *cxt) -{ - int rc; - char *value; - size_t valsz; - - const char *o = mnt_fs_get_user_options(cxt->fs); - if (!o) - return 0; - - if ((rc = mnt_optstr_get_option(o, "X-mount.owner", &value, &valsz)) < 0) - return -MNT_ERR_MOUNTOPT; - if (!rc) { - if (!valsz) - return errno = EINVAL, -MNT_ERR_MOUNTOPT; - - if (mnt_parse_uid(value, valsz, &cxt->tgt_owner)) - return -MNT_ERR_MOUNTOPT; - } - - if ((rc = mnt_optstr_get_option(o, "X-mount.group", &value, &valsz)) < 0) - return -MNT_ERR_MOUNTOPT; - if (!rc) { - if (!valsz) - return errno = EINVAL, -MNT_ERR_MOUNTOPT; - - if (mnt_parse_gid(value, valsz, &cxt->tgt_group)) - return -MNT_ERR_MOUNTOPT; - } - - if ((rc = mnt_optstr_get_option(o, "X-mount.mode", &value, &valsz)) < 0) - return -MNT_ERR_MOUNTOPT; - if (!rc) { - if (!valsz) - return errno = EINVAL, -MNT_ERR_MOUNTOPT; - - if ((rc = mnt_parse_mode(value, valsz, &cxt->tgt_mode))) - return -MNT_ERR_MOUNTOPT; - } - - DBG(CXT, ul_debugobj(cxt, "ownership %d:%d, mode %04o", cxt->tgt_owner, cxt->tgt_group, cxt->tgt_mode)); - - return 0; -} - static int prepare_target(struct libmnt_context *cxt) { const char *tgt, *prefix; @@ -907,8 +859,6 @@ int mnt_context_prepare_mount(struct libmnt_context *cxt) rc = mnt_context_guess_fstype(cxt); if (!rc) rc = prepare_target(cxt); - if (!rc) - rc = parse_ownership_mode(cxt); if (!rc) rc = mnt_context_prepare_helper(cxt, "mount", NULL); @@ -934,25 +884,6 @@ end: return rc; } -static int set_ownership_mode(struct libmnt_context *cxt) -{ - const char *target = mnt_fs_get_target(cxt->fs); - - if (cxt->tgt_owner != (uid_t) -1 || cxt->tgt_group != (uid_t) -1) { - DBG(CXT, ul_debugobj(cxt, "mount: lchown(%s, %u, %u)", target, cxt->tgt_owner, cxt->tgt_group)); - if (lchown(target, cxt->tgt_owner, cxt->tgt_group) == -1) - return -MNT_ERR_CHOWN; - } - - if (cxt->tgt_mode != (mode_t) -1) { - DBG(CXT, ul_debugobj(cxt, "mount: chmod(%s, %04o)", target, cxt->tgt_mode)); - if (chmod(target, cxt->tgt_mode) == -1) - return -MNT_ERR_CHMOD; - } - - return 0; -} - /** * mnt_context_do_mount * @cxt: context @@ -1013,9 +944,6 @@ int mnt_context_do_mount(struct libmnt_context *cxt) if (mnt_context_is_veritydev(cxt)) mnt_context_deferred_delete_veritydev(cxt); - if (!res) - res = set_ownership_mode(cxt); - if (!mnt_context_switch_ns(cxt, ns_old)) return -MNT_ERR_NAMESPACE; @@ -1674,13 +1602,13 @@ int mnt_context_get_mount_excode( if (rc == -MNT_ERR_CHOWN) { if (buf) - snprintf(buf, bufsz, _("filesystem was mounted, but failed to change ownership to %u:%u: %m"), cxt->tgt_owner, cxt->tgt_group); + snprintf(buf, bufsz, _("filesystem was mounted, but failed to change ownership: %m")); return MNT_EX_SYSERR; } if (rc == -MNT_ERR_CHMOD) { if (buf) - snprintf(buf, bufsz, _("filesystem was mounted, but failed to change mode to %04o: %m"), cxt->tgt_mode); + snprintf(buf, bufsz, _("filesystem was mounted, but failed to change mode: %m")); return MNT_EX_SYSERR; } diff --git a/libmount/src/hook_owner.c b/libmount/src/hook_owner.c new file mode 100644 index 0000000000..5ded9e2c02 --- /dev/null +++ b/libmount/src/hook_owner.c @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * This file is part of libmount from util-linux project. + * + * Copyright (C) 2022 Karel Zak + * + * libmount is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * + * This is X-mount.owner=, X-mount.group= and X-mount.mode= implementation. + */ + +#include + +#include "mountP.h" +#include "fileutils.h" + +static int hook_prepare_options(struct libmnt_context *cxt, const struct libmnt_hookset *hs, void *data); + +struct hook_data { + uid_t owner; + gid_t group; + mode_t mode; +}; + +/* de-initiallize this module */ +static int hookset_deinit(struct libmnt_context *cxt, const struct libmnt_hookset *hs) +{ + void *data; + + DBG(HOOK, ul_debugobj(hs, "deinit '%s'", hs->name)); + + /* remove all our hooks and free hook data */ + while (mnt_context_remove_hook(cxt, hs, 0, &data) == 0) { + if (data) + free(data); + data = NULL; + } + + return 0; +} + +static int hook_mount_post( + struct libmnt_context *cxt, + const struct libmnt_hookset *hs __attribute__((__unused__)), + void *data) +{ + struct hook_data *hd = (struct hook_data *) data; + const char *target; + int rc = 0; + + assert(cxt); + + if (!hd || !cxt->fs) + return 0; + + target = mnt_fs_get_target(cxt->fs); + if (!target) + return 0; + + if (hd->owner != (uid_t) -1 || hd->group != (uid_t) -1) { + DBG(CXT, ul_debugobj(cxt, " lchown(%s, %u, %u)", target, hd->owner, hd->group)); + if (lchown(target, hd->owner, hd->group) == -1) + return -MNT_ERR_CHOWN; + } + + if (hd->mode != (mode_t) -1) { + DBG(CXT, ul_debugobj(cxt, " chmod(%s, %04o)", target, hd->mode)); + if (chmod(target, hd->mode) == -1) + return -MNT_ERR_CHMOD; + } + + return rc; +} + +static inline struct hook_data *new_hook_data(void) +{ + struct hook_data *hd = calloc(1, sizeof(*hd)); + + if (!hd) + return NULL; + + hd->owner = (uid_t) -1; + hd->group = (gid_t) -1; + hd->mode = (mode_t) -1; + return hd; +} + +static int hook_prepare_options( + struct libmnt_context *cxt, + const struct libmnt_hookset *hs, + void *data __attribute__((__unused__))) +{ + struct hook_data *hd = NULL; + const char *o; + int rc = 0; + char *value; + size_t valsz; + + o = mnt_fs_get_user_options(cxt->fs); + if (!o) + return 0; + + if ((rc = mnt_optstr_get_option(o, "X-mount.owner", &value, &valsz)) < 0) + goto fail; + if (rc == 0) { + if (!valsz) + goto fail; + if (!hd) { + hd = new_hook_data(); + if (!hd) + goto fail; + } + if (mnt_parse_uid(value, valsz, &hd->owner)) + goto fail; + } + + if ((rc = mnt_optstr_get_option(o, "X-mount.group", &value, &valsz)) < 0) + goto fail; + if (rc == 0) { + if (!valsz) + goto fail; + if (!hd) { + hd = new_hook_data(); + if (!hd) + goto fail; + } + if (mnt_parse_gid(value, valsz, &hd->group)) + goto fail; + } + + if ((rc = mnt_optstr_get_option(o, "X-mount.mode", &value, &valsz)) < 0) + goto fail; + if (rc == 0) { + if (!valsz) + goto fail; + if (!hd) { + hd = new_hook_data(); + if (!hd) + goto fail; + } + if (mnt_parse_mode(value, valsz, &hd->mode)) + goto fail; + } + + if (hd) { + DBG(CXT, ul_debugobj(cxt, " wanted ownership %d:%d, mode %04o", + hd->owner, hd->group, hd->mode)); + rc = mnt_context_append_hook(cxt, hs, + MNT_STAGE_MOUNT_POST, + hd, hook_mount_post); + if (rc < 0) + goto fail; + } + return 0; +fail: + if (rc == 0) + rc = -MNT_ERR_MOUNTOPT; + free(hd); + return rc; +} + + +const struct libmnt_hookset hookset_owner = +{ + .name = "__owner", + + .firststage = MNT_STAGE_PREP_OPTIONS, + .firstcall = hook_prepare_options, + + .deinit = hookset_deinit +}; diff --git a/libmount/src/hooks.c b/libmount/src/hooks.c index 5b345c4a63..7e9e9f35b2 100644 --- a/libmount/src/hooks.c +++ b/libmount/src/hooks.c @@ -26,7 +26,8 @@ static const struct libmnt_hookset *hooksets[] = #ifdef __linux__ &hookset_mkdir, &hookset_subdir, - &hookset_mount_legacy + &hookset_mount_legacy, + &hookset_owner #endif }; diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index 9a748513ed..c8364a7bf2 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -306,6 +306,7 @@ struct libmnt_hookset { extern const struct libmnt_hookset hookset_mount_legacy; extern const struct libmnt_hookset hookset_mkdir; extern const struct libmnt_hookset hookset_subdir; +extern const struct libmnt_hookset hookset_owner; extern int mnt_context_deinit_hooksets(struct libmnt_context *cxt); extern const struct libmnt_hookset *mnt_context_get_hookset(struct libmnt_context *cxt, const char *name); @@ -355,10 +356,6 @@ struct libmnt_context char *fstype_pattern; /* for mnt_match_fstype() */ char *optstr_pattern; /* for mnt_match_options() */ - uid_t tgt_owner; /* X-mount.owner= */ - gid_t tgt_group; /* X-mount.group= */ - mode_t tgt_mode; /* X-mount.mode= */ - struct libmnt_fs *fs; /* filesystem description (type, mountpoint, device, ...) */ struct libmnt_fs *fs_template; /* used for @fs on mnt_reset_context() */