summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2026-10-16 17:01:58 -0400
committerPaul Moore <paul@paul-moore.com>2026-10-16 17:01:58 -0400
commit436485132d2367a50aa22dcc8a89faeee24a4cc9 (patch)
treef4c7cafad0ec42898880ea53ab0ecd2a7b147cde /security
parentfd73f4a6659897191fa0d40695fe370925dd3780 (diff)
parent881f19c2ffbc73f351b257e09c71e6059939b770 (diff)
Automated merge of 'lsm/dev' into 'stable-7.4'
Manual merge fixup in ns_common_types.h:ns_common to work around a conflict with the nsfs RCU grace period fix. * lsm/dev: lsm: remove redundant NULL check in security_init() selftests/landlock: Check full ioctl commands in audit records lsm: Preserve full ioctl commands in audit records doc: fix LSM ordering description for /sys/kernel/security/lsm doc: describe CONFIG_LSM and lsm= as the selection mechanism selftests/bpf: verify mount idmaps reach inode hooks lsm: expose mount idmaps to inode hooks rust: lsm: replace `core::mem::zeroed` with `pin_init::zeroed` cred: prevent slab cache merging for cred_jar lsm: don't call security_backing_file_free() multiple times lsm: delete duplicate assignment in lsm_prepare() lsm: update the BUILD_BUG_ON() in audit_log_lsm_data() lsm: add LSM_AUDIT_DATA_NS for namespace audit records lsm: add LSM blob and hooks for namespaces ns: Free anonymous mount namespaces via ns_common_free() cred: clarify that task_struct::cred is only for the current task
Diffstat (limited to 'security')
-rw-r--r--security/lsm_audit.c8
-rw-r--r--security/lsm_init.c9
-rw-r--r--security/security.c115
-rw-r--r--security/selinux/hooks.c25
-rw-r--r--security/smack/smack_lsm.c9
5 files changed, 129 insertions, 37 deletions
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 737f5a263a8f..955b2e7b2c8e 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -182,7 +182,7 @@ void audit_log_lsm_data(struct audit_buffer *ab,
* start making this union too large! See struct lsm_network_audit
* as an example of how to deal with large data.
*/
- BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
+ BUILD_BUG_ON(sizeof(a->u) > (sizeof(u64) * 2));
switch (a->type) {
case LSM_AUDIT_DATA_NONE:
@@ -231,7 +231,7 @@ void audit_log_lsm_data(struct audit_buffer *ab,
audit_log_format(ab, " ino=%llu", inode->i_ino);
}
- audit_log_format(ab, " ioctlcmd=0x%hx", a->u.op->cmd);
+ audit_log_format(ab, " ioctlcmd=0x%x", a->u.op->cmd);
break;
}
case LSM_AUDIT_DATA_DENTRY: {
@@ -403,6 +403,10 @@ void audit_log_lsm_data(struct audit_buffer *ab,
case LSM_AUDIT_DATA_NLMSGTYPE:
audit_log_format(ab, " nl-msgtype=%hu", a->u.nlmsg_type);
break;
+ case LSM_AUDIT_DATA_NS:
+ audit_log_format(ab, " namespace_type=0x%x namespace_id=%llu",
+ a->u.ns.ns_type, a->u.ns.ns_id);
+ break;
} /* switch (a->type) */
}
diff --git a/security/lsm_init.c b/security/lsm_init.c
index a1ad641811de..8d5ecea99c46 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -290,7 +290,6 @@ static void __init lsm_prepare(struct lsm_info *lsm)
return;
/* Register the LSM blob sizes. */
- blobs = lsm->blobs;
lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
lsm_blob_size_update(&blobs->lbs_backing_file,
@@ -303,6 +302,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_blob_size_update(&blobs->lbs_ns, &blob_sizes.lbs_ns);
lsm_blob_size_update(&blobs->lbs_perf_event,
&blob_sizes.lbs_perf_event);
lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
@@ -431,8 +431,7 @@ int __init security_init(void)
}
if (lsm_order_cmdline) {
- if (lsm_order_legacy)
- lsm_order_legacy = NULL;
+ lsm_order_legacy = NULL;
lsm_order_parse(lsm_order_cmdline, "cmdline");
} else
lsm_order_parse(lsm_order_builtin, "builtin");
@@ -450,6 +449,7 @@ int __init security_init(void)
lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
+ lsm_pr("blob(ns) size %d\n", blob_sizes.lbs_ns);
lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
@@ -476,8 +476,7 @@ int __init security_init(void)
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
- if (lsm_cred_alloc((struct cred *)unrcu_pointer(current->cred),
- GFP_KERNEL))
+ if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
panic("early LSM cred alloc failed\n");
if (lsm_task_alloc(current))
panic("early LSM task alloc failed\n");
diff --git a/security/security.c b/security/security.c
index 2ee276ab15c5..7fa52d39a255 100644
--- a/security/security.c
+++ b/security/security.c
@@ -26,6 +26,7 @@
#include <linux/string.h>
#include <linux/xattr.h>
#include <linux/msg.h>
+#include <linux/ns_common.h>
#include <linux/overflow.h>
#include <linux/perf_event.h>
#include <linux/fs.h>
@@ -382,6 +383,19 @@ static int lsm_superblock_alloc(struct super_block *sb)
}
/**
+ * lsm_ns_alloc - allocate a composite namespace blob
+ * @ns: the namespace that needs a blob
+ *
+ * Allocate the namespace blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_ns_alloc(struct ns_common *ns)
+{
+ return lsm_blob_alloc(&ns->ns_security, blob_sizes.lbs_ns, GFP_KERNEL);
+}
+
+/**
* lsm_fill_user_ctx - Fill a user space lsm_ctx structure
* @uctx: a userspace LSM context to be filled
* @uctx_len: available uctx size (input), used uctx size (output)
@@ -1614,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
@@ -1622,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);
@@ -1648,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
@@ -1656,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);
}
/**
@@ -1682,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
@@ -1690,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
@@ -1709,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);
@@ -1735,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
@@ -1747,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);
}
/**
@@ -1823,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
*
@@ -1835,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);
}
/**
@@ -2486,9 +2508,8 @@ void security_backing_file_free(struct file *backing_file)
{
void *blob = backing_file_security(backing_file);
- call_void_hook(backing_file_free, backing_file);
-
if (blob) {
+ call_void_hook(backing_file_free, backing_file);
backing_file_set_security(backing_file, NULL);
kmem_cache_free(lsm_backing_file_cache, blob);
}
@@ -3358,6 +3379,64 @@ int security_create_user_ns(const struct cred *cred)
}
/**
+ * security_namespace_init() - Initialize LSM security data for a namespace
+ * @ns: the namespace being initialized
+ *
+ * Initialize the LSM security blob attached to the namespace. The namespace type
+ * is available via ns->ns_type, and the owning user namespace (if any)
+ * via ns->ops->owner(ns).
+ *
+ * Return: Returns 0 if successful, otherwise < 0 error code.
+ */
+int security_namespace_init(struct ns_common *ns)
+{
+ int rc;
+
+ rc = lsm_ns_alloc(ns);
+ if (unlikely(rc))
+ return rc;
+
+ rc = call_int_hook(namespace_init, ns);
+ if (unlikely(rc))
+ security_namespace_free(ns);
+
+ return rc;
+}
+
+/**
+ * security_namespace_free() - Release LSM security data from a namespace
+ * @ns: the namespace being freed
+ *
+ * Release security data attached to the namespace. Called before the
+ * namespace structure is freed.
+ */
+void security_namespace_free(struct ns_common *ns)
+{
+ if (!ns->ns_security)
+ return;
+
+ call_void_hook(namespace_free, ns);
+
+ kfree(ns->ns_security);
+ ns->ns_security = NULL;
+}
+
+/**
+ * security_namespace_install() - Check permission to install a namespace
+ * @nsset: the target nsset being configured
+ * @ns: the namespace being installed
+ *
+ * Check permission before allowing a namespace to be installed into the
+ * process's set of namespaces via setns(2).
+ *
+ * Return: Returns 0 if permission is granted, otherwise < 0 error code.
+ */
+int security_namespace_install(const struct nsset *nsset, struct ns_common *ns)
+{
+ return call_int_hook(namespace_install, nsset, ns);
+}
+
+/**
* security_ipc_permission() - Check if sysv ipc access is allowed
* @ipcp: ipc permission structure
* @flag: requested permissions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e5e17f100aae..dd85351cbfc7 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;
@@ -3859,7 +3866,7 @@ static int selinux_backing_file_alloc(struct file *backing_file,
* operation to an inode.
*/
static int ioctl_has_perm(const struct cred *cred, struct file *file,
- u32 requested, u16 cmd)
+ u32 requested, unsigned int cmd)
{
struct common_audit_data ad;
struct file_security_struct *fsec = selinux_file(file);
@@ -3930,14 +3937,14 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
case FIOCLEX:
case FIONCLEX:
if (!selinux_policycap_ioctl_skip_cloexec())
- error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+ error = ioctl_has_perm(cred, file, FILE__IOCTL, cmd);
break;
/* default case assumes that the command will go
* to the file's ioctl() function.
*/
default:
- error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+ error = ioctl_has_perm(cred, file, FILE__IOCTL, cmd);
}
return error;
}
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;