From bc5aaf0e8b9105e5abd6aa6ff28294a39f5822bc Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 29 Nov 2023 12:37:52 +0100 Subject: libmount: add missing utab options after helper call libmount is able to add missing entry to /run/mount/utab after external /sbin/mouht. helper execution. This is not enough, it's possible that the helper write proper entry to the utab, but there is missing some options expected by libmount (usually because the options are irrelevant fro the helper. Reproducer: Create a stupid mount.foo which writes x-foo=123 to utab: # echo -e '#!/bin/bash\n\n/bin/mount -i "$1" "$2" -o x-foo=123' > /sbin/mount.foo # chmod +x /sbin/mount.foo Run mount which needs to write x-bar=BAR options to utab and executes the helper (due to "-t foo", /dev/sdc1 is ext4): # mount -t foo /dev/sdc1 /mnt/test -o x-bar=BAR old mount: # cat /run/mount/utab ID=121 SRC=/dev/sdc1 TARGET=/mnt/test ROOT=/ OPTS=x-foo=123 fixed mount: # cat /run/mount/utab ID=121 SRC=/dev/sdc1 TARGET=/mnt/test ROOT=/ OPTS=x-foo=123,x-bar=BAR Addresses: https://issues.redhat.com/browse/RHEL-14612 Upstream: http://github.com/util-linux/util-linux/commit/477401f0de404aafbc7630f70c2f8b1d670e32f8 Fixes: https://github.com/util-linux/util-linux/issues/2554 Signed-off-by: Karel Zak --- libmount/src/tab_update.c | 81 +++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c index b68553515..f60f522ce 100644 --- a/libmount/src/tab_update.c +++ b/libmount/src/tab_update.c @@ -37,7 +37,9 @@ struct libmnt_update { char *filename; unsigned long mountflags; int userspace_only; - int ready; + + unsigned int ready : 1, + missing_options : 1; struct libmnt_table *mountinfo; }; @@ -183,7 +185,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags, mnt_unref_fs(upd->fs); free(upd->target); - upd->ready = FALSE; + upd->ready = 0; upd->fs = NULL; upd->target = NULL; upd->mountflags = 0; @@ -218,7 +220,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags, DBG(UPDATE, ul_debugobj(upd, "ready")); - upd->ready = TRUE; + upd->ready = 1; return 0; } @@ -778,6 +780,7 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l return rc; } +/* replaces option in the table entry by new options from @udp */ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc) { struct libmnt_table *tb = NULL; @@ -820,6 +823,58 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock * return rc; } +/* add user options missing in the table entry by new options from @udp */ +static int update_add_options(struct libmnt_update *upd, struct libmnt_lock *lc) +{ + struct libmnt_table *tb = NULL; + int rc = 0; + struct libmnt_fs *fs; + + assert(upd); + assert(upd->fs); + + if (!upd->fs->user_optstr) + return 0; + + DBG(UPDATE, ul_debugobj(upd, "%s: add options", upd->filename)); + + fs = upd->fs; + + if (lc) + rc = mnt_lock_file(lc); + if (rc) + return -MNT_ERR_LOCK; + + tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1); + if (tb) { + struct libmnt_fs *cur = mnt_table_find_target(tb, + mnt_fs_get_target(fs), + MNT_ITER_BACKWARD); + if (cur) { + char *u = NULL; + + rc = mnt_optstr_get_missing(cur->user_optstr, upd->fs->user_optstr, &u); + if (!rc && u) { + DBG(UPDATE, ul_debugobj(upd, " add missing: %s", u)); + rc = mnt_optstr_append_option(&cur->user_optstr, u, NULL); + } + if (!rc && u) + rc = update_table(upd, tb); + + if (rc == 1) /* nothing is missing */ + rc = 0; + } else + rc = add_file_entry(tb, upd); /* not found, add new */ + } + + if (lc) + mnt_unlock_file(lc); + + mnt_unref_table(tb); + return rc; + +} + /** * mnt_update_table: * @upd: update @@ -862,10 +917,12 @@ int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc) rc = update_modify_target(upd, lc); /* move */ else if (upd->mountflags & MS_REMOUNT) rc = update_modify_options(upd, lc); /* remount */ + else if (upd->fs && upd->missing_options) + rc = update_add_options(upd, lc); /* mount by externel helper */ else if (upd->fs) - rc = update_add_entry(upd, lc); /* mount */ + rc = update_add_entry(upd, lc); /* mount */ - upd->ready = FALSE; + upd->ready = 1; DBG(UPDATE, ul_debugobj(upd, "%s: update tab: done [rc=%d]", upd->filename, rc)); if (lc != lc0) @@ -908,16 +965,26 @@ int mnt_update_already_done(struct libmnt_update *upd, struct libmnt_lock *lc) if (upd->fs) { /* mount */ + struct libmnt_fs *fs; const char *tgt = mnt_fs_get_target(upd->fs); const char *src = mnt_fs_get_bindsrc(upd->fs) ? mnt_fs_get_bindsrc(upd->fs) : mnt_fs_get_source(upd->fs); - if (mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD)) { + fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD); + if (fs) { DBG(UPDATE, ul_debugobj(upd, "%s: found %s %s", upd->filename, src, tgt)); + + /* Check if utab entry (probably writen by /sbin/mount. + * helper) contains all options expected by this update */ + if (mnt_optstr_get_missing(fs->user_optstr, upd->fs->user_optstr, NULL) == 0) { + upd->missing_options = 1; + DBG(UPDATE, ul_debugobj(upd, " missing options detected")); + } + } else rc = 1; - } + } else if (upd->target) { /* umount */ if (!mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD)) { -- 2.43.0