From patchwork Thu Jan 23 19:41:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 13948589 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87D201ADC87 for ; Thu, 23 Jan 2025 19:41:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661279; cv=none; b=qWXkbKsIP5yed3dYaG9bevMRFgHKRTbykFAMBdzg/phIVV8i8OYacAecLa1FaJWBRniO35LQv2ZIJgWSYm5d/3wGwPm3S0++OmbjYXABaas0I+um0bKqbAnY3+f6DNO0G8Wa9coVgw6J9b7KiF8a1mHO9U0y3FViYCJcTPjkPmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661279; c=relaxed/simple; bh=R230SQtYU8NxTzAXUlHxyqxePrL9pm9fTS6QMF9HH6E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=FNSfGFRNzerBKySqw2AK9Hnu2s0CSAC1efuT/bfR/PBlFJVRFyE4yzQvd1YedIuwfx9pB2cQehnuzI6B8oVkewcCLBoQjIgXcD2YhmfSRbCSR/XJfZ18YzFaBDh4b44Nbd+ikBYCGsxe9CY91mPCOaFZ4CzCxdeu3GCwJdcaGxI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=eO9AN4oA; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="eO9AN4oA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737661274; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WAOJgc0l44DRSISzpCqPlibXPEkW/cra254VqDqmeYU=; b=eO9AN4oAhK8Y6ih+R8V63W34mu4wiqYXDe2PxyhRsAQyVvpDYOCB2QicvHcg7Jw9yjtZSg 6DNKNXbXls8H8E/RHF5zHyqExQM306LRlU9vL8au7InrWVXvQGN6+7XEoYXsuQYz6i6EIJ 2xgVxMg79IWSzJHJM9cLBb3WPCjquyI= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-317-ZBpM2R-KOeyDlVatrgzQmg-1; Thu, 23 Jan 2025 14:41:13 -0500 X-MC-Unique: ZBpM2R-KOeyDlVatrgzQmg-1 X-Mimecast-MFC-AGG-ID: ZBpM2R-KOeyDlVatrgzQmg Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-436328fcfeeso10651915e9.1 for ; Thu, 23 Jan 2025 11:41:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737661272; x=1738266072; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WAOJgc0l44DRSISzpCqPlibXPEkW/cra254VqDqmeYU=; b=Z9FO/0F055P0o0mJZ05OCva7MQ2ONMpogQsepJKuYI2a3EsLpxWlcWJxCFykFnko63 dlUKquSmFxKVZt2MzIprNREqFRFMQM8ByQ+UapMkjJ9KBUm4orxQtmo++1PoC2pHvpxB QPkT643TIB5ExpRyswhMEEIvEzIRGfKuDWJ/6nRM4NrEXfPj1D0TPDszA3YMYREl93AN MOgsrnHD7YwDB6gwspl++AG+9SVJEL4+HBcbhmQ8YqMcSdnlL4CvOZANiGU0FAxZ262T oC3Re4suu7nr3wRzFdjT99+pt4aHo6y/bkxJ2xaDmaXvFaJ5OFEMPUVBA9RXLnWyO2Id KTGw== X-Forwarded-Encrypted: i=1; AJvYcCVm6NyYaEk495pcBVrcZl6dfMC3O7Kr2PV0PF9Uf4bVKB3SrCkXvdk5sGuDgvtRoBibrxgl9lYiu4/MvY6oFeystneEvXU=@vger.kernel.org X-Gm-Message-State: AOJu0YwUdhZioQZI5QZQDeXc2gQkxHfNJ8WdCY9+yqXjTurKhQX3YE9S rD3cXqm4QbCy7NqrgvqddBJjWfFNKNep6KZDg/U/zFzuIzPdDDpHLyhs5IehVJIM0wQ8oQ9T7Jf jHRaRC4ltV8Fp/jXQgqdkeDNsHLY1z+l3beZ2Qys7cxbFdtOgbsGDmC3rfGdg3A8cPVU7OrWwag == X-Gm-Gg: ASbGncvQyQMmG+GcYiEaqWISWhhVCQsMfRpSj2+mB4gEi6W36f+cj6PJVWNHg8Uom1O 40zw4ujI9MDAqNXdU1wtnvyi4DAIA/2/gYHDqjelV/1HpyI8imo2mb8n0nYt2HxjXUPTMoMxjyv LO2IC3OGH/9etu9+hfalCHnTpN55xywSGz9ohz3t8Vi4+FyQ7oyT/5xOpjfof8s8/PwredVUnxU AfAEqcZR16TSmUXiEqVSf2obYxIE6NWI62Rj+2roV5rIXn/kjjbQU/eyFtRjTj/FIVwtsx9LUIJ aYYE0teRnTqVB7maBbzqgLXU5wuK6wAYfC8NLmFKT1waRQ== X-Received: by 2002:a05:600c:a45:b0:436:faeb:2a0b with SMTP id 5b1f17b1804b1-438913e32bemr271430245e9.15.1737661272090; Thu, 23 Jan 2025 11:41:12 -0800 (PST) X-Google-Smtp-Source: AGHT+IFtFUL4wg7wO1ipjblbwu2sumGjGss/GsywpcGVkDeEYjdEgH3Mv5QbEe+ycxgvIhUTytcQBg== X-Received: by 2002:a05:600c:a45:b0:436:faeb:2a0b with SMTP id 5b1f17b1804b1-438913e32bemr271429985e9.15.1737661271679; Thu, 23 Jan 2025 11:41:11 -0800 (PST) Received: from maszat.piliscsaba.szeredi.hu (91-82-183-41.pool.digikabel.hu. [91.82.183.41]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd507e46sm1687245e9.21.2025.01.23.11.41.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2025 11:41:10 -0800 (PST) From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org Cc: Christian Brauner , Jan Kara , Amir Goldstein , Karel Zak , Lennart Poettering , Ian Kent , Al Viro , linux-security-module@vger.kernel.org, Paul Moore Subject: [PATCH v4 1/4] fsnotify: add mount notification infrastructure Date: Thu, 23 Jan 2025 20:41:04 +0100 Message-ID: <20250123194108.1025273-2-mszeredi@redhat.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250123194108.1025273-1-mszeredi@redhat.com> References: <20250123194108.1025273-1-mszeredi@redhat.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OSAC8PgNJhx9xuXGd92rXeBMJWX5cpcWFr2jMtOepRo_1737661272 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true This is just the plumbing between the event source (fs/namespace.c) and the event consumer (fanotify). In itself it does nothing. Signed-off-by: Miklos Szeredi --- fs/mount.h | 4 +++ fs/notify/fsnotify.c | 47 +++++++++++++++++++++++++++----- fs/notify/fsnotify.h | 11 ++++++++ fs/notify/mark.c | 14 ++++++++-- include/linux/fsnotify.h | 20 ++++++++++++++ include/linux/fsnotify_backend.h | 40 ++++++++++++++++++++++++++- 6 files changed, 125 insertions(+), 11 deletions(-) diff --git a/fs/mount.h b/fs/mount.h index 179f690a0c72..33311ad81042 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -14,6 +14,10 @@ struct mnt_namespace { u64 seq; /* Sequence number to prevent loops */ wait_queue_head_t poll; u64 event; +#ifdef CONFIG_FSNOTIFY + __u32 n_fsnotify_mask; + struct fsnotify_mark_connector __rcu *n_fsnotify_marks; +#endif unsigned int nr_mounts; /* # of mounts in the namespace */ unsigned int pending_mounts; struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */ diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index f976949d2634..2b2c3fd907c7 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -28,6 +28,11 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt) fsnotify_clear_marks_by_mount(mnt); } +void __fsnotify_mntns_delete(struct mnt_namespace *mntns) +{ + fsnotify_clear_marks_by_mntns(mntns); +} + /** * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. * @sb: superblock being unmounted. @@ -402,7 +407,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, file_name, cookie, iter_info); } -static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) +static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector *const *connp) { struct fsnotify_mark_connector *conn; struct hlist_node *node = NULL; @@ -520,14 +525,15 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, { const struct path *path = fsnotify_data_path(data, data_type); struct super_block *sb = fsnotify_data_sb(data, data_type); - struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb); + const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type); + struct fsnotify_sb_info *sbinfo = sb ? fsnotify_sb_info(sb) : NULL; struct fsnotify_iter_info iter_info = {}; struct mount *mnt = NULL; struct inode *inode2 = NULL; struct dentry *moved; int inode2_type; int ret = 0; - __u32 test_mask, marks_mask; + __u32 test_mask, marks_mask = 0; if (path) mnt = real_mount(path->mnt); @@ -560,17 +566,20 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, if ((!sbinfo || !sbinfo->sb_marks) && (!mnt || !mnt->mnt_fsnotify_marks) && (!inode || !inode->i_fsnotify_marks) && - (!inode2 || !inode2->i_fsnotify_marks)) + (!inode2 || !inode2->i_fsnotify_marks) && + (!mnt_data || !mnt_data->ns->n_fsnotify_marks)) return 0; - marks_mask = READ_ONCE(sb->s_fsnotify_mask); + if (sb) + marks_mask |= READ_ONCE(sb->s_fsnotify_mask); if (mnt) marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask); if (inode) marks_mask |= READ_ONCE(inode->i_fsnotify_mask); if (inode2) marks_mask |= READ_ONCE(inode2->i_fsnotify_mask); - + if (mnt_data) + marks_mask |= READ_ONCE(mnt_data->ns->n_fsnotify_mask); /* * If this is a modify event we may need to clear some ignore masks. @@ -600,6 +609,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, iter_info.marks[inode2_type] = fsnotify_first_mark(&inode2->i_fsnotify_marks); } + if (mnt_data) { + iter_info.marks[FSNOTIFY_ITER_TYPE_MNTNS] = + fsnotify_first_mark(&mnt_data->ns->n_fsnotify_marks); + } /* * We need to merge inode/vfsmount/sb mark lists so that e.g. inode mark @@ -623,11 +636,31 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, } EXPORT_SYMBOL_GPL(fsnotify); +void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) +{ + struct fsnotify_mnt data = { + .ns = ns, + .mnt_id = real_mount(mnt)->mnt_id_unique, + }; + + if (WARN_ON_ONCE(!ns)) + return; + + /* + * This is an optimization as well as making sure fsnotify_init() has + * been called. + */ + if (!ns->n_fsnotify_marks) + return; + + fsnotify(mask, &data, FSNOTIFY_EVENT_MNT, NULL, NULL, NULL, 0); +} + static __init int fsnotify_init(void) { int ret; - BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 23); + BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 25); ret = init_srcu_struct(&fsnotify_mark_srcu); if (ret) diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 663759ed6fbc..5950c7a67f41 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h @@ -33,6 +33,12 @@ static inline struct super_block *fsnotify_conn_sb( return conn->obj; } +static inline struct mnt_namespace *fsnotify_conn_mntns( + struct fsnotify_mark_connector *conn) +{ + return conn->obj; +} + static inline struct super_block *fsnotify_object_sb(void *obj, enum fsnotify_obj_type obj_type) { @@ -89,6 +95,11 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) fsnotify_destroy_marks(fsnotify_sb_marks(sb)); } +static inline void fsnotify_clear_marks_by_mntns(struct mnt_namespace *mntns) +{ + fsnotify_destroy_marks(&mntns->n_fsnotify_marks); +} + /* * update the dentry->d_flags of all of inode's children to indicate if inode cares * about events that happen to its children. diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 4981439e6209..798340db69d7 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -107,6 +107,8 @@ static fsnotify_connp_t *fsnotify_object_connp(void *obj, return &real_mount(obj)->mnt_fsnotify_marks; case FSNOTIFY_OBJ_TYPE_SB: return fsnotify_sb_marks(obj); + case FSNOTIFY_OBJ_TYPE_MNTNS: + return &((struct mnt_namespace *)obj)->n_fsnotify_marks; default: return NULL; } @@ -120,6 +122,8 @@ static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn) return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask; else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) return &fsnotify_conn_sb(conn)->s_fsnotify_mask; + else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) + return &fsnotify_conn_mntns(conn)->n_fsnotify_mask; return NULL; } @@ -346,12 +350,15 @@ static void *fsnotify_detach_connector_from_object( fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { fsnotify_conn_sb(conn)->s_fsnotify_mask = 0; + } else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) { + fsnotify_conn_mntns(conn)->n_fsnotify_mask = 0; } rcu_assign_pointer(*connp, NULL); conn->obj = NULL; conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; - fsnotify_update_sb_watchers(sb, conn); + if (sb) + fsnotify_update_sb_watchers(sb, conn); return inode; } @@ -724,7 +731,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj, * Attach the sb info before attaching a connector to any object on sb. * The sb info will remain attached as long as sb lives. */ - if (!fsnotify_sb_info(sb)) { + if (sb && !fsnotify_sb_info(sb)) { err = fsnotify_attach_info_to_sb(sb); if (err) return err; @@ -770,7 +777,8 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj, /* mark should be the last entry. last is the current last entry */ hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); added: - fsnotify_update_sb_watchers(sb, conn); + if (sb) + fsnotify_update_sb_watchers(sb, conn); /* * Since connector is attached to object using cmpxchg() we are * guaranteed that connector initialization is fully visible by anyone diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 278620e063ab..ea998551dd0d 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -255,6 +255,11 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) __fsnotify_vfsmount_delete(mnt); } +static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns) +{ + __fsnotify_mntns_delete(mntns); +} + /* * fsnotify_inoderemove - an inode is going away */ @@ -463,4 +468,19 @@ static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode, NULL, NULL, NULL, 0); } +static inline void fsnotify_mnt_attach(struct mnt_namespace *ns, struct vfsmount *mnt) +{ + fsnotify_mnt(FS_MNT_ATTACH, ns, mnt); +} + +static inline void fsnotify_mnt_detach(struct mnt_namespace *ns, struct vfsmount *mnt) +{ + fsnotify_mnt(FS_MNT_DETACH, ns, mnt); +} + +static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount *mnt) +{ + fsnotify_mnt(FS_MNT_MOVE, ns, mnt); +} + #endif /* _LINUX_FS_NOTIFY_H */ diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 3ecf7768e577..6c3e3a4a7b10 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -56,6 +56,10 @@ #define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ #define FS_OPEN_EXEC_PERM 0x00040000 /* open/exec event in a permission hook */ +#define FS_MNT_ATTACH 0x01000000 /* Mount was attached */ +#define FS_MNT_DETACH 0x02000000 /* Mount was detached */ +#define FS_MNT_MOVE (FS_MNT_ATTACH | FS_MNT_DETACH) + /* * Set on inode mark that cares about things that happen to its children. * Always set for dnotify and inotify. @@ -102,7 +106,7 @@ FS_EVENTS_POSS_ON_CHILD | \ FS_DELETE_SELF | FS_MOVE_SELF | \ FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ - FS_ERROR) + FS_ERROR | FS_MNT_ATTACH | FS_MNT_DETACH) /* Extra flags that may be reported with event or control handling of events */ #define ALL_FSNOTIFY_FLAGS (FS_ISDIR | FS_EVENT_ON_CHILD | FS_DN_MULTISHOT) @@ -288,6 +292,7 @@ enum fsnotify_data_type { FSNOTIFY_EVENT_PATH, FSNOTIFY_EVENT_INODE, FSNOTIFY_EVENT_DENTRY, + FSNOTIFY_EVENT_MNT, FSNOTIFY_EVENT_ERROR, }; @@ -297,6 +302,11 @@ struct fs_error_report { struct super_block *sb; }; +struct fsnotify_mnt { + const struct mnt_namespace *ns; + u64 mnt_id; +}; + static inline struct inode *fsnotify_data_inode(const void *data, int data_type) { switch (data_type) { @@ -354,6 +364,24 @@ static inline struct super_block *fsnotify_data_sb(const void *data, } } +static inline const struct fsnotify_mnt *fsnotify_data_mnt(const void *data, + int data_type) +{ + switch (data_type) { + case FSNOTIFY_EVENT_MNT: + return data; + default: + return NULL; + } +} + +static inline u64 fsnotify_data_mnt_id(const void *data, int data_type) +{ + const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type); + + return mnt_data ? mnt_data->mnt_id : 0; +} + static inline struct fs_error_report *fsnotify_data_error_report( const void *data, int data_type) @@ -379,6 +407,7 @@ enum fsnotify_iter_type { FSNOTIFY_ITER_TYPE_SB, FSNOTIFY_ITER_TYPE_PARENT, FSNOTIFY_ITER_TYPE_INODE2, + FSNOTIFY_ITER_TYPE_MNTNS, FSNOTIFY_ITER_TYPE_COUNT }; @@ -388,6 +417,7 @@ enum fsnotify_obj_type { FSNOTIFY_OBJ_TYPE_INODE, FSNOTIFY_OBJ_TYPE_VFSMOUNT, FSNOTIFY_OBJ_TYPE_SB, + FSNOTIFY_OBJ_TYPE_MNTNS, FSNOTIFY_OBJ_TYPE_COUNT, FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT }; @@ -572,8 +602,10 @@ extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern void fsnotify_sb_delete(struct super_block *sb); +extern void __fsnotify_mntns_delete(struct mnt_namespace *mntns); extern void fsnotify_sb_free(struct super_block *sb); extern u32 fsnotify_get_cookie(void); +extern void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt); static inline __u32 fsnotify_parent_needed_mask(__u32 mask) { @@ -879,6 +911,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) static inline void fsnotify_sb_delete(struct super_block *sb) {} +static inline void __fsnotify_mntns_delete(struct mnt_namespace *mntns) +{} + static inline void fsnotify_sb_free(struct super_block *sb) {} @@ -893,6 +928,9 @@ static inline u32 fsnotify_get_cookie(void) static inline void fsnotify_unmount_inodes(struct super_block *sb) {} +static inline void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) +{} + #endif /* CONFIG_FSNOTIFY */ #endif /* __KERNEL __ */ From patchwork Thu Jan 23 19:41:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 13948588 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 859161B6CF5 for ; Thu, 23 Jan 2025 19:41:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661279; cv=none; b=jbs4OqaBa9pUZPglppgWOr4I8+ZX2EQm9s5YEB9Dmty8KD2D5kndbWYhOikryYVA4TUlR5QNXpGEMUixOOVuw1Gx2VVxjbkCVBgkpXvJjc0QydfPRYzM1QeyCyhIHrXvpPsI4PCc7itu8BCaRlANrbFMMm06t25t+LE2TqZtRGI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661279; c=relaxed/simple; bh=DfvdbrrQ9fbO0Hva6Zd1MCsmhJdquMFinSncN93w4Jo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=KZID57dv6vNcjdSdJpL7MxVl8JyAjHfm26MhD4fcvAhzYS+P3hARZQqfpbWpoVnTjJM/B5BjcSVhpYGgJhRgyn0Sfsq354lFFAxN0syxVvEyWhkmYQL6Safmwl0LY8kUjDG7k1Xc0dRkRVwSlqUZ0N5c4nEaifdb6C4/zAa/dDA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=E4Ix2NUF; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="E4Ix2NUF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737661276; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cNJzcboFi8tAjHl3U9gH4h1OKVqCPBFW2xXRLutD69U=; b=E4Ix2NUF/7FAcJIhw3rsNepwE3u06wCADn6VC9TS9Tu+2Cmq1qCzJSHSF+Bzr9xqhGy2Ru WSj3yKktwMDySyeAdLySx91geAjWYkiMOUpSu1EMKmv/xrGaYsxR0wAem0jGYQ9Cuxwaxw HhIjM6UupG95b7dJTIUgt9G1+KtVU3Q= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-139-YNd_l-EdNNaSA8wVj_zNTg-1; Thu, 23 Jan 2025 14:41:15 -0500 X-MC-Unique: YNd_l-EdNNaSA8wVj_zNTg-1 X-Mimecast-MFC-AGG-ID: YNd_l-EdNNaSA8wVj_zNTg Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4361ecebc5bso6550835e9.1 for ; Thu, 23 Jan 2025 11:41:15 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737661274; x=1738266074; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=cNJzcboFi8tAjHl3U9gH4h1OKVqCPBFW2xXRLutD69U=; b=Y71b7wYJnPb/O/Y3h8Rc412MLvHihXXYou60BgJwxhh5V9VCV00GWJpxape5esBUc8 0Gdf8tCx9+PYSUI2xqkptJ+EHRrhgdZJq1Su0GlfCvZ8ZuBeed2FsgpU8EBV4hdeGLC+ ZwzgQO9jRIKncS9BQzqZr6d3F1OPEAvxzcNBvZMc5ukTU9c0cS6fLsTnoARTeQ88XmdB K6ikxjCZpfIgudE4d9Sq9Pgt3yLCIOf4i1qFfdlkfElm32w85SsQQGDlSDgnNzWIvSSD cHb19vVJxUAoL7/yNTEoLe7dq+hs3O6tBqLa7K+tRwhWynI43NmnOO7xXQoU1KH6KLtw uCYg== X-Forwarded-Encrypted: i=1; AJvYcCXzY652s2VwbebY8OHhFWKGpUeqAAK9c0t8/CeyFSTaCxXFe5CN+yDIv4DyRHpHOsFciOaweEwI4RrTdQQViWUCIaI5dXA=@vger.kernel.org X-Gm-Message-State: AOJu0Yy8kjALYFhRrNo2/7oa7HYsfdzySw3T9X/1fUCYTlmZAj5whZKS kpH9ym8XKj7iIXPfUl6BjLtWBK9LykbEHlwn2WpG+NT+YVKyAZEAoyMYI74mwy7VuGCqxPpM2Ie ce3FjYCLDObRW9vyi4zkGXiWKsP4No1wQuLDQVXPSTuVVNnwZyJay8PDcWM3UYrhkIHPeU1HLbg == X-Gm-Gg: ASbGnctQOqfETQ2QSfIvRUtSMXQ8v7xfej+ud/taOmCf/Zqw/fR4lXFq2ZGoduVqPov egcwZJvykzy5vPuuUawlRvcXEmtJc9RvNwk1OiJP7xCnqkVfJVJIEd+rYWAuOooVqN1a2MlSSsE 3aG2LQMq5heHEyaVgqNKRFi3fJLChj8A7QGQhqlY1qqpZgpzxF+/z7can5MCdxsi4hk/0f+KSJM y/mKkY6a5j2uqlJLq2GHTY+1jE5+eiw979pk5agC2/nBBe0utl+0pD0MASIJXzm9M5rXpkm7P/5 VNHQKbsM2EXl9pEbs1PUm1Yu+ZAJZJovm6qb5QlhiBATHA== X-Received: by 2002:a05:600c:5486:b0:436:51bb:7a52 with SMTP id 5b1f17b1804b1-438913c9c93mr260605265e9.7.1737661273880; Thu, 23 Jan 2025 11:41:13 -0800 (PST) X-Google-Smtp-Source: AGHT+IHLdoXm1SKIaw9/8givwSMtRJtQqPs51AUr5H2G/tZgOfq7K/GN6CRsG5PLb0gQxamJ8cbVjg== X-Received: by 2002:a05:600c:5486:b0:436:51bb:7a52 with SMTP id 5b1f17b1804b1-438913c9c93mr260605015e9.7.1737661273452; Thu, 23 Jan 2025 11:41:13 -0800 (PST) Received: from maszat.piliscsaba.szeredi.hu (91-82-183-41.pool.digikabel.hu. [91.82.183.41]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd507e46sm1687245e9.21.2025.01.23.11.41.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2025 11:41:12 -0800 (PST) From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org Cc: Christian Brauner , Jan Kara , Amir Goldstein , Karel Zak , Lennart Poettering , Ian Kent , Al Viro , linux-security-module@vger.kernel.org, Paul Moore Subject: [PATCH v4 2/4] fanotify: notify on mount attach and detach Date: Thu, 23 Jan 2025 20:41:05 +0100 Message-ID: <20250123194108.1025273-3-mszeredi@redhat.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250123194108.1025273-1-mszeredi@redhat.com> References: <20250123194108.1025273-1-mszeredi@redhat.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: HbrGD3S_tOFBSHaKmcv1kfrH3YjdW9ON2FT7McYEgD4_1737661274 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true Add notifications for attaching and detaching mounts. The following new event masks are added: FAN_MNT_ATTACH - Mount was attached FAN_MNT_DETACH - Mount was detached If a mount is moved, then the event is reported with (FAN_MNT_ATTACH | FAN_MNT_DETACH). These events add an info record of type FAN_EVENT_INFO_TYPE_MNT containing these fields identifying the affected mounts: __u64 mnt_id - the ID of the mount (see statmount(2)) FAN_REPORT_MNT must be supplied to fanotify_init() to receive these events and no other type of event can be received with this report type. Marks are added with FAN_MARK_MNTNS, which records the mount namespace from an nsfs file (e.g. /proc/self/ns/mnt). Signed-off-by: Miklos Szeredi --- fs/mount.h | 2 + fs/namespace.c | 14 +++-- fs/notify/fanotify/fanotify.c | 38 +++++++++++-- fs/notify/fanotify/fanotify.h | 18 +++++++ fs/notify/fanotify/fanotify_user.c | 86 +++++++++++++++++++++++++----- fs/notify/fdinfo.c | 5 ++ include/linux/fanotify.h | 12 +++-- include/uapi/linux/fanotify.h | 10 ++++ security/selinux/hooks.c | 4 ++ 9 files changed, 166 insertions(+), 23 deletions(-) diff --git a/fs/mount.h b/fs/mount.h index 33311ad81042..9689e7bf4501 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -174,3 +174,5 @@ static inline struct mnt_namespace *to_mnt_ns(struct ns_common *ns) { return container_of(ns, struct mnt_namespace, ns); } + +struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry); diff --git a/fs/namespace.c b/fs/namespace.c index eac057e56948..4d9072fd1263 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2101,16 +2101,24 @@ struct mnt_namespace *__lookup_next_mnt_ns(struct mnt_namespace *mntns, bool pre } } +struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry) +{ + if (!is_mnt_ns_file(dentry)) + return NULL; + + return to_mnt_ns(get_proc_ns(dentry->d_inode)); +} + static bool mnt_ns_loop(struct dentry *dentry) { /* Could bind mounting the mount namespace inode cause a * mount namespace loop? */ - struct mnt_namespace *mnt_ns; - if (!is_mnt_ns_file(dentry)) + struct mnt_namespace *mnt_ns = mnt_ns_from_dentry(dentry); + + if (!mnt_ns) return false; - mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)); return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; } diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 24c7c5df4998..b1937f92f105 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -166,6 +166,8 @@ static bool fanotify_should_merge(struct fanotify_event *old, case FANOTIFY_EVENT_TYPE_FS_ERROR: return fanotify_error_event_equal(FANOTIFY_EE(old), FANOTIFY_EE(new)); + case FANOTIFY_EVENT_TYPE_MNT: + return false; default: WARN_ON_ONCE(1); } @@ -303,7 +305,10 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n", __func__, iter_info->report_mask, event_mask, data, data_type); - if (!fid_mode) { + if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) { + if (data_type != FSNOTIFY_EVENT_MNT) + return 0; + } else if (!fid_mode) { /* Do we have path to open a file descriptor? */ if (!path) return 0; @@ -548,6 +553,20 @@ static struct fanotify_event *fanotify_alloc_path_event(const struct path *path, return &pevent->fae; } +static struct fanotify_event *fanotify_alloc_mnt_event(u64 mnt_id, gfp_t gfp) +{ + struct fanotify_mnt_event *pevent; + + pevent = kmem_cache_alloc(fanotify_mnt_event_cachep, gfp); + if (!pevent) + return NULL; + + pevent->fae.type = FANOTIFY_EVENT_TYPE_MNT; + pevent->mnt_id = mnt_id; + + return &pevent->fae; +} + static struct fanotify_event *fanotify_alloc_perm_event(const struct path *path, gfp_t gfp) { @@ -715,6 +734,7 @@ static struct fanotify_event *fanotify_alloc_event( fid_mode); struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); const struct path *path = fsnotify_data_path(data, data_type); + u64 mnt_id = fsnotify_data_mnt_id(data, data_type); struct mem_cgroup *old_memcg; struct dentry *moved = NULL; struct inode *child = NULL; @@ -810,8 +830,12 @@ static struct fanotify_event *fanotify_alloc_event( moved, &hash, gfp); } else if (fid_mode) { event = fanotify_alloc_fid_event(id, fsid, &hash, gfp); - } else { + } else if (path) { event = fanotify_alloc_path_event(path, &hash, gfp); + } else if (mnt_id) { + event = fanotify_alloc_mnt_event(mnt_id, gfp); + } else { + WARN_ON_ONCE(1); } if (!event) @@ -910,7 +934,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); BUILD_BUG_ON(FAN_RENAME != FS_RENAME); - BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 21); + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 23); mask = fanotify_group_event_mask(group, iter_info, &match_mask, mask, data, data_type, dir); @@ -1011,6 +1035,11 @@ static void fanotify_free_error_event(struct fsnotify_group *group, mempool_free(fee, &group->fanotify_data.error_events_pool); } +static void fanotify_free_mnt_event(struct fanotify_event *event) +{ + kmem_cache_free(fanotify_mnt_event_cachep, FANOTIFY_ME(event)); +} + static void fanotify_free_event(struct fsnotify_group *group, struct fsnotify_event *fsn_event) { @@ -1037,6 +1066,9 @@ static void fanotify_free_event(struct fsnotify_group *group, case FANOTIFY_EVENT_TYPE_FS_ERROR: fanotify_free_error_event(group, event); break; + case FANOTIFY_EVENT_TYPE_MNT: + fanotify_free_mnt_event(event); + break; default: WARN_ON_ONCE(1); } diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index e5ab33cae6a7..f1a7cbedc9e3 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -9,6 +9,7 @@ extern struct kmem_cache *fanotify_mark_cache; extern struct kmem_cache *fanotify_fid_event_cachep; extern struct kmem_cache *fanotify_path_event_cachep; extern struct kmem_cache *fanotify_perm_event_cachep; +extern struct kmem_cache *fanotify_mnt_event_cachep; /* Possible states of the permission event */ enum { @@ -244,6 +245,7 @@ enum fanotify_event_type { FANOTIFY_EVENT_TYPE_PATH_PERM, FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */ + FANOTIFY_EVENT_TYPE_MNT, __FANOTIFY_EVENT_TYPE_NUM }; @@ -409,12 +411,23 @@ struct fanotify_path_event { struct path path; }; +struct fanotify_mnt_event { + struct fanotify_event fae; + u64 mnt_id; +}; + static inline struct fanotify_path_event * FANOTIFY_PE(struct fanotify_event *event) { return container_of(event, struct fanotify_path_event, fae); } +static inline struct fanotify_mnt_event * +FANOTIFY_ME(struct fanotify_event *event) +{ + return container_of(event, struct fanotify_mnt_event, fae); +} + /* * Structure for permission fanotify events. It gets allocated and freed in * fanotify_handle_event() since we wait there for user response. When the @@ -456,6 +469,11 @@ static inline bool fanotify_is_error_event(u32 mask) return mask & FAN_FS_ERROR; } +static inline bool fanotify_is_mnt_event(u32 mask) +{ + return mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH); +} + static inline const struct path *fanotify_event_path(struct fanotify_event *event) { if (event->type == FANOTIFY_EVENT_TYPE_PATH) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 2d85c71717d6..da97eb01e2fa 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -114,6 +114,7 @@ struct kmem_cache *fanotify_mark_cache __ro_after_init; struct kmem_cache *fanotify_fid_event_cachep __ro_after_init; struct kmem_cache *fanotify_path_event_cachep __ro_after_init; struct kmem_cache *fanotify_perm_event_cachep __ro_after_init; +struct kmem_cache *fanotify_mnt_event_cachep __ro_after_init; #define FANOTIFY_EVENT_ALIGN 4 #define FANOTIFY_FID_INFO_HDR_LEN \ @@ -122,6 +123,8 @@ struct kmem_cache *fanotify_perm_event_cachep __ro_after_init; sizeof(struct fanotify_event_info_pidfd) #define FANOTIFY_ERROR_INFO_LEN \ (sizeof(struct fanotify_event_info_error)) +#define FANOTIFY_MNT_INFO_LEN \ + (sizeof(struct fanotify_event_info_mnt)) static int fanotify_fid_info_len(int fh_len, int name_len) { @@ -183,6 +186,8 @@ static size_t fanotify_event_len(unsigned int info_mode, fh_len = fanotify_event_object_fh_len(event); event_len += fanotify_fid_info_len(fh_len, dot_len); } + if (fanotify_is_mnt_event(event->mask)) + event_len += FANOTIFY_MNT_INFO_LEN; return event_len; } @@ -380,6 +385,25 @@ static int process_access_response(struct fsnotify_group *group, return -ENOENT; } +static size_t copy_mnt_info_to_user(struct fanotify_event *event, + char __user *buf, int count) +{ + struct fanotify_event_info_mnt info = { }; + + info.hdr.info_type = FAN_EVENT_INFO_TYPE_MNT; + info.hdr.len = FANOTIFY_MNT_INFO_LEN; + + if (WARN_ON(count < info.hdr.len)) + return -EFAULT; + + info.mnt_id = FANOTIFY_ME(event)->mnt_id; + + if (copy_to_user(buf, &info, sizeof(info))) + return -EFAULT; + + return info.hdr.len; +} + static size_t copy_error_info_to_user(struct fanotify_event *event, char __user *buf, int count) { @@ -642,6 +666,14 @@ static int copy_info_records_to_user(struct fanotify_event *event, total_bytes += ret; } + if (fanotify_is_mnt_event(event->mask)) { + ret = copy_mnt_info_to_user(event, buf, count); + if (ret < 0) + return ret; + buf += ret; + count -= ret; + total_bytes += ret; + } return total_bytes; } @@ -1446,6 +1478,14 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) if ((flags & FAN_REPORT_PIDFD) && (flags & FAN_REPORT_TID)) return -EINVAL; + /* Don't allow mixing mnt events with inode events for now */ + if (flags & FAN_REPORT_MNT) { + if (class != FAN_CLASS_NOTIF) + return -EINVAL; + if (flags & (FANOTIFY_FID_BITS | FAN_REPORT_FD_ERROR)) + return -EINVAL; + } + if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS) return -EINVAL; @@ -1685,7 +1725,6 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, int dfd, const char __user *pathname) { struct inode *inode = NULL; - struct vfsmount *mnt = NULL; struct fsnotify_group *group; struct path path; struct fan_fsid __fsid, *fsid = NULL; @@ -1718,6 +1757,9 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, case FAN_MARK_FILESYSTEM: obj_type = FSNOTIFY_OBJ_TYPE_SB; break; + case FAN_MARK_MNTNS: + obj_type = FSNOTIFY_OBJ_TYPE_MNTNS; + break; default: return -EINVAL; } @@ -1765,6 +1807,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, return -EINVAL; group = fd_file(f)->private_data; + /* Only report mount events on mnt namespace */ + if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) { + if (mask & ~FANOTIFY_MOUNT_EVENTS) + return -EINVAL; + if (mark_type != FAN_MARK_MNTNS) + return -EINVAL; + } else { + if (mask & FANOTIFY_MOUNT_EVENTS) + return -EINVAL; + if (mark_type == FAN_MARK_MNTNS) + return -EINVAL; + } + /* * An unprivileged user is not allowed to setup mount nor filesystem * marks. This also includes setting up such marks by a group that @@ -1802,7 +1857,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, * point. */ fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); - if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_EVENT_FLAGS) && + if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_MOUNT_EVENTS|FANOTIFY_EVENT_FLAGS) && (!fid_mode || mark_type == FAN_MARK_MOUNT)) return -EINVAL; @@ -1848,17 +1903,21 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, } /* inode held in place by reference to path; group by fget on fd */ - if (mark_type == FAN_MARK_INODE) { + if (obj_type == FSNOTIFY_OBJ_TYPE_INODE) { inode = path.dentry->d_inode; obj = inode; - } else { - mnt = path.mnt; - if (mark_type == FAN_MARK_MOUNT) - obj = mnt; - else - obj = mnt->mnt_sb; + } else if (obj_type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { + obj = path.mnt; + } else if (obj_type == FSNOTIFY_OBJ_TYPE_SB) { + obj = path.mnt->mnt_sb; + } else if (obj_type == FSNOTIFY_OBJ_TYPE_MNTNS) { + obj = mnt_ns_from_dentry(path.dentry); } + ret = -EINVAL; + if (!obj) + goto path_put_and_out; + /* * If some other task has this inode open for write we should not add * an ignore mask, unless that ignore mask is supposed to survive @@ -1866,10 +1925,10 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, */ if (mark_cmd == FAN_MARK_ADD && (flags & FANOTIFY_MARK_IGNORE_BITS) && !(flags & FAN_MARK_IGNORED_SURV_MODIFY)) { - ret = mnt ? -EINVAL : -EISDIR; + ret = !inode ? -EINVAL : -EISDIR; /* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */ if (ignore == FAN_MARK_IGNORE && - (mnt || S_ISDIR(inode->i_mode))) + (!inode || S_ISDIR(inode->i_mode))) goto path_put_and_out; ret = 0; @@ -1878,7 +1937,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, } /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ - if (mnt || !S_ISDIR(inode->i_mode)) { + if (!inode || !S_ISDIR(inode->i_mode)) { mask &= ~FAN_EVENT_ON_CHILD; umask = FAN_EVENT_ON_CHILD; /* @@ -1952,7 +2011,7 @@ static int __init fanotify_user_setup(void) FANOTIFY_DEFAULT_MAX_USER_MARKS); BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 13); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 14); BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11); fanotify_mark_cache = KMEM_CACHE(fanotify_mark, @@ -1965,6 +2024,7 @@ static int __init fanotify_user_setup(void) fanotify_perm_event_cachep = KMEM_CACHE(fanotify_perm_event, SLAB_PANIC); } + fanotify_mnt_event_cachep = KMEM_CACHE(fanotify_mnt_event, SLAB_PANIC); fanotify_max_queued_events = FANOTIFY_DEFAULT_MAX_EVENTS; init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS] = diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index e933f9c65d90..1161eabf11ee 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c @@ -121,6 +121,11 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n", sb->s_dev, mflags, mark->mask, mark->ignore_mask); + } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_MNTNS) { + struct mnt_namespace *mnt_ns = fsnotify_conn_mntns(mark->connector); + + seq_printf(m, "fanotify mnt_ns:%u mflags:%x mask:%x ignored_mask:%x\n", + mnt_ns->ns.inum, mflags, mark->mask, mark->ignore_mask); } } diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index 89ff45bd6f01..fc142be2542d 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -25,7 +25,7 @@ #define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET) -#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD) +#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD | FAN_REPORT_MNT) /* * fanotify_init() flags that require CAP_SYS_ADMIN. @@ -38,7 +38,8 @@ FAN_REPORT_PIDFD | \ FAN_REPORT_FD_ERROR | \ FAN_UNLIMITED_QUEUE | \ - FAN_UNLIMITED_MARKS) + FAN_UNLIMITED_MARKS | \ + FAN_REPORT_MNT) /* * fanotify_init() flags that are allowed for user without CAP_SYS_ADMIN. @@ -58,7 +59,7 @@ #define FANOTIFY_INTERNAL_GROUP_FLAGS (FANOTIFY_UNPRIV) #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ - FAN_MARK_FILESYSTEM) + FAN_MARK_FILESYSTEM | FAN_MARK_MNTNS) #define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \ FAN_MARK_FLUSH) @@ -99,10 +100,13 @@ /* Events that can only be reported with data type FSNOTIFY_EVENT_ERROR */ #define FANOTIFY_ERROR_EVENTS (FAN_FS_ERROR) +#define FANOTIFY_MOUNT_EVENTS (FAN_MNT_ATTACH | FAN_MNT_DETACH) + /* Events that user can request to be notified on */ #define FANOTIFY_EVENTS (FANOTIFY_PATH_EVENTS | \ FANOTIFY_INODE_EVENTS | \ - FANOTIFY_ERROR_EVENTS) + FANOTIFY_ERROR_EVENTS | \ + FANOTIFY_MOUNT_EVENTS) /* Events that require a permission response from user */ #define FANOTIFY_PERM_EVENTS (FAN_OPEN_PERM | FAN_ACCESS_PERM | \ diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index 34f221d3a1b9..69340e483ae7 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -25,6 +25,8 @@ #define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ #define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ #define FAN_OPEN_EXEC_PERM 0x00040000 /* File open/exec in perm check */ +#define FAN_MNT_ATTACH 0x01000000 /* Mount was attached */ +#define FAN_MNT_DETACH 0x02000000 /* Mount was detached */ #define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */ @@ -61,6 +63,7 @@ #define FAN_REPORT_NAME 0x00000800 /* Report events with name */ #define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */ #define FAN_REPORT_FD_ERROR 0x00002000 /* event->fd can report error */ +#define FAN_REPORT_MNT 0x00004000 /* Report mount events */ /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) @@ -91,6 +94,7 @@ #define FAN_MARK_INODE 0x00000000 #define FAN_MARK_MOUNT 0x00000010 #define FAN_MARK_FILESYSTEM 0x00000100 +#define FAN_MARK_MNTNS 0x00000110 /* * Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY @@ -143,6 +147,7 @@ struct fanotify_event_metadata { #define FAN_EVENT_INFO_TYPE_DFID 3 #define FAN_EVENT_INFO_TYPE_PIDFD 4 #define FAN_EVENT_INFO_TYPE_ERROR 5 +#define FAN_EVENT_INFO_TYPE_MNT 6 /* Special info types for FAN_RENAME */ #define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10 @@ -189,6 +194,11 @@ struct fanotify_event_info_error { __u32 error_count; }; +struct fanotify_event_info_mnt { + struct fanotify_event_info_header hdr; + __u64 mnt_id; +}; + /* * User space may need to record additional information about its decision. * The extra information type records what kind of information is included. diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 171dd7fceac5..d2b3e60e2be9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3395,6 +3395,10 @@ static int selinux_path_notify(const struct path *path, u64 mask, case FSNOTIFY_OBJ_TYPE_INODE: perm = FILE__WATCH; break; + case FSNOTIFY_OBJ_TYPE_MNTNS: + /* FIXME: Is this correct??? */ + perm = FILE__WATCH; + break; default: return -EINVAL; } From patchwork Thu Jan 23 19:41:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 13948590 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C5BD1ADC77 for ; Thu, 23 Jan 2025 19:41:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661280; cv=none; b=N4ymLEuaSgQIQULX5a/Loxrt4rAMz/qUjJPDn8vXlbuAYGLj5W2EUdd5ganeT6divwlAYRPhLip/2fGf0uD4A3jXG2TSPk/O4r2V90TnSZDh/Y4sw9pQZqnqD3KnaaWoTiEOvErOrrMAv4eRvahHgm267cxc3CHguhm9s6DA/SQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661280; c=relaxed/simple; bh=GIF+fk9IobFSfNhuFhApJTMzkrK12SVgNFfAKA+iy3w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=B9LieCl2BpNHudISQ5x2rR2VFoBaOASB7l8mjffuNhYRPWHw9fVEbQHT+7CCfyQ5YBTFfx3rGVTj3H4AAChPlrjiQyi8SZ8t9IXkajC6GNjgSnK7e2a4jEyDpusDAsR/QU72dk2J9HpmwHkFhEfB8iam8oN0ZjsMg1d4OPk0Lew= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ao0g4cmf; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ao0g4cmf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737661277; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+V+IxkaybUSMW2r1YO28wGSsGSHInaXvUKJ337QNsU4=; b=ao0g4cmfD115ZEl+DWrVxUZisDK5FEe7TbRWBtAPXrrEkEkNrWCyphU9LbooTzlsIKjQiZ 1oTq+PLjDbx6M56Rp6e19vwUu1Zp/uWutSD+rkZNAdENUHpeUapXbQXF77OZgA+SMUM4Sm o9a6YB+NLmU0hjYoqEHPpHoVe0K20uc= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-672-2k4cmDUyN8aD4G5nESB2Fg-1; Thu, 23 Jan 2025 14:41:16 -0500 X-MC-Unique: 2k4cmDUyN8aD4G5nESB2Fg-1 X-Mimecast-MFC-AGG-ID: 2k4cmDUyN8aD4G5nESB2Fg Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-3862f3ccf4fso531682f8f.0 for ; Thu, 23 Jan 2025 11:41:15 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737661275; x=1738266075; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+V+IxkaybUSMW2r1YO28wGSsGSHInaXvUKJ337QNsU4=; b=OSgl0Vh6Hmk16OM4q+Vos0F3WTVS/kQyrWow5T+ktczpcdZMKuZFBB3ujf+Kuq83EL juFSSx/sZXpVN5TsMbgHxEaJekkfbYkRiqezTgG0Xyu9mmj08Q/39V85VT3L5vImWdfV CEtlCV6lXjq7y+mTrd7e4W66/NC98t7bQUocwz85hPW5kElrCsWFBuSu+1/13emb1Glu fIsYZDwU/m5rxbIvyij4NT6rbQyRYS38awlChgIDdaDzUWWSny5HhKkSuDcfiPDOul9V PSCpnYFgKmd12NJwEWzs3BqszD5o5I808x3J/NqKTQ+0Wm/t8xfg2VVamvERxhmeFISs 5d6w== X-Forwarded-Encrypted: i=1; AJvYcCXeu04ij6JpcYh5OzuaL9XeF/RHQ3Z4pWmaoMEIeUByQz2b67ZQJY7apLPfHd8JVulKLqMu57PnHCEBAqy/7URZfZ5L6vM=@vger.kernel.org X-Gm-Message-State: AOJu0YzqH5FvOL10mOr0T7HtNcstI96NYcDKuGbS3sQ3O2hMhUU2AhxX aBHuaZ8xXTcJnbpQoMJJm75SDIuJNpcnfhazz960f6HKcdj825gN1+gPdKAAZ1uJJqaEcKdd/NR +PYXy0kPCZukXtc57hHl586EQ7IVomxER3XFpO323C9oVHzgeVyFUzhYMIKtmriNLf6QF13Do/Q == X-Gm-Gg: ASbGncvONi+QEDYfdU92gczAC5MN3isKErHz6vNoPBCXzxi9s02O0YITt6cVhvR1vTW Fhc1S+HqQRHYQvM1vCaIfCIpY6d9Ey6e821IJiTpGbtrysIF6nYomE0NFYmLQnididYuGlUXhjM smLeqFTpw8izYCWhXxaKiyXKrenbiFJqhFJwarus6DVY/fb/MGqEkmVIfsHjkQ7SP+LER5z5GZ2 BBqbrkh4AdvxW+fMSeklnBlKH20uuhtTJoHlNjI4CnVbCHQliKFw/OHmMTpEu7VLyEIPHKEwtaa qXg/sKovHgThMAsV0NErxvcJvS1mR/cfSvhpzT3SbiJ2Kg== X-Received: by 2002:a5d:5f54:0:b0:38a:4184:151a with SMTP id ffacd0b85a97d-38bf57a662bmr23000428f8f.37.1737661274810; Thu, 23 Jan 2025 11:41:14 -0800 (PST) X-Google-Smtp-Source: AGHT+IF6bvb2a3XGHOGcH/RcOdmYEOAisg6ahNrkQ9wKfU4H2gSMzXslaNmQdhwD6k+hdMTBdlXNDw== X-Received: by 2002:a5d:5f54:0:b0:38a:4184:151a with SMTP id ffacd0b85a97d-38bf57a662bmr23000397f8f.37.1737661274407; Thu, 23 Jan 2025 11:41:14 -0800 (PST) Received: from maszat.piliscsaba.szeredi.hu (91-82-183-41.pool.digikabel.hu. [91.82.183.41]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd507e46sm1687245e9.21.2025.01.23.11.41.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2025 11:41:14 -0800 (PST) From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org Cc: Christian Brauner , Jan Kara , Amir Goldstein , Karel Zak , Lennart Poettering , Ian Kent , Al Viro , linux-security-module@vger.kernel.org, Paul Moore Subject: [PATCH v4 3/4] vfs: add notifications for mount attach and detach Date: Thu, 23 Jan 2025 20:41:06 +0100 Message-ID: <20250123194108.1025273-4-mszeredi@redhat.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250123194108.1025273-1-mszeredi@redhat.com> References: <20250123194108.1025273-1-mszeredi@redhat.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: CLk8IkDxgsy7wQoOdKDokAKOVgF5uQE5d-NjbduNyzA_1737661275 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true Add notifications for attaching and detaching mounts to fs/namespace.c Signed-off-by: Miklos Szeredi --- fs/mount.h | 20 +++++++++++++ fs/namespace.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++- fs/pnode.c | 4 ++- 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/fs/mount.h b/fs/mount.h index 9689e7bf4501..7dd22a226a6e 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -5,6 +5,8 @@ #include #include +extern struct list_head notify_list; + struct mnt_namespace { struct ns_common ns; struct mount * root; @@ -72,6 +74,8 @@ struct mount { #ifdef CONFIG_FSNOTIFY struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks; __u32 mnt_fsnotify_mask; + struct list_head to_notify; /* need to queue notification */ + struct mnt_namespace *prev_ns; /* previous namespace (NULL if none) */ #endif int mnt_id; /* mount identifier, reused */ u64 mnt_id_unique; /* mount ID unique until reboot */ @@ -175,4 +179,20 @@ static inline struct mnt_namespace *to_mnt_ns(struct ns_common *ns) return container_of(ns, struct mnt_namespace, ns); } +#ifdef CONFIG_FSNOTIFY +static inline void mnt_notify_add(struct mount *m) +{ + /* Optimize the case where there are no watches */ + if ((m->mnt_ns && m->mnt_ns->n_fsnotify_marks) || + (m->prev_ns && m->prev_ns->n_fsnotify_marks)) + list_add_tail(&m->to_notify, ¬ify_list); + else + m->prev_ns = m->mnt_ns; +} +#else +static inline void mnt_notify_add(struct mount *m) +{ +} +#endif + struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry); diff --git a/fs/namespace.c b/fs/namespace.c index 4d9072fd1263..948348a37f6c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -79,6 +79,9 @@ static struct kmem_cache *mnt_cache __ro_after_init; static DECLARE_RWSEM(namespace_sem); static HLIST_HEAD(unmounted); /* protected by namespace_sem */ static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */ +#ifdef CONFIG_FSNOTIFY +LIST_HEAD(notify_list); /* protected by namespace_sem */ +#endif static DEFINE_RWLOCK(mnt_ns_tree_lock); static struct rb_root mnt_ns_tree = RB_ROOT; /* protected by mnt_ns_tree_lock */ @@ -145,6 +148,7 @@ static void mnt_ns_release(struct mnt_namespace *ns) /* keep alive for {list,stat}mount() */ if (refcount_dec_and_test(&ns->passive)) { + fsnotify_mntns_delete(ns); put_user_ns(ns->user_ns); kfree(ns); } @@ -1136,6 +1140,8 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt) } rb_link_node(&mnt->mnt_node, parent, link); rb_insert_color(&mnt->mnt_node, &ns->mounts); + + mnt_notify_add(mnt); } /* @@ -1683,6 +1689,50 @@ int may_umount(struct vfsmount *mnt) EXPORT_SYMBOL(may_umount); +#ifdef CONFIG_FSNOTIFY +static void mnt_notify(struct mount *p) +{ + if (!p->prev_ns && p->mnt_ns) { + fsnotify_mnt_attach(p->mnt_ns, &p->mnt); + } else if (p->prev_ns && !p->mnt_ns) { + fsnotify_mnt_detach(p->prev_ns, &p->mnt); + } else if (p->prev_ns == p->mnt_ns) { + fsnotify_mnt_move(p->mnt_ns, &p->mnt); + } else { + fsnotify_mnt_detach(p->prev_ns, &p->mnt); + fsnotify_mnt_attach(p->mnt_ns, &p->mnt); + } + p->prev_ns = p->mnt_ns; +} + +static void notify_mnt_list(void) +{ + struct mount *m, *tmp; + /* + * Notify about mounts that were added/reparented/detached/remain + * connected after unmount. + */ + list_for_each_entry_safe(m, tmp, ¬ify_list, to_notify) { + mnt_notify(m); + list_del_init(&m->to_notify); + } +} + +static bool need_notify_mnt_list(void) +{ + return !list_empty(¬ify_list); +} +#else +static void notify_mnt_list(void) +{ +} + +static bool need_notify_mnt_list(void) +{ + return false; +} +#endif + static void namespace_unlock(void) { struct hlist_head head; @@ -1693,7 +1743,18 @@ static void namespace_unlock(void) hlist_move_list(&unmounted, &head); list_splice_init(&ex_mountpoints, &list); - up_write(&namespace_sem); + if (need_notify_mnt_list()) { + /* + * No point blocking out concurrent readers while notifications + * are sent. This will also allow statmount()/listmount() to run + * concurrently. + */ + downgrade_write(&namespace_sem); + notify_mnt_list(); + up_read(&namespace_sem); + } else { + up_write(&namespace_sem); + } shrink_dentry_list(&list); @@ -1806,6 +1867,19 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) change_mnt_propagation(p, MS_PRIVATE); if (disconnect) hlist_add_head(&p->mnt_umount, &unmounted); + + /* + * At this point p->mnt_ns is NULL, notification will be queued + * only if + * + * - p->prev_ns is non-NULL *and* + * - p->prev_ns->n_fsnotify_marks is non-NULL + * + * This will preclude queuing the mount if this is a cleanup + * after a failed copy_tree() or destruction of an anonymous + * namespace, etc. + */ + mnt_notify_add(p); } } @@ -2511,6 +2585,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, dest_mp = smp; unhash_mnt(source_mnt); attach_mnt(source_mnt, top_mnt, dest_mp, beneath); + mnt_notify_add(source_mnt); touch_mnt_namespace(source_mnt->mnt_ns); } else { if (source_mnt->mnt_ns) { @@ -4426,6 +4501,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, list_del_init(&new_mnt->mnt_expire); put_mountpoint(root_mp); unlock_mount_hash(); + mnt_notify_add(root_mnt); + mnt_notify_add(new_mnt); chroot_fs_refs(&root, &new); error = 0; out4: diff --git a/fs/pnode.c b/fs/pnode.c index a799e0315cc9..d42b71c3567a 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -549,8 +549,10 @@ static void restore_mounts(struct list_head *to_restore) mp = parent->mnt_mp; parent = parent->mnt_parent; } - if (parent != mnt->mnt_parent) + if (parent != mnt->mnt_parent) { mnt_change_mountpoint(parent, mp, mnt); + mnt_notify_add(mnt); + } } } From patchwork Thu Jan 23 19:41:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 13948591 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C9B0C1B86D5 for ; Thu, 23 Jan 2025 19:41:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661281; cv=none; b=fSxZcqPF/r1R4kJZVUK0SG99NCjQoeRQXsFf6Izjo1znKjLIWjceAbiPKA93jQzeGsz2rzqBV9pPsab1KV7BMEbDCqnbZa23q34D8UszkugxG//x4/MRMxWv97QVQL5WDeQaAlabGwrEJO2hi5DNEVj00PPIiYijlZOG7rSL5bU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737661281; c=relaxed/simple; bh=8Rex1jue2v4oXkNDV+SsESvmvUW9hToBize8zaIzoh0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:content-type; b=Akf6WbE8HaTMDfwNi3aRyyoWgRLddv3mRTq6BoWk31YUcpeMkLWQ/WNLK3bQMmwAr61pwycwz71XC4kcazg4/L24F4aqtRt3Mxl0Lmy48VyeAAOh2rixtbg/sARMHmtvIXAA3EoBbQzs7hZxZwAfU+VJ3x7NzUWSjH7fI7aCVT8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=DbNoBuoA; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="DbNoBuoA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737661279; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lVWBJyMVn3pq9QMtoCCB0cgOGlE9eZyl9LQ5JXqGeCA=; b=DbNoBuoA19mM6XSgTRsoMqpTQxBA5RhzeuwZrlZ9u22tsDVPJjdZk/gmSbQToUjp5+aYk1 lZGib+udR/z46gVEZPqn1bl1scp62bMyKHBtQ8sI5HxGRPxGVWEo15unKQSAlm5V/tEXs4 Ba/pJ8w8d9hCZuWHPrYJHNlVR8j/NCM= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-237-7PmMWVVrO-Kw6MbfHYeYFA-1; Thu, 23 Jan 2025 14:41:17 -0500 X-MC-Unique: 7PmMWVVrO-Kw6MbfHYeYFA-1 X-Mimecast-MFC-AGG-ID: 7PmMWVVrO-Kw6MbfHYeYFA Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-385e00ebb16so499119f8f.3 for ; Thu, 23 Jan 2025 11:41:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737661276; x=1738266076; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lVWBJyMVn3pq9QMtoCCB0cgOGlE9eZyl9LQ5JXqGeCA=; b=Qwoc7trl4oQgAk4ZyVYBshWj1SjCLKxaU1b0g5iYD9lONBiB2vOnMI65kANgQqsa5V jgbHFKZsze9UmAXnrZRupiIXD9RsLNiY9vUf3k0FOkNCXC2MvHTU30WL2Z99RPirNSIP LgNwXaw0ndkA5zDDW8MQ9KQtMCey6HT5i6RA/+0uPfhofG99BTe7j3FM0eWBMkq0YKVk fCGPQw38vpU3Suzw2mBh8ey5JL2ABHTqeAMA0uyYkeLg0sbzB8WhxJWVa2jfw0msWqaW qCjpHp4QM8UmSVBoqodIebT52oD5pWmbrfwB68rHpYCnQC/89IjuKyKhQ1EKHpMXdnfK x81g== X-Forwarded-Encrypted: i=1; AJvYcCUPAVNFwRAfBUt/GQRlLhAV/MI2KwX8rn50Vpt98KfFB7rdW0L6cL3vXVhDJPuecDhipe9JqyOwuI1qV7JdTo00HtmMsnU=@vger.kernel.org X-Gm-Message-State: AOJu0YwRmw/wTKAe3d7NFdS+m6VZnNQmdWY6Td5XnslBa/sKSprN5NuH 3rUhsITj2Yl8w3EmRcWecRzNdWfd8huxOIM8JMu23bA/xjTjWxBUOTILna0JzQrzatw+2+p6UUP bai8LIS8Yr9ubWTwxrxAJiqg+CzUInzpktvoZcWfqO9wCz4Mt4Do5jhef2HieAcVFddDRhiVOuQ == X-Gm-Gg: ASbGnctGc6fK6aZgrkZs5COJS6VgivotdMzupxr6R2n8U9eoAKQ/vvnqC+0QvoctuDD 1csLBEABlpE1xD8ueEB5gVb50gCjIYHbFHhUA8Jagcw9jwwwQIp24llxx+j5oW2yzwhHt7BAzdf lvhGCc2r720Dxyp23XrlAr6TYU3McOATx284JyfpEeugbzNTAllmIFegYukdIOEzCvUh5G+c/65 hogLhtPVwuj3pCkYIxF40LLXaKZpT2PFYfXnKSrHm5TKbOGoittrp+Y/9392r0aPLg1KP6/yVgx VwG8dtAoyVSXAUJWf4VrPRzDDKozwClT8qA7N+97Bj6beg== X-Received: by 2002:a05:6000:1863:b0:385:df2c:91aa with SMTP id ffacd0b85a97d-38bf565579fmr22252053f8f.7.1737661276521; Thu, 23 Jan 2025 11:41:16 -0800 (PST) X-Google-Smtp-Source: AGHT+IGCwYvNPnsOpcrz/YUWLahtCRlJYVF7u4D+kUx15s09iLwHMLIFq/9r+tNumdffqIr6q0gPGA== X-Received: by 2002:a05:6000:1863:b0:385:df2c:91aa with SMTP id ffacd0b85a97d-38bf565579fmr22252032f8f.7.1737661276130; Thu, 23 Jan 2025 11:41:16 -0800 (PST) Received: from maszat.piliscsaba.szeredi.hu (91-82-183-41.pool.digikabel.hu. [91.82.183.41]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd507e46sm1687245e9.21.2025.01.23.11.41.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2025 11:41:15 -0800 (PST) From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org Cc: Christian Brauner , Jan Kara , Amir Goldstein , Karel Zak , Lennart Poettering , Ian Kent , Al Viro , linux-security-module@vger.kernel.org, Paul Moore Subject: [PATCH v4 4/4] vfs: add notifications for mount attribute change Date: Thu, 23 Jan 2025 20:41:07 +0100 Message-ID: <20250123194108.1025273-5-mszeredi@redhat.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250123194108.1025273-1-mszeredi@redhat.com> References: <20250123194108.1025273-1-mszeredi@redhat.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: l7kh4Ik8rqaS3ebFqomKXzs-IjWyWM1PyDwjEuOEGqc_1737661277 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true Notify when mount flags, propagation or idmap changes. Just like attach and detach, no details are given in the notification, only the mount ID. Signed-off-by: Miklos Szeredi --- fs/namespace.c | 27 +++++++++++++++++++++++++++ fs/notify/fanotify/fanotify.c | 2 +- fs/notify/fanotify/fanotify.h | 2 +- fs/notify/fsnotify.c | 2 +- include/linux/fanotify.h | 2 +- include/linux/fsnotify.h | 5 +++++ include/linux/fsnotify_backend.h | 5 ++++- include/uapi/linux/fanotify.h | 1 + 8 files changed, 41 insertions(+), 5 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 948348a37f6c..9b9b13665dce 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2807,6 +2807,9 @@ static int do_change_type(struct path *path, int ms_flags) change_mnt_propagation(m, type); unlock_mount_hash(); + for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) + fsnotify_mnt_change(m->mnt_ns, &m->mnt); + out_unlock: namespace_unlock(); return err; @@ -3089,6 +3092,12 @@ static int do_reconfigure_mnt(struct path *path, unsigned int mnt_flags) unlock_mount_hash(); up_read(&sb->s_umount); + if (!ret) { + down_read(&namespace_sem); + fsnotify_mnt_change(mnt->mnt_ns, &mnt->mnt); + up_read(&namespace_sem); + } + mnt_warn_timestamp_expiry(path, &mnt->mnt); return ret; @@ -3141,6 +3150,13 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags, up_write(&sb->s_umount); } + if (!err) { + down_read(&namespace_sem); + fsnotify_mnt_change(mnt->mnt_ns, &mnt->mnt); + up_read(&namespace_sem); + } + + mnt_warn_timestamp_expiry(path, &mnt->mnt); put_fs_context(fc); @@ -4708,6 +4724,8 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr) return err; } } + } else { + down_read(&namespace_sem); } err = -EINVAL; @@ -4743,10 +4761,19 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr) out: unlock_mount_hash(); + if (!err) { + struct mount *m; + + for (m = mnt; m; m = kattr->recurse ? next_mnt(m, mnt) : NULL) + fsnotify_mnt_change(m->mnt_ns, &m->mnt); + } + if (kattr->propagation) { if (err) cleanup_group_ids(mnt, NULL); namespace_unlock(); + } else { + up_read(&namespace_sem); } return err; diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index b1937f92f105..c7ddd145f3d8 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -934,7 +934,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); BUILD_BUG_ON(FAN_RENAME != FS_RENAME); - BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 23); + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 24); mask = fanotify_group_event_mask(group, iter_info, &match_mask, mask, data, data_type, dir); diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h index f1a7cbedc9e3..8d6289da06f1 100644 --- a/fs/notify/fanotify/fanotify.h +++ b/fs/notify/fanotify/fanotify.h @@ -471,7 +471,7 @@ static inline bool fanotify_is_error_event(u32 mask) static inline bool fanotify_is_mnt_event(u32 mask) { - return mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH); + return mask & FANOTIFY_MOUNT_EVENTS; } static inline const struct path *fanotify_event_path(struct fanotify_event *event) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 2b2c3fd907c7..5872dd27172d 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -660,7 +660,7 @@ static __init int fsnotify_init(void) { int ret; - BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 25); + BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 26); ret = init_srcu_struct(&fsnotify_mark_srcu); if (ret) diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index fc142be2542d..61e112d25303 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -100,7 +100,7 @@ /* Events that can only be reported with data type FSNOTIFY_EVENT_ERROR */ #define FANOTIFY_ERROR_EVENTS (FAN_FS_ERROR) -#define FANOTIFY_MOUNT_EVENTS (FAN_MNT_ATTACH | FAN_MNT_DETACH) +#define FANOTIFY_MOUNT_EVENTS (FAN_MNT_ATTACH | FAN_MNT_DETACH | FAN_MNT_CHANGE) /* Events that user can request to be notified on */ #define FANOTIFY_EVENTS (FANOTIFY_PATH_EVENTS | \ diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index ea998551dd0d..ba3e05c69aaa 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -483,4 +483,9 @@ static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount * fsnotify_mnt(FS_MNT_MOVE, ns, mnt); } +static inline void fsnotify_mnt_change(struct mnt_namespace *ns, struct vfsmount *mnt) +{ + fsnotify_mnt(FS_MNT_CHANGE, ns, mnt); +} + #endif /* _LINUX_FS_NOTIFY_H */ diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 6c3e3a4a7b10..54e01803e309 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -58,6 +58,8 @@ #define FS_MNT_ATTACH 0x01000000 /* Mount was attached */ #define FS_MNT_DETACH 0x02000000 /* Mount was detached */ +#define FS_MNT_CHANGE 0x04000000 /* Mount was changed */ + #define FS_MNT_MOVE (FS_MNT_ATTACH | FS_MNT_DETACH) /* @@ -106,7 +108,8 @@ FS_EVENTS_POSS_ON_CHILD | \ FS_DELETE_SELF | FS_MOVE_SELF | \ FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ - FS_ERROR | FS_MNT_ATTACH | FS_MNT_DETACH) + FS_ERROR | \ + FS_MNT_ATTACH | FS_MNT_DETACH | FS_MNT_CHANGE ) /* Extra flags that may be reported with event or control handling of events */ #define ALL_FSNOTIFY_FLAGS (FS_ISDIR | FS_EVENT_ON_CHILD | FS_DN_MULTISHOT) diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h index 69340e483ae7..256fc5755b45 100644 --- a/include/uapi/linux/fanotify.h +++ b/include/uapi/linux/fanotify.h @@ -27,6 +27,7 @@ #define FAN_OPEN_EXEC_PERM 0x00040000 /* File open/exec in perm check */ #define FAN_MNT_ATTACH 0x01000000 /* Mount was attached */ #define FAN_MNT_DETACH 0x02000000 /* Mount was detached */ +#define FAN_MNT_CHANGE 0x04000000 /* Mount was changed */ #define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */