summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorDaan De Meyer <daan@amutable.com>2026-09-04 16:48:55 +0200
committerPaul Moore <paul@paul-moore.com>2026-09-11 14:15:19 -0400
commit16959c469f232f5c76cfb628297cafbf6dbdba79 (patch)
tree7d255089e7c17a29d83016a0674fbe3608cc41b7 /security
parentcd1f696de880c41ef0983d2c54999384a5cbf393 (diff)
lsm: expose mount idmaps to inode hooks
OverlayFS performs upper-layer operations through inode-based security hooks. Those hooks receive the upper inode and dentry, but not the mount idmap used by the VFS operation. The security layer cannot distinguish an identity-mapped upper from an idmapped one or make the same ownership decision as the VFS. The VFS layer already passes the idmap down into all relevant inode operations so this just brings the security hooks to parity. So pass the mount idmap through the create, link, symlink, mkdir, mknod, and permission hooks. Update the in-tree security implementations and non-VFS callers accordingly. Signed-off-by: Daan De Meyer <daan@amutable.com> Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org> [PM: updated the commit description as discussed on-list] Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security')
-rw-r--r--security/security.c40
-rw-r--r--security/selinux/hooks.c19
-rw-r--r--security/smack/smack_lsm.c9
3 files changed, 43 insertions, 25 deletions
diff --git a/security/security.c b/security/security.c
index ecfb875f0c69..7fa52d39a255 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1628,6 +1628,7 @@ int security_path_chroot(const struct path *path)
/**
* security_inode_create() - Check if creating a file is allowed
+ * @idmap: idmap of the mount
* @dir: the parent directory
* @dentry: the file being created
* @mode: requested file mode
@@ -1636,12 +1637,12 @@ int security_path_chroot(const struct path *path)
*
* Return: Returns 0 if permission is granted.
*/
-int security_inode_create(struct inode *dir, struct dentry *dentry,
- umode_t mode)
+int security_inode_create(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return call_int_hook(inode_create, dir, dentry, mode);
+ return call_int_hook(inode_create, idmap, dir, dentry, mode);
}
EXPORT_SYMBOL_GPL(security_inode_create);
@@ -1662,6 +1663,7 @@ void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
/**
* security_inode_link() - Check if creating a hard link is allowed
+ * @idmap: idmap of the mount
* @old_dentry: existing file
* @dir: new parent directory
* @new_dentry: new link
@@ -1670,12 +1672,12 @@ void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
*
* Return: Returns 0 if permission is granted.
*/
-int security_inode_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *new_dentry)
+int security_inode_link(struct mnt_idmap *idmap, struct dentry *old_dentry,
+ struct inode *dir, struct dentry *new_dentry)
{
if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
return 0;
- return call_int_hook(inode_link, old_dentry, dir, new_dentry);
+ return call_int_hook(inode_link, idmap, old_dentry, dir, new_dentry);
}
/**
@@ -1696,6 +1698,7 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry)
/**
* security_inode_symlink() - Check if creating a symbolic link is allowed
+ * @idmap: idmap of the mount
* @dir: parent directory
* @dentry: symbolic link
* @old_name: existing filename
@@ -1704,16 +1707,17 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry)
*
* Return: Returns 0 if permission is granted.
*/
-int security_inode_symlink(struct inode *dir, struct dentry *dentry,
- const char *old_name)
+int security_inode_symlink(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, const char *old_name)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return call_int_hook(inode_symlink, dir, dentry, old_name);
+ return call_int_hook(inode_symlink, idmap, dir, dentry, old_name);
}
/**
* security_inode_mkdir() - Check if creating a new directory is allowed
+ * @idmap: idmap of the mount
* @dir: parent directory
* @dentry: new directory
* @mode: new directory mode
@@ -1723,11 +1727,12 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
*
* Return: Returns 0 if permission is granted.
*/
-int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int security_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return call_int_hook(inode_mkdir, dir, dentry, mode);
+ return call_int_hook(inode_mkdir, idmap, dir, dentry, mode);
}
EXPORT_SYMBOL_GPL(security_inode_mkdir);
@@ -1749,6 +1754,7 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
/**
* security_inode_mknod() - Check if creating a special file is allowed
+ * @idmap: idmap of the mount
* @dir: parent directory
* @dentry: new file
* @mode: new file mode
@@ -1761,12 +1767,12 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
*
* Return: Returns 0 if permission is granted.
*/
-int security_inode_mknod(struct inode *dir, struct dentry *dentry,
- umode_t mode, dev_t dev)
+int security_inode_mknod(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, umode_t mode, dev_t dev)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return call_int_hook(inode_mknod, dir, dentry, mode, dev);
+ return call_int_hook(inode_mknod, idmap, dir, dentry, mode, dev);
}
/**
@@ -1837,6 +1843,7 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
/**
* security_inode_permission() - Check if accessing an inode is allowed
+ * @idmap: idmap of the mount
* @inode: inode
* @mask: access mask
*
@@ -1849,11 +1856,12 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
*
* Return: Returns 0 if permission is granted.
*/
-int security_inode_permission(struct inode *inode, int mask)
+int security_inode_permission(struct mnt_idmap *idmap, struct inode *inode,
+ int mask)
{
if (unlikely(IS_PRIVATE(inode)))
return 0;
- return call_int_hook(inode_permission, inode, mask);
+ return call_int_hook(inode_permission, idmap, inode, mask);
}
/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 035aaf113d1d..967984d0af30 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3074,12 +3074,14 @@ static int selinux_inode_init_security_anon(struct inode *inode,
&ad);
}
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
+static int selinux_inode_create(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, umode_t mode)
{
return may_create(dir, dentry, SECCLASS_FILE);
}
-static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+static int selinux_inode_link(struct mnt_idmap *idmap, struct dentry *old_dentry,
+ struct inode *dir, struct dentry *new_dentry)
{
return may_link(dir, old_dentry, MAY_LINK);
}
@@ -3089,12 +3091,14 @@ static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
return may_link(dir, dentry, MAY_UNLINK);
}
-static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
+static int selinux_inode_symlink(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, const char *name)
{
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
+static int selinux_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, umode_t mask)
{
return may_create(dir, dentry, SECCLASS_DIR);
}
@@ -3104,7 +3108,8 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
return may_link(dir, dentry, MAY_RMDIR);
}
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+static int selinux_inode_mknod(struct mnt_idmap *idmap, struct inode *dir,
+ struct dentry *dentry, umode_t mode, dev_t dev)
{
return may_create(dir, dentry, inode_mode_to_security_class(mode));
}
@@ -3236,13 +3241,15 @@ static inline void task_avdcache_update(struct task_security_struct *tsec,
/**
* selinux_inode_permission - Check if the current task can access an inode
+ * @idmap: idmap of the mount
* @inode: the inode that is being accessed
* @requested: the accesses being requested
*
* Check if the current task is allowed to access @inode according to
* @requested. Returns 0 if allowed, negative values otherwise.
*/
-static int selinux_inode_permission(struct inode *inode, int requested)
+static int selinux_inode_permission(struct mnt_idmap *idmap,
+ struct inode *inode, int requested)
{
int mask;
u32 perms;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 8e88ac65fd7f..a45819d13c0d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1089,14 +1089,15 @@ instant_inode:
/**
* smack_inode_link - Smack check on link
+ * @idmap: idmap of the mount
* @old_dentry: the existing object
* @dir: unused
* @new_dentry: the new object
*
* Returns 0 if access is permitted, an error code otherwise
*/
-static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *new_dentry)
+static int smack_inode_link(struct mnt_idmap *idmap, struct dentry *old_dentry,
+ struct inode *dir, struct dentry *new_dentry)
{
struct smack_known *isp;
struct smk_audit_info ad;
@@ -1226,6 +1227,7 @@ static int smack_inode_rename(struct inode *old_inode,
/**
* smack_inode_permission - Smack version of permission()
+ * @idmap: idmap of the mount
* @inode: the inode in question
* @mask: the access requested
*
@@ -1233,7 +1235,8 @@ static int smack_inode_rename(struct inode *old_inode,
*
* Returns 0 if access is permitted, an error code otherwise
*/
-static int smack_inode_permission(struct inode *inode, int mask)
+static int smack_inode_permission(struct mnt_idmap *idmap, struct inode *inode,
+ int mask)
{
struct superblock_smack *sbsp = smack_superblock(inode->i_sb);
struct smk_audit_info ad;