Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Apr 2026 18:48:09 +0000
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0faa88f26c23 - main - kern: vfs: add MAC checks for mount/unmount/update
Message-ID:  <69ea6969.47d5a.1dc7dd46@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=0faa88f26c239b19ea543309f2c70384438eae73

commit 0faa88f26c239b19ea543309f2c70384438eae73
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2026-04-23 18:47:09 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-04-23 18:47:09 +0000

    kern: vfs: add MAC checks for mount/unmount/update
    
    The unmount check is straightforward and only really needs the
    struct mount and flags used, in case a MAC policy wants to reject
    force-unmounts or do special handling for FSID-based unmounts.
    
    The mount check offers as much information as I think might be of
    interest to a MAC policy: the vnode to be mounted on, vfsconf, and
    applicable mount options.   XNU also has a later version that just takes
    a struct mount for everything that VFS_MOUNT() has to offer, but my
    draft policy doesn't need any of that.  It also doesn't really need the
    unmount check, but it seems reasonable to add it while I'm here.
    
    The update check similarly passes the flags/options for the operation,
    along with the struct mount and label.
    
    Reviewed by:    kib, olce
    Differential Revision:  https://reviews.freebsd.org/D55601
---
 sys/kern/vfs_mount.c             | 25 +++++++++++++++++++-
 sys/security/mac/mac_framework.h |  7 ++++++
 sys/security/mac/mac_policy.h    | 12 ++++++++++
 sys/security/mac/mac_vfs.c       | 50 ++++++++++++++++++++++++++++++++++++++++
 sys/security/mac_stub/mac_stub.c | 28 ++++++++++++++++++++++
 sys/security/mac_test/mac_test.c | 37 +++++++++++++++++++++++++++++
 6 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 383ccf98c10e..ddc5a1b70887 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -1152,6 +1152,17 @@ vfs_domount_first(
 	error = VOP_GETATTR(vp, &va, td->td_ucred);
 	if (error == 0 && va.va_uid != td->td_ucred->cr_uid)
 		error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN);
+#ifdef MAC
+	/*
+	 * XXX XNU also has a check_mount_late variant, which takes the
+	 * struct mount instead and gives MAC visibility into, e.g.,
+	 * f_mntfromname and other facts.
+	 */
+	if (error == 0) {
+		error = mac_mount_check_mount(td->td_ucred, vp, vfsp,
+		    optlist, fsflags);
+	}
+#endif
 	if (error == 0)
 		error = vinvalbuf(vp, V_SAVE, 0, 0);
 	if (vfsp->vfc_flags & VFCF_FILEMOUNT) {
@@ -1371,6 +1382,12 @@ vfs_domount_update(
 		error = 0;
 		vfs_suser_failed = true;
 	}
+#ifdef MAC
+	if (error == 0) {
+		error = mac_mount_check_update(td->td_ucred, mp, optlist,
+		    fsflags);
+	}
+#endif
 	if (error != 0) {
 		vput(vp);
 		return (error);
@@ -1750,7 +1767,6 @@ kern_unmount(struct thread *td, const char *path, uint64_t flags)
 		if (error)
 			return (error);
 	}
-
 	if (flags & MNT_BYFSID) {
 		fsidbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 		error = copyinstr(path, fsidbuf, MNAMELEN, NULL);
@@ -1818,6 +1834,13 @@ kern_unmount(struct thread *td, const char *path, uint64_t flags)
 		vfs_rel(mp);
 		return (EINVAL);
 	}
+#ifdef MAC
+	error = mac_mount_check_unmount(td->td_ucred, mp, flags);
+	if (error != 0) {
+		vfs_rel(mp);
+		return (error);
+	}
+#endif
 	error = dounmount(mp, flags, td);
 	return (error);
 }
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
index 5e13434e5ecc..09e5c96c7885 100644
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -86,6 +86,7 @@ struct thread;
 struct timespec;
 struct ucred;
 struct vattr;
+struct vfsconf;
 struct vfsoptlist;
 struct vnode;
 struct vop_setlabel_args;
@@ -248,6 +249,12 @@ int	mac_mount_check_stat(struct ucred *cred, struct mount *mp);
 void	mac_mount_create(struct ucred *cred, struct mount *mp);
 void	mac_mount_destroy(struct mount *);
 void	mac_mount_init(struct mount *);
