216 lines
6.1 KiB
Diff
216 lines
6.1 KiB
Diff
|
From 2e22136c0ef7fd5744460d783ef570525df42337 Mon Sep 17 00:00:00 2001
|
||
|
From: Karel Zak <kzak@redhat.com>
|
||
|
Date: Mon, 22 Jan 2024 12:56:24 +0100
|
||
|
Subject: libmount: add utab.act file
|
||
|
|
||
|
The file exists when libmount works with utab, and more steps are
|
||
|
expected during a single mount operation (more kernel events, more
|
||
|
updates to utab, etc.).
|
||
|
|
||
|
It is possible to monitor the file through the mnt_monitor_...() API
|
||
|
by a simple access() after any event. No locks are expected in
|
||
|
monitor, making it usable for non-root users without any security
|
||
|
impact. The monitor can ignore events if the file exist.
|
||
|
|
||
|
Addresses: https://issues.redhat.com/browse/RHEL-14612
|
||
|
Upstream: http://github.com/util-linux/util-linux/commit/9218c9678a6aa9b163705364246ed128e94fabb7
|
||
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
||
|
---
|
||
|
libmount/src/context.c | 7 +++
|
||
|
libmount/src/mountP.h | 2 +
|
||
|
libmount/src/tab_update.c | 109 ++++++++++++++++++++++++++++++++++++++
|
||
|
3 files changed, 118 insertions(+)
|
||
|
|
||
|
diff --git a/libmount/src/context.c b/libmount/src/context.c
|
||
|
index 06ac50dc2..27e06a19c 100644
|
||
|
--- a/libmount/src/context.c
|
||
|
+++ b/libmount/src/context.c
|
||
|
@@ -2261,6 +2261,10 @@ int mnt_context_prepare_update(struct libmnt_context *cxt)
|
||
|
rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
|
||
|
NULL, cxt->fs);
|
||
|
|
||
|
+ if (mnt_update_is_ready(cxt->update)) {
|
||
|
+ DBG(CXT, ul_debugobj(cxt, "update is ready"));
|
||
|
+ mnt_update_start(cxt->update);
|
||
|
+ }
|
||
|
return rc < 0 ? rc : 0;
|
||
|
}
|
||
|
|
||
|
@@ -2319,7 +2323,10 @@ int mnt_context_update_tabs(struct libmnt_context *cxt)
|
||
|
emit:
|
||
|
if (rc == 0 && !mnt_context_within_helper(cxt))
|
||
|
mnt_update_emit_event(cxt->update);
|
||
|
+
|
||
|
end:
|
||
|
+ mnt_update_end(cxt->update);
|
||
|
+
|
||
|
if (!mnt_context_switch_ns(cxt, ns_old))
|
||
|
return -MNT_ERR_NAMESPACE;
|
||
|
return rc;
|
||
|
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
|
||
|
index eddc82bde..505d70808 100644
|
||
|
--- a/libmount/src/mountP.h
|
||
|
+++ b/libmount/src/mountP.h
|
||
|
@@ -478,6 +478,8 @@ extern int mnt_update_set_filename(struct libmnt_update *upd,
|
||
|
const char *filename, int userspace_only);
|
||
|
extern int mnt_update_emit_event(struct libmnt_update *upd);
|
||
|
extern int mnt_update_already_done(struct libmnt_update *upd);
|
||
|
+extern int mnt_update_start(struct libmnt_update *upd);
|
||
|
+extern int mnt_update_end(struct libmnt_update *upd);
|
||
|
|
||
|
#if __linux__
|
||
|
/* btrfs.c */
|
||
|
diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
|
||
|
index 25a734e9d..7b088c025 100644
|
||
|
--- a/libmount/src/tab_update.c
|
||
|
+++ b/libmount/src/tab_update.c
|
||
|
@@ -38,6 +38,9 @@ struct libmnt_update {
|
||
|
unsigned long mountflags;
|
||
|
int userspace_only;
|
||
|
|
||
|
+ int act_fd;
|
||
|
+ char *act_filename;
|
||
|
+
|
||
|
unsigned int ready : 1,
|
||
|
missing_options : 1;
|
||
|
|
||
|
@@ -61,6 +64,7 @@ struct libmnt_update *mnt_new_update(void)
|
||
|
if (!upd)
|
||
|
return NULL;
|
||
|
|
||
|
+ upd->act_fd = -1;
|
||
|
DBG(UPDATE, ul_debugobj(upd, "allocate"));
|
||
|
return upd;
|
||
|
}
|
||
|
@@ -81,8 +85,11 @@ void mnt_free_update(struct libmnt_update *upd)
|
||
|
mnt_unref_lock(upd->lock);
|
||
|
mnt_unref_fs(upd->fs);
|
||
|
mnt_unref_table(upd->mountinfo);
|
||
|
+ if (upd->act_fd >= 0)
|
||
|
+ close(upd->act_fd);
|
||
|
free(upd->target);
|
||
|
free(upd->filename);
|
||
|
+ free(upd->act_filename);
|
||
|
free(upd);
|
||
|
}
|
||
|
|
||
|
@@ -1004,6 +1011,8 @@ int mnt_update_emit_event(struct libmnt_update *upd)
|
||
|
if (asprintf(&filename, "%s.event", upd->filename) <= 0)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
+ DBG(UPDATE, ul_debugobj(upd, "emitting utab event"));
|
||
|
+
|
||
|
fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC,
|
||
|
S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
|
||
|
free(filename);
|
||
|
@@ -1013,6 +1022,106 @@ int mnt_update_emit_event(struct libmnt_update *upd)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Let's use /run/mount/utab.act file to report to libmount monitor that
|
||
|
+ * libmount is working with utab. In this case, the monitor can ignore all
|
||
|
+ * events from kernel until entire mount (with all steps) is done.
|
||
|
+ *
|
||
|
+ * For example mount NFS with x-* options, means
|
||
|
+ * - create utab.act and mark it as used (by LOCK_SH)
|
||
|
+ * - exec /sbin/mount.nfs
|
||
|
+ * - call mount(2) (kernel event on /proc/self/mounts)
|
||
|
+ * - utab update (NFS stuff)
|
||
|
+ * - utab update (add x-* userspace options)
|
||
|
+ * - unlink utab.act (if not use anyone else)
|
||
|
+ * - release event by /run/mount/utab.event
|
||
|
+ *
|
||
|
+ * Note, this is used only when utab is in the game (x-* options).
|
||
|
+ */
|
||
|
+int mnt_update_start(struct libmnt_update *upd)
|
||
|
+{
|
||
|
+ int rc = 0;
|
||
|
+ mode_t oldmask;
|
||
|
+
|
||
|
+ if (!upd || !upd->filename)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ if (!upd->act_filename &&
|
||
|
+ asprintf(&upd->act_filename, "%s.act", upd->filename) <= 0)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ /* Use exclusive lock to avoid some other proces will remove the the
|
||
|
+ * file before it's marked as used by LOCK_SH (below) */
|
||
|
+ rc = update_init_lock(upd, NULL);
|
||
|
+ if (rc)
|
||
|
+ return rc;
|
||
|
+
|
||
|
+ rc = mnt_lock_file(upd->lock);
|
||
|
+ if (rc)
|
||
|
+ return -MNT_ERR_LOCK;
|
||
|
+
|
||
|
+ DBG(UPDATE, ul_debugobj(upd, "creating act file"));
|
||
|
+
|
||
|
+ oldmask = umask(S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
|
||
|
+ upd->act_fd = open(upd->act_filename, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||
|
+ umask(oldmask);
|
||
|
+
|
||
|
+ if (upd->act_fd < 0) {
|
||
|
+ rc = -errno;
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* mark the file as used */
|
||
|
+ rc = flock(upd->act_fd, LOCK_SH);
|
||
|
+ if (rc) {
|
||
|
+ rc = -errno;
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ mnt_unlock_file(upd->lock);
|
||
|
+ return 0;
|
||
|
+fail:
|
||
|
+ DBG(UPDATE, ul_debugobj(upd, "act file failed [rc=%d]", rc));
|
||
|
+ mnt_unlock_file(upd->lock);
|
||
|
+ unlink(upd->act_filename);
|
||
|
+ close(upd->act_fd);
|
||
|
+ upd->act_fd = -1;
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+int mnt_update_end(struct libmnt_update *upd)
|
||
|
+{
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (!upd || upd->act_fd < 0)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(UPDATE, ul_debugobj(upd, "removing act file"));
|
||
|
+
|
||
|
+ /* make sure nobody else will use the file */
|
||
|
+ rc = mnt_lock_file(upd->lock);
|
||
|
+ if (rc)
|
||
|
+ return -MNT_ERR_LOCK;
|
||
|
+
|
||
|
+ /* mark the file as unused */
|
||
|
+ flock(upd->act_fd, LOCK_UN);
|
||
|
+ errno = 0;
|
||
|
+
|
||
|
+ /* check if nobody else need the file (if yes, then the file is under LOCK_SH) )*/
|
||
|
+ if (flock(upd->act_fd, LOCK_EX | LOCK_NB) != 0) {
|
||
|
+ if (errno == EWOULDBLOCK)
|
||
|
+ DBG(UPDATE, ul_debugobj(upd, "act file used, no unlink"));
|
||
|
+ } else {
|
||
|
+ DBG(UPDATE, ul_debugobj(upd, "unlinking act file"));
|
||
|
+ unlink(upd->act_filename);
|
||
|
+ }
|
||
|
+
|
||
|
+ mnt_unlock_file(upd->lock);
|
||
|
+ close(upd->act_fd);
|
||
|
+ upd->act_fd = -1;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
#ifdef TEST_PROGRAM
|
||
|
|
||
|
static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
|
||
|
--
|
||
|
2.43.0
|
||
|
|