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
This commit is contained in:
Paul Moore committed 2026-10-16 17:01:58 -04:00
commit 436485132d
26 files changed
+599 -111

No files matched your search

+14 -6
View File
@@ -6,9 +6,11 @@ The Linux Security Module (LSM) framework provides a mechanism for
various security checks to be hooked by new kernel extensions. The name
"module" is a bit of a misnomer since these extensions are not actually
loadable kernel modules. Instead, they are selectable at build-time via
CONFIG_DEFAULT_SECURITY and can be overridden at boot-time via the
``"security=..."`` kernel command line argument, in the case where multiple
LSMs were built into a given kernel.
CONFIG_LSM, an ordered list of the LSMs to enable, and can be
overridden at boot-time via the ``"lsm=..."`` kernel command line
argument. The ``"security=..."`` kernel command line argument remains
available to choose a legacy "major" security module, but has been
deprecated by the ``"lsm=..."`` parameter.
The primary users of the LSM interface are Mandatory Access Control
(MAC) extensions which provide a comprehensive security policy. Examples
@@ -25,9 +27,15 @@ man-pages project.
A list of the active security modules can be found by reading
``/sys/kernel/security/lsm``. This is a comma separated list, and
will always include the capability module. The list reflects the
order in which checks are made. The capability module will always
be first, followed by any "minor" modules (e.g. Yama) and then
the one "major" module (e.g. SELinux) if there is one configured.
order in which checks are made. The capability module will be
first, unless CONFIG_SECURITY_LOCKDOWN_LSM_EARLY is enabled, in
which case the lockdown module will precede it. The integrity
modules (e.g. IMA and EVM), if enabled in the kernel
configuration, are always placed at the end of the list. Any
other "minor" modules (e.g. Yama) and the one "major" module
(e.g. SELinux), if there is one configured, appear in between,
in the order given by CONFIG_LSM or the ``"lsm=..."`` kernel
command line parameter.
Process attributes associated with "major" security modules should
be accessed and maintained using the special files in ``/proc/.../attr``.
+2 -2
View File
@@ -51,14 +51,14 @@ static int cachefiles_check_cache_dir(struct cachefiles_cache *cache,
{
int ret;
ret = security_inode_mkdir(d_backing_inode(root), root, 0);
ret = security_inode_mkdir(&nop_mnt_idmap, d_backing_inode(root), root, 0);
if (ret < 0) {
pr_err("Security denies permission to make dirs: error %d",
ret);
return ret;
}
ret = security_inode_create(d_backing_inode(root), root, 0);
ret = security_inode_create(&nop_mnt_idmap, d_backing_inode(root), root, 0);
if (ret < 0)
pr_err("Security denies permission to create files: error %d",
ret);
+9 -9
View File
@@ -658,7 +658,7 @@ int inode_permission(struct mnt_idmap *idmap,
if (unlikely(retval))
return retval;
return security_inode_permission(inode, mask);
return security_inode_permission(idmap, inode, mask);
}
EXPORT_SYMBOL(inode_permission);
@@ -695,7 +695,7 @@ static __always_inline int lookup_inode_permission_may_exec(struct mnt_idmap *id
if (unlikely(((inode->i_mode & 0111) != 0111) || !no_acl_inode(inode)))
return inode_permission(idmap, inode, mask);
return security_inode_permission(inode, mask);
return security_inode_permission(idmap, inode, mask);
}
/**
@@ -4188,7 +4188,7 @@ int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode,
return -EACCES; /* shouldn't it be ENOSYS? */
mode = vfs_prepare_mode(idmap, dir, mode, S_IALLUGO, S_IFREG);
error = security_inode_create(dir, dentry, mode);
error = security_inode_create(idmap, dir, dentry, mode);
if (error)
return error;
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, di);
@@ -4212,7 +4212,7 @@ int vfs_mkobj(struct dentry *dentry, umode_t mode,
mode &= S_IALLUGO;
mode |= S_IFREG;
error = security_inode_create(dir, dentry, mode);
error = security_inode_create(&nop_mnt_idmap, dir, dentry, mode);
if (error)
return error;
error = f(dentry, mode, arg);
@@ -4328,7 +4328,7 @@ static int may_o_create(struct mnt_idmap *idmap,
if (error)
return error;
return security_inode_create(dir->dentry->d_inode, dentry, mode);
return security_inode_create(idmap, dir->dentry->d_inode, dentry, mode);
}
/**
@@ -5258,7 +5258,7 @@ int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
if (error)
return error;
error = security_inode_mknod(dir, dentry, mode, dev);
error = security_inode_mknod(idmap, dir, dentry, mode, dev);
if (error)
return error;
@@ -5395,7 +5395,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
goto err;
mode = vfs_prepare_mode(idmap, dir, mode, S_IRWXUGO | S_ISVTX, S_IFDIR);
error = security_inode_mkdir(dir, dentry, mode);
error = security_inode_mkdir(idmap, dir, dentry, mode);
if (error)
goto err;
@@ -5783,7 +5783,7 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
if (!dir->i_op->symlink)
return -EPERM;
error = security_inode_symlink(dir, dentry, oldname);
error = security_inode_symlink(idmap, dir, dentry, oldname);
if (error)
return error;
@@ -5907,7 +5907,7 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
if (S_ISDIR(inode->i_mode))
return -EPERM;
error = security_inode_link(old_dentry, dir, new_dentry);
error = security_inode_link(idmap, old_dentry, dir, new_dentry);
if (error)
return error;
+1 -2
View File
@@ -4193,8 +4193,7 @@ static void dec_mnt_namespaces(struct ucounts *ucounts)
static void free_mnt_ns(struct mnt_namespace *ns)
{
if (!is_anon_ns(ns))
ns_common_free(ns);
ns_common_free(ns);
dec_mnt_namespaces(ns->ucounts);
mnt_ns_tree_remove(ns);
}
+11 -6
View File
@@ -180,12 +180,18 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
static inline const struct cred *override_creds(const struct cred *override_cred)
{
return rcu_replace_pointer(current->cred, override_cred, 1);
const struct cred *old = current->cred;
current->cred = override_cred;
return old;
}
static inline const struct cred *revert_creds(const struct cred *revert_cred)
{
return rcu_replace_pointer(current->cred, revert_cred, 1);
const struct cred *override_cred = current->cred;
current->cred = revert_cred;
return override_cred;
}
DEFINE_CLASS(override_creds,
@@ -293,11 +299,10 @@ DEFINE_FREE(put_cred, struct cred *, if (!IS_ERR_OR_NULL(_T)) put_cred(_T))
/**
* current_cred - Access the current task's subjective credentials
*
* Access the subjective credentials of the current task. RCU-safe,
* since nobody else can modify it.
* Access the subjective credentials of the current task.
* Nobody else can modify it.
*/
#define current_cred() \
rcu_dereference_protected(current->cred, 1)
#define current_cred() (current->cred)
/**
* current_real_cred - Access the current task's objective credentials
+6 -1
View File
@@ -44,7 +44,7 @@ struct lsm_network_audit {
struct lsm_ioctlop_audit {
struct path path;
u16 cmd;
unsigned int cmd;
};
struct lsm_ibpkey_audit {
@@ -78,6 +78,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_NOTIFICATION 16
#define LSM_AUDIT_DATA_ANONINODE 17
#define LSM_AUDIT_DATA_NLMSGTYPE 18
#define LSM_AUDIT_DATA_NS 19
union {
struct path path;
struct dentry *dentry;
@@ -100,6 +101,10 @@ struct common_audit_data {
int reason;
const char *anonclass;
u16 nlmsg_type;
struct {
u32 ns_type;
u64 ns_id;
} ns;
} u;
/* this union contains LSM specific data */
union {
+15 -11
View File
@@ -120,26 +120,27 @@ LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode,
int *xattr_count)
LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
const struct qstr *name, const struct inode *context_inode)
LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
umode_t mode)
LSM_HOOK(int, 0, inode_create, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode)
LSM_HOOK(void, LSM_RET_VOID, inode_post_create_tmpfile, struct mnt_idmap *idmap,
struct inode *inode)
LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
LSM_HOOK(int, 0, inode_link, struct mnt_idmap *idmap,
struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
LSM_HOOK(int, 0, inode_unlink, struct inode *dir, struct dentry *dentry)
LSM_HOOK(int, 0, inode_symlink, struct inode *dir, struct dentry *dentry,
const char *old_name)
LSM_HOOK(int, 0, inode_mkdir, struct inode *dir, struct dentry *dentry,
umode_t mode)
LSM_HOOK(int, 0, inode_symlink, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *old_name)
LSM_HOOK(int, 0, inode_mkdir, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode)
LSM_HOOK(int, 0, inode_rmdir, struct inode *dir, struct dentry *dentry)
LSM_HOOK(int, 0, inode_mknod, struct inode *dir, struct dentry *dentry,
umode_t mode, dev_t dev)
LSM_HOOK(int, 0, inode_mknod, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t dev)
LSM_HOOK(int, 0, inode_rename, struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
LSM_HOOK(int, 0, inode_readlink, struct dentry *dentry)
LSM_HOOK(int, 0, inode_follow_link, struct dentry *dentry, struct inode *inode,
bool rcu)
LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
LSM_HOOK(int, 0, inode_permission, struct mnt_idmap *idmap,
struct inode *inode, int mask)
LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
LSM_HOOK(void, LSM_RET_VOID, inode_post_setattr, struct mnt_idmap *idmap,
@@ -265,6 +266,9 @@ LSM_HOOK(int, -ENOSYS, task_prctl, int option, unsigned long arg2,
LSM_HOOK(void, LSM_RET_VOID, task_to_inode, struct task_struct *p,
struct inode *inode)
LSM_HOOK(int, 0, userns_create, const struct cred *cred)
LSM_HOOK(int, 0, namespace_init, struct ns_common *ns)
LSM_HOOK(void, LSM_RET_VOID, namespace_free, struct ns_common *ns)
LSM_HOOK(int, 0, namespace_install, const struct nsset *nsset, struct ns_common *ns)
LSM_HOOK(int, 0, ipc_permission, struct kern_ipc_perm *ipcp, short flag)
LSM_HOOK(void, LSM_RET_VOID, ipc_getlsmprop, struct kern_ipc_perm *ipcp,
struct lsm_prop *prop)
+1
View File
@@ -112,6 +112,7 @@ struct lsm_blob_sizes {
unsigned int lbs_ipc;
unsigned int lbs_key;
unsigned int lbs_msg_msg;
unsigned int lbs_ns;
unsigned int lbs_perf_event;
unsigned int lbs_task;
unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
+3
View File
@@ -116,6 +116,9 @@ struct ns_common {
struct dentry *stashed;
const struct proc_ns_operations *ops;
unsigned int inum;
#ifdef CONFIG_SECURITY
void *ns_security;
#endif
struct ns_tree;
struct rcu_head ns_rcu;
};
+6 -2
View File
@@ -1172,8 +1172,12 @@ struct task_struct {
/* Objective and real subjective task credentials (COW): */
const struct cred __rcu *real_cred;
/* Effective (overridable) subjective task credentials (COW): */
const struct cred __rcu *cred;
/*
* Effective (overridable) subjective task credentials (COW).
* Only accessible for the current task and during task creation/freeing.
* This pointer is not managed by RCU!
*/
const struct cred *cred;
#ifdef CONFIG_KEYS
/* Cached requested key. */
+54 -24
View File
@@ -67,6 +67,7 @@ enum fs_value_type;
struct watch;
struct watch_notification;
struct lsm_ctx;
struct nsset;
/* Default (no) options for the capable function */
#define CAP_OPT_NONE 0x0
@@ -80,6 +81,7 @@ struct lsm_ctx;
struct ctl_table;
struct audit_krule;
struct ns_common;
struct user_namespace;
struct timezone;
@@ -404,24 +406,28 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
int security_inode_init_security_anon(struct inode *inode,
const struct qstr *name,
const struct inode *context_inode);
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);
void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
struct inode *inode);
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);
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
const char *old_name);
int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
int security_inode_symlink(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *old_name);
int security_inode_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
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);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags);
int security_inode_readlink(struct dentry *dentry);
int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu);
int security_inode_permission(struct inode *inode, int mask);
int security_inode_permission(struct mnt_idmap *idmap, struct inode *inode,
int mask);
int security_inode_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr);
void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
@@ -540,6 +546,9 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
void security_task_to_inode(struct task_struct *p, struct inode *inode);
int security_create_user_ns(const struct cred *cred);
int security_namespace_init(struct ns_common *ns);
void security_namespace_free(struct ns_common *ns);
int security_namespace_install(const struct nsset *nsset, struct ns_common *ns);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
void security_ipc_getlsmprop(struct kern_ipc_perm *ipcp, struct lsm_prop *prop);
int security_msg_msg_alloc(struct msg_msg *msg);
@@ -902,9 +911,10 @@ static inline int security_inode_init_security_anon(struct inode *inode,
return 0;
}
static inline int security_inode_create(struct inode *dir,
struct dentry *dentry,
umode_t mode)
static inline int security_inode_create(struct mnt_idmap *idmap,
struct inode *dir,
struct dentry *dentry,
umode_t mode)
{
return 0;
}
@@ -913,9 +923,10 @@ static inline void
security_inode_post_create_tmpfile(struct mnt_idmap *idmap, struct inode *inode)
{ }
static inline int security_inode_link(struct dentry *old_dentry,
struct inode *dir,
struct dentry *new_dentry)
static inline int security_inode_link(struct mnt_idmap *idmap,
struct dentry *old_dentry,
struct inode *dir,
struct dentry *new_dentry)
{
return 0;
}
@@ -926,16 +937,18 @@ static inline int security_inode_unlink(struct inode *dir,
return 0;
}
static inline int security_inode_symlink(struct inode *dir,
struct dentry *dentry,
const char *old_name)
static inline int security_inode_symlink(struct mnt_idmap *idmap,
struct inode *dir,
struct dentry *dentry,
const char *old_name)
{
return 0;
}
static inline int security_inode_mkdir(struct inode *dir,
struct dentry *dentry,
int mode)
static inline int security_inode_mkdir(struct mnt_idmap *idmap,
struct inode *dir,
struct dentry *dentry,
int mode)
{
return 0;
}
@@ -946,9 +959,10 @@ static inline int security_inode_rmdir(struct inode *dir,
return 0;
}
static inline int security_inode_mknod(struct inode *dir,
struct dentry *dentry,
int mode, dev_t dev)
static inline int security_inode_mknod(struct mnt_idmap *idmap,
struct inode *dir,
struct dentry *dentry,
int mode, dev_t dev)
{
return 0;
}
@@ -974,7 +988,8 @@ static inline int security_inode_follow_link(struct dentry *dentry,
return 0;
}
static inline int security_inode_permission(struct inode *inode, int mask)
static inline int security_inode_permission(struct mnt_idmap *idmap,
struct inode *inode, int mask)
{
return 0;
}
@@ -1431,6 +1446,21 @@ static inline int security_create_user_ns(const struct cred *cred)
return 0;
}
static inline int security_namespace_init(struct ns_common *ns)
{
return 0;
}
static inline void security_namespace_free(struct ns_common *ns)
{
}
static inline int security_namespace_install(const struct nsset *nsset,
struct ns_common *ns)
{
return 0;
}
static inline int security_ipc_permission(struct kern_ipc_perm *ipcp,
short flag)
{
+1
View File
@@ -55,6 +55,7 @@ enum init_ns_ino {
MNT_NS_INIT_INO = 0xEFFFFFF8U,
#ifdef __KERNEL__
MNT_NS_ANON_INO = 0xEFFFFFF7U,
MNT_NS_INO_SPECIAL_MAX = MNT_NS_ANON_INO,
#endif
};
+1 -1
View File
@@ -160,7 +160,7 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.sibling = LIST_HEAD_INIT(init_task.sibling),
.group_leader = &init_task,
RCU_POINTER_INITIALIZER(real_cred, &init_cred),
RCU_POINTER_INITIALIZER(cred, &init_cred),
.cred = &init_cred,
.comm = INIT_TASK_COMM,
.thread = INIT_THREAD,
.real_fs = &init_fs,
+3 -2
View File
@@ -459,7 +459,7 @@ static int audit_field_compare(struct task_struct *tsk,
*
* If task_creation is true, this is an explicit indication that we are
* filtering a task rule at task creation time. This and tsk == current are
* the only situations where tsk->cred may be accessed without an rcu read lock.
* the only situations where tsk->cred may be accessed.
*/
static int audit_filter_rules(struct task_struct *tsk,
struct audit_krule *rule,
@@ -476,7 +476,8 @@ static int audit_filter_rules(struct task_struct *tsk,
if (ctx && rule->prio <= ctx->prio)
return 0;
cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
WARN_ON(tsk != current && !task_creation);
cred = tsk->cred;
for (i = 0; i < rule->field_count; i++) {
struct audit_field *f = &rule->fields[i];
+3 -2
View File
@@ -414,7 +414,7 @@ int commit_creds(struct cred *new)
inc_rlimit_ucounts(new->ucounts, UCOUNT_RLIMIT_NPROC, 1);
rcu_assign_pointer(task->real_cred, new);
rcu_assign_pointer(task->cred, new);
task->cred = new;
if (new->user != old->user || new->user_ns != old->user_ns)
dec_rlimit_ucounts(old->ucounts, UCOUNT_RLIMIT_NPROC, 1);
if (new->user_ns != old->user_ns)
@@ -537,7 +537,8 @@ void __init cred_init(void)
{
/* allocate a slab in which we can store credentials */
cred_jar = KMEM_CACHE(cred,
SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);
SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT |
SLAB_NO_MERGE);
}
/**
+16 -1
View File
@@ -4,6 +4,7 @@
#include <linux/ns_common.h>
#include <linux/nstree.h>
#include <linux/proc_ns.h>
#include <linux/security.h>
#include <linux/user_namespace.h>
#include <linux/vfsdebug.h>
@@ -59,6 +60,9 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
refcount_set(&ns->__ns_ref, 1);
ns->stashed = NULL;
#ifdef CONFIG_SECURITY
ns->ns_security = NULL;
#endif
ns->ops = ops;
ns->ns_id = 0;
ns->ns_type = ns_type;
@@ -77,6 +81,14 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
ret = proc_alloc_inum(&ns->inum);
if (ret)
return ret;
ret = security_namespace_init(ns);
if (ret) {
if (!inum)
proc_free_inum(ns->inum);
return ret;
}
/*
* Tree ref starts at 0. It's incremented when namespace enters
* active use (installed in nsproxy) and decremented when all
@@ -91,7 +103,10 @@ int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_ope
void __ns_common_free(struct ns_common *ns)
{
proc_free_inum(ns->inum);
security_namespace_free(ns);
if (ns->inum > MNT_NS_INO_SPECIAL_MAX)
proc_free_inum(ns->inum);
}
struct ns_common *__must_check ns_owner(struct ns_common *ns)
+6
View File
@@ -385,6 +385,12 @@ out:
static inline int validate_ns(struct nsset *nsset, struct ns_common *ns)
{
int ret;
ret = security_namespace_install(nsset, ns);
if (ret)
return ret;
return ns->ops->install(nsset, ns);
}
+1 -2
View File
@@ -62,8 +62,7 @@ impl SecurityCtx {
/// Get the security context given its id.
#[inline]
pub fn from_secid(secid: u32) -> Result<Self> {
// SAFETY: `struct lsm_context` can be initialized to all zeros.
let mut ctx: bindings::lsm_context = unsafe { core::mem::zeroed() };
let mut ctx: bindings::lsm_context = pin_init::zeroed();
// SAFETY: Just a C FFI call. The pointer is valid for writes.
to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut ctx) })?;
+6 -2
View File
@@ -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) */
}
+4 -5
View File
@@ -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");
+97 -18
View File
@@ -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>
@@ -381,6 +382,19 @@ static int lsm_superblock_alloc(struct super_block *sb)
GFP_KERNEL);
}
/**
* 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
@@ -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);
}
@@ -3357,6 +3378,64 @@ int security_create_user_ns(const struct cred *cred)
return call_int_hook(userns_create, 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
+16 -9
View File
@@ -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;
}
+6 -3
View File
@@ -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;
@@ -1,18 +1,30 @@
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
/*
* Copyright (C) 2020 Google LLC.
*/
#include <test_progs.h>
#include <sched.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/mount.h>
#include "lsm.skel.h"
#include "lsm_tailcall.skel.h"
char *CMD_ARGS[] = {"true", NULL};
enum {
INODE_IDMAP_ALL = (1U << 6) - 1,
};
int exec_cmd(int *monitored_pid)
{
int child_pid, child_status;
@@ -30,6 +42,219 @@ int exec_cmd(int *monitored_pid)
return -EINVAL;
}
static ssize_t write_nointr(int fd, const void *buf, size_t count)
{
ssize_t ret;
do {
ret = write(fd, buf, count);
} while (ret < 0 && errno == EINTR);
return ret;
}
static int write_file(const char *path, const char *value)
{
size_t len = strlen(value);
int fd, saved_errno = 0;
ssize_t ret;
fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
if (fd < 0)
return -1;
ret = write_nointr(fd, value, len);
if (ret < 0)
saved_errno = errno;
else if ((size_t)ret != len)
saved_errno = EIO;
close(fd);
if (saved_errno) {
errno = saved_errno;
return -1;
}
return 0;
}
static int write_userns_file(pid_t pid, const char *name, const char *value)
{
char path[64];
int len;
len = snprintf(path, sizeof(path), "/proc/%d/%s", pid, name);
if (len < 0 || (size_t)len >= sizeof(path)) {
errno = EOVERFLOW;
return -1;
}
return write_file(path, value);
}
static int create_userns_fd(void)
{
char path[64];
pid_t pid, waited;
int fd = -1, len, saved_errno, status;
pid = fork();
if (pid < 0)
return -1;
if (pid == 0) {
if (unshare(CLONE_NEWUSER))
_exit(1);
raise(SIGSTOP);
_exit(0);
}
do {
waited = waitpid(pid, &status, WUNTRACED);
} while (waited < 0 && errno == EINTR);
if (waited != pid)
goto out;
if (!WIFSTOPPED(status)) {
pid = -1;
goto out;
}
/* A one-entry map is identity for root but remains distinct from nop_mnt_idmap. */
if (write_userns_file(pid, "setgroups", "deny") && errno != ENOENT)
goto out;
if (write_userns_file(pid, "uid_map", "0 0 1") ||
write_userns_file(pid, "gid_map", "0 0 1"))
goto out;
len = snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
if (len < 0 || (size_t)len >= sizeof(path)) {
errno = EOVERFLOW;
goto out;
}
fd = open(path, O_RDONLY | O_CLOEXEC);
out:
saved_errno = errno;
if (pid > 0) {
kill(pid, SIGKILL);
do {
waited = waitpid(pid, NULL, 0);
} while (waited < 0 && errno == EINTR);
}
errno = saved_errno;
return fd;
}
static int create_idmapped_tmpfs(void)
{
struct mount_attr attr = {
.attr_set = MOUNT_ATTR_IDMAP,
};
int fsfd = -1, mntfd = -1, saved_errno, userns_fd = -1;
userns_fd = create_userns_fd();
if (userns_fd < 0)
goto out;
/* A detached tmpfs avoids relying on the host test directory supporting idmaps. */
fsfd = syscall(__NR_fsopen, "tmpfs", FSOPEN_CLOEXEC);
if (fsfd < 0)
goto out;
if (syscall(__NR_fsconfig, fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0))
goto out;
mntfd = syscall(__NR_fsmount, fsfd, FSMOUNT_CLOEXEC, 0);
if (mntfd < 0)
goto out;
attr.userns_fd = userns_fd;
if (syscall(__NR_mount_setattr, mntfd, "", AT_EMPTY_PATH, &attr,
sizeof(attr))) {
close(mntfd);
mntfd = -1;
}
out:
saved_errno = errno;
if (fsfd >= 0)
close(fsfd);
if (userns_fd >= 0)
close(userns_fd);
errno = saved_errno;
return mntfd;
}
static int exercise_inode_idmap_hooks(int dirfd)
{
int fd = -1, ret = -1;
fd = openat(dirfd, "file", O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC,
0600);
if (!ASSERT_GE(fd, 0, "create"))
goto out;
close(fd);
fd = -1;
if (!ASSERT_OK(mkdirat(dirfd, "dir", 0700), "mkdir"))
goto out;
if (!ASSERT_OK(symlinkat("target", dirfd, "symlink"), "symlink"))
goto out;
if (!ASSERT_OK(linkat(dirfd, "file", dirfd, "link", 0), "link"))
goto out;
if (!ASSERT_OK(mkfifoat(dirfd, "fifo", 0600), "mknod"))
goto out;
ret = 0;
out:
if (fd >= 0)
close(fd);
unlinkat(dirfd, "link", 0);
unlinkat(dirfd, "fifo", 0);
unlinkat(dirfd, "symlink", 0);
unlinkat(dirfd, "file", 0);
unlinkat(dirfd, "dir", AT_REMOVEDIR);
return ret;
}
static int test_lsm_inode_idmap(struct lsm *skel)
{
char tmpdir[] = "/var/tmp/test_lsm_idmap.XXXXXX";
__u32 expected = INODE_IDMAP_ALL;
int dirfd = -1, idmapped_dirfd = -1;
int ret = -1;
if (!ASSERT_OK_PTR(mkdtemp(tmpdir), "mkdtemp"))
return -1;
dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (!ASSERT_GE(dirfd, 0, "open_tmpdir"))
goto out;
idmapped_dirfd = create_idmapped_tmpfs();
if (!ASSERT_GE(idmapped_dirfd, 0, "create_idmapped_tmpfs"))
goto out;
skel->bss->inode_identity_idmap_seen = 0;
skel->bss->inode_idmapped_mount_seen = 0;
if (!ASSERT_OK(exercise_inode_idmap_hooks(dirfd), "identity_idmap"))
goto out;
if (!ASSERT_OK(exercise_inode_idmap_hooks(idmapped_dirfd),
"idmapped_mount"))
goto out;
if (!ASSERT_EQ(skel->bss->inode_identity_idmap_seen, expected,
"inode_identity_idmap_seen"))
goto out;
ret = ASSERT_EQ(skel->bss->inode_idmapped_mount_seen, expected,
"inode_idmapped_mount_seen") ? 0 : -1;
out:
if (idmapped_dirfd >= 0)
close(idmapped_dirfd);
if (dirfd >= 0)
close(dirfd);
rmdir(tmpdir);
return ret;
}
static int test_lsm(struct lsm *skel)
{
struct bpf_link *link;
@@ -53,6 +278,10 @@ static int test_lsm(struct lsm *skel)
skel->bss->monitored_pid = getpid();
err = test_lsm_inode_idmap(skel);
if (!ASSERT_OK(err, "test_lsm_inode_idmap"))
return err;
err = stack_mprotect();
if (!ASSERT_EQ(err, -1, "stack_mprotect") ||
!ASSERT_EQ(errno, EPERM, "stack_mprotect"))
@@ -71,6 +300,8 @@ static int test_lsm(struct lsm *skel)
skel->bss->copy_test = 0;
skel->bss->bprm_count = 0;
skel->bss->mprotect_count = 0;
skel->bss->inode_identity_idmap_seen = 0;
skel->bss->inode_idmapped_mount_seen = 0;
return 0;
}
+79
View File
@@ -84,6 +84,85 @@ char _license[] SEC("license") = "GPL";
int monitored_pid = 0;
int mprotect_count = 0;
int bprm_count = 0;
__u32 inode_identity_idmap_seen = 0;
__u32 inode_idmapped_mount_seen = 0;
enum {
INODE_IDMAP_CREATE = 1U << 0,
INODE_IDMAP_LINK = 1U << 1,
INODE_IDMAP_SYMLINK = 1U << 2,
INODE_IDMAP_MKDIR = 1U << 3,
INODE_IDMAP_MKNOD = 1U << 4,
INODE_IDMAP_PERMISSION = 1U << 5,
};
static __always_inline bool is_monitored_idmap(struct mnt_idmap *idmap)
{
__u32 pid = bpf_get_current_pid_tgid() >> 32;
return monitored_pid == pid && idmap;
}
static __always_inline bool is_identity_idmap(struct mnt_idmap *idmap)
{
return idmap->uid_map.nr_extents == 0 &&
idmap->gid_map.nr_extents == 0;
}
static __always_inline int record_inode_idmap(struct mnt_idmap *idmap,
__u32 hook, int ret)
{
if (ret || !is_monitored_idmap(idmap))
return ret;
if (is_identity_idmap(idmap))
inode_identity_idmap_seen |= hook;
else
inode_idmapped_mount_seen |= hook;
return 0;
}
SEC("lsm/inode_create")
int BPF_PROG(test_inode_create, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, int ret)
{
return record_inode_idmap(idmap, INODE_IDMAP_CREATE, ret);
}
SEC("lsm/inode_link")
int BPF_PROG(test_inode_link, struct mnt_idmap *idmap,
struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry, int ret)
{
return record_inode_idmap(idmap, INODE_IDMAP_LINK, ret);
}
SEC("lsm/inode_symlink")
int BPF_PROG(test_inode_symlink, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *old_name, int ret)
{
return record_inode_idmap(idmap, INODE_IDMAP_SYMLINK, ret);
}
SEC("lsm/inode_mkdir")
int BPF_PROG(test_inode_mkdir, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, int ret)
{
return record_inode_idmap(idmap, INODE_IDMAP_MKDIR, ret);
}
SEC("lsm/inode_mknod")
int BPF_PROG(test_inode_mknod, struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t dev, int ret)
{
return record_inode_idmap(idmap, INODE_IDMAP_MKNOD, ret);
}
SEC("lsm/inode_permission")
int BPF_PROG(test_inode_permission, struct mnt_idmap *idmap,
struct inode *inode, int mask, int ret)
{
return record_inode_idmap(idmap, INODE_IDMAP_PERMISSION, ret);
}
SEC("lsm/file_mprotect")
int BPF_PROG(test_int_hook, struct vm_area_struct *vma,
+7 -3
View File
@@ -4146,6 +4146,9 @@ TEST_F_FORK(layout1, o_path_ftruncate_and_ioctl)
ASSERT_EQ(0, close(fd));
}
/* Arbitrary command with nonzero bits in both 16-bit halves. */
static const unsigned int unknown_ioctl_cmd = 0xc00ffeee;
/*
* ioctl_error - generically call the given ioctl with a pointer to a
* sufficiently large zeroed-out memory region.
@@ -4249,7 +4252,7 @@ TEST_F_FORK(layout1, blanket_permitted_ioctls)
EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FS_IOC_ZERO_RANGE));
/* Default case is also blocked. */
EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, 0xc00ffeee));
EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, unknown_ioctl_cmd));
ASSERT_EQ(0, close(fd));
}
@@ -7943,6 +7946,7 @@ TEST_F(audit_layout1, truncate)
EXPECT_EQ(1, records.domain);
}
/* Checks that audit records preserve every ioctl command bit. */
TEST_F(audit_layout1, ioctl_dev)
{
struct audit_records records;
@@ -7952,10 +7956,10 @@ TEST_F(audit_layout1, ioctl_dev)
fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
ASSERT_LE(0, fd);
EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, FIONREAD));
EXPECT_EQ(EACCES, ioctl_error(_metadata, fd, unknown_ioctl_cmd));
EXPECT_EQ(0, matches_log_fs_extra(_metadata, self->audit_fd,
"fs\\.ioctl_dev", "/dev/null",
" ioctlcmd=0x541b"));
" ioctlcmd=0xc00ffeee"));
EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
EXPECT_EQ(0, records.access);