+int	mac_mount_check_mount(struct ucred *cred, struct vnode *vp,
+	    struct vfsconf *, struct vfsoptlist **optlist, uint64_t fsflags);
+int	mac_mount_check_update(struct ucred *cred, struct mount *mp,
+	    struct vfsoptlist **optlist, uint64_t fsflags);
+int	mac_mount_check_unmount(struct ucred *cred, struct mount *mp,
+	    uint64_t flags);
 
 void	mac_netinet_arp_send(struct ifnet *ifp, struct mbuf *m);
 void	mac_netinet_firewall_reply(struct mbuf *mrecv, struct mbuf *msend);
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
index a080d8cc4b8b..03c0ea2f8550 100644
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -101,6 +101,7 @@ struct sysctl_req;
 struct thread;
 struct ucred;
 struct vattr;
+struct vfsconf;
 struct vfsoptlist;
 struct vnode;
 
@@ -295,6 +296,14 @@ typedef void	(*mpo_mount_create_t)(struct ucred *cred, struct mount *mp,
 		    struct label *mplabel);
 typedef void	(*mpo_mount_destroy_label_t)(struct label *label);
 typedef void	(*mpo_mount_init_label_t)(struct label *label);
+typedef int	(*mpo_mount_check_mount_t)(struct ucred *cred, struct vnode *vp,
+		    struct label *vplabel, struct vfsconf *vfsp,
+		    struct vfsoptlist **optlist, uint64_t fsflags);
+typedef int	(*mpo_mount_check_update_t)(struct ucred *cred,
+		    struct mount *mp, struct label *mplabel,
+		    struct vfsoptlist **optlist, uint64_t fsflags);
+typedef int	(*mpo_mount_check_unmount_t)(struct ucred *cred,
+		    struct mount *mp, struct label *mplabel, uint64_t flags);
 
 typedef void	(*mpo_netinet_arp_send_t)(struct ifnet *ifp,
 		    struct label *ifplabel, struct mbuf *m,
@@ -846,6 +855,9 @@ struct mac_policy_ops {
 	mpo_mount_create_t			mpo_mount_create;
 	mpo_mount_destroy_label_t		mpo_mount_destroy_label;
 	mpo_mount_init_label_t			mpo_mount_init_label;
+	mpo_mount_check_mount_t			mpo_mount_check_mount;
+	mpo_mount_check_update_t		mpo_mount_check_update;
+	mpo_mount_check_unmount_t		mpo_mount_check_unmount;
 
 	mpo_netinet_arp_send_t			mpo_netinet_arp_send;
 	mpo_netinet_firewall_reply_t		mpo_netinet_firewall_reply;
diff --git a/sys/security/mac/mac_vfs.c b/sys/security/mac/mac_vfs.c
index dc2bfa7c643b..2b88742c5c8e 100644
--- a/sys/security/mac/mac_vfs.c
+++ b/sys/security/mac/mac_vfs.c
@@ -123,6 +123,56 @@ mac_mount_init(struct mount *mp)
 		mp->mnt_label = NULL;
 }
 
+/*
+ * SDT doesn't have a PROBE7 version anymore, so we just drop the label.
+ */
+MAC_CHECK_PROBE_DEFINE5(mount_check_mount, "struct ucred *",
+    "struct vnode *", "struct vfsconf *",
+    "struct vfsoptlist **", "uint64_t");
+int
+mac_mount_check_mount(struct ucred *cred, struct vnode *vp,
+     struct vfsconf *vfsp, struct vfsoptlist **optlist, uint64_t fsflags)
+{
+	int error;
+
+	MAC_POLICY_CHECK(mount_check_mount, cred, vp, vp->v_label, vfsp,
+	    optlist, fsflags);
+	MAC_CHECK_PROBE5(mount_check_mount, error, cred, vp, vfsp, optlist,
+	    fsflags);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE5(mount_check_update, "struct ucred *",
+    "struct mount *", "struct label *", "struct vfsoptlist **", "uint64_t");
+int
+mac_mount_check_update(struct ucred *cred, struct mount *mp,
+	    struct vfsoptlist **optlist, uint64_t fsflags)
+{
+	int error;
+
+	MAC_POLICY_CHECK(mount_check_update, cred, mp, mp->mnt_label,
+	    optlist, fsflags);
+	MAC_CHECK_PROBE5(mount_check_update, error, cred, mp, mp->mnt_label,
+	    optlist, fsflags);
+
+	return (error);
+}
+
+MAC_CHECK_PROBE_DEFINE4(mount_check_unmount, "struct ucred *",
+    "struct mount *", "struct label *", "uint64_t");
+int
+mac_mount_check_unmount(struct ucred *cred, struct mount *mp, uint64_t flags)
+{
+	int error;
+
+	MAC_POLICY_CHECK(mount_check_unmount, cred, mp, mp->mnt_label, flags);
+	MAC_CHECK_PROBE4(mount_check_unmount, error, cred, mp, mp->mnt_label,
+	    flags);
+
+	return (error);
+}
+
 struct label *
 mac_vnode_label_alloc(void)
 {
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
index 1e1220300259..299950e95ea7 100644
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -574,6 +574,31 @@ stub_mount_create(struct ucred *cred, struct mount *mp,
 
 }
 
+static int
+stub_mount_check_mount(struct ucred *cred, struct vnode *vp,
+    struct label *vplabel, struct vfsconf *vfsconf,
+    struct vfsoptlist **optlist, uint64_t fsflags)
+{
+
+	return (0);
+}
+
+static int
+stub_mount_check_update(struct ucred *cred, struct mount *mp,
+    struct label *mplabel, struct vfsoptlist **optlist, uint64_t fsflags)
+{
+
+	return (0);
+}
+
+static int
+stub_mount_check_unmount(struct ucred *cred, struct mount *mp,
+    struct label *mplabel, uint64_t flags)
+{
+
+	return (0);
+}
+
 static void
 stub_netinet_arp_send(struct ifnet *ifp, struct label *iflpabel,
     struct mbuf *m, struct label *mlabel)
@@ -1864,6 +1889,9 @@ static struct mac_policy_ops stub_ops =
 	.mpo_mount_create = stub_mount_create,
 	.mpo_mount_destroy_label = stub_destroy_label,
 	.mpo_mount_init_label = stub_init_label,
+	.mpo_mount_check_mount = stub_mount_check_mount,
+	.mpo_mount_check_update = stub_mount_check_update,
+	.mpo_mount_check_unmount = stub_mount_check_unmount,
 
 	.mpo_netinet_arp_send = stub_netinet_arp_send,
 	.mpo_netinet_firewall_reply = stub_netinet_firewall_reply,
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
index f16073cfdf72..0879b03bb14f 100644
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -1078,6 +1078,40 @@ test_mount_init_label(struct label *label)
 	COUNTER_INC(mount_init_label);
 }
 
+COUNTER_DECL(mount_check_mount);
+static int
+test_mount_check_mount(struct ucred *cred, struct vnode *vp,
+    struct label *vplabel, struct vfsconf *vfsconf,
+    struct vfsoptlist **optlist, uint64_t fsflags)
+{
+
+	LABEL_CHECK(vplabel, MAGIC_VNODE);
+	COUNTER_INC(mount_check_mount);
+	return (0);
+}
+
+COUNTER_DECL(mount_check_update);
+static int
+test_mount_check_update(struct ucred *cred, struct mount *mp,
+    struct label *mplabel, struct vfsoptlist **optlist, uint64_t fsflags)
+{
+
+	LABEL_CHECK(mplabel, MAGIC_MOUNT);
+	COUNTER_INC(mount_check_update);
+	return (0);
+}
+
+COUNTER_DECL(mount_check_unmount);
+static int
+test_mount_check_unmount(struct ucred *cred, struct mount *mp,
+    struct label *mplabel, uint64_t flags)
+{
+
+	LABEL_CHECK(mplabel, MAGIC_MOUNT);
+	COUNTER_INC(mount_check_unmount);
+	return (0);
+}
+
 COUNTER_DECL(netinet_arp_send);
 static void
 test_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
@@ -3323,6 +3357,9 @@ static struct mac_policy_ops test_ops =
 	.mpo_mount_create = test_mount_create,
 	.mpo_mount_destroy_label = test_mount_destroy_label,
 	.mpo_mount_init_label = test_mount_init_label,
+	.mpo_mount_check_mount = test_mount_check_mount,
+	.mpo_mount_check_update = test_mount_check_update,
+	.mpo_mount_check_unmount = test_mount_check_unmount,
 
 	.mpo_netinet_arp_send = test_netinet_arp_send,
 	.mpo_netinet_fragment = test_netinet_fragment,


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69ea6969.47d5a.1dc7dd46>