2023-12-15 22:16:59

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 00/42] LSM: General module stacking

This patchset provides the changes required to allow arbitrary
combination of all the existing Linux Security Modules (LSM).
It does not provide for all possible configurations of all of
co-existing modules. It does not ensure that the enforcement
of policy provided by one module does not interfere with the
behavior of another module.

The bulk of the code change is in support of the audit system.
Because subjects and objects may have multiple LSM specific
attributes that are used to make access control decisions it
was necessary to enhance the audit system to report these
security attributes. Separate audit records have been added
to include the additional information for each of the audit
event subject and object. Providing the required security
information using 32-bit secids was no longer sufficient. A
new structure, lsmblob, has been introduced to include the
data for all relevant modules.

The lsmblob structure has an entry for each of the modules
that has used secids. Each module provides a structure of
its own which contains the information it uses. For SELinux
this is a u32 secid. Smack provides a pointer into the label
list. Modules that are not configured use conditional compilation
to have empty structures.

Because audit records may need to include the text representation
of more than one module's security attributes (commonly referred
to as the "security context") the interfaces that convert the
lsmblob into a text representation need to identify which module
provided the text. An structure lsmcontext has been added that
contains the text, its length and the identifier of the module
than created it.

Security attributes for network facilities have provided certain
challenges. The security information allowed in socket buffers
and secmarks is limited to a single u32 secid, and there is no
indication that this will ever be allowed to change. The netlabel
subsystem, which provides CIPSO and CALIPSO labeling on internet
packets, supports only one IP packet option at a time. Labeled
NFS3 also supports only one security module. The existing modules
have been updated to accept that they may not have access to
these networking security attributes. The first module to
register that uses them is given exclusive access.

The issue of multiple modules using the /proc/.../attr interfaces
has been largely addressed for some time by the inclusion of module
specific sub-directories. Applications should be using these except
for the case of SELinux.

Patch 0001 removes an interface dependency on audit from IMA.
Patch 0002 moves management of socket security blobs out of the
modules and into the LSM infrastructure.
Patch 0003 introduces the lsmblob structure.
Patch 0004 introduces mechanism for the IMA mechanisms to handle
the possibility of multiple modules that use attributes.
Patches 0005-0015 add new interfaces and change existing interfaces
to use the lsmblob to represent security data.
Patches 0016-0021 replace a the use of string and length pairs to
use a "security context" with an lsmcontext structure.
Patches 0022-0026 implement audit records describing the multiple
security attributes on subjects and objects.
Patch 0027 removes scaffolding code used in support on lsmcontext.
Patches 0028-0030 optimize LSM hooks for the networking single
module user case.
Patch 0031 implements mechanism to reserve use of network secmarks.
Patch 0032 limits security_secctx_to_secid() to a single module.
Patch 0033 removes the exclusive tag from AppArmor.
Patches 0034-0035 adds mount operation security blobs.
Patch 0036 moves management of key security blobs out of the
modules and into the LSM infrastructure.
Patch 0037 enables management of mount operation security blobs
in the modules.
Patches 0038-0039 remove scaffolding for lsmblobs.
Patch 0040 implements mechanism to reserve use of netlabel.
Patch 0041 restricts a hook used only by binder to a single module.
Patch 0042 removes the exclusive tag from Smack.

https://github.com:cschaufler/lsm-stacking.git#stack-6.7-rc1-pcmoore-dev-v39-b

Casey Schaufler (42):
integrity: disassociate ima_filter_rule from security_audit_rule
SM: Infrastructure management of the sock security
LSM: Add the lsmblob data structure.
IMA: avoid label collisions with stacked LSMs
LSM: Use lsmblob in security_audit_rule_match
LSM: Add lsmblob_to_secctx hook
Audit: maintain an lsmblob in audit_context
LSM: Use lsmblob in security_ipc_getsecid
Audit: Update shutdown LSM data
LSM: Use lsmblob in security_current_getsecid
LSM: Use lsmblob in security_inode_getsecid
Audit: use an lsmblob in audit_names
LSM: Create new security_cred_getlsmblob LSM hook
Audit: Change context data from secid to lsmblob
Netlabel: Use lsmblob for audit data
LSM: Ensure the correct LSM context releaser
LSM: Use lsmcontext in security_secid_to_secctx
LSM: Use lsmcontext in security_lsmblob_to_secctx
LSM: Use lsmcontext in security_inode_getsecctx
LSM: Use lsmcontext in security_dentry_init_security
LSM: security_lsmblob_to_secctx module selection
Audit: Create audit_stamp structure
Audit: Allow multiple records in an audit_buffer
Audit: Add record for multiple task security contexts
audit: multiple subject lsm values for netlabel
Audit: Add record for multiple object contexts
LSM: Remove unused lsmcontext_init()
LSM: Improve logic in security_getprocattr
LSM: secctx provider check on release
LSM: Single calls in socket_getpeersec hooks
LSM: Exclusive secmark usage
LSM: Identify which LSM handles the context string
AppArmor: Remove the exclusive flag
LSM: Add mount opts blob size tracking
LSM: allocate mnt_opts blobs instead of module specific data
LSM: Infrastructure management of the key security blob
LSM: Infrastructure management of the mnt_opts security blob
LSM: Correct handling of ENOSYS in inode_setxattr
LSM: Remove lsmblob scaffolding
LSM: Allow reservation of netlabel
LSM: restrict security_cred_getsecid() to a single LSM
Smack: Remove LSM_FLAG_EXCLUSIVE

Documentation/ABI/testing/ima_policy | 8 +-
drivers/android/binder.c | 25 +-
fs/ceph/super.h | 3 +-
fs/ceph/xattr.c | 15 +-
fs/fuse/dir.c | 35 +-
fs/nfs/dir.c | 2 +-
fs/nfs/inode.c | 17 +-
fs/nfs/internal.h | 8 +-
fs/nfs/nfs4proc.c | 16 +-
fs/nfs/nfs4xdr.c | 22 +-
fs/nfsd/nfs4xdr.c | 21 +-
include/linux/audit.h | 13 +
include/linux/lsm/apparmor.h | 17 +
include/linux/lsm/bpf.h | 16 +
include/linux/lsm/selinux.h | 16 +
include/linux/lsm/smack.h | 17 +
include/linux/lsm_hook_defs.h | 35 +-
include/linux/lsm_hooks.h | 8 +
include/linux/nfs4.h | 8 +-
include/linux/nfs_fs.h | 2 +-
include/linux/security.h | 158 +++++++--
include/net/netlabel.h | 2 +-
include/net/scm.h | 12 +-
include/uapi/linux/audit.h | 2 +
kernel/audit.c | 269 +++++++++++----
kernel/audit.h | 20 +-
kernel/auditfilter.c | 9 +-
kernel/auditsc.c | 142 +++-----
net/ipv4/ip_sockglue.c | 12 +-
net/netfilter/nf_conntrack_netlink.c | 16 +-
net/netfilter/nf_conntrack_standalone.c | 11 +-
net/netfilter/nfnetlink_queue.c | 22 +-
net/netlabel/netlabel_unlabeled.c | 46 ++-
net/netlabel/netlabel_user.c | 10 +-
net/netlabel/netlabel_user.h | 2 +-
security/apparmor/audit.c | 19 +-
security/apparmor/include/audit.h | 8 +-
security/apparmor/include/net.h | 8 +-
security/apparmor/include/secid.h | 5 +-
security/apparmor/lsm.c | 65 +---
security/apparmor/net.c | 2 +-
security/apparmor/secid.c | 52 ++-
security/bpf/hooks.c | 1 +
security/integrity/ima/ima.h | 32 +-
security/integrity/ima/ima_api.c | 6 +-
security/integrity/ima/ima_appraise.c | 6 +-
security/integrity/ima/ima_main.c | 60 ++--
security/integrity/ima/ima_policy.c | 91 +++++-
security/security.c | 415 ++++++++++++++++++------
security/selinux/hooks.c | 285 +++++++++-------
security/selinux/include/audit.h | 13 +-
security/selinux/include/netlabel.h | 5 +
security/selinux/include/objsec.h | 12 +
security/selinux/netlabel.c | 27 +-
security/selinux/ss/services.c | 20 +-
security/smack/smack.h | 22 ++
security/smack/smack_lsm.c | 347 ++++++++++++--------
security/smack/smack_netfilter.c | 12 +-
security/smack/smackfs.c | 24 +-
59 files changed, 1691 insertions(+), 883 deletions(-)
create mode 100644 include/linux/lsm/apparmor.h
create mode 100644 include/linux/lsm/bpf.h
create mode 100644 include/linux/lsm/selinux.h
create mode 100644 include/linux/lsm/smack.h

--
2.41.0



2023-12-15 22:18:41

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 03/42] LSM: Add the lsmblob data structure.

When more than one security module is exporting data to audit and
networking sub-systems a single 32 bit integer is no longer
sufficient to represent the data. Add a structure to be used instead.

The lsmblob structure definition is intended to keep the LSM
specific information private to the individual security modules.
The module specific information is included in a new set of
header files under include/lsm. Each security module is allowed
to define the information included for its use in the lsmblob.
SELinux includes a u32 secid. Smack includes a pointer into its
global label list. The conditional compilation based on feature
inclusion is contained in the include/lsm files.

Suggested-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm/apparmor.h | 17 +++++++++++++++++
include/linux/lsm/bpf.h | 16 ++++++++++++++++
include/linux/lsm/selinux.h | 16 ++++++++++++++++
include/linux/lsm/smack.h | 17 +++++++++++++++++
include/linux/security.h | 20 ++++++++++++++++++++
5 files changed, 86 insertions(+)
create mode 100644 include/linux/lsm/apparmor.h
create mode 100644 include/linux/lsm/bpf.h
create mode 100644 include/linux/lsm/selinux.h
create mode 100644 include/linux/lsm/smack.h

diff --git a/include/linux/lsm/apparmor.h b/include/linux/lsm/apparmor.h
new file mode 100644
index 000000000000..8ff1cd899a20
--- /dev/null
+++ b/include/linux/lsm/apparmor.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Linux Security Module interface to other subsystems.
+ * AppArmor presents a single u32 value which is known as a secid.
+ */
+#ifndef __LINUX_LSM_APPARMOR_H
+#define __LINUX_LSM_APPARMOR_H
+
+struct aa_label;
+
+struct lsmblob_apparmor {
+#ifdef CONFIG_SECURITY_APPARMOR
+ struct aa_label *label;
+#endif
+};
+
+#endif /* ! __LINUX_LSM_APPARMOR_H */
diff --git a/include/linux/lsm/bpf.h b/include/linux/lsm/bpf.h
new file mode 100644
index 000000000000..48abdcd82ded
--- /dev/null
+++ b/include/linux/lsm/bpf.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Linux Security Module interface to other subsystems.
+ * BPF may present a single u32 value.
+ */
+#ifndef __LINUX_LSM_BPF_H
+#define __LINUX_LSM_BPF_H
+#include <linux/types.h>
+
+struct lsmblob_bpf {
+#ifdef CONFIG_BPF_LSM
+ u32 secid;
+#endif
+};
+
+#endif /* ! __LINUX_LSM_BPF_H */
diff --git a/include/linux/lsm/selinux.h b/include/linux/lsm/selinux.h
new file mode 100644
index 000000000000..fd16456b36ac
--- /dev/null
+++ b/include/linux/lsm/selinux.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Linux Security Module interface to other subsystems.
+ * SELinux presents a single u32 value which is known as a secid.
+ */
+#ifndef __LINUX_LSM_SELINUX_H
+#define __LINUX_LSM_SELINUX_H
+#include <linux/types.h>
+
+struct lsmblob_selinux {
+#ifdef CONFIG_SECURITY_SELINUX
+ u32 secid;
+#endif
+};
+
+#endif /* ! __LINUX_LSM_SELINUX_H */
diff --git a/include/linux/lsm/smack.h b/include/linux/lsm/smack.h
new file mode 100644
index 000000000000..2018f288302f
--- /dev/null
+++ b/include/linux/lsm/smack.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Linux Security Module interface to other subsystems.
+ * Smack presents a pointer into the global Smack label list.
+ */
+#ifndef __LINUX_LSM_SMACK_H
+#define __LINUX_LSM_SMACK_H
+
+struct smack_known;
+
+struct lsmblob_smack {
+#ifdef CONFIG_SECURITY_SMACK
+ struct smack_known *skp;
+#endif
+};
+
+#endif /* ! __LINUX_LSM_SMACK_H */
diff --git a/include/linux/security.h b/include/linux/security.h
index 4790508818ee..d4103b6cd3fc 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -33,6 +33,10 @@
#include <linux/mm.h>
#include <linux/sockptr.h>
#include <uapi/linux/lsm.h>
+#include <linux/lsm/selinux.h>
+#include <linux/lsm/smack.h>
+#include <linux/lsm/apparmor.h>
+#include <linux/lsm/bpf.h>

struct linux_binprm;
struct cred;
@@ -139,6 +143,22 @@ enum lockdown_reason {
LOCKDOWN_CONFIDENTIALITY_MAX,
};

+/* stacking scaffolding */
+struct lsmblob_scaffold {
+ u32 secid;
+};
+
+/*
+ * Data exported by the security modules
+ */
+struct lsmblob {
+ struct lsmblob_selinux selinux;
+ struct lsmblob_smack smack;
+ struct lsmblob_apparmor apparmor;
+ struct lsmblob_bpf bpf;
+ struct lsmblob_scaffold scaffold;
+};
+
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
extern u32 lsm_active_cnt;
extern const struct lsm_id *lsm_idlist[];
--
2.41.0


2023-12-15 22:18:59

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 02/42] SM: Infrastructure management of the sock security

Move management of the sock->sk_security blob out
of the individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.

Acked-by: Paul Moore <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Acked-by: Stephen Smalley <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/apparmor/include/net.h | 3 +-
security/apparmor/lsm.c | 20 +-------
security/apparmor/net.c | 2 +-
security/security.c | 36 ++++++++++++++-
security/selinux/hooks.c | 76 ++++++++++++++-----------------
security/selinux/include/objsec.h | 5 ++
security/selinux/netlabel.c | 23 +++++-----
security/smack/smack.h | 5 ++
security/smack/smack_lsm.c | 70 ++++++++++++++--------------
security/smack/smack_netfilter.c | 4 +-
11 files changed, 131 insertions(+), 114 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index a2ade0ffe9e7..efd4a0655159 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -73,6 +73,7 @@ struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
int lbs_inode;
+ int lbs_sock;
int lbs_superblock;
int lbs_ipc;
int lbs_msg_msg;
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index 67bf888c3bd6..c42ed8a73f1c 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -51,10 +51,9 @@ struct aa_sk_ctx {
struct aa_label *peer;
};

-#define SK_CTX(X) ((X)->sk_security)
static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
{
- return sk->sk_security;
+ return sk->sk_security + apparmor_blob_sizes.lbs_sock;
}

#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index e490a7000408..8af5f458e218 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1056,22 +1056,6 @@ static int apparmor_userns_create(const struct cred *cred)
return error;
}

-/**
- * apparmor_sk_alloc_security - allocate and attach the sk_security field
- */
-static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
-{
- struct aa_sk_ctx *ctx;
-
- ctx = kzalloc(sizeof(*ctx), flags);
- if (!ctx)
- return -ENOMEM;
-
- sk->sk_security = ctx;
-
- return 0;
-}
-
/**
* apparmor_sk_free_security - free the sk_security field
*/
@@ -1079,10 +1063,8 @@ static void apparmor_sk_free_security(struct sock *sk)
{
struct aa_sk_ctx *ctx = aa_sock(sk);

- sk->sk_security = NULL;
aa_put_label(ctx->label);
aa_put_label(ctx->peer);
- kfree(ctx);
}

/**
@@ -1452,6 +1434,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
.lbs_cred = sizeof(struct aa_label *),
.lbs_file = sizeof(struct aa_file_ctx),
.lbs_task = sizeof(struct aa_task_ctx),
+ .lbs_sock = sizeof(struct aa_sk_ctx),
};

static const struct lsm_id apparmor_lsmid = {
@@ -1497,7 +1480,6 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),

- LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),

diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index 87e934b2b548..77413a519117 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -151,7 +151,7 @@ static int aa_label_sk_perm(const struct cred *subj_cred,
const char *op, u32 request,
struct sock *sk)
{
- struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_sk_ctx *ctx = aa_sock(sk);
int error = 0;

AA_BUG(!label);
diff --git a/security/security.c b/security/security.c
index 8e5379a76369..0a51e3d23570 100644
--- a/security/security.c
+++ b/security/security.c
@@ -30,6 +30,7 @@
#include <linux/string.h>
#include <linux/msg.h>
#include <net/flow.h>
+#include <net/sock.h>

/* How many LSMs were built into the kernel? */
#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
@@ -226,6 +227,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
lsm_set_blob_size(&needed->lbs_xattr_count,
@@ -400,6 +402,7 @@ static void __init ordered_lsm_init(void)
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
+ init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
init_debug("task blob size = %d\n", blob_sizes.lbs_task);
init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
@@ -4626,6 +4629,28 @@ int security_socket_getpeersec_dgram(struct socket *sock,
}
EXPORT_SYMBOL(security_socket_getpeersec_dgram);

+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ * @priority: allocation mode
+ *
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_sock_alloc(struct sock *sock, gfp_t priority)
+{
+ if (blob_sizes.lbs_sock == 0) {
+ sock->sk_security = NULL;
+ return 0;
+ }
+
+ sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
+ if (sock->sk_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
/**
* security_sk_alloc() - Allocate and initialize a sock's LSM blob
* @sk: sock
@@ -4639,7 +4664,14 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
*/
int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
{
- return call_int_hook(sk_alloc_security, 0, sk, family, priority);
+ int rc = lsm_sock_alloc(sk, priority);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(sk_alloc_security, 0, sk, family, priority);
+ if (unlikely(rc))
+ security_sk_free(sk);
+ return rc;
}

/**
@@ -4651,6 +4683,8 @@ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
void security_sk_free(struct sock *sk)
{
call_void_hook(sk_free_security, sk);
+ kfree(sk->sk_security);
+ sk->sk_security = NULL;
}

/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b340425ccfae..aa15acd344ea 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4547,7 +4547,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,

static int sock_has_perm(struct sock *sk, u32 perms)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct common_audit_data ad;
struct lsm_network_audit net;

@@ -4600,7 +4600,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
isec->initialized = LABEL_INITIALIZED;

if (sock->sk) {
- sksec = sock->sk->sk_security;
+ sksec = selinux_sock(sock->sk);
sksec->sclass = sclass;
sksec->sid = sid;
/* Allows detection of the first association on this socket */
@@ -4616,8 +4616,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
static int selinux_socket_socketpair(struct socket *socka,
struct socket *sockb)
{
- struct sk_security_struct *sksec_a = socka->sk->sk_security;
- struct sk_security_struct *sksec_b = sockb->sk->sk_security;
+ struct sk_security_struct *sksec_a = selinux_sock(socka->sk);
+ struct sk_security_struct *sksec_b = selinux_sock(sockb->sk);

sksec_a->peer_sid = sksec_b->sid;
sksec_b->peer_sid = sksec_a->sid;
@@ -4632,7 +4632,7 @@ static int selinux_socket_socketpair(struct socket *socka,
static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u16 family;
int err;

@@ -4765,7 +4765,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
int err;

err = sock_has_perm(sk, SOCKET__CONNECT);
@@ -4943,9 +4943,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
struct sock *other,
struct sock *newsk)
{
- struct sk_security_struct *sksec_sock = sock->sk_security;
- struct sk_security_struct *sksec_other = other->sk_security;
- struct sk_security_struct *sksec_new = newsk->sk_security;
+ struct sk_security_struct *sksec_sock = selinux_sock(sock);
+ struct sk_security_struct *sksec_other = selinux_sock(other);
+ struct sk_security_struct *sksec_new = selinux_sock(newsk);
struct common_audit_data ad;
struct lsm_network_audit net;
int err;
@@ -4974,8 +4974,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
static int selinux_socket_unix_may_send(struct socket *sock,
struct socket *other)
{
- struct sk_security_struct *ssec = sock->sk->sk_security;
- struct sk_security_struct *osec = other->sk->sk_security;
+ struct sk_security_struct *ssec = selinux_sock(sock->sk);
+ struct sk_security_struct *osec = selinux_sock(other->sk);
struct common_audit_data ad;
struct lsm_network_audit net;

@@ -5012,7 +5012,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
u16 family)
{
int err = 0;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
struct lsm_network_audit net;
@@ -5041,7 +5041,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
int err, peerlbl_active, secmark_active;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u16 family = sk->sk_family;
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
@@ -5109,7 +5109,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
int err = 0;
char *scontext = NULL;
u32 scontext_len;
- struct sk_security_struct *sksec = sock->sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sock->sk);
u32 peer_sid = SECSID_NULL;

if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
@@ -5167,34 +5167,27 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *

static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
- struct sk_security_struct *sksec;
-
- sksec = kzalloc(sizeof(*sksec), priority);
- if (!sksec)
- return -ENOMEM;
+ struct sk_security_struct *sksec = selinux_sock(sk);

sksec->peer_sid = SECINITSID_UNLABELED;
sksec->sid = SECINITSID_UNLABELED;
sksec->sclass = SECCLASS_SOCKET;
selinux_netlbl_sk_security_reset(sksec);
- sk->sk_security = sksec;

return 0;
}

static void selinux_sk_free_security(struct sock *sk)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

- sk->sk_security = NULL;
selinux_netlbl_sk_security_free(sksec);
- kfree(sksec);
}

static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
+ struct sk_security_struct *newsksec = selinux_sock(newsk);

newsksec->sid = sksec->sid;
newsksec->peer_sid = sksec->peer_sid;
@@ -5208,7 +5201,7 @@ static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
if (!sk)
*secid = SECINITSID_ANY_SOCKET;
else {
- const struct sk_security_struct *sksec = sk->sk_security;
+ const struct sk_security_struct *sksec = selinux_sock(sk);

*secid = sksec->sid;
}
@@ -5218,7 +5211,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
{
struct inode_security_struct *isec =
inode_security_novalidate(SOCK_INODE(parent));
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
sk->sk_family == PF_UNIX)
@@ -5235,7 +5228,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
{
struct sock *sk = asoc->base.sk;
u16 family = sk->sk_family;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct common_audit_data ad;
struct lsm_network_audit net;
int err;
@@ -5290,7 +5283,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
static int selinux_sctp_assoc_request(struct sctp_association *asoc,
struct sk_buff *skb)
{
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
u32 conn_sid;
int err;

@@ -5323,7 +5316,7 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
static int selinux_sctp_assoc_established(struct sctp_association *asoc,
struct sk_buff *skb)
{
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);

if (!selinux_policycap_extsockclass())
return 0;
@@ -5422,8 +5415,8 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
struct sock *newsk)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
+ struct sk_security_struct *newsksec = selinux_sock(newsk);

/* If policy does not support SECCLASS_SCTP_SOCKET then call
* the non-sctp clone version.
@@ -5455,7 +5448,7 @@ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
int err;
u16 family = req->rsk_ops->family;
u32 connsid;
@@ -5476,7 +5469,7 @@ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
static void selinux_inet_csk_clone(struct sock *newsk,
const struct request_sock *req)
{
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *newsksec = selinux_sock(newsk);

newsksec->sid = req->secid;
newsksec->peer_sid = req->peer_secid;
@@ -5493,7 +5486,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
{
u16 family = sk->sk_family;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

/* handle mapped IPv4 packets arriving via IPv6 sockets */
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -5574,7 +5567,7 @@ static int selinux_tun_dev_attach_queue(void *security)
static int selinux_tun_dev_attach(struct sock *sk, void *security)
{
struct tun_security_struct *tunsec = security;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

/* we don't currently perform any NetLabel based labeling here and it
* isn't clear that we would want to do so anyway; while we could apply
@@ -5697,7 +5690,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
return NF_ACCEPT;

/* standard practice, label using the parent socket */
- sksec = sk->sk_security;
+ sksec = selinux_sock(sk);
sid = sksec->sid;
} else
sid = SECINITSID_KERNEL;
@@ -5720,7 +5713,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
sk = skb_to_full_sk(skb);
if (sk == NULL)
return NF_ACCEPT;
- sksec = sk->sk_security;
+ sksec = selinux_sock(sk);

ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
@@ -5809,7 +5802,7 @@ static unsigned int selinux_ip_postroute(void *priv,
u32 skb_sid;
struct sk_security_struct *sksec;

- sksec = sk->sk_security;
+ sksec = selinux_sock(sk);
if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
return NF_DROP;
/* At this point, if the returned skb peerlbl is SECSID_NULL
@@ -5838,7 +5831,7 @@ static unsigned int selinux_ip_postroute(void *priv,
} else {
/* Locally generated packet, fetch the security label from the
* associated socket. */
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
peer_sid = sksec->sid;
secmark_perm = PACKET__SEND;
}
@@ -5881,7 +5874,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
unsigned int data_len = skb->len;
unsigned char *data = skb->data;
struct nlmsghdr *nlh;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u16 sclass = sksec->sclass;
u32 perm;

@@ -6915,6 +6908,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
.lbs_msg_msg = sizeof(struct msg_security_struct),
+ .lbs_sock = sizeof(struct sk_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
};
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 8159fd53c3de..ca12d4d7cfc6 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -194,4 +194,9 @@ static inline struct superblock_security_struct *selinux_superblock(
return superblock->s_security + selinux_blob_sizes.lbs_superblock;
}

+static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
+{
+ return sock->sk_security + selinux_blob_sizes.lbs_sock;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 8f182800e412..e8832726bd86 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -17,6 +17,7 @@
#include <linux/gfp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
+#include <linux/lsm_hooks.h>
#include <net/sock.h>
#include <net/netlabel.h>
#include <net/ip.h>
@@ -68,7 +69,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr;

if (sksec->nlbl_secattr != NULL)
@@ -100,7 +101,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
const struct sock *sk,
u32 sid)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;

if (secattr == NULL)
@@ -240,7 +241,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
* being labeled by it's parent socket, if it is just exit */
sk = skb_to_full_sk(skb);
if (sk != NULL) {
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

if (sksec->nlbl_state != NLBL_REQSKB)
return 0;
@@ -277,7 +278,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
{
int rc;
struct netlbl_lsm_secattr secattr;
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;

@@ -356,7 +357,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
*/
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

if (family == PF_INET)
sksec->nlbl_state = NLBL_LABELED;
@@ -374,8 +375,8 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
*/
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
+ struct sk_security_struct *newsksec = selinux_sock(newsk);

newsksec->nlbl_state = sksec->nlbl_state;
}
@@ -393,7 +394,7 @@ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr;

if (family != PF_INET && family != PF_INET6)
@@ -507,7 +508,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
{
int rc = 0;
struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr secattr;

if (selinux_netlbl_option(level, optname) &&
@@ -545,7 +546,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
struct sockaddr *addr)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr;

/* connected sockets are allowed to disconnect when the address family
@@ -584,7 +585,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
int selinux_netlbl_socket_connect_locked(struct sock *sk,
struct sockaddr *addr)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);

if (sksec->nlbl_state != NLBL_REQSKB &&
sksec->nlbl_state != NLBL_CONNLABELED)
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 041688e5a77a..297f21446f45 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -355,6 +355,11 @@ static inline struct superblock_smack *smack_superblock(
return superblock->s_security + smack_blob_sizes.lbs_superblock;
}

+static inline struct socket_smack *smack_sock(const struct sock *sock)
+{
+ return sock->sk_security + smack_blob_sizes.lbs_sock;
+}
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 53336d7daa93..cd44f7f3f393 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1572,7 +1572,7 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
if (sock == NULL || sock->sk == NULL)
return -EOPNOTSUPP;

- ssp = sock->sk->sk_security;
+ ssp = smack_sock(sock->sk);

if (strcmp(name, XATTR_SMACK_IPIN) == 0)
isp = ssp->smk_in;
@@ -1960,7 +1960,7 @@ static int smack_file_receive(struct file *file)

if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
sock = SOCKET_I(inode);
- ssp = sock->sk->sk_security;
+ ssp = smack_sock(sock->sk);
tsp = smack_cred(current_cred());
/*
* If the receiving process can't write to the
@@ -2380,11 +2380,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
{
struct smack_known *skp = smk_of_current();
- struct socket_smack *ssp;
-
- ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
- if (ssp == NULL)
- return -ENOMEM;
+ struct socket_smack *ssp = smack_sock(sk);

/*
* Sockets created by kernel threads receive web label.
@@ -2398,11 +2394,10 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
}
ssp->smk_packet = NULL;

- sk->sk_security = ssp;
-
return 0;
}

+#ifdef SMACK_IPV6_PORT_LABELING
/**
* smack_sk_free_security - Free a socket blob
* @sk: the socket
@@ -2411,7 +2406,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
*/
static void smack_sk_free_security(struct sock *sk)
{
-#ifdef SMACK_IPV6_PORT_LABELING
struct smk_port_label *spp;

if (sk->sk_family == PF_INET6) {
@@ -2424,9 +2418,8 @@ static void smack_sk_free_security(struct sock *sk)
}
rcu_read_unlock();
}
-#endif
- kfree(sk->sk_security);
}
+#endif

/**
* smack_sk_clone_security - Copy security context
@@ -2437,8 +2430,8 @@ static void smack_sk_free_security(struct sock *sk)
*/
static void smack_sk_clone_security(const struct sock *sk, struct sock *newsk)
{
- struct socket_smack *ssp_old = sk->sk_security;
- struct socket_smack *ssp_new = newsk->sk_security;
+ struct socket_smack *ssp_old = smack_sock(sk);
+ struct socket_smack *ssp_new = smack_sock(newsk);

*ssp_new = *ssp_old;
}
@@ -2554,7 +2547,7 @@ static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip)
*/
static int smack_netlbl_add(struct sock *sk)
{
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp = ssp->smk_out;
int rc;

@@ -2586,7 +2579,7 @@ static int smack_netlbl_add(struct sock *sk)
*/
static void smack_netlbl_delete(struct sock *sk)
{
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);

/*
* Take the label off the socket if one is set.
@@ -2618,7 +2611,7 @@ static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap)
struct smack_known *skp;
int rc = 0;
struct smack_known *hkp;
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);
struct smk_audit_info ad;

rcu_read_lock();
@@ -2691,7 +2684,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
{
struct sock *sk = sock->sk;
struct sockaddr_in6 *addr6;
- struct socket_smack *ssp = sock->sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sock->sk);
struct smk_port_label *spp;
unsigned short port = 0;

@@ -2779,7 +2772,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
int act)
{
struct smk_port_label *spp;
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp = NULL;
unsigned short port;
struct smack_known *object;
@@ -2873,7 +2866,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
if (sock == NULL || sock->sk == NULL)
return -EOPNOTSUPP;

- ssp = sock->sk->sk_security;
+ ssp = smack_sock(sock->sk);

if (strcmp(name, XATTR_SMACK_IPIN) == 0)
ssp->smk_in = skp;
@@ -2921,7 +2914,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
* Sockets created by kernel threads receive web label.
*/
if (unlikely(current->flags & PF_KTHREAD)) {
- ssp = sock->sk->sk_security;
+ ssp = smack_sock(sock->sk);
ssp->smk_in = &smack_known_web;
ssp->smk_out = &smack_known_web;
}
@@ -2946,8 +2939,8 @@ static int smack_socket_post_create(struct socket *sock, int family,
static int smack_socket_socketpair(struct socket *socka,
struct socket *sockb)
{
- struct socket_smack *asp = socka->sk->sk_security;
- struct socket_smack *bsp = sockb->sk->sk_security;
+ struct socket_smack *asp = smack_sock(socka->sk);
+ struct socket_smack *bsp = smack_sock(sockb->sk);

asp->smk_packet = bsp->smk_out;
bsp->smk_packet = asp->smk_out;
@@ -3010,7 +3003,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
if (__is_defined(SMACK_IPV6_SECMARK_LABELING))
rsp = smack_ipv6host_label(sip);
if (rsp != NULL) {
- struct socket_smack *ssp = sock->sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sock->sk);

rc = smk_ipv6_check(ssp->smk_out, rsp, sip,
SMK_CONNECTING);
@@ -3805,9 +3798,9 @@ static int smack_unix_stream_connect(struct sock *sock,
{
struct smack_known *skp;
struct smack_known *okp;
- struct socket_smack *ssp = sock->sk_security;
- struct socket_smack *osp = other->sk_security;
- struct socket_smack *nsp = newsk->sk_security;
+ struct socket_smack *ssp = smack_sock(sock);
+ struct socket_smack *osp = smack_sock(other);
+ struct socket_smack *nsp = smack_sock(newsk);
struct smk_audit_info ad;
int rc = 0;
#ifdef CONFIG_AUDIT
@@ -3853,8 +3846,8 @@ static int smack_unix_stream_connect(struct sock *sock,
*/
static int smack_unix_may_send(struct socket *sock, struct socket *other)
{
- struct socket_smack *ssp = sock->sk->sk_security;
- struct socket_smack *osp = other->sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sock->sk);
+ struct socket_smack *osp = smack_sock(other->sk);
struct smk_audit_info ad;
int rc;

@@ -3891,7 +3884,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
#endif
#ifdef SMACK_IPV6_SECMARK_LABELING
- struct socket_smack *ssp = sock->sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sock->sk);
struct smack_known *rsp;
#endif
int rc = 0;
@@ -4103,7 +4096,7 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
netlbl_secattr_init(&secattr);

if (sk)
- ssp = sk->sk_security;
+ ssp = smack_sock(sk);

if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) {
skp = smack_from_secattr(&secattr, ssp);
@@ -4125,7 +4118,7 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
*/
static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp = NULL;
int rc = 0;
struct smk_audit_info ad;
@@ -4229,7 +4222,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
u32 slen = 1;
int rc = 0;

- ssp = sock->sk->sk_security;
+ ssp = smack_sock(sock->sk);
if (ssp->smk_packet != NULL) {
rcp = ssp->smk_packet->smk_known;
slen = strlen(rcp) + 1;
@@ -4279,7 +4272,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,

switch (family) {
case PF_UNIX:
- ssp = sock->sk->sk_security;
+ ssp = smack_sock(sock->sk);
s = ssp->smk_out->smk_secid;
break;
case PF_INET:
@@ -4328,7 +4321,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
(sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
return;

- ssp = sk->sk_security;
+ ssp = smack_sock(sk);
ssp->smk_in = skp;
ssp->smk_out = skp;
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
@@ -4348,7 +4341,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
{
u16 family = sk->sk_family;
struct smack_known *skp;
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);
struct sockaddr_in addr;
struct iphdr *hdr;
struct smack_known *hskp;
@@ -4434,7 +4427,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
static void smack_inet_csk_clone(struct sock *sk,
const struct request_sock *req)
{
- struct socket_smack *ssp = sk->sk_security;
+ struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp;

if (req->peer_secid != 0) {
@@ -5002,6 +4995,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_inode = sizeof(struct inode_smack),
.lbs_ipc = sizeof(struct smack_known *),
.lbs_msg_msg = sizeof(struct smack_known *),
+ .lbs_sock = sizeof(struct socket_smack),
.lbs_superblock = sizeof(struct superblock_smack),
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
};
@@ -5124,7 +5118,9 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream),
LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram),
LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security),
+#ifdef SMACK_IPV6_PORT_LABELING
LSM_HOOK_INIT(sk_free_security, smack_sk_free_security),
+#endif
LSM_HOOK_INIT(sk_clone_security, smack_sk_clone_security),
LSM_HOOK_INIT(sock_graft, smack_sock_graft),
LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request),
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index b945c1d3a743..bad71b7e648d 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -26,8 +26,8 @@ static unsigned int smack_ip_output(void *priv,
struct socket_smack *ssp;
struct smack_known *skp;

- if (sk && sk->sk_security) {
- ssp = sk->sk_security;
+ if (sk) {
+ ssp = smack_sock(sk);
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
}
--
2.41.0


2023-12-15 22:20:26

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 05/42] LSM: Use lsmblob in security_audit_rule_match

Change the secid parameter of security_audit_rule_match
to a lsmblob structure pointer. Pass the entry from the
lsmblob structure for the approprite slot to the LSM hook.

Change the users of security_audit_rule_match to use the
lsmblob instead of a u32. The scaffolding function lsmblob_init()
fills the blob with the value of the old secid, ensuring that
it is available to the appropriate module hook. The sources of
the secid, security_task_getsecid() and security_inode_getsecid(),
will be converted to use the blob structure later in the series.
At the point the use of lsmblob_init() is dropped.

Signed-off-by: Casey Schaufler <[email protected]>
Acked-by: Paul Moore <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Cc: [email protected]
---
include/linux/lsm_hook_defs.h | 4 ++--
include/linux/security.h | 13 +++++++------
kernel/auditfilter.c | 10 +++++++---
kernel/auditsc.c | 18 ++++++++++++++----
security/apparmor/audit.c | 10 ++++++++--
security/apparmor/include/audit.h | 3 ++-
security/integrity/ima/ima_policy.c | 11 +++++++----
security/security.c | 12 ++++++------
security/selinux/include/audit.h | 5 +++--
security/selinux/ss/services.c | 11 ++++++++---
security/smack/smack_lsm.c | 12 ++++++++----
11 files changed, 72 insertions(+), 37 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2159013890aa..24c588b87412 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -394,8 +394,8 @@ LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
void **lsmrule, int lsmid)
LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
-LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
- int lsmid)
+LSM_HOOK(int, 0, audit_rule_match, struct lsmblob *blob, u32 field, u32 op,
+ void *lsmrule, int lsmid)
LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule, int lsmid)
#endif /* CONFIG_AUDIT */

diff --git a/include/linux/security.h b/include/linux/security.h
index 2320ed78c4de..6ded4f04f117 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2013,7 +2013,8 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
#ifdef CONFIG_SECURITY
int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
int security_audit_rule_known(struct audit_krule *krule);
-int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
+int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
+ void *lsmrule);
void security_audit_rule_free(void *lsmrule);

#else
@@ -2029,8 +2030,8 @@ static inline int security_audit_rule_known(struct audit_krule *krule)
return 0;
}

-static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
- void *lsmrule)
+static inline int security_audit_rule_match(struct lsmblob *blob, u32 field,
+ u32 op, void *lsmrule)
{
return 0;
}
@@ -2044,8 +2045,8 @@ static inline void security_audit_rule_free(void *lsmrule)
#if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
int lsmid);
-int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
- int lsmid);
+int ima_filter_rule_match(struct lsmblob *blob, u32 field, u32 op,
+ void *lsmrule, int lsmid);
void ima_filter_rule_free(void *lsmrule, int lsmid);

#else
@@ -2056,7 +2057,7 @@ static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
return 0;
}

-static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
+static inline int ima_filter_rule_match(struct lsmblob *blob, u32 field, u32 op,
void *lsmrule, int lsmid)
{
return 0;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 8317a37dea0b..0a6a1c4c3507 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1338,6 +1338,7 @@ int audit_filter(int msgtype, unsigned int listtype)

for (i = 0; i < e->rule.field_count; i++) {
struct audit_field *f = &e->rule.fields[i];
+ struct lsmblob blob = { };
pid_t pid;
u32 sid;

@@ -1369,9 +1370,12 @@ int audit_filter(int msgtype, unsigned int listtype)
case AUDIT_SUBJ_SEN:
case AUDIT_SUBJ_CLR:
if (f->lsm_rule) {
- security_current_getsecid_subj(&sid);
- result = security_audit_rule_match(sid,
- f->type, f->op, f->lsm_rule);
+ /* stacking scaffolding */
+ security_current_getsecid_subj(
+ &blob.scaffold.secid);
+ result = security_audit_rule_match(
+ &blob, f->type, f->op,
+ f->lsm_rule);
}
break;
case AUDIT_EXE:
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6f0d6fb6523f..fb001300f0c2 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -471,6 +471,7 @@ static int audit_filter_rules(struct task_struct *tsk,
const struct cred *cred;
int i, need_sid = 1;
u32 sid;
+ struct lsmblob blob = { };
unsigned int sessionid;

if (ctx && rule->prio <= ctx->prio)
@@ -681,7 +682,10 @@ static int audit_filter_rules(struct task_struct *tsk,
security_current_getsecid_subj(&sid);
need_sid = 0;
}
- result = security_audit_rule_match(sid, f->type,
+ /* stacking scaffolding */
+ blob.scaffold.secid = sid;
+ result = security_audit_rule_match(&blob,
+ f->type,
f->op,
f->lsm_rule);
}
@@ -696,15 +700,19 @@ static int audit_filter_rules(struct task_struct *tsk,
if (f->lsm_rule) {
/* Find files that match */
if (name) {
+ /* stacking scaffolding */
+ blob.scaffold.secid = name->osid;
result = security_audit_rule_match(
- name->osid,
+ &blob,
f->type,
f->op,
f->lsm_rule);
} else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
+ /* stacking scaffolding */
+ blob.scaffold.secid = n->osid;
if (security_audit_rule_match(
- n->osid,
+ &blob,
f->type,
f->op,
f->lsm_rule)) {
@@ -716,7 +724,9 @@ static int audit_filter_rules(struct task_struct *tsk,
/* Find ipc objects that match */
if (!ctx || ctx->type != AUDIT_IPC)
break;
- if (security_audit_rule_match(ctx->ipc.osid,
+ /* stacking scaffolding */
+ blob.scaffold.secid = ctx->ipc.osid;
+ if (security_audit_rule_match(&blob,
f->type, f->op,
f->lsm_rule))
++result;
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 0a9f0019355a..72c414d00ba6 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -269,7 +269,8 @@ int aa_audit_rule_known(struct audit_krule *rule)
return 0;
}

-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
+int aa_audit_rule_match(struct lsmblob *blob, u32 field, u32 op, void *vrule,
+ int lsmid)
{
struct aa_audit_rule *rule = vrule;
struct aa_label *label;
@@ -277,7 +278,12 @@ int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)

if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
return 0;
- label = aa_secid_to_label(sid);
+
+ /* stacking scaffolding */
+ if (!blob->apparmor.label && blob->scaffold.secid)
+ label = aa_secid_to_label(blob->scaffold.secid);
+ else
+ label = blob->apparmor.label;

if (!label)
return -ENOENT;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index a75c45dd059f..ae3fc4089b00 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -203,6 +203,7 @@ void aa_audit_rule_free(void *vrule, int lsmid);
int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
int lsmid);
int aa_audit_rule_known(struct audit_krule *rule);
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid);
+int aa_audit_rule_match(struct lsmblob *blob, u32 field, u32 op, void *vrule,
+ int lsmid);

#endif /* __AA_AUDIT_H */
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index a563e0478cc6..d24205aa1beb 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -657,7 +657,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
int rc = 0;
- u32 osid;
+ struct lsmblob blob = { };

if (!lsm_rule->lsm[i].rule) {
if (!lsm_rule->lsm[i].args_p)
@@ -671,8 +671,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
case LSM_OBJ_USER:
case LSM_OBJ_ROLE:
case LSM_OBJ_TYPE:
- security_inode_getsecid(inode, &osid);
- rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
+ /* stacking scaffolding */
+ security_inode_getsecid(inode, &blob.scaffold.secid);
+ rc = ima_filter_rule_match(&blob, lsm_rule->lsm[i].type,
Audit_equal,
lsm_rule->lsm[i].rule,
lsm_rule->lsm[i].lsm_id);
@@ -680,7 +681,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
case LSM_SUBJ_TYPE:
- rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
+ /* stacking scaffolding */
+ blob.scaffold.secid = secid;
+ rc = ima_filter_rule_match(&blob, lsm_rule->lsm[i].type,
Audit_equal,
lsm_rule->lsm[i].rule,
lsm_rule->lsm[i].lsm_id);
diff --git a/security/security.c b/security/security.c
index cdf9ee12b064..b3d150b6248e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5408,7 +5408,7 @@ void security_audit_rule_free(void *lsmrule)

/**
* security_audit_rule_match() - Check if a label matches an audit rule
- * @secid: security label
+ * @lsmblob: security label
* @field: LSM audit field
* @op: matching operator
* @lsmrule: audit rule
@@ -5419,9 +5419,9 @@ void security_audit_rule_free(void *lsmrule)
* Return: Returns 1 if secid matches the rule, 0 if it does not, -ERRNO on
* failure.
*/
-int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
+int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op, void *lsmrule)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
+ return call_int_hook(audit_rule_match, 0, blob, field, op, lsmrule,
LSM_ID_UNDEF);
}
#endif /* CONFIG_AUDIT */
@@ -5443,10 +5443,10 @@ void ima_filter_rule_free(void *lsmrule, int lsmid)
call_void_hook(audit_rule_free, lsmrule, lsmid);
}

-int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
- int lsmid)
+int ima_filter_rule_match(struct lsmblob *blob, u32 field, u32 op,
+ void *lsmrule, int lsmid)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
+ return call_int_hook(audit_rule_match, 0, blob, field, op, lsmrule,
lsmid);
}
#endif /* CONFIG_IMA_LSM_RULES */
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 59468baf0c91..61a396c9d9ae 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -42,7 +42,7 @@ void selinux_audit_rule_free(void *rule, int lsmid);

/**
* selinux_audit_rule_match - determine if a context ID matches a rule.
- * @sid: the context ID to check
+ * @blob: includes the context ID to check
* @field: the field this rule refers to
* @op: the operator the rule uses
* @rule: pointer to the audit rule to check against
@@ -51,7 +51,8 @@ void selinux_audit_rule_free(void *rule, int lsmid);
* Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure.
*/
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, int lsmid);
+int selinux_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
+ void *rule, int lsmid);

/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index a9fe8d85acae..eef6655f7730 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3627,7 +3627,8 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}

-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
+int selinux_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
+ void *vrule, int lsmid)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
@@ -3655,10 +3656,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
goto out;
}

- ctxt = sidtab_search(policy->sidtab, sid);
+ /* stacking scaffolding */
+ if (!blob->selinux.secid && blob->scaffold.secid)
+ blob->selinux.secid = blob->scaffold.secid;
+
+ ctxt = sidtab_search(policy->sidtab, blob->selinux.secid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
- sid);
+ blob->selinux.secid);
match = -ENOENT;
goto out;
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 4342947f51d8..9851d56dff69 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4726,7 +4726,7 @@ static int smack_audit_rule_known(struct audit_krule *krule)

/**
* smack_audit_rule_match - Audit given object ?
- * @secid: security id for identifying the object to test
+ * @blob: security id for identifying the object to test
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
@@ -4735,8 +4735,8 @@ static int smack_audit_rule_known(struct audit_krule *krule)
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
*/
-static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
- int lsmid)
+static int smack_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
+ void *vrule, int lsmid)
{
struct smack_known *skp;
char *rule = vrule;
@@ -4751,7 +4751,11 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return 0;

- skp = smack_from_secid(secid);
+ /* stacking scaffolding */
+ if (!blob->smack.skp && blob->scaffold.secid)
+ skp = smack_from_secid(blob->scaffold.secid);
+ else
+ skp = blob->smack.skp;

/*
* No need to do string comparisons. If a match occurs,
--
2.41.0


2023-12-15 22:21:43

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 07/42] Audit: maintain an lsmblob in audit_context

Replace the secid value stored in struct audit_context with a struct
lsmblob. Change the code that uses this value to accommodate the
change. security_audit_rule_match() expects a lsmblob, so existing
scaffolding can be removed. A call to security_secid_to_secctx()
is changed to security_lsmblob_to_secctx(). The call to
security_ipc_getsecid() is scaffolded.

A new function lsmblob_is_set() is introduced to identify whether
an lsmblob contains a non-zero value.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/security.h | 13 +++++++++++++
kernel/audit.h | 3 ++-
kernel/auditsc.c | 19 ++++++++-----------
3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 7e4b31b771c1..029cf071148b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -276,6 +276,19 @@ static inline const char *kernel_load_data_id_str(enum kernel_load_data_id id)
return kernel_load_data_str[id];
}

+/**
+ * lsmblob_is_set - report if there is a value in the lsmblob
+ * @blob: Pointer to the exported LSM data
+ *
+ * Returns true if there is a value set, false otherwise
+ */
+static inline bool lsmblob_is_set(struct lsmblob *blob)
+{
+ const struct lsmblob empty = {};
+
+ return !!memcmp(blob, &empty, sizeof(*blob));
+}
+
#ifdef CONFIG_SECURITY

int call_blocking_lsm_notifier(enum lsm_event event, void *data);
diff --git a/kernel/audit.h b/kernel/audit.h
index a60d2840559e..b1f2de4d4f1e 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -11,6 +11,7 @@

#include <linux/fs.h>
#include <linux/audit.h>
+#include <linux/security.h>
#include <linux/skbuff.h>
#include <uapi/linux/mqueue.h>
#include <linux/tty.h>
@@ -160,7 +161,7 @@ struct audit_context {
kuid_t uid;
kgid_t gid;
umode_t mode;
- u32 osid;
+ struct lsmblob oblob;
int has_perm;
uid_t perm_uid;
gid_t perm_gid;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index fb001300f0c2..52b4697d938c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -724,9 +724,7 @@ static int audit_filter_rules(struct task_struct *tsk,
/* Find ipc objects that match */
if (!ctx || ctx->type != AUDIT_IPC)
break;
- /* stacking scaffolding */
- blob.scaffold.secid = ctx->ipc.osid;
- if (security_audit_rule_match(&blob,
+ if (security_audit_rule_match(&ctx->ipc.oblob,
f->type, f->op,
f->lsm_rule))
++result;
@@ -1394,19 +1392,17 @@ static void show_special(struct audit_context *context, int *call_panic)
audit_log_format(ab, " a%d=%lx", i,
context->socketcall.args[i]);
break; }
- case AUDIT_IPC: {
- u32 osid = context->ipc.osid;
-
+ case AUDIT_IPC:
audit_log_format(ab, "ouid=%u ogid=%u mode=%#ho",
from_kuid(&init_user_ns, context->ipc.uid),
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
- if (osid) {
+ if (lsmblob_is_set(&context->ipc.oblob)) {
char *ctx = NULL;
u32 len;

- if (security_secid_to_secctx(osid, &ctx, &len)) {
- audit_log_format(ab, " osid=%u", osid);
+ if (security_lsmblob_to_secctx(&context->ipc.oblob,
+ &ctx, &len)) {
*call_panic = 1;
} else {
audit_log_format(ab, " obj=%s", ctx);
@@ -1426,7 +1422,7 @@ static void show_special(struct audit_context *context, int *call_panic)
context->ipc.perm_gid,
context->ipc.perm_mode);
}
- break; }
+ break;
case AUDIT_MQ_OPEN:
audit_log_format(ab,
"oflag=0x%x mode=%#ho mq_flags=0x%lx mq_maxmsg=%ld "
@@ -2642,7 +2638,8 @@ void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
context->ipc.gid = ipcp->gid;
context->ipc.mode = ipcp->mode;
context->ipc.has_perm = 0;
- security_ipc_getsecid(ipcp, &context->ipc.osid);
+ /* stacking scaffolding */
+ security_ipc_getsecid(ipcp, &context->ipc.oblob.scaffold.secid);
context->type = AUDIT_IPC;
}

--
2.41.0


2023-12-15 22:23:19

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 08/42] LSM: Use lsmblob in security_ipc_getsecid

There may be more than one LSM that provides IPC data for auditing.
Change security_ipc_getsecid() to fill in a lsmblob structure instead
of the u32 secid. Change the name to security_ipc_getlsmblob() to
reflect the change. The audit data structure containing the secid
will be updated later, so there is a bit of scaffolding here.

Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Acked-by: Stephen Smalley <[email protected]>
Acked-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
include/linux/lsm_hook_defs.h | 4 ++--
include/linux/security.h | 18 +++++++++++++++---
kernel/auditsc.c | 3 +--
security/security.c | 14 +++++++-------
security/selinux/hooks.c | 9 ++++++---
security/smack/smack_lsm.c | 17 ++++++++++-------
6 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 52d090d1957c..d69332031270 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -234,8 +234,8 @@ 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, ipc_permission, struct kern_ipc_perm *ipcp, short flag)
-LSM_HOOK(void, LSM_RET_VOID, ipc_getsecid, struct kern_ipc_perm *ipcp,
- u32 *secid)
+LSM_HOOK(void, LSM_RET_VOID, ipc_getlsmblob, struct kern_ipc_perm *ipcp,
+ struct lsmblob *blob)
LSM_HOOK(int, 0, msg_msg_alloc_security, struct msg_msg *msg)
LSM_HOOK(void, LSM_RET_VOID, msg_msg_free_security, struct msg_msg *msg)
LSM_HOOK(int, 0, msg_queue_alloc_security, struct kern_ipc_perm *perm)
diff --git a/include/linux/security.h b/include/linux/security.h
index 029cf071148b..2ca118960234 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -289,6 +289,17 @@ static inline bool lsmblob_is_set(struct lsmblob *blob)
return !!memcmp(blob, &empty, sizeof(*blob));
}

+/**
+ * lsmblob_init - initialize a lsmblob structure
+ * @blob: Pointer to the data to initialize
+ *
+ * Set all secid for all modules to the specified value.
+ */
+static inline void lsmblob_init(struct lsmblob *blob)
+{
+ memset(blob, 0, sizeof(*blob));
+}
+
#ifdef CONFIG_SECURITY

int call_blocking_lsm_notifier(enum lsm_event event, void *data);
@@ -487,7 +498,7 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
void security_task_to_inode(struct task_struct *p, struct inode *inode);
int security_create_user_ns(const struct cred *cred);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
-void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
+void security_ipc_getlsmblob(struct kern_ipc_perm *ipcp, struct lsmblob *blob);
int security_msg_msg_alloc(struct msg_msg *msg);
void security_msg_msg_free(struct msg_msg *msg);
int security_msg_queue_alloc(struct kern_ipc_perm *msq);
@@ -1299,9 +1310,10 @@ static inline int security_ipc_permission(struct kern_ipc_perm *ipcp,
return 0;
}

-static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+static inline void security_ipc_getlsmblob(struct kern_ipc_perm *ipcp,
+ struct lsmblob *blob)
{
- *secid = 0;
+ lsmblob_init(blob);
}

static inline int security_msg_msg_alloc(struct msg_msg *msg)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 52b4697d938c..89d490db0494 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2638,8 +2638,7 @@ void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
context->ipc.gid = ipcp->gid;
context->ipc.mode = ipcp->mode;
context->ipc.has_perm = 0;
- /* stacking scaffolding */
- security_ipc_getsecid(ipcp, &context->ipc.oblob.scaffold.secid);
+ security_ipc_getlsmblob(ipcp, &context->ipc.oblob);
context->type = AUDIT_IPC;
}

diff --git a/security/security.c b/security/security.c
index 4b78bface040..b82245d55f66 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3595,17 +3595,17 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
}

/**
- * security_ipc_getsecid() - Get the sysv ipc object's secid
+ * security_ipc_getlsmblob() - Get the sysv ipc object LSM data
* @ipcp: ipc permission structure
- * @secid: secid pointer
+ * @blob: pointer to lsm information
*
- * Get the secid associated with the ipc object. In case of failure, @secid
- * will be set to zero.
+ * Get the lsm information associated with the ipc object.
*/
-void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+
+void security_ipc_getlsmblob(struct kern_ipc_perm *ipcp, struct lsmblob *blob)
{
- *secid = 0;
- call_void_hook(ipc_getsecid, ipcp, secid);
+ lsmblob_init(blob);
+ call_void_hook(ipc_getlsmblob, ipcp, blob);
}

/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 83ce496e8ef6..f15991ef6ca8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6266,10 +6266,13 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
return ipc_has_perm(ipcp, av);
}

-static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+static void selinux_ipc_getlsmblob(struct kern_ipc_perm *ipcp,
+ struct lsmblob *blob)
{
struct ipc_security_struct *isec = selinux_ipc(ipcp);
- *secid = isec->sid;
+ blob->selinux.secid = isec->sid;
+ /* stacking scaffolding */
+ blob->scaffold.secid = isec->sid;
}

static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
@@ -7165,7 +7168,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(userns_create, selinux_userns_create),

LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
- LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
+ LSM_HOOK_INIT(ipc_getlsmblob, selinux_ipc_getlsmblob),

LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a4ace6ea2ab0..b00f4f44f9c5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3396,16 +3396,19 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
}

/**
- * smack_ipc_getsecid - Extract smack security id
+ * smack_ipc_getlsmblob - Extract smack security data
* @ipp: the object permissions
- * @secid: where result will be saved
+ * @blob: where result will be saved
*/
-static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
+static void smack_ipc_getlsmblob(struct kern_ipc_perm *ipp,
+ struct lsmblob *blob)
{
- struct smack_known **blob = smack_ipc(ipp);
- struct smack_known *iskp = *blob;
+ struct smack_known **iskpp = smack_ipc(ipp);
+ struct smack_known *iskp = *iskpp;

- *secid = iskp->smk_secid;
+ blob->smack.skp = iskp;
+ /* stacking scaffolding */
+ blob->scaffold.secid = iskp->smk_secid;
}

/**
@@ -5109,7 +5112,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_to_inode, smack_task_to_inode),

LSM_HOOK_INIT(ipc_permission, smack_ipc_permission),
- LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid),
+ LSM_HOOK_INIT(ipc_getlsmblob, smack_ipc_getlsmblob),

LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security),

--
2.41.0


2023-12-15 22:24:43

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 01/42] integrity: disassociate ima_filter_rule from security_audit_rule

Create real functions for the ima_filter_rule interfaces.
These replace #defines that obscure the reuse of audit
interfaces. The new functions are put in security.c because
they use security module registered hooks that we don't
want exported.

Acked-by: Paul Moore <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
To: Mimi Zohar <[email protected]>
Cc: [email protected]
---
include/linux/security.h | 24 ++++++++++++++++++++++++
security/integrity/ima/ima.h | 26 --------------------------
security/security.c | 21 +++++++++++++++++++++
3 files changed, 45 insertions(+), 26 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 750130a7b9dd..4790508818ee 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2009,6 +2009,30 @@ static inline void security_audit_rule_free(void *lsmrule)
#endif /* CONFIG_SECURITY */
#endif /* CONFIG_AUDIT */

+#if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
+int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
+int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
+void ima_filter_rule_free(void *lsmrule);
+
+#else
+
+static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
+ void **lsmrule)
+{
+ return 0;
+}
+
+static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
+ void *lsmrule)
+{
+ return 0;
+}
+
+static inline void ima_filter_rule_free(void *lsmrule)
+{ }
+
+#endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
+
#ifdef CONFIG_SECURITYFS

extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c29db699c996..560d6104de72 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -420,32 +420,6 @@ static inline void ima_free_modsig(struct modsig *modsig)
}
#endif /* CONFIG_IMA_APPRAISE_MODSIG */

-/* LSM based policy rules require audit */
-#ifdef CONFIG_IMA_LSM_RULES
-
-#define ima_filter_rule_init security_audit_rule_init
-#define ima_filter_rule_free security_audit_rule_free
-#define ima_filter_rule_match security_audit_rule_match
-
-#else
-
-static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
- void **lsmrule)
-{
- return -EINVAL;
-}
-
-static inline void ima_filter_rule_free(void *lsmrule)
-{
-}
-
-static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
- void *lsmrule)
-{
- return -EINVAL;
-}
-#endif /* CONFIG_IMA_LSM_RULES */
-
#ifdef CONFIG_IMA_READ_POLICY
#define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
#else
diff --git a/security/security.c b/security/security.c
index d7b15ea67c3f..8e5379a76369 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5350,6 +5350,27 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
}
#endif /* CONFIG_AUDIT */

+#ifdef CONFIG_IMA_LSM_RULES
+/*
+ * The integrity subsystem uses the same hooks as
+ * the audit subsystem.
+ */
+int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
+{
+ return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
+}
+
+void ima_filter_rule_free(void *lsmrule)
+{
+ call_void_hook(audit_rule_free, lsmrule);
+}
+
+int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
+{
+ return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
+}
+#endif /* CONFIG_IMA_LSM_RULES */
+
#ifdef CONFIG_BPF_SYSCALL
/**
* security_bpf() - Check if the bpf syscall operation is allowed
--
2.41.0


2023-12-15 22:25:12

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 10/42] LSM: Use lsmblob in security_current_getsecid

Change the security_current_getsecid_subj() and
security_task_getsecid_obj() interfaces to fill in
a lsmblob structure instead of a u32 secid in support of
LSM stacking. Audit interfaces will need to collect all
possible security data for possible reporting.

Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Acked-by: Stephen Smalley <[email protected]>
Acked-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
include/linux/lsm_hook_defs.h | 6 +--
include/linux/security.h | 13 +++---
kernel/audit.c | 11 +++--
kernel/auditfilter.c | 3 +-
kernel/auditsc.c | 22 ++++++----
net/netlabel/netlabel_unlabeled.c | 5 ++-
net/netlabel/netlabel_user.h | 6 ++-
security/apparmor/lsm.c | 20 ++++++---
security/integrity/ima/ima.h | 6 +--
security/integrity/ima/ima_api.c | 6 +--
security/integrity/ima/ima_appraise.c | 6 +--
security/integrity/ima/ima_main.c | 59 ++++++++++++++-------------
security/integrity/ima/ima_policy.c | 14 +++----
security/security.c | 28 ++++++-------
security/selinux/hooks.c | 17 +++++---
security/smack/smack_lsm.c | 23 +++++++----
16 files changed, 138 insertions(+), 107 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index d69332031270..2db7320a1e05 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -213,9 +213,9 @@ LSM_HOOK(int, 0, task_fix_setgroups, struct cred *new, const struct cred * old)
LSM_HOOK(int, 0, task_setpgid, struct task_struct *p, pid_t pgid)
LSM_HOOK(int, 0, task_getpgid, struct task_struct *p)
LSM_HOOK(int, 0, task_getsid, struct task_struct *p)
-LSM_HOOK(void, LSM_RET_VOID, current_getsecid_subj, u32 *secid)
-LSM_HOOK(void, LSM_RET_VOID, task_getsecid_obj,
- struct task_struct *p, u32 *secid)
+LSM_HOOK(void, LSM_RET_VOID, current_getlsmblob_subj, struct lsmblob *blob)
+LSM_HOOK(void, LSM_RET_VOID, task_getlsmblob_obj,
+ struct task_struct *p, struct lsmblob *blob)
LSM_HOOK(int, 0, task_setnice, struct task_struct *p, int nice)
LSM_HOOK(int, 0, task_setioprio, struct task_struct *p, int ioprio)
LSM_HOOK(int, 0, task_getioprio, struct task_struct *p)
diff --git a/include/linux/security.h b/include/linux/security.h
index 2ca118960234..6306e8ab0cf6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -479,8 +479,8 @@ int security_task_fix_setgroups(struct cred *new, const struct cred *old);
int security_task_setpgid(struct task_struct *p, pid_t pgid);
int security_task_getpgid(struct task_struct *p);
int security_task_getsid(struct task_struct *p);
-void security_current_getsecid_subj(u32 *secid);
-void security_task_getsecid_obj(struct task_struct *p, u32 *secid);
+void security_current_getlsmblob_subj(struct lsmblob *blob);
+void security_task_getlsmblob_obj(struct task_struct *p, struct lsmblob *blob);
int security_task_setnice(struct task_struct *p, int nice);
int security_task_setioprio(struct task_struct *p, int ioprio);
int security_task_getioprio(struct task_struct *p);
@@ -1227,14 +1227,15 @@ static inline int security_task_getsid(struct task_struct *p)
return 0;
}

-static inline void security_current_getsecid_subj(u32 *secid)
+static inline void security_current_getlsmblob_subj(struct lsmblob *blob)
{
- *secid = 0;
+ lsmblob_init(blob);
}

-static inline void security_task_getsecid_obj(struct task_struct *p, u32 *secid)
+static inline void security_task_getlsmblob_obj(struct task_struct *p,
+ struct lsmblob *blob)
{
- *secid = 0;
+ lsmblob_init(blob);
}

static inline int security_task_setnice(struct task_struct *p, int nice)
diff --git a/kernel/audit.c b/kernel/audit.c
index 875df831fb61..54dfe339e341 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -2164,16 +2164,16 @@ void audit_log_key(struct audit_buffer *ab, char *key)

int audit_log_task_context(struct audit_buffer *ab)
{
+ struct lsmblob blob;
char *ctx = NULL;
unsigned len;
int error;
- u32 sid;

- security_current_getsecid_subj(&sid);
- if (!sid)
+ security_current_getlsmblob_subj(&blob);
+ if (!lsmblob_is_set(&blob))
return 0;

- error = security_secid_to_secctx(sid, &ctx, &len);
+ error = security_lsmblob_to_secctx(&blob, &ctx, &len);
if (error) {
if (error != -EINVAL)
goto error_path;
@@ -2390,8 +2390,7 @@ int audit_signal_info(int sig, struct task_struct *t)
audit_sig_uid = auid;
else
audit_sig_uid = uid;
- /* stacking scaffolding */
- security_current_getsecid_subj(&audit_sig_lsm.scaffold.secid);
+ security_current_getlsmblob_subj(&audit_sig_lsm);
}

return audit_signal_info_syscall(t);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 08dc64bb8496..d0df226bdc51 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1370,8 +1370,7 @@ int audit_filter(int msgtype, unsigned int listtype)
case AUDIT_SUBJ_CLR:
if (f->lsm_rule) {
/* stacking scaffolding */
- security_current_getsecid_subj(
- &blob.scaffold.secid);
+ security_current_getlsmblob_subj(&blob);
result = security_audit_rule_match(
&blob, f->type, f->op,
f->lsm_rule);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 89d490db0494..7afeae468745 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -470,7 +470,6 @@ static int audit_filter_rules(struct task_struct *tsk,
{
const struct cred *cred;
int i, need_sid = 1;
- u32 sid;
struct lsmblob blob = { };
unsigned int sessionid;

@@ -675,15 +674,14 @@ static int audit_filter_rules(struct task_struct *tsk,
* fork()/copy_process() in which case
* the new @tsk creds are still a dup
* of @current's creds so we can still
- * use security_current_getsecid_subj()
+ * use
+ * security_current_getlsmblob_subj()
* here even though it always refs
* @current's creds
*/
- security_current_getsecid_subj(&sid);
+ security_current_getlsmblob_subj(&blob);
need_sid = 0;
}
- /* stacking scaffolding */
- blob.scaffold.secid = sid;
result = security_audit_rule_match(&blob,
f->type,
f->op,
@@ -2730,12 +2728,15 @@ int __audit_sockaddr(int len, void *a)
void __audit_ptrace(struct task_struct *t)
{
struct audit_context *context = audit_context();
+ struct lsmblob blob;

context->target_pid = task_tgid_nr(t);
context->target_auid = audit_get_loginuid(t);
context->target_uid = task_uid(t);
context->target_sessionid = audit_get_sessionid(t);
- security_task_getsecid_obj(t, &context->target_sid);
+ security_task_getlsmblob_obj(t, &blob);
+ /* stacking scaffolding */
+ context->target_sid = blob.scaffold.secid;
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
}

@@ -2751,6 +2752,7 @@ int audit_signal_info_syscall(struct task_struct *t)
struct audit_aux_data_pids *axp;
struct audit_context *ctx = audit_context();
kuid_t t_uid = task_uid(t);
+ struct lsmblob blob;

if (!audit_signals || audit_dummy_context())
return 0;
@@ -2762,7 +2764,9 @@ int audit_signal_info_syscall(struct task_struct *t)
ctx->target_auid = audit_get_loginuid(t);
ctx->target_uid = t_uid;
ctx->target_sessionid = audit_get_sessionid(t);
- security_task_getsecid_obj(t, &ctx->target_sid);
+ security_task_getlsmblob_obj(t, &blob);
+ /* stacking scaffolding */
+ ctx->target_sid = blob.scaffold.secid;
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
return 0;
}
@@ -2783,7 +2787,9 @@ int audit_signal_info_syscall(struct task_struct *t)
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
axp->target_uid[axp->pid_count] = t_uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
- security_task_getsecid_obj(t, &axp->target_sid[axp->pid_count]);
+ security_task_getlsmblob_obj(t, &blob);
+ /* stacking scaffolding */
+ axp->target_sid[axp->pid_count] = blob.scaffold.secid;
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
axp->pid_count++;

diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 9996883bf2b7..129d71c147f1 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1534,11 +1534,14 @@ int __init netlbl_unlabel_defconf(void)
int ret_val;
struct netlbl_dom_map *entry;
struct netlbl_audit audit_info;
+ struct lsmblob blob;

/* Only the kernel is allowed to call this function and the only time
* it is called is at bootup before the audit subsystem is reporting
* messages so don't worry to much about these values. */
- security_current_getsecid_subj(&audit_info.secid);
+ security_current_getlsmblob_subj(&blob);
+ /* stacking scaffolding */
+ audit_info.secid = blob.scaffold.secid;
audit_info.loginuid = GLOBAL_ROOT_UID;
audit_info.sessionid = 0;

diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index d6c5b31eb4eb..c4864fa18a08 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -32,7 +32,11 @@
*/
static inline void netlbl_netlink_auditinfo(struct netlbl_audit *audit_info)
{
- security_current_getsecid_subj(&audit_info->secid);
+ struct lsmblob blob;
+
+ security_current_getlsmblob_subj(&blob);
+ /* stacking scaffolding */
+ audit_info->secid = blob.scaffold.secid;
audit_info->loginuid = audit_get_loginuid(current);
audit_info->sessionid = audit_get_sessionid(current);
}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 1b230ade84fc..b5f3beb26d5a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -979,17 +979,24 @@ static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm)
return;
}

-static void apparmor_current_getsecid_subj(u32 *secid)
+static void apparmor_current_getlsmblob_subj(struct lsmblob *blob)
{
struct aa_label *label = __begin_current_label_crit_section();
- *secid = label->secid;
+
+ blob->apparmor.label = label;
+ /* stacking scaffolding */
+ blob->scaffold.secid = label->secid;
__end_current_label_crit_section(label);
}

-static void apparmor_task_getsecid_obj(struct task_struct *p, u32 *secid)
+static void apparmor_task_getlsmblob_obj(struct task_struct *p,
+ struct lsmblob *blob)
{
struct aa_label *label = aa_get_task_label(p);
- *secid = label->secid;
+
+ blob->apparmor.label = label;
+ /* stacking scaffolding */
+ blob->scaffold.secid = label->secid;
aa_put_label(label);
}

@@ -1519,8 +1526,9 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {

LSM_HOOK_INIT(task_free, apparmor_task_free),
LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
- LSM_HOOK_INIT(current_getsecid_subj, apparmor_current_getsecid_subj),
- LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid_obj),
+ LSM_HOOK_INIT(current_getlsmblob_subj,
+ apparmor_current_getlsmblob_subj),
+ LSM_HOOK_INIT(task_getlsmblob_obj, apparmor_task_getlsmblob_obj),
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
LSM_HOOK_INIT(task_kill, apparmor_task_kill),
LSM_HOOK_INIT(userns_create, apparmor_userns_create),
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 560d6104de72..53f794b75bf9 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -256,7 +256,7 @@ static inline void ima_process_queued_keys(void) {}

/* LIM API function definitions */
int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
- const struct cred *cred, u32 secid, int mask,
+ const struct cred *cred, struct lsmblob *blob, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos);
@@ -287,8 +287,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);

/* IMA policy related functions */
int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode,
- const struct cred *cred, u32 secid, enum ima_hooks func,
- int mask, int flags, int *pcr,
+ const struct cred *cred, struct lsmblob *blob,
+ enum ima_hooks func, int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos);
void ima_init_policy(void);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 597ea0c4d72f..f9f74419f5ef 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -165,7 +165,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* @idmap: idmap of the mount the inode was found from
* @inode: pointer to the inode associated with the object being validated
* @cred: pointer to credentials structure to validate
- * @secid: secid of the task being validated
+ * @blob: secid(s) of the task being validated
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
* MAY_APPEND)
* @func: caller identifier
@@ -187,7 +187,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
*
*/
int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
- const struct cred *cred, u32 secid, int mask,
+ const struct cred *cred, struct lsmblob *blob, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos)
@@ -196,7 +196,7 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,

flags &= ima_policy_flag;

- return ima_match_policy(idmap, inode, cred, secid, func, mask,
+ return ima_match_policy(idmap, inode, cred, blob, func, mask,
flags, pcr, template_desc, func_data,
allowed_algos);
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 870dde67707b..41cf92d15972 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -73,13 +73,13 @@ bool is_ima_appraise_enabled(void)
int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
int mask, enum ima_hooks func)
{
- u32 secid;
+ struct lsmblob blob;

if (!ima_appraise)
return 0;

- security_current_getsecid_subj(&secid);
- return ima_match_policy(idmap, inode, current_cred(), secid,
+ security_current_getlsmblob_subj(&blob);
+ return ima_match_policy(idmap, inode, current_cred(), &blob,
func, mask, IMA_APPRAISE | IMA_HASH, NULL,
NULL, NULL, NULL);
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cc1217ac2c6f..657143fe558d 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -205,8 +205,8 @@ void ima_file_free(struct file *file)
}

static int process_measurement(struct file *file, const struct cred *cred,
- u32 secid, char *buf, loff_t size, int mask,
- enum ima_hooks func)
+ struct lsmblob *blob, char *buf, loff_t size,
+ int mask, enum ima_hooks func)
{
struct inode *backing_inode, *inode = file_inode(file);
struct integrity_iint_cache *iint = NULL;
@@ -230,7 +230,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
* bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask.
*/
- action = ima_get_action(file_mnt_idmap(file), inode, cred, secid,
+ action = ima_get_action(file_mnt_idmap(file), inode, cred, blob,
mask, func, &pcr, &template_desc, NULL,
&allowed_algos);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
@@ -430,23 +430,23 @@ static int process_measurement(struct file *file, const struct cred *cred,
int ima_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags)
{
- u32 secid;
+ struct lsmblob blob;
int ret;

if (!file)
return 0;

- security_current_getsecid_subj(&secid);
+ security_current_getlsmblob_subj(&blob);

if (reqprot & PROT_EXEC) {
- ret = process_measurement(file, current_cred(), secid, NULL,
+ ret = process_measurement(file, current_cred(), &blob, NULL,
0, MAY_EXEC, MMAP_CHECK_REQPROT);
if (ret)
return ret;
}

if (prot & PROT_EXEC)
- return process_measurement(file, current_cred(), secid, NULL,
+ return process_measurement(file, current_cred(), &blob, NULL,
0, MAY_EXEC, MMAP_CHECK);

return 0;
@@ -473,9 +473,9 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
char *pathbuf = NULL;
const char *pathname = NULL;
struct inode *inode;
+ struct lsmblob blob;
int result = 0;
int action;
- u32 secid;
int pcr;

/* Is mprotect making an mmap'ed file executable? */
@@ -483,13 +483,13 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
!(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
return 0;

- security_current_getsecid_subj(&secid);
+ security_current_getlsmblob_subj(&blob);
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_idmap(vma->vm_file), inode,
- current_cred(), secid, MAY_EXEC, MMAP_CHECK,
+ current_cred(), &blob, MAY_EXEC, MMAP_CHECK,
&pcr, &template, NULL, NULL);
action |= ima_get_action(file_mnt_idmap(vma->vm_file), inode,
- current_cred(), secid, MAY_EXEC,
+ current_cred(), &blob, MAY_EXEC,
MMAP_CHECK_REQPROT, &pcr, &template, NULL,
NULL);

@@ -527,15 +527,18 @@ int ima_bprm_check(struct linux_binprm *bprm)
{
int ret;
u32 secid;
+ struct lsmblob blob = { };

- security_current_getsecid_subj(&secid);
- ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
- MAY_EXEC, BPRM_CHECK);
+ security_current_getlsmblob_subj(&blob);
+ ret = process_measurement(bprm->file, current_cred(),
+ &blob, NULL, 0, MAY_EXEC, BPRM_CHECK);
if (ret)
return ret;

security_cred_getsecid(bprm->cred, &secid);
- return process_measurement(bprm->file, bprm->cred, secid, NULL, 0,
+ /* stacking scaffolding */
+ blob.scaffold.secid = secid;
+ return process_measurement(bprm->file, bprm->cred, &blob, NULL, 0,
MAY_EXEC, CREDS_CHECK);
}

@@ -551,10 +554,10 @@ int ima_bprm_check(struct linux_binprm *bprm)
*/
int ima_file_check(struct file *file, int mask)
{
- u32 secid;
+ struct lsmblob blob;

- security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL, 0,
+ security_current_getlsmblob_subj(&blob);
+ return process_measurement(file, current_cred(), &blob, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
}
@@ -755,7 +758,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
bool contents)
{
enum ima_hooks func;
- u32 secid;
+ struct lsmblob blob;

/*
* Do devices using pre-allocated memory run the risk of the
@@ -775,9 +778,9 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id,

/* Read entire file for all partial reads. */
func = read_idmap[read_id] ?: FILE_CHECK;
- security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, NULL,
- 0, MAY_READ, func);
+ security_current_getlsmblob_subj(&blob);
+ return process_measurement(file, current_cred(), &blob, NULL, 0,
+ MAY_READ, func);
}

const int read_idmap[READING_MAX_ID] = {
@@ -805,7 +808,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id read_id)
{
enum ima_hooks func;
- u32 secid;
+ struct lsmblob blob;

/* permit signed certs */
if (!file && read_id == READING_X509_CERTIFICATE)
@@ -818,8 +821,8 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
}

func = read_idmap[read_id] ?: FILE_CHECK;
- security_current_getsecid_subj(&secid);
- return process_measurement(file, current_cred(), secid, buf, size,
+ security_current_getlsmblob_subj(&blob);
+ return process_measurement(file, current_cred(), &blob, buf, size,
MAY_READ, func);
}

@@ -945,7 +948,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
int digest_hash_len = hash_digest_size[ima_hash_algo];
int violation = 0;
int action = 0;
- u32 secid;
+ struct lsmblob blob;

if (digest && digest_len < digest_hash_len)
return -EINVAL;
@@ -968,9 +971,9 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
* buffer measurements.
*/
if (func) {
- security_current_getsecid_subj(&secid);
+ security_current_getlsmblob_subj(&blob);
action = ima_get_action(idmap, inode, current_cred(),
- secid, 0, func, &pcr, &template,
+ &blob, 0, func, &pcr, &template,
func_data, NULL);
if (!(action & IMA_MEASURE) && !digest)
return -ENOENT;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index d24205aa1beb..48287b75fe77 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -579,7 +579,7 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule,
* @idmap: idmap of the mount the inode was found from
* @inode: a pointer to an inode
* @cred: a pointer to a credentials structure for user validation
- * @secid: the secid of the task to be validated
+ * @blob: the secid(s) of the task to be validated
* @func: LIM hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @func_data: func specific data, may be NULL
@@ -589,7 +589,7 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule,
static bool ima_match_rules(struct ima_rule_entry *rule,
struct mnt_idmap *idmap,
struct inode *inode, const struct cred *cred,
- u32 secid, enum ima_hooks func, int mask,
+ struct lsmblob *blob, enum ima_hooks func, int mask,
const char *func_data)
{
int i;
@@ -681,8 +681,6 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
case LSM_SUBJ_TYPE:
- /* stacking scaffolding */
- blob.scaffold.secid = secid;
rc = ima_filter_rule_match(&blob, lsm_rule->lsm[i].type,
Audit_equal,
lsm_rule->lsm[i].rule,
@@ -748,7 +746,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @inode: pointer to an inode for which the policy decision is being made
* @cred: pointer to a credentials structure for which the policy decision is
* being made
- * @secid: LSM secid of the task to be validated
+ * @blob: LSM secid(s) of the task to be validated
* @func: IMA hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @flags: IMA actions to consider (e.g. IMA_MEASURE | IMA_APPRAISE)
@@ -765,8 +763,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* than writes so ima_match_policy() is classical RCU candidate.
*/
int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode,
- const struct cred *cred, u32 secid, enum ima_hooks func,
- int mask, int flags, int *pcr,
+ const struct cred *cred, struct lsmblob *blob,
+ enum ima_hooks func, int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos)
{
@@ -784,7 +782,7 @@ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode,
if (!(entry->action & actmask))
continue;

- if (!ima_match_rules(entry, idmap, inode, cred, secid,
+ if (!ima_match_rules(entry, idmap, inode, cred, blob,
func, mask, func_data))
continue;

diff --git a/security/security.c b/security/security.c
index b82245d55f66..58387e1f0c04 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3357,33 +3357,33 @@ int security_task_getsid(struct task_struct *p)
}

/**
- * security_current_getsecid_subj() - Get the current task's subjective secid
- * @secid: secid value
+ * security_current_getlsmblob_subj() - Current task's subjective LSM data
+ * @blob: lsm specific information
*
* Retrieve the subjective security identifier of the current task and return
- * it in @secid. In case of failure, @secid will be set to zero.
+ * it in @blob.
*/
-void security_current_getsecid_subj(u32 *secid)
+void security_current_getlsmblob_subj(struct lsmblob *blob)
{
- *secid = 0;
- call_void_hook(current_getsecid_subj, secid);
+ lsmblob_init(blob);
+ call_void_hook(current_getlsmblob_subj, blob);
}
-EXPORT_SYMBOL(security_current_getsecid_subj);
+EXPORT_SYMBOL(security_current_getlsmblob_subj);

/**
- * security_task_getsecid_obj() - Get a task's objective secid
+ * security_task_getlsmblob_obj() - Get a task's objective LSM data
* @p: target task
- * @secid: secid value
+ * @blob: lsm specific information
*
* Retrieve the objective security identifier of the task_struct in @p and
- * return it in @secid. In case of failure, @secid will be set to zero.
+ * return it in @blob.
*/
-void security_task_getsecid_obj(struct task_struct *p, u32 *secid)
+void security_task_getlsmblob_obj(struct task_struct *p, struct lsmblob *blob)
{
- *secid = 0;
- call_void_hook(task_getsecid_obj, p, secid);
+ lsmblob_init(blob);
+ call_void_hook(task_getlsmblob_obj, p, blob);
}
-EXPORT_SYMBOL(security_task_getsecid_obj);
+EXPORT_SYMBOL(security_task_getlsmblob_obj);

/**
* security_task_setnice() - Check if setting a task's nice value is allowed
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f15991ef6ca8..d70000363b7a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4124,14 +4124,19 @@ static int selinux_task_getsid(struct task_struct *p)
PROCESS__GETSESSION, NULL);
}

-static void selinux_current_getsecid_subj(u32 *secid)
+static void selinux_current_getlsmblob_subj(struct lsmblob *blob)
{
- *secid = current_sid();
+ blob->selinux.secid = current_sid();
+ /* stacking scaffolding */
+ blob->scaffold.secid = blob->selinux.secid;
}

-static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
+static void selinux_task_getlsmblob_obj(struct task_struct *p,
+ struct lsmblob *blob)
{
- *secid = task_sid_obj(p);
+ blob->selinux.secid = task_sid_obj(p);
+ /* stacking scaffolding */
+ blob->scaffold.secid = blob->selinux.secid;
}

static int selinux_task_setnice(struct task_struct *p, int nice)
@@ -7153,8 +7158,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
- LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj),
- LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj),
+ LSM_HOOK_INIT(current_getlsmblob_subj, selinux_current_getlsmblob_subj),
+ LSM_HOOK_INIT(task_getlsmblob_obj, selinux_task_getlsmblob_obj),
LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b00f4f44f9c5..46cc79eb1200 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2210,30 +2210,35 @@ static int smack_task_getsid(struct task_struct *p)
}

/**
- * smack_current_getsecid_subj - get the subjective secid of the current task
- * @secid: where to put the result
+ * smack_current_getlsmblob_subj - get the subjective secid of the current task
+ * @blob: where to put the result
*
* Sets the secid to contain a u32 version of the task's subjective smack label.
*/
-static void smack_current_getsecid_subj(u32 *secid)
+static void smack_current_getlsmblob_subj(struct lsmblob *blob)
{
struct smack_known *skp = smk_of_current();

- *secid = skp->smk_secid;
+ blob->smack.skp = skp;
+ /* stacking scaffolding */
+ blob->scaffold.secid = skp->smk_secid;
}

/**
- * smack_task_getsecid_obj - get the objective secid of the task
+ * smack_task_getlsmblob_obj - get the objective data of the task
* @p: the task
* @secid: where to put the result
*
* Sets the secid to contain a u32 version of the task's objective smack label.
*/
-static void smack_task_getsecid_obj(struct task_struct *p, u32 *secid)
+static void smack_task_getlsmblob_obj(struct task_struct *p,
+ struct lsmblob *blob)
{
struct smack_known *skp = smk_of_task_struct_obj(p);

- *secid = skp->smk_secid;
+ blob->smack.skp = skp;
+ /* stacking scaffolding */
+ blob->scaffold.secid = skp->smk_secid;
}

/**
@@ -5100,8 +5105,8 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_setpgid, smack_task_setpgid),
LSM_HOOK_INIT(task_getpgid, smack_task_getpgid),
LSM_HOOK_INIT(task_getsid, smack_task_getsid),
- LSM_HOOK_INIT(current_getsecid_subj, smack_current_getsecid_subj),
- LSM_HOOK_INIT(task_getsecid_obj, smack_task_getsecid_obj),
+ LSM_HOOK_INIT(current_getlsmblob_subj, smack_current_getlsmblob_subj),
+ LSM_HOOK_INIT(task_getlsmblob_obj, smack_task_getlsmblob_obj),
LSM_HOOK_INIT(task_setnice, smack_task_setnice),
LSM_HOOK_INIT(task_setioprio, smack_task_setioprio),
LSM_HOOK_INIT(task_getioprio, smack_task_getioprio),
--
2.41.0


2023-12-15 22:27:19

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 04/42] IMA: avoid label collisions with stacked LSMs

Integrity measurement may filter on security module information
and needs to be clear in the case of multiple active security
modules which applies. Provide a boot option ima_rules_lsm= to
allow the user to specify an active security module to apply
filters to. If not specified, use the first registered module
that supports the audit_rule_match() LSM hook. Allow the user
to specify in the IMA policy an lsm= option to specify the
security module to use for a particular rule.

This requires adding the LSM of interest as a parameter
to three of the audit hooks.

Signed-off-by: Casey Schaufler <[email protected]>
To: Mimi Zohar <[email protected]>
To: [email protected]
To: [email protected]
---
Documentation/ABI/testing/ima_policy | 8 +++-
include/linux/lsm_hook_defs.h | 7 +--
include/linux/security.h | 26 +++++++---
security/apparmor/audit.c | 15 ++++--
security/apparmor/include/audit.h | 7 +--
security/integrity/ima/ima_policy.c | 71 ++++++++++++++++++++++++----
security/security.c | 64 +++++++++++++++++++++----
security/selinux/include/audit.h | 10 ++--
security/selinux/ss/services.c | 15 ++++--
security/smack/smack_lsm.c | 12 ++++-
10 files changed, 192 insertions(+), 43 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index c2385183826c..a59291b97c24 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -26,7 +26,7 @@ Description:
[uid=] [euid=] [gid=] [egid=]
[fowner=] [fgroup=]]
lsm: [[subj_user=] [subj_role=] [subj_type=]
- [obj_user=] [obj_role=] [obj_type=]]
+ [obj_user=] [obj_role=] [obj_type=] [lsm=]]
option: [digest_type=] [template=] [permit_directio]
[appraise_type=] [appraise_flag=]
[appraise_algos=] [keyrings=]
@@ -138,6 +138,12 @@ Description:

measure subj_user=_ func=FILE_CHECK mask=MAY_READ

+ It is possible to explicitly specify which security
+ module a rule applies to using lsm=. If the security
+ module specified is not active on the system the rule
+ will be rejected. If lsm= is not specified the first
+ security module registered on the system will be assumed.
+
Example of measure rules using alternate PCRs::

measure func=KEXEC_KERNEL_CHECK pcr=4
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index c925a0d26edf..2159013890aa 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -392,10 +392,11 @@ LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)

#ifdef CONFIG_AUDIT
LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
- void **lsmrule)
+ void **lsmrule, int lsmid)
LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
-LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
-LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
+LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
+ int lsmid)
+LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule, int lsmid)
#endif /* CONFIG_AUDIT */

#ifdef CONFIG_BPF_SYSCALL
diff --git a/include/linux/security.h b/include/linux/security.h
index d4103b6cd3fc..2320ed78c4de 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -286,6 +286,8 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
extern int security_init(void);
extern int early_security_init(void);
extern u64 lsm_name_to_attr(const char *name);
+extern u64 lsm_name_to_id(const char *name);
+extern const char *lsm_id_to_name(u64 id);

/* Security operations */
int security_binder_set_context_mgr(const struct cred *mgr);
@@ -536,6 +538,16 @@ static inline u64 lsm_name_to_attr(const char *name)
return LSM_ATTR_UNDEF;
}

+static inline u64 lsm_name_to_id(const char *name)
+{
+ return LSM_ID_UNDEF;
+}
+
+static inline const char *lsm_id_to_name(u64 id)
+{
+ return NULL;
+}
+
static inline void security_free_mnt_opts(void **mnt_opts)
{
}
@@ -2030,25 +2042,27 @@ static inline void security_audit_rule_free(void *lsmrule)
#endif /* CONFIG_AUDIT */

#if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
-int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
-int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
-void ima_filter_rule_free(void *lsmrule);
+int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
+ int lsmid);
+int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
+ int lsmid);
+void ima_filter_rule_free(void *lsmrule, int lsmid);

#else

static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
- void **lsmrule)
+ void **lsmrule, int lsmid)
{
return 0;
}

static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
- void *lsmrule)
+ void *lsmrule, int lsmid)
{
return 0;
}

-static inline void ima_filter_rule_free(void *lsmrule)
+static inline void ima_filter_rule_free(void *lsmrule, int lsmid)
{ }

#endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 45beb1c5f747..0a9f0019355a 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -206,10 +206,12 @@ struct aa_audit_rule {
struct aa_label *label;
};

-void aa_audit_rule_free(void *vrule)
+void aa_audit_rule_free(void *vrule, int lsmid)
{
struct aa_audit_rule *rule = vrule;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
+ return;
if (rule) {
if (!IS_ERR(rule->label))
aa_put_label(rule->label);
@@ -217,10 +219,13 @@ void aa_audit_rule_free(void *vrule)
}
}

-int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
+ int lsmid)
{
struct aa_audit_rule *rule;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
+ return 0;
switch (field) {
case AUDIT_SUBJ_ROLE:
if (op != Audit_equal && op != Audit_not_equal)
@@ -240,7 +245,7 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
GFP_KERNEL, true, false);
if (IS_ERR(rule->label)) {
int err = PTR_ERR(rule->label);
- aa_audit_rule_free(rule);
+ aa_audit_rule_free(rule, LSM_ID_APPARMOR);
return err;
}

@@ -264,12 +269,14 @@ int aa_audit_rule_known(struct audit_krule *rule)
return 0;
}

-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
{
struct aa_audit_rule *rule = vrule;
struct aa_label *label;
int found = 0;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
+ return 0;
label = aa_secid_to_label(sid);

if (!label)
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index acbb03b9bd25..a75c45dd059f 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -199,9 +199,10 @@ static inline int complain_error(int error)
return error;
}

-void aa_audit_rule_free(void *vrule);
-int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
+void aa_audit_rule_free(void *vrule, int lsmid);
+int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
+ int lsmid);
int aa_audit_rule_known(struct audit_krule *rule);
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid);

#endif /* __AA_AUDIT_H */
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index f69062617754..a563e0478cc6 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -117,6 +117,8 @@ struct ima_rule_entry {
void *rule; /* LSM file metadata specific */
char *args_p; /* audit value */
int type; /* audit type */
+ int lsm_id; /* which LSM rule applies to */
+ bool lsm_specific; /* true if lsm is specified */
} lsm[MAX_LSM_RULES];
char *fsname;
struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
@@ -309,6 +311,25 @@ static int __init default_appraise_policy_setup(char *str)
}
__setup("ima_appraise_tcb", default_appraise_policy_setup);

+static int default_rules_lsm __ro_after_init = LSM_ID_UNDEF;
+
+static int __init ima_rules_lsm_init(char *str)
+{
+ int newdrl;
+
+ newdrl = lsm_name_to_id(str);
+ if (newdrl >= 0) {
+ default_rules_lsm = newdrl;
+ return 1;
+ }
+
+ pr_err("default ima rule lsm \"%s\" not registered, value unchanged.",
+ str);
+
+ return 1;
+}
+__setup("ima_rules_lsm=", ima_rules_lsm_init);
+
static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
{
struct ima_rule_opt_list *opt_list;
@@ -380,7 +401,8 @@ static void ima_lsm_free_rule(struct ima_rule_entry *entry)
int i;

for (i = 0; i < MAX_LSM_RULES; i++) {
- ima_filter_rule_free(entry->lsm[i].rule);
+ ima_filter_rule_free(entry->lsm[i].rule,
+ entry->lsm[i].lsm_id);
kfree(entry->lsm[i].args_p);
}
}
@@ -425,7 +447,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)

ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
nentry->lsm[i].args_p,
- &nentry->lsm[i].rule);
+ &nentry->lsm[i].rule,
+ entry->lsm[i].lsm_id);
if (!nentry->lsm[i].rule)
pr_warn("rule for LSM \'%s\' is undefined\n",
nentry->lsm[i].args_p);
@@ -451,7 +474,8 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
* be owned by nentry.
*/
for (i = 0; i < MAX_LSM_RULES; i++)
- ima_filter_rule_free(entry->lsm[i].rule);
+ ima_filter_rule_free(entry->lsm[i].rule,
+ entry->lsm[i].lsm_id);
kfree(entry);

return 0;
@@ -650,14 +674,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
security_inode_getsecid(inode, &osid);
rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
Audit_equal,
- lsm_rule->lsm[i].rule);
+ lsm_rule->lsm[i].rule,
+ lsm_rule->lsm[i].lsm_id);
break;
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
case LSM_SUBJ_TYPE:
rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
Audit_equal,
- lsm_rule->lsm[i].rule);
+ lsm_rule->lsm[i].rule,
+ lsm_rule->lsm[i].lsm_id);
break;
default:
break;
@@ -680,7 +706,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
out:
if (rule_reinitialized) {
for (i = 0; i < MAX_LSM_RULES; i++)
- ima_filter_rule_free(lsm_rule->lsm[i].rule);
+ ima_filter_rule_free(lsm_rule->lsm[i].rule,
+ lsm_rule->lsm[i].lsm_id);
kfree(lsm_rule);
}
return result;
@@ -1073,7 +1100,7 @@ enum policy_opt {
Opt_digest_type,
Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
- Opt_label, Opt_err
+ Opt_lsm, Opt_label, Opt_err
};

static const match_table_t policy_tokens = {
@@ -1121,6 +1148,7 @@ static const match_table_t policy_tokens = {
{Opt_pcr, "pcr=%s"},
{Opt_template, "template=%s"},
{Opt_keyrings, "keyrings=%s"},
+ {Opt_lsm, "lsm=%s"},
{Opt_label, "label=%s"},
{Opt_err, NULL}
};
@@ -1140,7 +1168,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
entry->lsm[lsm_rule].type = audit_type;
result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal,
entry->lsm[lsm_rule].args_p,
- &entry->lsm[lsm_rule].rule);
+ &entry->lsm[lsm_rule].rule,
+ entry->lsm[lsm_rule].lsm_id);
if (!entry->lsm[lsm_rule].rule) {
pr_warn("rule for LSM \'%s\' is undefined\n",
entry->lsm[lsm_rule].args_p);
@@ -1878,6 +1907,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
&(template_desc->num_fields));
entry->template = template_desc;
break;
+ case Opt_lsm: {
+ int i;
+
+ result = lsm_name_to_id(args[0].from);
+ if (result < 0) {
+ for (i = 0; i < MAX_LSM_RULES; i++)
+ entry->lsm[i].args_p = NULL;
+ result = -EINVAL;
+ break;
+ }
+ for (i = 0; i < MAX_LSM_RULES; i++) {
+ entry->lsm[i].lsm_id = result;
+ entry->lsm[i].lsm_specific = true;
+ }
+ result = 0;
+ break;
+ }
case Opt_err:
ima_log_string(ab, "UNKNOWN", p);
result = -EINVAL;
@@ -1923,6 +1969,7 @@ ssize_t ima_parse_add_rule(char *rule)
struct ima_rule_entry *entry;
ssize_t result, len;
int audit_info = 0;
+ int i;

p = strsep(&rule, "\n");
len = strlen(p) + 1;
@@ -1940,6 +1987,11 @@ ssize_t ima_parse_add_rule(char *rule)

INIT_LIST_HEAD(&entry->list);

+ for (i = 0; i < MAX_LSM_RULES; i++) {
+ entry->lsm[i].lsm_id = default_rules_lsm;
+ entry->lsm[i].lsm_specific = false;
+ }
+
result = ima_parse_rule(p, entry);
if (result) {
ima_free_rule(entry);
@@ -2251,6 +2303,9 @@ int ima_policy_show(struct seq_file *m, void *v)
entry->lsm[i].args_p);
break;
}
+ if (entry->lsm[i].lsm_specific)
+ seq_printf(m, pt(Opt_lsm),
+ lsm_id_to_name(entry->lsm[i].lsm_id));
seq_puts(m, " ");
}
}
diff --git a/security/security.c b/security/security.c
index 0a51e3d23570..cdf9ee12b064 100644
--- a/security/security.c
+++ b/security/security.c
@@ -271,6 +271,46 @@ static void __init initialize_lsm(struct lsm_info *lsm)
u32 lsm_active_cnt __ro_after_init;
const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT];

+/**
+ * lsm_name_to_id - get the LSM ID for a registered LSM
+ * @name: the name of the LSM
+ *
+ * Returns the LSM ID associated with the named LSM or
+ * LSM_ID_UNDEF if the name isn't recongnized.
+ */
+u64 lsm_name_to_id(const char *name)
+{
+ int i;
+
+ for (i = 0; i < LSM_CONFIG_COUNT; i++) {
+ if (!lsm_idlist[i]->name)
+ return LSM_ID_UNDEF;
+ if (!strcmp(name, lsm_idlist[i]->name))
+ return lsm_idlist[i]->id;
+ }
+ return LSM_ID_UNDEF;
+}
+
+/**
+ * lsm_id_to_name - get the LSM name for a registered LSM ID
+ * @id: the ID of the LSM
+ *
+ * Returns the LSM name associated with the LSM ID or
+ * NULL if the ID isn't recongnized.
+ */
+const char *lsm_id_to_name(u64 id)
+{
+ int i;
+
+ for (i = 0; i < LSM_CONFIG_COUNT; i++) {
+ if (!lsm_idlist[i]->name)
+ return NULL;
+ if (id == lsm_idlist[i]->id)
+ return lsm_idlist[i]->name;
+ }
+ return NULL;
+}
+
/* Populate ordered LSMs list from comma-separated LSM name list. */
static void __init ordered_lsm_parse(const char *order, const char *origin)
{
@@ -5336,7 +5376,8 @@ int security_key_getsecurity(struct key *key, char **buffer)
*/
int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
{
- return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
+ return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
+ LSM_ID_UNDEF);
}

/**
@@ -5362,7 +5403,7 @@ int security_audit_rule_known(struct audit_krule *krule)
*/
void security_audit_rule_free(void *lsmrule)
{
- call_void_hook(audit_rule_free, lsmrule);
+ call_void_hook(audit_rule_free, lsmrule, LSM_ID_UNDEF);
}

/**
@@ -5380,7 +5421,8 @@ void security_audit_rule_free(void *lsmrule)
*/
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
+ return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
+ LSM_ID_UNDEF);
}
#endif /* CONFIG_AUDIT */

@@ -5389,19 +5431,23 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
* The integrity subsystem uses the same hooks as
* the audit subsystem.
*/
-int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
+int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
+ int lsmid)
{
- return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
+ return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
+ lsmid);
}

-void ima_filter_rule_free(void *lsmrule)
+void ima_filter_rule_free(void *lsmrule, int lsmid)
{
- call_void_hook(audit_rule_free, lsmrule);
+ call_void_hook(audit_rule_free, lsmrule, lsmid);
}

-int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
+int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
+ int lsmid)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
+ return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
+ lsmid);
}
#endif /* CONFIG_IMA_LSM_RULES */

diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index d5495134a5b9..59468baf0c91 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -21,21 +21,24 @@
* @op: the operator the rule uses
* @rulestr: the text "target" of the rule
* @rule: pointer to the new rule structure returned via this
+ * @lsmid: the relevant LSM
*
* Returns 0 if successful, -errno if not. On success, the rule structure
* will be allocated internally. The caller must free this structure with
* selinux_audit_rule_free() after use.
*/
-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
+ int lsmid);

/**
* selinux_audit_rule_free - free an selinux audit rule structure.
* @rule: pointer to the audit rule to be freed
+ * @lsmid: which LSM this rule relates to
*
* This will free all memory associated with the given rule.
* If @rule is NULL, no operation is performed.
*/
-void selinux_audit_rule_free(void *rule);
+void selinux_audit_rule_free(void *rule, int lsmid);

/**
* selinux_audit_rule_match - determine if a context ID matches a rule.
@@ -43,11 +46,12 @@ void selinux_audit_rule_free(void *rule);
* @field: the field this rule refers to
* @op: the operator the rule uses
* @rule: pointer to the audit rule to check against
+ * @lsmid: the relevant LSM
*
* Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure.
*/
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, int lsmid);

/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1eeffc66ea7d..a9fe8d85acae 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3487,17 +3487,20 @@ struct selinux_audit_rule {
struct context au_ctxt;
};

-void selinux_audit_rule_free(void *vrule)
+void selinux_audit_rule_free(void *vrule, int lsmid)
{
struct selinux_audit_rule *rule = vrule;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
+ return;
if (rule) {
context_destroy(&rule->au_ctxt);
kfree(rule);
}
}

-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
+ int lsmid)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
@@ -3511,6 +3514,8 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)

*rule = NULL;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
+ return 0;
if (!selinux_initialized())
return -EOPNOTSUPP;

@@ -3592,7 +3597,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)

err:
rcu_read_unlock();
- selinux_audit_rule_free(tmprule);
+ selinux_audit_rule_free(tmprule, LSM_ID_SELINUX);
*rule = NULL;
return rc;
}
@@ -3622,7 +3627,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}

-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
@@ -3631,6 +3636,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
struct selinux_audit_rule *rule = vrule;
int match = 0;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
+ return 0;
if (unlikely(!rule)) {
WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
return -ENOENT;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index cd44f7f3f393..4342947f51d8 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4672,16 +4672,20 @@ static int smack_post_notification(const struct cred *w_cred,
* @op: required testing operator (=, !=, >, <, ...)
* @rulestr: smack label to be audited
* @vrule: pointer to save our own audit rule representation
+ * @lsmid: the relevant LSM
*
* Prepare to audit cases where (@field @op @rulestr) is true.
* The label to be audited is created if necessay.
*/
-static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
+ int lsmid)
{
struct smack_known *skp;
char **rule = (char **)vrule;
*rule = NULL;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
+ return 0;
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return -EINVAL;

@@ -4726,15 +4730,19 @@ static int smack_audit_rule_known(struct audit_krule *krule)
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
+ * @lsmid: the relevant LSM
*
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
*/
-static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+ int lsmid)
{
struct smack_known *skp;
char *rule = vrule;

+ if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
+ return 0;
if (unlikely(!rule)) {
WARN_ONCE(1, "Smack: missing rule\n");
return -ENOENT;
--
2.41.0


2023-12-15 22:28:03

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 14/42] Audit: Change context data from secid to lsmblob

Change the LSM data stored in the audit transactions from a secid
to an LSM blob. This is done in struct audit_context and struct
audit_aux_data_pids. Several cases of scaffolding can be removed.

Signed-off-by: Casey Schaufler <[email protected]>
---
kernel/audit.h | 2 +-
kernel/auditfilter.c | 1 -
kernel/auditsc.c | 31 ++++++++++++-------------------
3 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/kernel/audit.h b/kernel/audit.h
index 6c664aed8f89..b413c0420c6f 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -144,7 +144,7 @@ struct audit_context {
kuid_t target_auid;
kuid_t target_uid;
unsigned int target_sessionid;
- u32 target_sid;
+ struct lsmblob target_blob;
char target_comm[TASK_COMM_LEN];

struct audit_tree_refs *trees, *first_trees;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index d0df226bdc51..24cb8259e5b1 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1369,7 +1369,6 @@ int audit_filter(int msgtype, unsigned int listtype)
case AUDIT_SUBJ_SEN:
case AUDIT_SUBJ_CLR:
if (f->lsm_rule) {
- /* stacking scaffolding */
security_current_getlsmblob_subj(&blob);
result = security_audit_rule_match(
&blob, f->type, f->op,
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index aaea62822505..bfe2ee3ccbe6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -100,7 +100,7 @@ struct audit_aux_data_pids {
kuid_t target_auid[AUDIT_AUX_PIDS];
kuid_t target_uid[AUDIT_AUX_PIDS];
unsigned int target_sessionid[AUDIT_AUX_PIDS];
- u32 target_sid[AUDIT_AUX_PIDS];
+ struct lsmblob target_blob[AUDIT_AUX_PIDS];
char target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
int pid_count;
};
@@ -1019,7 +1019,7 @@ static void audit_reset_context(struct audit_context *ctx)
ctx->target_pid = 0;
ctx->target_auid = ctx->target_uid = KUIDT_INIT(0);
ctx->target_sessionid = 0;
- ctx->target_sid = 0;
+ lsmblob_init(&ctx->target_blob);
ctx->target_comm[0] = '\0';
unroll_tree_refs(ctx, NULL, 0);
WARN_ON(!list_empty(&ctx->killed_trees));
@@ -1093,8 +1093,9 @@ static inline void audit_free_context(struct audit_context *context)
}

static int audit_log_pid_context(struct audit_context *context, pid_t pid,
- kuid_t auid, kuid_t uid, unsigned int sessionid,
- u32 sid, char *comm)
+ kuid_t auid, kuid_t uid,
+ unsigned int sessionid, struct lsmblob *blob,
+ char *comm)
{
struct audit_buffer *ab;
char *ctx = NULL;
@@ -1108,8 +1109,8 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
- if (sid) {
- if (security_secid_to_secctx(sid, &ctx, &len)) {
+ if (lsmblob_is_set(blob)) {
+ if (security_lsmblob_to_secctx(blob, &ctx, &len)) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1778,7 +1779,7 @@ static void audit_log_exit(void)
axs->target_auid[i],
axs->target_uid[i],
axs->target_sessionid[i],
- axs->target_sid[i],
+ &axs->target_blob[i],
axs->target_comm[i]))
call_panic = 1;
}
@@ -1787,7 +1788,7 @@ static void audit_log_exit(void)
audit_log_pid_context(context, context->target_pid,
context->target_auid, context->target_uid,
context->target_sessionid,
- context->target_sid, context->target_comm))
+ &context->target_blob, context->target_comm))
call_panic = 1;

if (context->pwd.dentry && context->pwd.mnt) {
@@ -2722,15 +2723,12 @@ int __audit_sockaddr(int len, void *a)
void __audit_ptrace(struct task_struct *t)
{
struct audit_context *context = audit_context();
- struct lsmblob blob;

context->target_pid = task_tgid_nr(t);
context->target_auid = audit_get_loginuid(t);
context->target_uid = task_uid(t);
context->target_sessionid = audit_get_sessionid(t);
- security_task_getlsmblob_obj(t, &blob);
- /* stacking scaffolding */
- context->target_sid = blob.scaffold.secid;
+ security_task_getlsmblob_obj(t, &context->target_blob);
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
}

@@ -2746,7 +2744,6 @@ int audit_signal_info_syscall(struct task_struct *t)
struct audit_aux_data_pids *axp;
struct audit_context *ctx = audit_context();
kuid_t t_uid = task_uid(t);
- struct lsmblob blob;

if (!audit_signals || audit_dummy_context())
return 0;
@@ -2758,9 +2755,7 @@ int audit_signal_info_syscall(struct task_struct *t)
ctx->target_auid = audit_get_loginuid(t);
ctx->target_uid = t_uid;
ctx->target_sessionid = audit_get_sessionid(t);
- security_task_getlsmblob_obj(t, &blob);
- /* stacking scaffolding */
- ctx->target_sid = blob.scaffold.secid;
+ security_task_getlsmblob_obj(t, &ctx->target_blob);
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
return 0;
}
@@ -2781,9 +2776,7 @@ int audit_signal_info_syscall(struct task_struct *t)
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
axp->target_uid[axp->pid_count] = t_uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
- security_task_getlsmblob_obj(t, &blob);
- /* stacking scaffolding */
- axp->target_sid[axp->pid_count] = blob.scaffold.secid;
+ security_task_getlsmblob_obj(t, &axp->target_blob[axp->pid_count]);
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
axp->pid_count++;

--
2.41.0


2023-12-15 22:28:15

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 15/42] Netlabel: Use lsmblob for audit data

Replace the secid in the netlbl_audit structure with an lsmblob.
Remove stacking scaffolding that was required when the value
was a secid.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/net/netlabel.h | 2 +-
net/netlabel/netlabel_unlabeled.c | 5 +----
net/netlabel/netlabel_user.c | 7 +++----
net/netlabel/netlabel_user.h | 6 +-----
security/smack/smackfs.c | 4 +---
5 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 43ae50337685..03656b8d0b4f 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -97,7 +97,7 @@ struct calipso_doi;

/* NetLabel audit information */
struct netlbl_audit {
- u32 secid;
+ struct lsmblob blob;
kuid_t loginuid;
unsigned int sessionid;
};
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 129d71c147f1..7bac13ae07a3 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1534,14 +1534,11 @@ int __init netlbl_unlabel_defconf(void)
int ret_val;
struct netlbl_dom_map *entry;
struct netlbl_audit audit_info;
- struct lsmblob blob;

/* Only the kernel is allowed to call this function and the only time
* it is called is at bootup before the audit subsystem is reporting
* messages so don't worry to much about these values. */
- security_current_getlsmblob_subj(&blob);
- /* stacking scaffolding */
- audit_info.secid = blob.scaffold.secid;
+ security_current_getlsmblob_subj(&audit_info.blob);
audit_info.loginuid = GLOBAL_ROOT_UID;
audit_info.sessionid = 0;

diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 3ed4fea2a2de..6cd1fcb3902b 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -98,10 +98,9 @@ struct audit_buffer *netlbl_audit_start_common(int type,
from_kuid(&init_user_ns, audit_info->loginuid),
audit_info->sessionid);

- if (audit_info->secid != 0 &&
- security_secid_to_secctx(audit_info->secid,
- &secctx,
- &secctx_len) == 0) {
+ if (lsmblob_is_set(&audit_info->blob) &&
+ security_lsmblob_to_secctx(&audit_info->blob, &secctx,
+ &secctx_len) == 0) {
audit_log_format(audit_buf, " subj=%s", secctx);
security_release_secctx(secctx, secctx_len);
}
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index c4864fa18a08..1a9639005d09 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -32,11 +32,7 @@
*/
static inline void netlbl_netlink_auditinfo(struct netlbl_audit *audit_info)
{
- struct lsmblob blob;
-
- security_current_getlsmblob_subj(&blob);
- /* stacking scaffolding */
- audit_info->secid = blob.scaffold.secid;
+ security_current_getlsmblob_subj(&audit_info->blob);
audit_info->loginuid = audit_get_loginuid(current);
audit_info->sessionid = audit_get_sessionid(current);
}
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index e22aad7604e8..878fe44b662d 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -182,11 +182,9 @@ static inline void smack_catset_bit(unsigned int cat, char *catsetp)
*/
static void smk_netlabel_audit_set(struct netlbl_audit *nap)
{
- struct smack_known *skp = smk_of_current();
-
nap->loginuid = audit_get_loginuid(current);
nap->sessionid = audit_get_sessionid(current);
- nap->secid = skp->smk_secid;
+ nap->blob.smack.skp = smk_of_current();
}

/*
--
2.41.0


2023-12-15 22:28:55

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 06/42] LSM: Add lsmblob_to_secctx hook

Add a new hook security_lsmblob_to_secctx() and its LSM specific
implementations. The LSM specific code will use the lsmblob element
allocated for that module. This allows for the possibility that more
than one module may be called upon to translate a secid to a string,
as can occur in the audit code.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hook_defs.h | 2 ++
include/linux/security.h | 11 +++++++++-
kernel/auditfilter.c | 1 -
security/apparmor/include/secid.h | 2 ++
security/apparmor/lsm.c | 1 +
security/apparmor/secid.c | 36 +++++++++++++++++++++++++++++++
security/security.c | 30 ++++++++++++++++++++++++++
security/selinux/hooks.c | 16 ++++++++++++--
security/smack/smack_lsm.c | 31 +++++++++++++++++++++-----
9 files changed, 121 insertions(+), 9 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 24c588b87412..52d090d1957c 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -272,6 +272,8 @@ LSM_HOOK(int, -EINVAL, setprocattr, const char *name, void *value, size_t size)
LSM_HOOK(int, 0, ismaclabel, const char *name)
LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, char **secdata,
u32 *seclen)
+LSM_HOOK(int, -EOPNOTSUPP, lsmblob_to_secctx, struct lsmblob *blob,
+ char **secdata, u32 *seclen)
LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
LSM_HOOK(void, LSM_RET_VOID, release_secctx, char *secdata, u32 seclen)
LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
diff --git a/include/linux/security.h b/include/linux/security.h
index 6ded4f04f117..7e4b31b771c1 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -507,6 +507,8 @@ int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int security_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
+ u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
void security_inode_invalidate_secctx(struct inode *inode);
@@ -1420,7 +1422,14 @@ static inline int security_ismaclabel(const char *name)
return 0;
}

-static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static inline int security_secid_to_secctx(u32 secid, char **secdata,
+ u32 *seclen)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int security_lsmblob_to_secctx(struct lsmblob *blob,
+ char **secdata, u32 *seclen)
{
return -EOPNOTSUPP;
}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 0a6a1c4c3507..08dc64bb8496 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1340,7 +1340,6 @@ int audit_filter(int msgtype, unsigned int listtype)
struct audit_field *f = &e->rule.fields[i];
struct lsmblob blob = { };
pid_t pid;
- u32 sid;

switch (f->type) {
case AUDIT_PID:
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index a912a5d5d04f..816a425e2023 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -26,6 +26,8 @@ extern int apparmor_display_secid_mode;

struct aa_label *aa_secid_to_label(u32 secid);
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
+ u32 *seclen);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void apparmor_release_secctx(char *secdata, u32 seclen);

diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8af5f458e218..1b230ade84fc 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1533,6 +1533,7 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
#endif

LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
+ LSM_HOOK_INIT(lsmblob_to_secctx, apparmor_lsmblob_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),

diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 83d3d1e6d9dc..a7c6f5061882 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -90,6 +90,42 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
return 0;
}

+int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
+ u32 *seclen)
+{
+ /* TODO: cache secctx and ref count so we don't have to recreate */
+ struct aa_label *label;
+ int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
+ int len;
+
+ AA_BUG(!seclen);
+
+ /* stacking scaffolding */
+ if (!blob->apparmor.label && blob->scaffold.secid)
+ label = aa_secid_to_label(blob->scaffold.secid);
+ else
+ label = blob->apparmor.label;
+
+ if (!label)
+ return -EINVAL;
+
+ if (apparmor_display_secid_mode)
+ flags |= FLAG_SHOW_MODE;
+
+ if (secdata)
+ len = aa_label_asxprint(secdata, root_ns, label,
+ flags, GFP_ATOMIC);
+ else
+ len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
+
+ if (len < 0)
+ return -ENOMEM;
+
+ *seclen = len;
+
+ return 0;
+}
+
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
struct aa_label *label;
diff --git a/security/security.c b/security/security.c
index b3d150b6248e..4b78bface040 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4187,6 +4187,36 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
}
EXPORT_SYMBOL(security_secid_to_secctx);

+/**
+ * security_lsmblob_to_secctx() - Convert a lsmblob to a secctx
+ * @blob: lsm specific information
+ * @secdata: secctx
+ * @seclen: secctx length
+ *
+ * Convert a @blob entry to security context. If @secdata is NULL the
+ * length of the result will be returned in @seclen, but no @secdata
+ * will be returned. This does mean that the length could change between
+ * calls to check the length and the next call which actually allocates
+ * and returns the @secdata.
+ *
+ * Return: Return 0 on success, error on failure.
+ */
+int security_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
+ u32 *seclen)
+{
+ struct security_hook_list *hp;
+ int rc;
+
+ hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
+ rc = hp->hook.lsmblob_to_secctx(blob, secdata, seclen);
+ if (rc != LSM_RET_DEFAULT(secid_to_secctx))
+ return rc;
+ }
+
+ return LSM_RET_DEFAULT(secid_to_secctx);
+}
+EXPORT_SYMBOL(security_lsmblob_to_secctx);
+
/**
* security_secctx_to_secid() - Convert a secctx to a secid
* @secdata: secctx
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index aa15acd344ea..83ce496e8ef6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6549,8 +6549,19 @@ static int selinux_ismaclabel(const char *name)

static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
- return security_sid_to_context(secid,
- secdata, seclen);
+ return security_sid_to_context(secid, secdata, seclen);
+}
+
+static int selinux_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
+ u32 *seclen)
+{
+ u32 secid = blob->selinux.secid;
+
+ /* stacking scaffolding */
+ if (!secid)
+ secid = blob->scaffold.secid;
+
+ return security_sid_to_context(secid, secdata, seclen);
}

static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
@@ -7300,6 +7311,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
+ LSM_HOOK_INIT(lsmblob_to_secctx, selinux_lsmblob_to_secctx),
LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9851d56dff69..a4ace6ea2ab0 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4738,7 +4738,7 @@ static int smack_audit_rule_known(struct audit_krule *krule)
static int smack_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
void *vrule, int lsmid)
{
- struct smack_known *skp;
+ struct smack_known *skp = blob->smack.skp;
char *rule = vrule;

if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
@@ -4752,10 +4752,8 @@ static int smack_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
return 0;

/* stacking scaffolding */
- if (!blob->smack.skp && blob->scaffold.secid)
+ if (!skp && blob->scaffold.secid)
skp = smack_from_secid(blob->scaffold.secid);
- else
- skp = blob->smack.skp;

/*
* No need to do string comparisons. If a match occurs,
@@ -4786,7 +4784,6 @@ static int smack_ismaclabel(const char *name)
return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
}

-
/**
* smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer
@@ -4805,6 +4802,29 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
return 0;
}

+/**
+ * smack_lsmblob_to_secctx - return the smack label
+ * @blob: includes incoming Smack data
+ * @secdata: destination
+ * @seclen: how long it is
+ *
+ * Exists for audit code.
+ */
+static int smack_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
+ u32 *seclen)
+{
+ struct smack_known *skp = blob->smack.skp;
+
+ /* stacking scaffolding */
+ if (!skp && blob->scaffold.secid)
+ skp = smack_from_secid(blob->scaffold.secid);
+
+ if (secdata)
+ *secdata = skp->smk_known;
+ *seclen = strlen(skp->smk_known);
+ return 0;
+}
+
/**
* smack_secctx_to_secid - return the secid for a smack label
* @secdata: smack label
@@ -5162,6 +5182,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {

LSM_HOOK_INIT(ismaclabel, smack_ismaclabel),
LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
+ LSM_HOOK_INIT(lsmblob_to_secctx, smack_lsmblob_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
--
2.41.0


2023-12-15 22:31:14

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 09/42] Audit: Update shutdown LSM data

The audit process LSM information is changed from a secid audit_sig_sid
to an lsmblob in audit_sig_lsm. Update the users of this data
appropriately. Calls to security_secid_to_secctx() are changed to use
security_lsmblob_to_secctx() instead. security_current_getsecid_subj()
is scaffolded. It will be updated in a subsequent patch.

Signed-off-by: Casey Schaufler <[email protected]>
---
kernel/audit.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 16205dd29843..875df831fb61 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -123,7 +123,7 @@ static u32 audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
/* The identity of the user shutting down the audit system. */
static kuid_t audit_sig_uid = INVALID_UID;
static pid_t audit_sig_pid = -1;
-static u32 audit_sig_sid;
+static struct lsmblob audit_sig_lsm;

/* Records can be lost in several ways:
0) [suppressed in audit_alloc]
@@ -1460,20 +1460,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
case AUDIT_SIGNAL_INFO:
len = 0;
- if (audit_sig_sid) {
- err = security_secid_to_secctx(audit_sig_sid, &ctx, &len);
+ if (lsmblob_is_set(&audit_sig_lsm)) {
+ err = security_lsmblob_to_secctx(&audit_sig_lsm, &ctx,
+ &len);
if (err)
return err;
}
sig_data = kmalloc(struct_size(sig_data, ctx, len), GFP_KERNEL);
if (!sig_data) {
- if (audit_sig_sid)
+ if (lsmblob_is_set(&audit_sig_lsm))
security_release_secctx(ctx, len);
return -ENOMEM;
}
sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
sig_data->pid = audit_sig_pid;
- if (audit_sig_sid) {
+ if (lsmblob_is_set(&audit_sig_lsm)) {
memcpy(sig_data->ctx, ctx, len);
security_release_secctx(ctx, len);
}
@@ -2389,7 +2390,8 @@ int audit_signal_info(int sig, struct task_struct *t)
audit_sig_uid = auid;
else
audit_sig_uid = uid;
- security_current_getsecid_subj(&audit_sig_sid);
+ /* stacking scaffolding */
+ security_current_getsecid_subj(&audit_sig_lsm.scaffold.secid);
}

return audit_signal_info_syscall(t);
--
2.41.0


2023-12-15 22:31:15

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 18/42] LSM: Use lsmcontext in security_lsmblob_to_secctx

Replace the (secctx,seclen) pointer pair with a single
lsmcontext pointer to allow return of the LSM identifier
along with the context and context length. This allows
security_release_secctx() to know how to release the
context. Callers have been modified to use or save the
returned data from the new structure.

security_lsmblob_to_secctx() will now return the length value
on success instead of 0.

Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: Todd Kjos <[email protected]>
---
include/linux/lsm_hook_defs.h | 2 +-
include/linux/security.h | 5 ++---
kernel/audit.c | 9 ++++-----
kernel/auditsc.c | 17 ++++++-----------
net/netlabel/netlabel_user.c | 3 +--
security/apparmor/include/secid.h | 3 +--
security/apparmor/secid.c | 14 ++++++++------
security/security.c | 24 +++++++++++-------------
security/selinux/hooks.c | 18 +++++++++++++++---
security/smack/smack_lsm.c | 16 ++++++++++------
10 files changed, 59 insertions(+), 52 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 8e0155ac6697..339a4559daf8 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -275,7 +275,7 @@ LSM_HOOK(int, -EINVAL, setprocattr, const char *name, void *value, size_t size)
LSM_HOOK(int, 0, ismaclabel, const char *name)
LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, struct lsmcontext *cp)
LSM_HOOK(int, -EOPNOTSUPP, lsmblob_to_secctx, struct lsmblob *blob,
- char **secdata, u32 *seclen)
+ struct lsmcontext *cp)
LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsmcontext *cp)
LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
diff --git a/include/linux/security.h b/include/linux/security.h
index 03b79089eaf7..2a0615a62125 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -563,8 +563,7 @@ int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, struct lsmcontext *cp);
-int security_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
- u32 *seclen);
+int security_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(struct lsmcontext *cp);
void security_inode_invalidate_secctx(struct inode *inode);
@@ -1493,7 +1492,7 @@ static inline int security_secid_to_secctx(u32 secid, struct lsmcontext *cp)
}

static inline int security_lsmblob_to_secctx(struct lsmblob *blob,
- char **secdata, u32 *seclen)
+ struct lsmcontext *cp)
{
return -EOPNOTSUPP;
}
diff --git a/kernel/audit.c b/kernel/audit.c
index 47cfb6b20c3c..a93a710c980e 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1462,9 +1462,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)

if (lsmblob_is_set(&audit_sig_lsm)) {
err = security_lsmblob_to_secctx(&audit_sig_lsm,
- &lsmctx.context,
- &lsmctx.len);
- if (err)
+ &lsmctx);
+ if (err < 0)
return err;
}
sig_data_size = struct_size(sig_data, ctx, lsmctx.len);
@@ -2175,8 +2174,8 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsmblob_is_set(&blob))
return 0;

- error = security_lsmblob_to_secctx(&blob, &ctx.context, &ctx.len);
- if (error) {
+ error = security_lsmblob_to_secctx(&blob, &ctx);
+ if (error < 0) {
if (error != -EINVAL)
goto error_path;
return 0;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 2874255f5f25..c37cc02ea4cc 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1109,7 +1109,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
if (lsmblob_is_set(blob)) {
- if (security_lsmblob_to_secctx(blob, &ctx.context, &ctx.len)) {
+ if (security_lsmblob_to_secctx(blob, &ctx) < 0) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1370,7 +1370,7 @@ static void audit_log_time(struct audit_context *context, struct audit_buffer **

static void show_special(struct audit_context *context, int *call_panic)
{
- struct lsmcontext lsmcxt;
+ struct lsmcontext lsmctx;
struct audit_buffer *ab;
int i;

@@ -1393,16 +1393,12 @@ static void show_special(struct audit_context *context, int *call_panic)
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
if (lsmblob_is_set(&context->ipc.oblob)) {
- char *ctx = NULL;
- u32 len;
-
if (security_lsmblob_to_secctx(&context->ipc.oblob,
- &ctx, &len)) {
+ &lsmctx) < 0) {
*call_panic = 1;
} else {
- audit_log_format(ab, " obj=%s", ctx);
- lsmcontext_init(&lsmcxt, ctx, len, 0);
- security_release_secctx(&lsmcxt);
+ audit_log_format(ab, " obj=%s", lsmctx.context);
+ security_release_secctx(&lsmctx);
}
}
if (context->ipc.has_perm) {
@@ -1563,8 +1559,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
if (lsmblob_is_set(&n->oblob)) {
struct lsmcontext ctx;

- if (security_lsmblob_to_secctx(&n->oblob, &ctx.context,
- &ctx.len)) {
+ if (security_lsmblob_to_secctx(&n->oblob, &ctx) < 0) {
if (call_panic)
*call_panic = 2;
} else {
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index b9289a22b363..561e1e476a49 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -98,8 +98,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
audit_info->sessionid);

if (lsmblob_is_set(&audit_info->blob) &&
- security_lsmblob_to_secctx(&audit_info->blob, &ctx.context,
- &ctx.len) == 0) {
+ security_lsmblob_to_secctx(&audit_info->blob, &ctx) >= 0) {
audit_log_format(audit_buf, " subj=%s", ctx.context);
security_release_secctx(&ctx);
}
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index b66c2d043a02..568820a11efc 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -26,8 +26,7 @@ extern int apparmor_display_secid_mode;

struct aa_label *aa_secid_to_label(u32 secid);
int apparmor_secid_to_secctx(u32 secid, struct lsmcontext *cp);
-int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
- u32 *seclen);
+int apparmor_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void apparmor_release_secctx(struct lsmcontext *cp);

diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 55d6c54fe90e..c9b9a8d90afa 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -93,8 +93,7 @@ int apparmor_secid_to_secctx(u32 secid, struct lsmcontext *cp)
return len;
}

-int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
- u32 *seclen)
+int apparmor_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
{
/* TODO: cache secctx and ref count so we don't have to recreate */
struct aa_label *label;
@@ -115,8 +114,8 @@ int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
if (apparmor_display_secid_mode)
flags |= FLAG_SHOW_MODE;

- if (secdata)
- len = aa_label_asxprint(secdata, root_ns, label,
+ if (cp)
+ len = aa_label_asxprint(&cp->context, root_ns, label,
flags, GFP_ATOMIC);
else
len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
@@ -124,9 +123,12 @@ int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
if (len < 0)
return -ENOMEM;

- *seclen = len;
+ if (cp) {
+ cp->len = len;
+ cp->id = LSM_ID_APPARMOR;
+ }

- return 0;
+ return len;
}

int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
diff --git a/security/security.c b/security/security.c
index 708a26a88447..e070a6cd4089 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4203,30 +4203,28 @@ EXPORT_SYMBOL(security_secid_to_secctx);
/**
* security_lsmblob_to_secctx() - Convert a lsmblob to a secctx
* @blob: lsm specific information
- * @secdata: secctx
- * @seclen: secctx length
+ * @cp: the LSM context
*
- * Convert a @blob entry to security context. If @secdata is NULL the
- * length of the result will be returned in @seclen, but no @secdata
- * will be returned. This does mean that the length could change between
- * calls to check the length and the next call which actually allocates
- * and returns the @secdata.
+ * Convert a @blob entry to security context. If @cp is NULL the
+ * length of the result will be returned, but no data will be returned.
+ * This does mean that the length could change between calls to check
+ * the length and the next call which actually allocates and returns
+ * the data.
*
- * Return: Return 0 on success, error on failure.
+ * Return: Return length of data on success, error on failure.
*/
-int security_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
- u32 *seclen)
+int security_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
{
struct security_hook_list *hp;
int rc;

hlist_for_each_entry(hp, &security_hook_heads.lsmblob_to_secctx, list) {
- rc = hp->hook.lsmblob_to_secctx(blob, secdata, seclen);
- if (rc != LSM_RET_DEFAULT(secid_to_secctx))
+ rc = hp->hook.lsmblob_to_secctx(blob, cp);
+ if (rc != LSM_RET_DEFAULT(lsmblob_to_secctx))
return rc;
}

- return LSM_RET_DEFAULT(secid_to_secctx);
+ return LSM_RET_DEFAULT(lsmblob_to_secctx);
}
EXPORT_SYMBOL(security_lsmblob_to_secctx);

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 37b97cf81da1..d138aa692abd 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6583,16 +6583,28 @@ static int selinux_secid_to_secctx(u32 secid, struct lsmcontext *cp)
return seclen;
}

-static int selinux_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
- u32 *seclen)
+static int selinux_lsmblob_to_secctx(struct lsmblob *blob,
+ struct lsmcontext *cp)
{
u32 secid = blob->selinux.secid;
+ u32 seclen;
+ u32 ret;

/* stacking scaffolding */
if (!secid)
secid = blob->scaffold.secid;

- return security_sid_to_context(secid, secdata, seclen);
+ if (cp) {
+ cp->id = LSM_ID_SELINUX;
+ ret = security_sid_to_context(secid, &cp->context, &cp->len);
+ if (ret < 0)
+ return ret;
+ return cp->len;
+ }
+ ret = security_sid_to_context(secid, NULL, &seclen);
+ if (ret < 0)
+ return ret;
+ return seclen;
}

static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index d82753bc52ab..1fdd4233a9b3 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4839,19 +4839,23 @@ static int smack_secid_to_secctx(u32 secid, struct lsmcontext *cp)
*
* Exists for audit code.
*/
-static int smack_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
- u32 *seclen)
+static int smack_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
{
struct smack_known *skp = blob->smack.skp;
+ int len;

/* stacking scaffolding */
if (!skp && blob->scaffold.secid)
skp = smack_from_secid(blob->scaffold.secid);

- if (secdata)
- *secdata = skp->smk_known;
- *seclen = strlen(skp->smk_known);
- return 0;
+ len = strlen(skp->smk_known);
+
+ if (cp) {
+ cp->context = skp->smk_known;
+ cp->len = len;
+ cp->id = LSM_ID_SMACK;
+ }
+ return len;
}

/**
--
2.41.0


2023-12-15 22:31:34

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 19/42] LSM: Use lsmcontext in security_inode_getsecctx

Change the security_inode_getsecctx() interface to fill
a lsmcontext structure instead of data and length pointers.
This provides the information about which LSM created the
context so that security_release_secctx() can use the
correct hook.

Acked-by: Stephen Smalley <[email protected]>
Acked-by: Paul Moore <[email protected]>
Acked-by: Chuck Lever <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
---
fs/nfsd/nfs4xdr.c | 25 +++++++++----------------
include/linux/lsm_hook_defs.h | 4 ++--
include/linux/security.h | 5 +++--
security/security.c | 12 ++++++------
security/selinux/hooks.c | 10 ++++++----
security/smack/smack_lsm.c | 7 ++++---
6 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 9cade754356a..d81a32c5929c 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2805,11 +2805,11 @@ static __be32 nfsd4_encode_nfsace4(struct xdr_stream *xdr, struct svc_rqst *rqst
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
static inline __be32
nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- void *context, int len)
+ const struct lsmcontext *context)
{
__be32 *p;

- p = xdr_reserve_space(xdr, len + 4 + 4 + 4);
+ p = xdr_reserve_space(xdr, context->len + 4 + 4 + 4);
if (!p)
return nfserr_resource;

@@ -2819,13 +2819,13 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
*/
*p++ = cpu_to_be32(0); /* lfs */
*p++ = cpu_to_be32(0); /* pi */
- p = xdr_encode_opaque(p, context, len);
+ p = xdr_encode_opaque(p, context->context, context->len);
return 0;
}
#else
static inline __be32
nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- void *context, int len)
+ struct lsmcontext *context)
{ return 0; }
#endif

@@ -2908,8 +2908,7 @@ struct nfsd4_fattr_args {
struct nfs4_acl *acl;
u64 size;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- void *context;
- int contextlen;
+ struct lsmcontext context;
#endif
u32 rdattr_err;
bool contextsupport;
@@ -3364,8 +3363,7 @@ static __be32 nfsd4_encode_fattr4_suppattr_exclcreat(struct xdr_stream *xdr,
static __be32 nfsd4_encode_fattr4_sec_label(struct xdr_stream *xdr,
const struct nfsd4_fattr_args *args)
{
- return nfsd4_encode_security_label(xdr, args->rqstp,
- args->context, args->contextlen);
+ return nfsd4_encode_security_label(xdr, args->rqstp, &args->context);
}
#endif

@@ -3587,12 +3585,11 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
args.contextsupport = false;

#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- args.context = NULL;
if ((u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
u.attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
err = security_inode_getsecctx(d_inode(dentry),
- &args.context, &args.contextlen);
+ &args.context);
else
err = -EOPNOTSUPP;
args.contextsupport = (err == 0);
@@ -3627,12 +3624,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,

out:
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- if (args.context) {
- struct lsmcontext scaff; /* scaffolding */
-
- lsmcontext_init(&scaff, args.context, args.contextlen, 0);
- security_release_secctx(&scaff);
- }
+ if (args.context.context)
+ security_release_secctx(&args.context);
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
kfree(args.acl);
if (tempfh) {
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 339a4559daf8..f2bbce7fb28e 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -281,8 +281,8 @@ LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsmcontext *cp)
LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
LSM_HOOK(int, 0, inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)
-LSM_HOOK(int, -EOPNOTSUPP, inode_getsecctx, struct inode *inode, void **ctx,
- u32 *ctxlen)
+LSM_HOOK(int, -EOPNOTSUPP, inode_getsecctx, struct inode *inode,
+ struct lsmcontext *cp)

#if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
diff --git a/include/linux/security.h b/include/linux/security.h
index 2a0615a62125..dbbfbcfbb299 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -569,7 +569,7 @@ void security_release_secctx(struct lsmcontext *cp);
void security_inode_invalidate_secctx(struct inode *inode);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
-int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
+int security_inode_getsecctx(struct inode *inode, struct lsmcontext *cp);
int security_locked_down(enum lockdown_reason what);
int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, size_t *uctx_len,
void *val, size_t val_len, u64 id, u64 flags);
@@ -1520,7 +1520,8 @@ static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32
{
return -EOPNOTSUPP;
}
-static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+static inline int security_inode_getsecctx(struct inode *inode,
+ struct lsmcontext *cp)
{
return -EOPNOTSUPP;
}
diff --git a/security/security.c b/security/security.c
index e070a6cd4089..e1487979603e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4317,17 +4317,17 @@ EXPORT_SYMBOL(security_inode_setsecctx);
/**
* security_inode_getsecctx() - Get the security label of an inode
* @inode: inode
- * @ctx: secctx
- * @ctxlen: length of secctx
+ * @cp: security context
*
- * On success, returns 0 and fills out @ctx and @ctxlen with the security
- * context for the given @inode.
+ * On success, returns 0 and fills out @cp with the security context
+ * for the given @inode.
*
* Return: Returns 0 on success, error on failure.
*/
-int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+int security_inode_getsecctx(struct inode *inode, struct lsmcontext *cp)
{
- return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
+ memset(cp, 0, sizeof(*cp));
+ return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, cp);
}
EXPORT_SYMBOL(security_inode_getsecctx);

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d138aa692abd..1e97b703f252 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6654,14 +6654,16 @@ static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
ctx, ctxlen, 0);
}

-static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+static int selinux_inode_getsecctx(struct inode *inode, struct lsmcontext *cp)
{
- int len = 0;
+ int len;
len = selinux_inode_getsecurity(&nop_mnt_idmap, inode,
- XATTR_SELINUX_SUFFIX, ctx, true);
+ XATTR_SELINUX_SUFFIX,
+ (void **)&cp->context, true);
if (len < 0)
return len;
- *ctxlen = len;
+ cp->len = len;
+ cp->id = LSM_ID_SELINUX;
return 0;
}
#ifdef CONFIG_KEYS
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1fdd4233a9b3..a58e2c14f120 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4895,12 +4895,13 @@ static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
ctx, ctxlen, 0);
}

-static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+static int smack_inode_getsecctx(struct inode *inode, struct lsmcontext *cp)
{
struct smack_known *skp = smk_of_inode(inode);

- *ctx = skp->smk_known;
- *ctxlen = strlen(skp->smk_known);
+ cp->context = skp->smk_known;
+ cp->len = strlen(skp->smk_known);
+ cp->id = LSM_ID_SMACK;
return 0;
}

--
2.41.0


2023-12-15 22:32:53

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 11/42] LSM: Use lsmblob in security_inode_getsecid

Change the security_inode_getsecid() interface to fill in a
lsmblob structure instead of a u32 secid. This allows for its
callers to gather data from all registered LSMs. Data is provided
for IMA and audit. Change the name to security_inode_getlsmblob().

Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Acked-by: Stephen Smalley <[email protected]>
Acked-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
include/linux/lsm_hook_defs.h | 3 ++-
include/linux/security.h | 7 ++++---
kernel/auditsc.c | 6 +++++-
security/integrity/ima/ima_policy.c | 3 +--
security/security.c | 11 +++++------
security/selinux/hooks.c | 15 +++++++++------
security/smack/smack_lsm.c | 12 +++++++-----
7 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2db7320a1e05..3c51ee8e3d6c 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -161,7 +161,8 @@ LSM_HOOK(int, -EOPNOTSUPP, inode_setsecurity, struct inode *inode,
const char *name, const void *value, size_t size, int flags)
LSM_HOOK(int, 0, inode_listsecurity, struct inode *inode, char *buffer,
size_t buffer_size)
-LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
+LSM_HOOK(void, LSM_RET_VOID, inode_getlsmblob, struct inode *inode,
+ struct lsmblob *blob)
LSM_HOOK(int, 0, inode_copy_up, struct dentry *src, struct cred **new)
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, const char *name)
LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
diff --git a/include/linux/security.h b/include/linux/security.h
index 6306e8ab0cf6..e8b7f858de04 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -431,7 +431,7 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
-void security_inode_getsecid(struct inode *inode, u32 *secid);
+void security_inode_getlsmblob(struct inode *inode, struct lsmblob *blob);
int security_inode_copy_up(struct dentry *src, struct cred **new);
int security_inode_copy_up_xattr(const char *name);
int security_kernfs_init_security(struct kernfs_node *kn_dir,
@@ -1020,9 +1020,10 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,
return 0;
}

-static inline void security_inode_getsecid(struct inode *inode, u32 *secid)
+static inline void security_inode_getlsmblob(struct inode *inode,
+ struct lsmblob *blob)
{
- *secid = 0;
+ lsmblob_init(blob);
}

static inline int security_inode_copy_up(struct dentry *src, struct cred **new)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 7afeae468745..b15e44e56409 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2276,13 +2276,17 @@ static void audit_copy_inode(struct audit_names *name,
const struct dentry *dentry,
struct inode *inode, unsigned int flags)
{
+ struct lsmblob blob;
+
name->ino = inode->i_ino;
name->dev = inode->i_sb->s_dev;
name->mode = inode->i_mode;
name->uid = inode->i_uid;
name->gid = inode->i_gid;
name->rdev = inode->i_rdev;
- security_inode_getsecid(inode, &name->osid);
+ security_inode_getlsmblob(inode, &blob);
+ /* stacking scaffolding */
+ name->osid = blob.scaffold.secid;
if (flags & AUDIT_INODE_NOEVAL) {
name->fcap_ver = -1;
return;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 48287b75fe77..8edf7a0ef9f6 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -671,8 +671,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
case LSM_OBJ_USER:
case LSM_OBJ_ROLE:
case LSM_OBJ_TYPE:
- /* stacking scaffolding */
- security_inode_getsecid(inode, &blob.scaffold.secid);
+ security_inode_getlsmblob(inode, &blob);
rc = ima_filter_rule_match(&blob, lsm_rule->lsm[i].type,
Audit_equal,
lsm_rule->lsm[i].rule,
diff --git a/security/security.c b/security/security.c
index 58387e1f0c04..ed4e9b5fdf70 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2607,16 +2607,15 @@ int security_inode_listsecurity(struct inode *inode,
EXPORT_SYMBOL(security_inode_listsecurity);

/**
- * security_inode_getsecid() - Get an inode's secid
+ * security_inode_getlsmblob() - Get an inode's LSM data
* @inode: inode
- * @secid: secid to return
+ * @blob: lsm specific information to return
*
- * Get the secid associated with the node. In case of failure, @secid will be
- * set to zero.
+ * Get the lsm specific information associated with the node.
*/
-void security_inode_getsecid(struct inode *inode, u32 *secid)
+void security_inode_getlsmblob(struct inode *inode, struct lsmblob *blob)
{
- call_void_hook(inode_getsecid, inode, secid);
+ call_void_hook(inode_getlsmblob, inode, blob);
}

/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d70000363b7a..4ab923698da9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3496,15 +3496,18 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
return len;
}

-static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
+static void selinux_inode_getlsmblob(struct inode *inode, struct lsmblob *blob)
{
struct inode_security_struct *isec = inode_security_novalidate(inode);
- *secid = isec->sid;
+
+ blob->selinux.secid = isec->sid;
+ /* stacking scaffolding */
+ blob->scaffold.secid = isec->sid;
}

static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
{
- u32 sid;
+ struct lsmblob blob;
struct task_security_struct *tsec;
struct cred *new_creds = *new;

@@ -3516,8 +3519,8 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)

tsec = selinux_cred(new_creds);
/* Get label from overlay inode and set it in create_sid */
- selinux_inode_getsecid(d_inode(src), &sid);
- tsec->create_sid = sid;
+ selinux_inode_getlsmblob(d_inode(src), &blob);
+ tsec->create_sid = blob.selinux.secid;
*new = new_creds;
return 0;
}
@@ -7125,7 +7128,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
- LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
+ LSM_HOOK_INIT(inode_getlsmblob, selinux_inode_getlsmblob),
LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
LSM_HOOK_INIT(path_notify, selinux_path_notify),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 46cc79eb1200..e6d49e59a0c0 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1615,15 +1615,17 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
}

/**
- * smack_inode_getsecid - Extract inode's security id
+ * smack_inode_getlsmblob - Extract inode's security id
* @inode: inode to extract the info from
- * @secid: where result will be saved
+ * @blob: where result will be saved
*/
-static void smack_inode_getsecid(struct inode *inode, u32 *secid)
+static void smack_inode_getlsmblob(struct inode *inode, struct lsmblob *blob)
{
struct smack_known *skp = smk_of_inode(inode);

- *secid = skp->smk_secid;
+ blob->smack.skp = skp;
+ /* stacking scaffolding */
+ blob->scaffold.secid = skp->smk_secid;
}

/*
@@ -5081,7 +5083,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_getsecurity, smack_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, smack_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity),
- LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
+ LSM_HOOK_INIT(inode_getlsmblob, smack_inode_getlsmblob),

LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
--
2.41.0


2023-12-15 22:33:54

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 12/42] Audit: use an lsmblob in audit_names

Replace the osid field in the audit_names structure with a
lsmblob structure. This accommodates the use of an lsmblob in
security_audit_rule_match() and security_inode_getsecid().

Signed-off-by: Casey Schaufler <[email protected]>
---
kernel/audit.h | 2 +-
kernel/auditsc.c | 20 +++++---------------
2 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/kernel/audit.h b/kernel/audit.h
index b1f2de4d4f1e..6c664aed8f89 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -82,7 +82,7 @@ struct audit_names {
kuid_t uid;
kgid_t gid;
dev_t rdev;
- u32 osid;
+ struct lsmblob oblob;
struct audit_cap_data fcap;
unsigned int fcap_ver;
unsigned char type; /* record type */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b15e44e56409..aaea62822505 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -698,19 +698,15 @@ static int audit_filter_rules(struct task_struct *tsk,
if (f->lsm_rule) {
/* Find files that match */
if (name) {
- /* stacking scaffolding */
- blob.scaffold.secid = name->osid;
result = security_audit_rule_match(
- &blob,
+ &name->oblob,
f->type,
f->op,
f->lsm_rule);
} else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- /* stacking scaffolding */
- blob.scaffold.secid = n->osid;
if (security_audit_rule_match(
- &blob,
+ &n->oblob,
f->type,
f->op,
f->lsm_rule)) {
@@ -1562,13 +1558,11 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
from_kgid(&init_user_ns, n->gid),
MAJOR(n->rdev),
MINOR(n->rdev));
- if (n->osid != 0) {
+ if (lsmblob_is_set(&n->oblob)) {
char *ctx = NULL;
u32 len;

- if (security_secid_to_secctx(
- n->osid, &ctx, &len)) {
- audit_log_format(ab, " osid=%u", n->osid);
+ if (security_lsmblob_to_secctx(&n->oblob, &ctx, &len)) {
if (call_panic)
*call_panic = 2;
} else {
@@ -2276,17 +2270,13 @@ static void audit_copy_inode(struct audit_names *name,
const struct dentry *dentry,
struct inode *inode, unsigned int flags)
{
- struct lsmblob blob;
-
name->ino = inode->i_ino;
name->dev = inode->i_sb->s_dev;
name->mode = inode->i_mode;
name->uid = inode->i_uid;
name->gid = inode->i_gid;
name->rdev = inode->i_rdev;
- security_inode_getlsmblob(inode, &blob);
- /* stacking scaffolding */
- name->osid = blob.scaffold.secid;
+ security_inode_getlsmblob(inode, &name->oblob);
if (flags & AUDIT_INODE_NOEVAL) {
name->fcap_ver = -1;
return;
--
2.41.0


2023-12-15 22:34:00

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 13/42] LSM: Create new security_cred_getlsmblob LSM hook

Create a new LSM hook security_cred_getlsmblob() which, like
security_cred_getsecid(), fetches LSM specific attributes from the
cred structure. The associated data elements in the audit sub-system
are changed from a secid to a lsmblob to accommodate multiple possible
LSM audit users.

Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: John Johansen <[email protected]>
Acked-by: Stephen Smalley <[email protected]>
Acked-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: Todd Kjos <[email protected]>
---
include/linux/lsm_hook_defs.h | 2 ++
include/linux/security.h | 7 +++++++
security/integrity/ima/ima_main.c | 7 ++-----
security/security.c | 15 +++++++++++++++
security/selinux/hooks.c | 8 ++++++++
security/smack/smack_lsm.c | 18 ++++++++++++++++++
6 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 3c51ee8e3d6c..fe9c1d89dc66 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -196,6 +196,8 @@ LSM_HOOK(int, 0, cred_prepare, struct cred *new, const struct cred *old,
LSM_HOOK(void, LSM_RET_VOID, cred_transfer, struct cred *new,
const struct cred *old)
LSM_HOOK(void, LSM_RET_VOID, cred_getsecid, const struct cred *c, u32 *secid)
+LSM_HOOK(void, LSM_RET_VOID, cred_getlsmblob, const struct cred *c,
+ struct lsmblob *blob)
LSM_HOOK(int, 0, kernel_act_as, struct cred *new, u32 secid)
LSM_HOOK(int, 0, kernel_create_files_as, struct cred *new, struct inode *inode)
LSM_HOOK(int, 0, kernel_module_request, char *kmod_name)
diff --git a/include/linux/security.h b/include/linux/security.h
index e8b7f858de04..67ecf8588c90 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -460,6 +460,7 @@ void security_cred_free(struct cred *cred);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_transfer_creds(struct cred *new, const struct cred *old);
void security_cred_getsecid(const struct cred *c, u32 *secid);
+void security_cred_getlsmblob(const struct cred *c, struct lsmblob *blob);
int security_kernel_act_as(struct cred *new, u32 secid);
int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_kernel_module_request(char *kmod_name);
@@ -1151,6 +1152,12 @@ static inline void security_cred_getsecid(const struct cred *c, u32 *secid)
*secid = 0;
}

+static inline void security_cred_getlsmblob(const struct cred *c,
+ struct lsmblob *blob)
+{
+ *secid = 0;
+}
+
static inline int security_kernel_act_as(struct cred *cred, u32 secid)
{
return 0;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 657143fe558d..c69eb9665cc1 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -526,8 +526,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
int ima_bprm_check(struct linux_binprm *bprm)
{
int ret;
- u32 secid;
- struct lsmblob blob = { };
+ struct lsmblob blob;

security_current_getlsmblob_subj(&blob);
ret = process_measurement(bprm->file, current_cred(),
@@ -535,9 +534,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
if (ret)
return ret;

- security_cred_getsecid(bprm->cred, &secid);
- /* stacking scaffolding */
- blob.scaffold.secid = secid;
+ security_cred_getlsmblob(bprm->cred, &blob);
return process_measurement(bprm->file, bprm->cred, &blob, NULL, 0,
MAY_EXEC, CREDS_CHECK);
}
diff --git a/security/security.c b/security/security.c
index ed4e9b5fdf70..1cbd45310f63 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3111,6 +3111,21 @@ void security_cred_getsecid(const struct cred *c, u32 *secid)
}
EXPORT_SYMBOL(security_cred_getsecid);

+/**
+ * security_cred_getlsmblob() - Get the LSM data from a set of credentials
+ * @c: credentials
+ * @blob: destination for the LSM data
+ *
+ * Retrieve the security data of the cred structure @c. In case of
+ * failure, @blob will be cleared.
+ */
+void security_cred_getlsmblob(const struct cred *c, struct lsmblob *blob)
+{
+ lsmblob_init(blob);
+ call_void_hook(cred_getlsmblob, c, blob);
+}
+EXPORT_SYMBOL(security_cred_getlsmblob);
+
/**
* security_kernel_act_as() - Set the kernel credentials to act as secid
* @new: credentials
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4ab923698da9..1bc28f5f6870 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3992,6 +3992,13 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
*secid = cred_sid(c);
}

+static void selinux_cred_getlsmblob(const struct cred *c, struct lsmblob *blob)
+{
+ blob->selinux.secid = cred_sid(c);
+ /* stacking scaffolding */
+ blob->scaffold.secid = blob->selinux.secid;
+}
+
/*
* set the security data for a kernel service
* - all the creation contexts are set to unlabelled
@@ -7153,6 +7160,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
+ LSM_HOOK_INIT(cred_getlsmblob, selinux_cred_getlsmblob),
LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e6d49e59a0c0..7dab00bbd0ed 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2121,6 +2121,23 @@ static void smack_cred_getsecid(const struct cred *cred, u32 *secid)
rcu_read_unlock();
}

+/**
+ * smack_cred_getlsmblob - get the Smack label for a creds structure
+ * @cred: the object creds
+ * @blob: where to put the data
+ *
+ * Sets the Smack part of the blob
+ */
+static void smack_cred_getlsmblob(const struct cred *cred,
+ struct lsmblob *blob)
+{
+ rcu_read_lock();
+ blob->smack.skp = smk_of_task(smack_cred(cred));
+ /* stacking scaffolding */
+ blob->scaffold.secid = blob->smack.skp->smk_secid;
+ rcu_read_unlock();
+}
+
/**
* smack_kernel_act_as - Set the subjective context in a set of credentials
* @new: points to the set of credentials to be modified.
@@ -5102,6 +5119,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(cred_prepare, smack_cred_prepare),
LSM_HOOK_INIT(cred_transfer, smack_cred_transfer),
LSM_HOOK_INIT(cred_getsecid, smack_cred_getsecid),
+ LSM_HOOK_INIT(cred_getlsmblob, smack_cred_getlsmblob),
LSM_HOOK_INIT(kernel_act_as, smack_kernel_act_as),
LSM_HOOK_INIT(kernel_create_files_as, smack_kernel_create_files_as),
LSM_HOOK_INIT(task_setpgid, smack_task_setpgid),
--
2.41.0


2023-12-15 22:34:26

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 22/42] Audit: Create audit_stamp structure

Replace the timestamp and serial number pair used in audit records
with a structure containing the two elements.

Signed-off-by: Casey Schaufler <[email protected]>
Acked-by: Paul Moore <[email protected]>
---
kernel/audit.c | 17 +++++++++--------
kernel/audit.h | 13 +++++++++----
kernel/auditsc.c | 22 +++++++++-------------
3 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index edefb370a72e..5291f65a01c8 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1820,11 +1820,11 @@ unsigned int audit_serial(void)
}

static inline void audit_get_stamp(struct audit_context *ctx,
- struct timespec64 *t, unsigned int *serial)
+ struct audit_stamp *stamp)
{
- if (!ctx || !auditsc_get_stamp(ctx, t, serial)) {
- ktime_get_coarse_real_ts64(t);
- *serial = audit_serial();
+ if (!ctx || !auditsc_get_stamp(ctx, stamp)) {
+ ktime_get_coarse_real_ts64(&stamp->ctime);
+ stamp->serial = audit_serial();
}
}

@@ -1847,8 +1847,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
int type)
{
struct audit_buffer *ab;
- struct timespec64 t;
- unsigned int serial;
+ struct audit_stamp stamp;

if (audit_initialized != AUDIT_INITIALIZED)
return NULL;
@@ -1903,12 +1902,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
return NULL;
}

- audit_get_stamp(ab->ctx, &t, &serial);
+ audit_get_stamp(ab->ctx, &stamp);
/* cancel dummy context to enable supporting records */
if (ctx)
ctx->dummy = 0;
audit_log_format(ab, "audit(%llu.%03lu:%u): ",
- (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
+ (unsigned long long)stamp.ctime.tv_sec,
+ stamp.ctime.tv_nsec/1000000,
+ stamp.serial);

return ab;
}
diff --git a/kernel/audit.h b/kernel/audit.h
index b413c0420c6f..f147540862c7 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -99,6 +99,12 @@ struct audit_proctitle {
char *value; /* the cmdline field */
};

+/* A timestamp/serial pair to identify an event */
+struct audit_stamp {
+ struct timespec64 ctime; /* time of syscall entry */
+ unsigned int serial; /* serial number for record */
+};
+
/* The per-task audit context. */
struct audit_context {
int dummy; /* must be the first element */
@@ -108,10 +114,9 @@ struct audit_context {
AUDIT_CTX_URING, /* in use by io_uring */
} context;
enum audit_state state, current_state;
- unsigned int serial; /* serial number for record */
+ struct audit_stamp stamp; /* event identifier */
int major; /* syscall number */
int uring_op; /* uring operation */
- struct timespec64 ctime; /* time of syscall entry */
unsigned long argv[4]; /* syscall arguments */
long return_code;/* syscall return code */
u64 prio;
@@ -263,7 +268,7 @@ extern void audit_put_tty(struct tty_struct *tty);
extern unsigned int audit_serial(void);
#ifdef CONFIG_AUDITSYSCALL
extern int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec64 *t, unsigned int *serial);
+ struct audit_stamp *stamp);

extern void audit_put_watch(struct audit_watch *watch);
extern void audit_get_watch(struct audit_watch *watch);
@@ -304,7 +309,7 @@ extern void audit_filter_inodes(struct task_struct *tsk,
struct audit_context *ctx);
extern struct list_head *audit_killed_trees(void);
#else /* CONFIG_AUDITSYSCALL */
-#define auditsc_get_stamp(c, t, s) 0
+#define auditsc_get_stamp(c, s) 0
#define audit_put_watch(w) do { } while (0)
#define audit_get_watch(w) do { } while (0)
#define audit_to_watch(k, p, l, o) (-EINVAL)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 3c0559b01677..23f72c14276d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -994,10 +994,10 @@ static void audit_reset_context(struct audit_context *ctx)
*/

ctx->current_state = ctx->state;
- ctx->serial = 0;
+ ctx->stamp.serial = 0;
ctx->major = 0;
ctx->uring_op = 0;
- ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
+ ctx->stamp.ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
memset(ctx->argv, 0, sizeof(ctx->argv));
ctx->return_code = 0;
ctx->prio = (ctx->state == AUDIT_STATE_RECORD ? ~0ULL : 0);
@@ -1918,7 +1918,7 @@ void __audit_uring_entry(u8 op)

ctx->context = AUDIT_CTX_URING;
ctx->current_state = ctx->state;
- ktime_get_coarse_real_ts64(&ctx->ctime);
+ ktime_get_coarse_real_ts64(&ctx->stamp.ctime);
}

/**
@@ -2040,7 +2040,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
context->argv[3] = a4;
context->context = AUDIT_CTX_SYSCALL;
context->current_state = state;
- ktime_get_coarse_real_ts64(&context->ctime);
+ ktime_get_coarse_real_ts64(&context->stamp.ctime);
}

/**
@@ -2511,21 +2511,17 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
/**
* auditsc_get_stamp - get local copies of audit_context values
* @ctx: audit_context for the task
- * @t: timespec64 to store time recorded in the audit_context
- * @serial: serial value that is recorded in the audit_context
+ * @stamp: timestamp to record
*
* Also sets the context as auditable.
*/
-int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec64 *t, unsigned int *serial)
+int auditsc_get_stamp(struct audit_context *ctx, struct audit_stamp *stamp)
{
if (ctx->context == AUDIT_CTX_UNUSED)
return 0;
- if (!ctx->serial)
- ctx->serial = audit_serial();
- t->tv_sec = ctx->ctime.tv_sec;
- t->tv_nsec = ctx->ctime.tv_nsec;
- *serial = ctx->serial;
+ if (!ctx->stamp.serial)
+ ctx->stamp.serial = audit_serial();
+ *stamp = ctx->stamp;
if (!ctx->prio) {
ctx->prio = 1;
ctx->current_state = AUDIT_STATE_RECORD;
--
2.41.0


2023-12-15 22:34:35

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 23/42] Audit: Allow multiple records in an audit_buffer

Replace the single skb pointer in an audit_buffer with
a list of skb pointers. Add the audit_stamp information
to the audit_buffer as there's no guarantee that there
will be an audit_context containing the stamp associated
with the event. At audit_log_end() time create auxiliary
records (none are currently defined) as have been added
to the list. Functions are created to manage the skb list
in the audit_buffer.

Suggested-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
---
kernel/audit.c | 111 +++++++++++++++++++++++++++++++++++++++----------
1 file changed, 89 insertions(+), 22 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 5291f65a01c8..b194494c4dc4 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -195,8 +195,10 @@ static struct audit_ctl_mutex {
* to place it on a transmit queue. Multiple audit_buffers can be in
* use simultaneously. */
struct audit_buffer {
- struct sk_buff *skb; /* formatted skb ready to send */
+ struct sk_buff *skb; /* the skb for audit_log functions */
+ struct sk_buff_head skb_list; /* formatted skbs, ready to send */
struct audit_context *ctx; /* NULL or associated context */
+ struct audit_stamp stamp; /* audit stamp for these records */
gfp_t gfp_mask;
};

@@ -1763,10 +1765,13 @@ __setup("audit_backlog_limit=", audit_backlog_limit_set);

static void audit_buffer_free(struct audit_buffer *ab)
{
+ struct sk_buff *skb;
+
if (!ab)
return;

- kfree_skb(ab->skb);
+ while ((skb = skb_dequeue(&ab->skb_list)))
+ kfree_skb(skb);
kmem_cache_free(audit_buffer_cache, ab);
}

@@ -1782,6 +1787,10 @@ static struct audit_buffer *audit_buffer_alloc(struct audit_context *ctx,
ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
if (!ab->skb)
goto err;
+
+ skb_queue_head_init(&ab->skb_list);
+ skb_queue_tail(&ab->skb_list, ab->skb);
+
if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
goto err;

@@ -1847,7 +1856,6 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
int type)
{
struct audit_buffer *ab;
- struct audit_stamp stamp;

if (audit_initialized != AUDIT_INITIALIZED)
return NULL;
@@ -1902,14 +1910,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
return NULL;
}

- audit_get_stamp(ab->ctx, &stamp);
+ audit_get_stamp(ab->ctx, &ab->stamp);
/* cancel dummy context to enable supporting records */
if (ctx)
ctx->dummy = 0;
audit_log_format(ab, "audit(%llu.%03lu:%u): ",
- (unsigned long long)stamp.ctime.tv_sec,
- stamp.ctime.tv_nsec/1000000,
- stamp.serial);
+ (unsigned long long)ab->stamp.ctime.tv_sec,
+ ab->stamp.ctime.tv_nsec/1000000,
+ ab->stamp.serial);

return ab;
}
@@ -2165,6 +2173,57 @@ void audit_log_key(struct audit_buffer *ab, char *key)
audit_log_format(ab, "(null)");
}

+/**
+ * audit_buffer_aux_new - Add an aux record buffer to the skb list
+ * @ab: audit_buffer
+ * @type: message type
+ *
+ * Aux records are allocated and added to the skb list of
+ * the "main" record. The ab->skb is reset to point to the
+ * aux record on its creation. When the aux record in complete
+ * ab->skb has to be reset to point to the "main" record.
+ * This allows the audit_log_ functions to be ignorant of
+ * which kind of record it is logging to. It also avoids adding
+ * special data for aux records.
+ *
+ * On success ab->skb will point to the new aux record.
+ * Returns 0 on success, -ENOMEM should allocation fail.
+ */
+static int audit_buffer_aux_new(struct audit_buffer *ab, int type)
+{
+ WARN_ON(ab->skb != skb_peek(&ab->skb_list));
+
+ ab->skb = nlmsg_new(AUDIT_BUFSIZ, ab->gfp_mask);
+ if (!ab->skb)
+ goto err;
+ if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
+ goto err;
+ skb_queue_tail(&ab->skb_list, ab->skb);
+
+ audit_log_format(ab, "audit(%llu.%03lu:%u): ",
+ (unsigned long long)ab->stamp.ctime.tv_sec,
+ ab->stamp.ctime.tv_nsec/1000000,
+ ab->stamp.serial);
+
+ return 0;
+
+err:
+ kfree_skb(ab->skb);
+ ab->skb = skb_peek(&ab->skb_list);
+ return -ENOMEM;
+}
+
+/**
+ * audit_buffer_aux_end - Switch back to the "main" record from an aux record
+ * @ab: audit_buffer
+ *
+ * Restores the "main" audit record to ab->skb.
+ */
+static void audit_buffer_aux_end(struct audit_buffer *ab)
+{
+ ab->skb = skb_peek(&ab->skb_list);
+}
+
int audit_log_task_context(struct audit_buffer *ab)
{
struct lsmcontext ctx;
@@ -2399,26 +2458,14 @@ int audit_signal_info(int sig, struct task_struct *t)
}

/**
- * audit_log_end - end one audit record
- * @ab: the audit_buffer
- *
- * We can not do a netlink send inside an irq context because it blocks (last
- * arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed on a
- * queue and a kthread is scheduled to remove them from the queue outside the
- * irq context. May be called in any context.
+ * __audit_log_end - enqueue one audit record
+ * @skb: the buffer to send
*/
-void audit_log_end(struct audit_buffer *ab)
+static void __audit_log_end(struct sk_buff *skb)
{
- struct sk_buff *skb;
struct nlmsghdr *nlh;

- if (!ab)
- return;
-
if (audit_rate_check()) {
- skb = ab->skb;
- ab->skb = NULL;
-
/* setup the netlink header, see the comments in
* kauditd_send_multicast_skb() for length quirks */
nlh = nlmsg_hdr(skb);
@@ -2429,6 +2476,26 @@ void audit_log_end(struct audit_buffer *ab)
wake_up_interruptible(&kauditd_wait);
} else
audit_log_lost("rate limit exceeded");
+}
+
+/**
+ * audit_log_end - end one audit record
+ * @ab: the audit_buffer
+ *
+ * We can not do a netlink send inside an irq context because it blocks (last
+ * arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed on a
+ * queue and a kthread is scheduled to remove them from the queue outside the
+ * irq context. May be called in any context.
+ */
+void audit_log_end(struct audit_buffer *ab)
+{
+ struct sk_buff *skb;
+
+ if (!ab)
+ return;
+
+ while ((skb = skb_dequeue(&ab->skb_list)))
+ __audit_log_end(skb);

audit_buffer_free(ab);
}
--
2.41.0


2023-12-15 22:35:56

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 24/42] Audit: Add record for multiple task security contexts

Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
An example of the MAC_TASK_CONTEXTS (1420) record is:

type=MAC_TASK_CONTEXTS[1420]
msg=audit(1600880931.832:113)
subj_apparmor=unconfined
subj_smack=_

When an audit event includes a AUDIT_MAC_TASK_CONTEXTS record
the "subj=" field in other records in the event will be "subj=?".
An AUDIT_MAC_TASK_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based
on a subject security context.

Acked-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 2 ++
include/linux/security.h | 1 +
include/uapi/linux/audit.h | 1 +
kernel/audit.c | 45 ++++++++++++++++++++++++++++++++------
security/apparmor/lsm.c | 1 +
security/bpf/hooks.c | 1 +
security/security.c | 3 +++
security/selinux/hooks.c | 1 +
security/smack/smack_lsm.c | 1 +
9 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index efd4a0655159..605aaf38c3f5 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -47,12 +47,14 @@ struct security_hook_heads {
* struct lsm_id - Identify a Linux Security Module.
* @lsm: name of the LSM, must be approved by the LSM maintainers
* @id: LSM ID number from uapi/linux/lsm.h
+ * @lsmblob: indicates the LSM has an entry in struct lsmblob
*
* Contains the information that identifies the LSM.
*/
struct lsm_id {
const char *name;
u64 id;
+ bool lsmblob;
};

/*
diff --git a/include/linux/security.h b/include/linux/security.h
index 360a454d5f8e..947cb3a35db4 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -192,6 +192,7 @@ struct lsmblob {

extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
extern u32 lsm_active_cnt;
+extern u32 lsm_blob_cnt;
extern const struct lsm_id *lsm_idlist[];

/* These functions are in security/commoncap.c */
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index d676ed2b246e..dc045164b86b 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -143,6 +143,7 @@
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
#define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */
#define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */
+#define AUDIT_MAC_TASK_CONTEXTS 1420 /* Multiple LSM task contexts */

#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
diff --git a/kernel/audit.c b/kernel/audit.c
index b194494c4dc4..9d971fa96c0e 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -54,6 +54,7 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/freezer.h>
#include <linux/pid_namespace.h>
#include <net/netns/generic.h>
@@ -2228,21 +2229,51 @@ int audit_log_task_context(struct audit_buffer *ab)
{
struct lsmcontext ctx;
struct lsmblob blob;
+ bool space = false;
int error;
+ int i;

security_current_getlsmblob_subj(&blob);
if (!lsmblob_is_set(&blob))
return 0;

- error = security_lsmblob_to_secctx(&blob, &ctx, LSM_ID_UNDEF);
- if (error < 0) {
- if (error != -EINVAL)
- goto error_path;
+ if (lsm_blob_cnt < 2) {
+ error = security_lsmblob_to_secctx(&blob, &ctx, LSM_ID_UNDEF);
+ if (error < 0) {
+ if (error != -EINVAL)
+ goto error_path;
+ return 0;
+ }
+ audit_log_format(ab, " subj=%s", ctx.context);
+ security_release_secctx(&ctx);
return 0;
}
-
- audit_log_format(ab, " subj=%s", ctx.context);
- security_release_secctx(&ctx);
+ /* Multiple LSMs provide contexts. Include an aux record. */
+ audit_log_format(ab, " subj=?");
+ error = audit_buffer_aux_new(ab, AUDIT_MAC_TASK_CONTEXTS);
+ if (error)
+ goto error_path;
+
+ for (i = 0; i < lsm_active_cnt; i++) {
+ if (!lsm_idlist[i]->lsmblob)
+ continue;
+ error = security_lsmblob_to_secctx(&blob, &ctx,
+ lsm_idlist[i]->id);
+ if (error < 0) {
+ if (error == -EOPNOTSUPP)
+ continue;
+ audit_log_format(ab, "%ssubj_%s=?", space ? " " : "",
+ lsm_idlist[i]->name);
+ if (error != -EINVAL)
+ audit_panic("error in audit_log_task_context");
+ } else {
+ audit_log_format(ab, "%ssubj_%s=%s", space ? " " : "",
+ lsm_idlist[i]->name, ctx.context);
+ security_release_secctx(&ctx);
+ }
+ space = true;
+ }
+ audit_buffer_aux_end(ab);
return 0;

error_path:
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index b5f3beb26d5a..075942b253ae 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1447,6 +1447,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
static const struct lsm_id apparmor_lsmid = {
.name = "apparmor",
.id = LSM_ID_APPARMOR,
+ .lsmblob = true,
};

static struct security_hook_list apparmor_hooks[] __ro_after_init = {
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index 57b9ffd53c98..2da40774dd20 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -19,6 +19,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
static const struct lsm_id bpf_lsmid = {
.name = "bpf",
.id = LSM_ID_BPF,
+ .lsmblob = true,
};

static int __init bpf_lsm_init(void)
diff --git a/security/security.c b/security/security.c
index 444051575793..8ff6cef26e6c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -269,6 +269,7 @@ static void __init initialize_lsm(struct lsm_info *lsm)
* Current index to use while initializing the lsm id list.
*/
u32 lsm_active_cnt __ro_after_init;
+u32 lsm_blob_cnt __ro_after_init;
const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT];

/**
@@ -599,6 +600,8 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
if (lsm_active_cnt >= LSM_CONFIG_COUNT)
panic("%s Too many LSMs registered.\n", __func__);
lsm_idlist[lsm_active_cnt++] = lsmid;
+ if (lsmid->lsmblob)
+ lsm_blob_cnt++;
}

for (i = 0; i < count; i++) {
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ed4237223959..656f25337334 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7092,6 +7092,7 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
static const struct lsm_id selinux_lsmid = {
.name = "selinux",
.id = LSM_ID_SELINUX,
+ .lsmblob = true,
};

/*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a58e2c14f120..a9ab31a40e36 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5069,6 +5069,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
static const struct lsm_id smack_lsmid = {
.name = "smack",
.id = LSM_ID_SMACK,
+ .lsmblob = true,
};

static struct security_hook_list smack_hooks[] __ro_after_init = {
--
2.41.0


2023-12-15 22:36:13

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 25/42] audit: multiple subject lsm values for netlabel

Refactor audit_log_task_context(), creating a new
audit_log_subject_context(). This is used in netlabel auditing
to provide multiple subject security contexts as necessary.

Acked-by: Paul Moore <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/audit.h | 8 ++++++++
kernel/audit.c | 21 ++++++++++++++-------
net/netlabel/netlabel_user.c | 8 +-------
3 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 51b1b7054a23..8974500f730f 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -36,6 +36,7 @@ struct mqstat;
struct audit_watch;
struct audit_tree;
struct sk_buff;
+struct lsmblob;

struct audit_krule {
u32 pflags;
@@ -184,6 +185,8 @@ extern void audit_log_path_denied(int type,
const char *operation);
extern void audit_log_lost(const char *message);

+extern int audit_log_subject_context(struct audit_buffer *ab,
+ struct lsmblob *blob);
extern int audit_log_task_context(struct audit_buffer *ab);
extern void audit_log_task_info(struct audit_buffer *ab);

@@ -244,6 +247,11 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
{ }
static inline void audit_log_path_denied(int type, const char *operation)
{ }
+static inline int audit_log_subject_context(struct audit_buffer *ab,
+ struct lsmblob *blob)
+{
+ return 0;
+}
static inline int audit_log_task_context(struct audit_buffer *ab)
{
return 0;
diff --git a/kernel/audit.c b/kernel/audit.c
index 9d971fa96c0e..626942c38bca 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -2225,20 +2225,18 @@ static void audit_buffer_aux_end(struct audit_buffer *ab)
ab->skb = skb_peek(&ab->skb_list);
}

-int audit_log_task_context(struct audit_buffer *ab)
+int audit_log_subject_context(struct audit_buffer *ab, struct lsmblob *blob)
{
struct lsmcontext ctx;
- struct lsmblob blob;
bool space = false;
int error;
int i;

- security_current_getlsmblob_subj(&blob);
- if (!lsmblob_is_set(&blob))
+ if (!lsmblob_is_set(blob))
return 0;

if (lsm_blob_cnt < 2) {
- error = security_lsmblob_to_secctx(&blob, &ctx, LSM_ID_UNDEF);
+ error = security_lsmblob_to_secctx(blob, &ctx, LSM_ID_UNDEF);
if (error < 0) {
if (error != -EINVAL)
goto error_path;
@@ -2257,7 +2255,7 @@ int audit_log_task_context(struct audit_buffer *ab)
for (i = 0; i < lsm_active_cnt; i++) {
if (!lsm_idlist[i]->lsmblob)
continue;
- error = security_lsmblob_to_secctx(&blob, &ctx,
+ error = security_lsmblob_to_secctx(blob, &ctx,
lsm_idlist[i]->id);
if (error < 0) {
if (error == -EOPNOTSUPP)
@@ -2277,9 +2275,18 @@ int audit_log_task_context(struct audit_buffer *ab)
return 0;

error_path:
- audit_panic("error in audit_log_task_context");
+ audit_panic("error in audit_log_subject_context");
return error;
}
+EXPORT_SYMBOL(audit_log_subject_context);
+
+int audit_log_task_context(struct audit_buffer *ab)
+{
+ struct lsmblob blob;
+
+ security_current_getlsmblob_subj(&blob);
+ return audit_log_subject_context(ab, &blob);
+}
EXPORT_SYMBOL(audit_log_task_context);

void audit_log_d_path_exe(struct audit_buffer *ab,
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 842a236540b0..4dd0f453bb4e 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -84,7 +84,6 @@ struct audit_buffer *netlbl_audit_start_common(int type,
struct netlbl_audit *audit_info)
{
struct audit_buffer *audit_buf;
- struct lsmcontext ctx;

if (audit_enabled == AUDIT_OFF)
return NULL;
@@ -97,12 +96,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
from_kuid(&init_user_ns, audit_info->loginuid),
audit_info->sessionid);

- if (lsmblob_is_set(&audit_info->blob) &&
- security_lsmblob_to_secctx(&audit_info->blob, &ctx,
- LSM_ID_UNDEF) >= 0) {
- audit_log_format(audit_buf, " subj=%s", ctx.context);
- security_release_secctx(&ctx);
- }
+ audit_log_subject_context(audit_buf, &audit_info->blob);

return audit_buf;
}
--
2.41.0


2023-12-15 22:36:42

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 17/42] LSM: Use lsmcontext in security_secid_to_secctx

Replace the (secctx,seclen) pointer pair with a single
lsmcontext pointer to allow return of the LSM identifier
along with the context and context length. This allows
security_release_secctx() to know how to release the
context. Callers have been modified to use or save the
returned data from the new structure.

security_secid_to_secctx() will now return the length value
on success instead of 0.

Signed-off-by: Casey Schaufler <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: Todd Kjos <[email protected]>
---
drivers/android/binder.c | 5 ++---
include/linux/lsm_hook_defs.h | 3 +--
include/linux/security.h | 5 ++---
include/net/scm.h | 5 ++---
net/ipv4/ip_sockglue.c | 4 ++--
net/netfilter/nf_conntrack_netlink.c | 8 ++++----
net/netfilter/nf_conntrack_standalone.c | 4 ++--
net/netfilter/nfnetlink_queue.c | 27 ++++++++++---------------
net/netlabel/netlabel_unlabeled.c | 13 +++++-------
security/apparmor/include/secid.h | 2 +-
security/apparmor/secid.c | 13 +++++++-----
security/security.c | 17 ++++++++--------
security/selinux/hooks.c | 17 ++++++++++++++--
security/smack/smack_lsm.c | 16 ++++++++-------
14 files changed, 72 insertions(+), 67 deletions(-)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 58bdb5b75131..c0fa95e64e7c 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3199,9 +3199,8 @@ static void binder_transaction(struct binder_proc *proc,
size_t added_size;

security_cred_getsecid(proc->cred, &secid);
- ret = security_secid_to_secctx(secid, &lsmctx.context,
- &lsmctx.len);
- if (ret) {
+ ret = security_secid_to_secctx(secid, &lsmctx);
+ if (ret < 0) {
binder_txn_error("%d:%d failed to get security context\n",
thread->pid, proc->pid);
return_error = BR_FAILED_REPLY;
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index c5e5a32f5e07..8e0155ac6697 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -273,8 +273,7 @@ LSM_HOOK(int, -EINVAL, getprocattr, struct task_struct *p, const char *name,
char **value)
LSM_HOOK(int, -EINVAL, setprocattr, const char *name, void *value, size_t size)
LSM_HOOK(int, 0, ismaclabel, const char *name)
-LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, char **secdata,
- u32 *seclen)
+LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, struct lsmcontext *cp)
LSM_HOOK(int, -EOPNOTSUPP, lsmblob_to_secctx, struct lsmblob *blob,
char **secdata, u32 *seclen)
LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
diff --git a/include/linux/security.h b/include/linux/security.h
index 9712056d71a0..03b79089eaf7 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -562,7 +562,7 @@ int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
-int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int security_secid_to_secctx(u32 secid, struct lsmcontext *cp);
int security_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
@@ -1487,8 +1487,7 @@ static inline int security_ismaclabel(const char *name)
return 0;
}

-static inline int security_secid_to_secctx(u32 secid, char **secdata,
- u32 *seclen)
+static inline int security_secid_to_secctx(u32 secid, struct lsmcontext *cp)
{
return -EOPNOTSUPP;
}
diff --git a/include/net/scm.h b/include/net/scm.h
index 6e1add51d4c2..91452b36b5bf 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -97,10 +97,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
int err;

if (test_bit(SOCK_PASSSEC, &sock->flags)) {
- err = security_secid_to_secctx(scm->secid, &ctx.context,
- &ctx.len);
+ err = security_secid_to_secctx(scm->secid, &ctx);

- if (!err) {
+ if (err >= 0) {
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, ctx.len,
ctx.context);
security_release_secctx(&ctx);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 3bf8ff9d4434..38b9f822a70d 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -138,8 +138,8 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
if (err)
return;

- err = security_secid_to_secctx(secid, &ctx.context, &ctx.len);
- if (err)
+ err = security_secid_to_secctx(secid, &ctx);
+ if (err < 0)
return;

put_cmsg(msg, SOL_IP, SCM_SECURITY, ctx.len, ctx.context);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 3e79b339a1bc..a7dfc39bfbf3 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -360,8 +360,8 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
struct lsmcontext ctx;
int ret;

- ret = security_secid_to_secctx(ct->secmark, &ctx.context, &ctx.len);
- if (ret)
+ ret = security_secid_to_secctx(ct->secmark, &ctx);
+ if (ret < 0)
return 0;

ret = -1;
@@ -669,8 +669,8 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
#ifdef CONFIG_NF_CONNTRACK_SECMARK
int len, ret;

- ret = security_secid_to_secctx(ct->secmark, NULL, &len);
- if (ret)
+ ret = security_secid_to_secctx(ct->secmark, NULL);
+ if (ret < 0)
return 0;

return nla_total_size(0) /* CTA_SECCTX */
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 23949d233375..a1d8952db1c1 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -178,8 +178,8 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
struct lsmcontext ctx;
int ret;

- ret = security_secid_to_secctx(ct->secmark, &ctx.context, &ctx.len);
- if (ret)
+ ret = security_secid_to_secctx(ct->secmark, &ctx);
+ if (ret < 0)
return;

seq_printf(s, "secctx=%s ", ctx.context);
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 8b4c5c08daa7..f7918b21672d 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -319,18 +319,18 @@ static int nfqnl_put_sk_classid(struct sk_buff *skb, struct sock *sk)
return 0;
}

-static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
+static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *ctx)
{
u32 seclen = 0;
#if IS_ENABLED(CONFIG_NETWORK_SECMARK)
+
if (!skb || !sk_fullsock(skb->sk))
return 0;

read_lock_bh(&skb->sk->sk_callback_lock);

if (skb->secmark)
- security_secid_to_secctx(skb->secmark, secdata, &seclen);
-
+ seclen = security_secid_to_secctx(skb->secmark, ctx);
read_unlock_bh(&skb->sk->sk_callback_lock);
#endif
return seclen;
@@ -408,8 +408,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
enum ip_conntrack_info ctinfo = 0;
const struct nfnl_ct_hook *nfnl_ct;
bool csum_verify;
- struct lsmcontext scaff; /* scaffolding */
- char *secdata = NULL;
+ struct lsmcontext ctx;
u32 seclen = 0;
ktime_t tstamp;

@@ -484,8 +483,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
}

if ((queue->flags & NFQA_CFG_F_SECCTX) && entskb->sk) {
- seclen = nfqnl_get_sk_secctx(entskb, &secdata);
- if (seclen)
+ seclen = nfqnl_get_sk_secctx(entskb, &ctx);
+ if (seclen >= 0)
size += nla_total_size(seclen);
}

@@ -624,7 +623,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
if (nfqnl_put_sk_classid(skb, entskb->sk) < 0)
goto nla_put_failure;

- if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
+ if (seclen && nla_put(skb, NFQA_SECCTX, ctx.len, ctx.context))
goto nla_put_failure;

if (ct && nfnl_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
@@ -652,10 +651,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
}

nlh->nlmsg_len = skb->len;
- if (seclen) {
- lsmcontext_init(&scaff, secdata, seclen, 0);
- security_release_secctx(&scaff);
- }
+ if (seclen >= 0)
+ security_release_secctx(&ctx);
return skb;

nla_put_failure:
@@ -663,10 +660,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
kfree_skb(skb);
net_err_ratelimited("nf_queue: error creating packet message\n");
nlmsg_failure:
- if (seclen) {
- lsmcontext_init(&scaff, secdata, seclen, 0);
- security_release_secctx(&scaff);
- }
+ if (seclen >= 0)
+ security_release_secctx(&ctx);
return NULL;
}

diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 464105080245..b43cfb4fe4f1 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -437,8 +437,7 @@ int netlbl_unlhsh_add(struct net *net,
unlhsh_add_return:
rcu_read_unlock();
if (audit_buf != NULL) {
- if (security_secid_to_secctx(secid, &ctx.context,
- &ctx.len) == 0) {
+ if (security_secid_to_secctx(secid, &ctx) >= 0) {
audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
security_release_secctx(&ctx);
}
@@ -491,8 +490,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
addr->s_addr, mask->s_addr);
dev_put(dev);
if (entry != NULL &&
- security_secid_to_secctx(entry->secid, &ctx.context,
- &ctx.len) == 0) {
+ security_secid_to_secctx(entry->secid, &ctx) >= 0) {
audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
security_release_secctx(&ctx);
}
@@ -550,8 +548,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
addr, mask);
dev_put(dev);
if (entry != NULL &&
- security_secid_to_secctx(entry->secid, &ctx.context,
- &ctx.len) == 0) {
+ security_secid_to_secctx(entry->secid, &ctx) >= 0) {
audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
security_release_secctx(&ctx);
}
@@ -1122,8 +1119,8 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
secid = addr6->secid;
}

- ret_val = security_secid_to_secctx(secid, &ctx.context, &ctx.len);
- if (ret_val != 0)
+ ret_val = security_secid_to_secctx(secid, &ctx);
+ if (ret_val < 0)
goto list_cb_failure;
ret_val = nla_put(cb_arg->skb,
NLBL_UNLABEL_A_SECCTX,
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index e47c37c1beda..b66c2d043a02 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -25,7 +25,7 @@ struct aa_label;
extern int apparmor_display_secid_mode;

struct aa_label *aa_secid_to_label(u32 secid);
-int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int apparmor_secid_to_secctx(u32 secid, struct lsmcontext *cp);
int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
u32 *seclen);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index e9f655f54a42..55d6c54fe90e 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -61,7 +61,7 @@ struct aa_label *aa_secid_to_label(u32 secid)
return xa_load(&aa_secids, secid);
}

-int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+int apparmor_secid_to_secctx(u32 secid, struct lsmcontext *cp)
{
/* TODO: cache secctx and ref count so we don't have to recreate */
struct aa_label *label = aa_secid_to_label(secid);
@@ -76,8 +76,8 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
if (apparmor_display_secid_mode)
flags |= FLAG_SHOW_MODE;

- if (secdata)
- len = aa_label_asxprint(secdata, root_ns, label,
+ if (cp)
+ len = aa_label_asxprint(&cp->context, root_ns, label,
flags, GFP_ATOMIC);
else
len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
@@ -85,9 +85,12 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
if (len < 0)
return -ENOMEM;

- *seclen = len;
+ if (cp) {
+ cp->len = len;
+ cp->id = LSM_ID_APPARMOR;
+ }

- return 0;
+ return len;
}

int apparmor_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
diff --git a/security/security.c b/security/security.c
index 063a209ac17f..708a26a88447 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4172,17 +4172,16 @@ EXPORT_SYMBOL(security_ismaclabel);
/**
* security_secid_to_secctx() - Convert a secid to a secctx
* @secid: secid
- * @secdata: secctx
- * @seclen: secctx length
+ * @cp: the LSM context
*
- * Convert secid to security context. If @secdata is NULL the length of the
- * result will be returned in @seclen, but no @secdata will be returned. This
+ * Convert secid to security context. If @cp is NULL the length of the
+ * result will be returned, but no data will be returned. This
* does mean that the length could change between calls to check the length and
- * the next call which actually allocates and returns the @secdata.
+ * the next call which actually allocates and returns the data.
*
- * Return: Return 0 on success, error on failure.
+ * Return: Return length of data on success, error on failure.
*/
-int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+int security_secid_to_secctx(u32 secid, struct lsmcontext *cp)
{
struct security_hook_list *hp;
int rc;
@@ -4192,7 +4191,7 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
* LSM hook is not "stackable").
*/
hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
- rc = hp->hook.secid_to_secctx(secid, secdata, seclen);
+ rc = hp->hook.secid_to_secctx(secid, cp);
if (rc != LSM_RET_DEFAULT(secid_to_secctx))
return rc;
}
@@ -4221,7 +4220,7 @@ int security_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
struct security_hook_list *hp;
int rc;

- hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
+ hlist_for_each_entry(hp, &security_hook_heads.lsmblob_to_secctx, list) {
rc = hp->hook.lsmblob_to_secctx(blob, secdata, seclen);
if (rc != LSM_RET_DEFAULT(secid_to_secctx))
return rc;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1a428a6964a0..37b97cf81da1 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6565,9 +6565,22 @@ static int selinux_ismaclabel(const char *name)
return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
}

-static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static int selinux_secid_to_secctx(u32 secid, struct lsmcontext *cp)
{
- return security_sid_to_context(secid, secdata, seclen);
+ u32 seclen;
+ u32 ret;
+
+ if (cp) {
+ cp->id = LSM_ID_SELINUX;
+ ret = security_sid_to_context(secid, &cp->context, &cp->len);
+ if (ret < 0)
+ return ret;
+ return cp->len;
+ }
+ ret = security_sid_to_context(secid, NULL, &seclen);
+ if (ret < 0)
+ return ret;
+ return seclen;
}

static int selinux_lsmblob_to_secctx(struct lsmblob *blob, char **secdata,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7dab00bbd0ed..d82753bc52ab 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4814,19 +4814,21 @@ static int smack_ismaclabel(const char *name)
/**
* smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer
- * @secdata: destination
- * @seclen: how long it is
+ * @cp: destination
*
* Exists for networking code.
*/
-static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static int smack_secid_to_secctx(u32 secid, struct lsmcontext *cp)
{
struct smack_known *skp = smack_from_secid(secid);
+ int len = strlen(skp->smk_known);

- if (secdata)
- *secdata = skp->smk_known;
- *seclen = strlen(skp->smk_known);
- return 0;
+ if (cp) {
+ cp->context = skp->smk_known;
+ cp->len = len;
+ cp->id = LSM_ID_SMACK;
+ }
+ return len;
}

/**
--
2.41.0


2023-12-15 22:37:51

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 26/42] Audit: Add record for multiple object contexts

Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
An example of the MAC_OBJ_CONTEXTS (1421) record is:

type=MAC_OBJ_CONTEXTS[1421]
msg=audit(1601152467.009:1050):
obj_selinux=unconfined_u:object_r:user_home_t:s0

When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
the "obj=" field in other records in the event will be "obj=?".
An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based
on an object security context.

Signed-off-by: Casey Schaufler <[email protected]>
Acked-by: Paul Moore <[email protected]>
---
include/linux/audit.h | 5 +++
include/uapi/linux/audit.h | 1 +
kernel/audit.c | 51 +++++++++++++++++++++++-
kernel/auditsc.c | 81 ++++++++++++--------------------------
4 files changed, 82 insertions(+), 56 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 8974500f730f..914cfd563ce3 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -185,6 +185,8 @@ extern void audit_log_path_denied(int type,
const char *operation);
extern void audit_log_lost(const char *message);

+extern void audit_log_object_context(struct audit_buffer *ab,
+ struct lsmblob *blob);
extern int audit_log_subject_context(struct audit_buffer *ab,
struct lsmblob *blob);
extern int audit_log_task_context(struct audit_buffer *ab);
@@ -247,6 +249,9 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
{ }
static inline void audit_log_path_denied(int type, const char *operation)
{ }
+static inline void audit_log_object_context(struct audit_buffer *ab,
+ struct lsmblob *blob)
+{ }
static inline int audit_log_subject_context(struct audit_buffer *ab,
struct lsmblob *blob)
{
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index dc045164b86b..bed324162a7c 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -144,6 +144,7 @@
#define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */
#define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */
#define AUDIT_MAC_TASK_CONTEXTS 1420 /* Multiple LSM task contexts */
+#define AUDIT_MAC_OBJ_CONTEXTS 1421 /* Multiple LSM objext contexts */

#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
diff --git a/kernel/audit.c b/kernel/audit.c
index 626942c38bca..dc11dd4c41fc 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1105,7 +1105,6 @@ static int is_audit_feature_set(int i)
return af.features & AUDIT_FEATURE_TO_MASK(i);
}

-
static int audit_get_feature(struct sk_buff *skb)
{
u32 seq;
@@ -2289,6 +2288,56 @@ int audit_log_task_context(struct audit_buffer *ab)
}
EXPORT_SYMBOL(audit_log_task_context);

+void audit_log_object_context(struct audit_buffer *ab, struct lsmblob *blob)
+{
+ int i;
+ int error;
+ bool space = false;
+ struct lsmcontext context;
+
+ if (lsm_blob_cnt < 2) {
+ error = security_lsmblob_to_secctx(blob, &context,
+ LSM_ID_UNDEF);
+ if (error) {
+ if (error != -EINVAL)
+ goto error_path;
+ return;
+ }
+ audit_log_format(ab, " obj=%s", context.context);
+ security_release_secctx(&context);
+ return;
+ }
+ audit_log_format(ab, " obj=?");
+ error = audit_buffer_aux_new(ab, AUDIT_MAC_OBJ_CONTEXTS);
+ if (error)
+ goto error_path;
+
+ for (i = 0; i < lsm_blob_cnt; i++) {
+ if (!lsm_idlist[i]->lsmblob)
+ continue;
+ error = security_lsmblob_to_secctx(blob, &context,
+ lsm_idlist[i]->id);
+ if (error) {
+ audit_log_format(ab, "%sobj_%s=?",
+ space ? " " : "", lsm_idlist[i]->name);
+ if (error != -EINVAL)
+ audit_panic("error in audit_log_object_context");
+ } else {
+ audit_log_format(ab, "%sobj_%s=%s",
+ space ? " " : "", lsm_idlist[i]->name,
+ context.context);
+ security_release_secctx(&context);
+ }
+ space = true;
+ }
+
+ audit_buffer_aux_end(ab);
+ return;
+
+error_path:
+ audit_panic("error in audit_log_object_context");
+}
+
void audit_log_d_path_exe(struct audit_buffer *ab,
struct mm_struct *mm)
{
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 23f72c14276d..bc13666dd6ed 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1092,36 +1092,27 @@ static inline void audit_free_context(struct audit_context *context)
kfree(context);
}

-static int audit_log_pid_context(struct audit_context *context, pid_t pid,
- kuid_t auid, kuid_t uid,
- unsigned int sessionid, struct lsmblob *blob,
- char *comm)
+static void audit_log_pid_context(struct audit_context *context, pid_t pid,
+ kuid_t auid, kuid_t uid,
+ unsigned int sessionid, struct lsmblob *blob,
+ char *comm)
{
struct audit_buffer *ab;
- struct lsmcontext ctx;
- int rc = 0;

ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
if (!ab)
- return rc;
+ return;

audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
- if (lsmblob_is_set(blob)) {
- if (security_lsmblob_to_secctx(blob, &ctx, LSM_ID_UNDEF) < 0) {
- audit_log_format(ab, " obj=(none)");
- rc = 1;
- } else {
- audit_log_format(ab, " obj=%s", ctx.context);
- security_release_secctx(&ctx);
- }
- }
+ if (lsmblob_is_set(blob))
+ audit_log_object_context(ab, blob);
audit_log_format(ab, " ocomm=");
audit_log_untrustedstring(ab, comm);
audit_log_end(ab);

- return rc;
+ return;
}

static void audit_log_execve_info(struct audit_context *context,
@@ -1370,7 +1361,6 @@ static void audit_log_time(struct audit_context *context, struct audit_buffer **

static void show_special(struct audit_context *context, int *call_panic)
{
- struct lsmcontext lsmctx;
struct audit_buffer *ab;
int i;

@@ -1392,16 +1382,8 @@ static void show_special(struct audit_context *context, int *call_panic)
from_kuid(&init_user_ns, context->ipc.uid),
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
- if (lsmblob_is_set(&context->ipc.oblob)) {
- if (security_lsmblob_to_secctx(&context->ipc.oblob,
- &lsmctx,
- LSM_ID_UNDEF) < 0) {
- *call_panic = 1;
- } else {
- audit_log_format(ab, " obj=%s", lsmctx.context);
- security_release_secctx(&lsmctx);
- }
- }
+ if (lsmblob_is_set(&context->ipc.oblob))
+ audit_log_object_context(ab, &context->ipc.oblob);
if (context->ipc.has_perm) {
audit_log_end(ab);
ab = audit_log_start(context, GFP_KERNEL,
@@ -1557,18 +1539,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
from_kgid(&init_user_ns, n->gid),
MAJOR(n->rdev),
MINOR(n->rdev));
- if (lsmblob_is_set(&n->oblob)) {
- struct lsmcontext ctx;
-
- if (security_lsmblob_to_secctx(&n->oblob, &ctx,
- LSM_ID_UNDEF) < 0) {
- if (call_panic)
- *call_panic = 2;
- } else {
- audit_log_format(ab, " obj=%s", ctx.context);
- security_release_secctx(&ctx);
- }
- }
+ if (lsmblob_is_set(&n->oblob))
+ audit_log_object_context(ab, &n->oblob);

/* log the audit_names record type */
switch (n->type) {
@@ -1773,21 +1745,20 @@ static void audit_log_exit(void)
struct audit_aux_data_pids *axs = (void *)aux;

for (i = 0; i < axs->pid_count; i++)
- if (audit_log_pid_context(context, axs->target_pid[i],
- axs->target_auid[i],
- axs->target_uid[i],
- axs->target_sessionid[i],
- &axs->target_blob[i],
- axs->target_comm[i]))
- call_panic = 1;
- }
-
- if (context->target_pid &&
- audit_log_pid_context(context, context->target_pid,
- context->target_auid, context->target_uid,
- context->target_sessionid,
- &context->target_blob, context->target_comm))
- call_panic = 1;
+ audit_log_pid_context(context, axs->target_pid[i],
+ axs->target_auid[i],
+ axs->target_uid[i],
+ axs->target_sessionid[i],
+ &axs->target_blob[i],
+ axs->target_comm[i]);
+ }
+
+ if (context->target_pid)
+ audit_log_pid_context(context, context->target_pid,
+ context->target_auid, context->target_uid,
+ context->target_sessionid,
+ &context->target_blob,
+ context->target_comm);

if (context->pwd.dentry && context->pwd.mnt) {
ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
--
2.41.0


2023-12-15 22:38:32

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 21/42] LSM: security_lsmblob_to_secctx module selection

Add a parameter lsmid to security_lsmblob_to_secctx() to identify which
of the security modules that may be active should provide the security
context. If the value of lsmid is LSM_ID_UNDEF the first LSM providing
a hook is used. security_secid_to_secctx() is unchanged, and will
always report the first LSM providing a hook.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/security.h | 5 +++--
kernel/audit.c | 4 ++--
kernel/auditsc.c | 8 +++++---
net/netlabel/netlabel_user.c | 3 ++-
security/security.c | 11 ++++++-----
5 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 35604f43d4ff..360a454d5f8e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -563,7 +563,8 @@ int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, struct lsmcontext *cp);
-int security_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
+int security_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
+ int lsmid);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(struct lsmcontext *cp);
void security_inode_invalidate_secctx(struct inode *inode);
@@ -1491,7 +1492,7 @@ static inline int security_secid_to_secctx(u32 secid, struct lsmcontext *cp)
}

static inline int security_lsmblob_to_secctx(struct lsmblob *blob,
- struct lsmcontext *cp)
+ struct lsmcontext *cp, int lsmid)
{
return -EOPNOTSUPP;
}
diff --git a/kernel/audit.c b/kernel/audit.c
index a93a710c980e..edefb370a72e 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1462,7 +1462,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)

if (lsmblob_is_set(&audit_sig_lsm)) {
err = security_lsmblob_to_secctx(&audit_sig_lsm,
- &lsmctx);
+ &lsmctx, LSM_ID_UNDEF);
if (err < 0)
return err;
}
@@ -2174,7 +2174,7 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsmblob_is_set(&blob))
return 0;

- error = security_lsmblob_to_secctx(&blob, &ctx);
+ error = security_lsmblob_to_secctx(&blob, &ctx, LSM_ID_UNDEF);
if (error < 0) {
if (error != -EINVAL)
goto error_path;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index c37cc02ea4cc..3c0559b01677 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1109,7 +1109,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
if (lsmblob_is_set(blob)) {
- if (security_lsmblob_to_secctx(blob, &ctx) < 0) {
+ if (security_lsmblob_to_secctx(blob, &ctx, LSM_ID_UNDEF) < 0) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1394,7 +1394,8 @@ static void show_special(struct audit_context *context, int *call_panic)
context->ipc.mode);
if (lsmblob_is_set(&context->ipc.oblob)) {
if (security_lsmblob_to_secctx(&context->ipc.oblob,
- &lsmctx) < 0) {
+ &lsmctx,
+ LSM_ID_UNDEF) < 0) {
*call_panic = 1;
} else {
audit_log_format(ab, " obj=%s", lsmctx.context);
@@ -1559,7 +1560,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
if (lsmblob_is_set(&n->oblob)) {
struct lsmcontext ctx;

- if (security_lsmblob_to_secctx(&n->oblob, &ctx) < 0) {
+ if (security_lsmblob_to_secctx(&n->oblob, &ctx,
+ LSM_ID_UNDEF) < 0) {
if (call_panic)
*call_panic = 2;
} else {
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 561e1e476a49..842a236540b0 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -98,7 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
audit_info->sessionid);

if (lsmblob_is_set(&audit_info->blob) &&
- security_lsmblob_to_secctx(&audit_info->blob, &ctx) >= 0) {
+ security_lsmblob_to_secctx(&audit_info->blob, &ctx,
+ LSM_ID_UNDEF) >= 0) {
audit_log_format(audit_buf, " subj=%s", ctx.context);
security_release_secctx(&ctx);
}
diff --git a/security/security.c b/security/security.c
index cea3c1b614a1..444051575793 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4203,6 +4203,7 @@ EXPORT_SYMBOL(security_secid_to_secctx);
* security_lsmblob_to_secctx() - Convert a lsmblob to a secctx
* @blob: lsm specific information
* @cp: the LSM context
+ * @lsmid: which security module to report
*
* Convert a @blob entry to security context. If @cp is NULL the
* length of the result will be returned, but no data will be returned.
@@ -4212,15 +4213,15 @@ EXPORT_SYMBOL(security_secid_to_secctx);
*
* Return: Return length of data on success, error on failure.
*/
-int security_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
+int security_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
+ int lsmid)
{
struct security_hook_list *hp;
- int rc;

hlist_for_each_entry(hp, &security_hook_heads.lsmblob_to_secctx, list) {
- rc = hp->hook.lsmblob_to_secctx(blob, cp);
- if (rc != LSM_RET_DEFAULT(lsmblob_to_secctx))
- return rc;
+ if (lsmid != hp->lsmid->id && lsmid != LSM_ID_UNDEF)
+ continue;
+ return hp->hook.lsmblob_to_secctx(blob, cp);
}

return LSM_RET_DEFAULT(lsmblob_to_secctx);
--
2.41.0


2023-12-15 22:39:11

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 28/42] LSM: Improve logic in security_getprocattr

The conditional in security_getprocattr() can be simplified
and made clearer. This change does that.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/security/security.c b/security/security.c
index 8ff6cef26e6c..f2ef6032a925 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4107,11 +4107,10 @@ int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
{
struct security_hook_list *hp;

- hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
- if (lsmid != 0 && lsmid != hp->lsmid->id)
- continue;
- return hp->hook.getprocattr(p, name, value);
- }
+ hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list)
+ if (lsmid == LSM_ID_UNDEF || lsmid == hp->lsmid->id)
+ return hp->hook.getprocattr(p, name, value);
+
return LSM_RET_DEFAULT(getprocattr);
}

--
2.41.0


2023-12-15 22:39:12

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 29/42] LSM: secctx provider check on release

Verify that the LSM releasing the secctx is the LSM that
allocated it. This was not necessary when only one LSM could
create a secctx, but once there can be more than one it is.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/apparmor/secid.c | 10 ++--------
security/selinux/hooks.c | 10 ++--------
2 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index c9b9a8d90afa..1df08372bf1b 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -146,14 +146,8 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)

void apparmor_release_secctx(struct lsmcontext *cp)
{
- /*
- * stacking scaffolding:
- * When it is possible for more than one LSM to provide a
- * release hook, do this check:
- * if (cp->id == LSM_ID_APPARMOR || cp->id == LSM_ID_UNDEF)
- */
-
- kfree(cp->context);
+ if (cp->id == LSM_ID_APPARMOR)
+ kfree(cp->context);
}

/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 656f25337334..a6deccbbcc40 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6616,14 +6616,8 @@ static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)

static void selinux_release_secctx(struct lsmcontext *cp)
{
- /*
- * stacking scaffolding:
- * When it is possible for more than one LSM to provide a
- * release hook, do this check:
- * if (cp->id == LSM_ID_SELINUX || cp->id == LSM_ID_UNDEF)
- */
-
- kfree(cp->context);
+ if (cp->id == LSM_ID_SELINUX)
+ kfree(cp->context);
}

static void selinux_inode_invalidate_secctx(struct inode *inode)
--
2.41.0


2023-12-15 22:40:47

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 30/42] LSM: Single calls in socket_getpeersec hooks

security_socket_getpeersec_stream() and security_socket_getpeersec_dgram()
can only provide a single security context or secid to their callers.
Open code these two hooks to return the first hook provided. Because
only one "major" LSM is allowed there will only be one hook in the list,
with the excepton being BPF. BPF is not expected to be using these
interfaces.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/security/security.c b/security/security.c
index f2ef6032a925..3f0a4c5094a5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4686,8 +4686,14 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
sockptr_t optlen, unsigned int len)
{
- return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
- optval, optlen, len);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream,
+ list)
+ return hp->hook.socket_getpeersec_stream(sock, optval, optlen,
+ len);
+
+ return -ENOPROTOOPT;
}

/**
@@ -4707,8 +4713,13 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
int security_socket_getpeersec_dgram(struct socket *sock,
struct sk_buff *skb, u32 *secid)
{
- return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
- skb, secid);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram,
+ list)
+ return hp->hook.socket_getpeersec_dgram(sock, skb, secid);
+
+ return -ENOPROTOOPT;
}
EXPORT_SYMBOL(security_socket_getpeersec_dgram);

--
2.41.0


2023-12-15 22:41:31

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 31/42] LSM: Exclusive secmark usage

The network secmark can only be used by one security module
at a time. Establish mechanism to identify to security modules
whether they have access to the secmark. SELinux already
incorparates mechanism, but it has to be added to Smack and
AppArmor.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/apparmor/include/net.h | 5 +++++
security/apparmor/lsm.c | 7 ++++---
security/security.c | 6 ++++++
security/selinux/hooks.c | 4 +++-
security/smack/smack.h | 5 +++++
security/smack/smack_lsm.c | 3 ++-
security/smack/smack_netfilter.c | 10 ++++++++--
8 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 605aaf38c3f5..4deb1a4d2d1a 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -81,6 +81,7 @@ struct lsm_blob_sizes {
int lbs_msg_msg;
int lbs_task;
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
+ bool lbs_secmark; /* expressed desire for secmark use */
};

/**
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index c42ed8a73f1c..2e43e1e8303c 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -51,6 +51,11 @@ struct aa_sk_ctx {
struct aa_label *peer;
};

+static inline bool aa_secmark(void)
+{
+ return apparmor_blob_sizes.lbs_secmark;
+}
+
static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
{
return sk->sk_security + apparmor_blob_sizes.lbs_sock;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 075942b253ae..ab9b0b37f1f7 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1322,7 +1322,7 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct aa_sk_ctx *ctx = aa_sock(sk);

- if (!skb->secmark)
+ if (!aa_secmark() || !skb->secmark)
return 0;

return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE,
@@ -1426,7 +1426,7 @@ static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb
{
struct aa_sk_ctx *ctx = aa_sock(sk);

- if (!skb->secmark)
+ if (!aa_secmark() || !skb->secmark)
return 0;

return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT,
@@ -1442,6 +1442,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
.lbs_file = sizeof(struct aa_file_ctx),
.lbs_task = sizeof(struct aa_task_ctx),
.lbs_sock = sizeof(struct aa_sk_ctx),
+ .lbs_secmark = true,
};

static const struct lsm_id apparmor_lsmid = {
@@ -2105,7 +2106,7 @@ static unsigned int apparmor_ip_postroute(void *priv,
struct aa_sk_ctx *ctx;
struct sock *sk;

- if (!skb->secmark)
+ if (!aa_secmark() || !skb->secmark)
return NF_ACCEPT;

sk = skb_to_full_sk(skb);
diff --git a/security/security.c b/security/security.c
index 3f0a4c5094a5..8469816c0472 100644
--- a/security/security.c
+++ b/security/security.c
@@ -232,6 +232,12 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
lsm_set_blob_size(&needed->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
+ if (needed->lbs_secmark) {
+ if (!blob_sizes.lbs_secmark)
+ blob_sizes.lbs_secmark = true;
+ else
+ needed->lbs_secmark = false;
+ }
}

/* Prepare LSM for initialization. */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a6deccbbcc40..3e590f632f59 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -164,7 +164,8 @@ __setup("checkreqprot=", checkreqprot_setup);
*/
static int selinux_secmark_enabled(void)
{
- return (selinux_policycap_alwaysnetwork() ||
+ return selinux_blob_sizes.lbs_secmark &&
+ (selinux_policycap_alwaysnetwork() ||
atomic_read(&selinux_secmark_refcount));
}

@@ -6969,6 +6970,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_sock = sizeof(struct sk_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
+ .lbs_secmark = true,
};

#ifdef CONFIG_PERF_EVENTS
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 297f21446f45..0f5bc5c03b9e 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -369,6 +369,11 @@ static inline int smk_inode_transmutable(const struct inode *isp)
return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
}

+static inline bool smack_secmark(void)
+{
+ return smack_blob_sizes.lbs_secmark;
+}
+
/*
* Present a pointer to the smack label entry in an inode blob.
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a9ab31a40e36..c93e81facf1b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4090,7 +4090,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
#ifdef CONFIG_NETWORK_SECMARK
static struct smack_known *smack_from_skb(struct sk_buff *skb)
{
- if (skb == NULL || skb->secmark == 0)
+ if (!smack_secmark() || skb == NULL || skb->secmark == 0)
return NULL;

return smack_from_secid(skb->secmark);
@@ -5064,6 +5064,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_sock = sizeof(struct socket_smack),
.lbs_superblock = sizeof(struct superblock_smack),
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+ .lbs_secmark = true,
};

static const struct lsm_id smack_lsmid = {
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index bad71b7e648d..fd146e3a2286 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -26,7 +26,7 @@ static unsigned int smack_ip_output(void *priv,
struct socket_smack *ssp;
struct smack_known *skp;

- if (sk) {
+ if (smack_secmark() && sk) {
ssp = smack_sock(sk);
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
@@ -54,12 +54,18 @@ static const struct nf_hook_ops smack_nf_ops[] = {

static int __net_init smack_nf_register(struct net *net)
{
+ if (!smack_secmark())
+ return 0;
+
return nf_register_net_hooks(net, smack_nf_ops,
ARRAY_SIZE(smack_nf_ops));
}

static void __net_exit smack_nf_unregister(struct net *net)
{
+ if (!smack_secmark())
+ return;
+
nf_unregister_net_hooks(net, smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
}

@@ -70,7 +76,7 @@ static struct pernet_operations smack_net_ops = {

static int __init smack_nf_ip_init(void)
{
- if (smack_enabled == 0)
+ if (smack_enabled == 0 || !smack_secmark())
return 0;

printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
--
2.41.0


2023-12-15 22:42:15

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 27/42] LSM: Remove unused lsmcontext_init()

The lsmcontext init functing is no longer used.
Remove it.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/security.h | 19 -------------------
1 file changed, 19 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 947cb3a35db4..529671a89ce0 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -160,25 +160,6 @@ struct lsmcontext {
int id; /* Identifies the module */
};

-/**
- * lsmcontext_init - initialize an lsmcontext structure.
- * @cp: Pointer to the context to initialize
- * @context: Initial context, or NULL
- * @size: Size of context, or 0
- * @id: Which LSM provided the context
- *
- * Fill in the lsmcontext from the provided information.
- * This is a scaffolding function that will be removed when
- * lsmcontext integration is complete.
- */
-static inline void lsmcontext_init(struct lsmcontext *cp, char *context,
- u32 size, int id)
-{
- cp->id = id;
- cp->context = context;
- cp->len = size;
-}
-
/*
* Data exported by the security modules
*/
--
2.41.0


2023-12-15 22:42:19

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 33/42] AppArmor: Remove the exclusive flag

With the inclusion of the interface LSM process attribute
mechanism AppArmor no longer needs to be treated as an
"exclusive" security module. Remove the flag that indicates
it is exclusive. Remove the stub getpeersec_dgram AppArmor
hook as it has no effect in the single LSM case and
interferes in the multiple LSM case.

Acked-by: Stephen Smalley <[email protected]>
Acked-by: John Johansen <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Casey Schaufler <[email protected]>
---
security/apparmor/lsm.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index ab9b0b37f1f7..d47816e91bd3 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1385,22 +1385,6 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
return error;
}

-/**
- * apparmor_socket_getpeersec_dgram - get security label of packet
- * @sock: the peer socket
- * @skb: packet data
- * @secid: pointer to where to put the secid of the packet
- *
- * Sets the netlabel socket state on sk from parent
- */
-static int apparmor_socket_getpeersec_dgram(struct socket *sock,
- struct sk_buff *skb, u32 *secid)
-
-{
- /* TODO: requires secid support */
- return -ENOPROTOOPT;
-}
-
/**
* apparmor_sock_graft - Initialize newly created socket
* @sk: child sock
@@ -1510,8 +1494,6 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
#endif
LSM_HOOK_INIT(socket_getpeersec_stream,
apparmor_socket_getpeersec_stream),
- LSM_HOOK_INIT(socket_getpeersec_dgram,
- apparmor_socket_getpeersec_dgram),
LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
#ifdef CONFIG_NETWORK_SECMARK
LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request),
@@ -2296,7 +2278,7 @@ static int __init apparmor_init(void)

DEFINE_LSM(apparmor) = {
.name = "apparmor",
- .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .flags = LSM_FLAG_LEGACY_MAJOR,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
.init = apparmor_init,
--
2.41.0


2023-12-15 22:42:28

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 32/42] LSM: Identify which LSM handles the context string

The security_secctx_to_secid() call can only interpret the
context string for a single LSM. Use the first LSM that supplies a hook.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/security/security.c b/security/security.c
index 8469816c0472..8576121fadb9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4248,8 +4248,13 @@ EXPORT_SYMBOL(security_lsmblob_to_secctx);
*/
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
+ struct security_hook_list *hp;
+
*secid = 0;
- return call_int_hook(secctx_to_secid, 0, secdata, seclen, secid);
+ hlist_for_each_entry(hp, &security_hook_heads.secctx_to_secid, list)
+ return hp->hook.secctx_to_secid(secdata, seclen, secid);
+
+ return LSM_RET_DEFAULT(secctx_to_secid);
}
EXPORT_SYMBOL(security_secctx_to_secid);

--
2.41.0


2023-12-15 22:43:52

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 34/42] LSM: Add mount opts blob size tracking

Add mount option data to the blob size accounting in anticipation
of using a shared mnt_opts blob.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/security.c | 2 ++
security/selinux/hooks.c | 1 +
security/smack/smack_lsm.c | 1 +
4 files changed, 5 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 4deb1a4d2d1a..59085248809a 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -81,6 +81,7 @@ struct lsm_blob_sizes {
int lbs_msg_msg;
int lbs_task;
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
+ int lbs_mnt_opts;
bool lbs_secmark; /* expressed desire for secmark use */
};

diff --git a/security/security.c b/security/security.c
index 8576121fadb9..fd429f67d2da 100644
--- a/security/security.c
+++ b/security/security.c
@@ -232,6 +232,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
lsm_set_blob_size(&needed->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
+ lsm_set_blob_size(&needed->lbs_mnt_opts, &blob_sizes.lbs_mnt_opts);
if (needed->lbs_secmark) {
if (!blob_sizes.lbs_secmark)
blob_sizes.lbs_secmark = true;
@@ -453,6 +454,7 @@ static void __init ordered_lsm_init(void)
init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
init_debug("task blob size = %d\n", blob_sizes.lbs_task);
init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
+ init_debug("mnt_opts blob size = %d\n", blob_sizes.lbs_mnt_opts);

/*
* Create any kmem_caches needed for blobs
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3e590f632f59..e0f6f2093708 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6970,6 +6970,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_sock = sizeof(struct sk_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
+ .lbs_mnt_opts = sizeof(struct selinux_mnt_opts),
.lbs_secmark = true,
};

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index c93e81facf1b..573d5bffb9e1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5064,6 +5064,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_sock = sizeof(struct socket_smack),
.lbs_superblock = sizeof(struct superblock_smack),
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+ .lbs_mnt_opts = sizeof(struct smack_mnt_opts),
.lbs_secmark = true,
};

--
2.41.0


2023-12-15 22:44:08

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 35/42] LSM: allocate mnt_opts blobs instead of module specific data

Replace allocations of LSM specific mount data with the
shared mnt_opts blob.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/security.c | 12 ++++++++++++
security/selinux/hooks.c | 10 +++++++---
security/smack/smack_lsm.c | 4 ++--
4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 59085248809a..24a0f62ec2ac 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -156,5 +156,6 @@ extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
__aligned(sizeof(unsigned long))

extern int lsm_inode_alloc(struct inode *inode);
+extern void *lsm_mnt_opts_alloc(gfp_t priority);

#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/security.c b/security/security.c
index fd429f67d2da..7a9fbe706525 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1385,6 +1385,18 @@ void security_sb_free(struct super_block *sb)
sb->s_security = NULL;
}

+/**
+ * lsm_mnt_opts_alloc - allocate a mnt_opts blob
+ * @priority: memory allocation priority
+ *
+ * Returns a newly allocated mnt_opts blob or NULL if
+ * memory isn't available.
+ */
+void *lsm_mnt_opts_alloc(gfp_t priority)
+{
+ return kzalloc(blob_sizes.lbs_mnt_opts, priority);
+}
+
/**
* security_free_mnt_opts() - Free memory associated with mount options
* @mnt_opts: LSM processed mount options
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e0f6f2093708..3d046c9d0121 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2787,7 +2787,7 @@ static int selinux_fs_context_submount(struct fs_context *fc,
if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
return 0;

- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ opts = lsm_mnt_opts_alloc(GFP_KERNEL);
if (!opts)
return -ENOMEM;

@@ -2809,8 +2809,12 @@ static int selinux_fs_context_dup(struct fs_context *fc,
if (!src)
return 0;

- fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
- return fc->security ? 0 : -ENOMEM;
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+
+ memcpy(fc->security, src, sizeof(*src));
+ return 0;
}

static const struct fs_parameter_spec selinux_fs_parameters[] = {
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 573d5bffb9e1..97ffb07797e9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -638,7 +638,7 @@ static int smack_fs_context_submount(struct fs_context *fc,
struct smack_mnt_opts *ctx;
struct inode_smack *isp;

- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = lsm_mnt_opts_alloc(GFP_KERNEL);
if (!ctx)
return -ENOMEM;
fc->security = ctx;
@@ -689,7 +689,7 @@ static int smack_fs_context_dup(struct fs_context *fc,
if (!src)
return 0;

- fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
if (!fc->security)
return -ENOMEM;

--
2.41.0


2023-12-15 22:45:29

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 37/42] LSM: Infrastructure management of the mnt_opts security blob

Move management of the mnt_opts->security blob out of the
individual security modules and into the security
infrastructure. Blobs are atill allocated within the modules
as they are only required when mount options are present.
The modules tell the infrastructure how much space is required,
and the space is allocated if needed. Modules can no longer
count on the presence of a blob implying that mount options
specific to that module are present, so flags are added
to the module specific blobs to indicate that this module
has options.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 14 ++++-----
security/selinux/hooks.c | 58 +++++++++++++++++++++++-------------
security/smack/smack_lsm.c | 61 ++++++++++++++++++++++++++------------
3 files changed, 85 insertions(+), 48 deletions(-)

diff --git a/security/security.c b/security/security.c
index 092752666fb6..64cdf0e09832 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1352,18 +1352,15 @@ int security_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
struct security_hook_list *hp;
- int trc;
- int rc = -ENOPARAM;
+ int rc;

hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param,
list) {
- trc = hp->hook.fs_context_parse_param(fc, param);
- if (trc == 0)
- rc = 0;
- else if (trc != -ENOPARAM)
- return trc;
+ rc = hp->hook.fs_context_parse_param(fc, param);
+ if (rc != -ENOPARAM)
+ return rc;
}
- return rc;
+ return -ENOPARAM;
}

/**
@@ -1437,6 +1434,7 @@ void security_free_mnt_opts(void **mnt_opts)
if (!*mnt_opts)
return;
call_void_hook(sb_free_mnt_opts, *mnt_opts);
+ kfree(*mnt_opts);
*mnt_opts = NULL;
}
EXPORT_SYMBOL(security_free_mnt_opts);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a9af3c848a16..46dee63eec12 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -365,15 +365,28 @@ static void inode_free_security(struct inode *inode)
}

struct selinux_mnt_opts {
+ bool initialized;
u32 fscontext_sid;
u32 context_sid;
u32 rootcontext_sid;
u32 defcontext_sid;
};

+static inline struct selinux_mnt_opts *selinux_mnt_opts(void *mnt_opts)
+{
+ if (mnt_opts)
+ return mnt_opts + selinux_blob_sizes.lbs_mnt_opts;
+ return NULL;
+}
+
static void selinux_free_mnt_opts(void *mnt_opts)
{
- kfree(mnt_opts);
+ struct selinux_mnt_opts *opts;
+
+ if (mnt_opts) {
+ opts = selinux_mnt_opts(mnt_opts);
+ opts->initialized = false;
+ }
}

enum {
@@ -628,7 +641,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
const struct cred *cred = current_cred();
struct superblock_security_struct *sbsec = selinux_superblock(sb);
struct dentry *root = sb->s_root;
- struct selinux_mnt_opts *opts = mnt_opts;
+ struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
struct inode_security_struct *root_isec;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0;
@@ -644,7 +657,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock);

if (!selinux_initialized()) {
- if (!opts) {
+ if (!opts || !opts->initialized) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
@@ -682,7 +695,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* also check if someone is trying to mount the same sb more
* than once with different security options.
*/
- if (opts) {
+ if (opts && opts->initialized) {
if (opts->fscontext_sid) {
fscontext_sid = opts->fscontext_sid;
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
@@ -991,7 +1004,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
*/
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
- struct selinux_mnt_opts *opts = *mnt_opts;
+ struct selinux_mnt_opts *opts;
u32 *dst_sid;
int rc;

@@ -1006,12 +1019,12 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
return -EINVAL;
}

- if (!opts) {
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
- if (!opts)
+ if (!*mnt_opts) {
+ *mnt_opts = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!*mnt_opts)
return -ENOMEM;
- *mnt_opts = opts;
}
+ opts = selinux_mnt_opts(*mnt_opts);

switch (token) {
case Opt_context:
@@ -1038,6 +1051,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
WARN_ON(1);
return -EINVAL;
}
+ opts->initialized = true;
rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL);
if (rc)
pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
@@ -2629,10 +2643,7 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
return 0;

free_opt:
- if (*mnt_opts) {
- selinux_free_mnt_opts(*mnt_opts);
- *mnt_opts = NULL;
- }
+ selinux_free_mnt_opts(*mnt_opts);
return rc;
}

@@ -2683,13 +2694,13 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)

static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
- struct selinux_mnt_opts *opts = mnt_opts;
+ struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
struct superblock_security_struct *sbsec = selinux_superblock(sb);

if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;

- if (!opts)
+ if (!opts || !opts->initialized)
return 0;

if (opts->fscontext_sid) {
@@ -2787,9 +2798,13 @@ static int selinux_fs_context_submount(struct fs_context *fc,
if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
return 0;

- opts = lsm_mnt_opts_alloc(GFP_KERNEL);
- if (!opts)
- return -ENOMEM;
+ if (!fc->security) {
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ }
+ opts = selinux_mnt_opts(fc->security);
+ opts->initialized = true;

if (sbsec->flags & FSCONTEXT_MNT)
opts->fscontext_sid = sbsec->sid;
@@ -2797,14 +2812,14 @@ static int selinux_fs_context_submount(struct fs_context *fc,
opts->context_sid = sbsec->mntpoint_sid;
if (sbsec->flags & DEFCONTEXT_MNT)
opts->defcontext_sid = sbsec->def_sid;
- fc->security = opts;
return 0;
}

static int selinux_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
- const struct selinux_mnt_opts *src = src_fc->security;
+ const struct selinux_mnt_opts *src = selinux_mnt_opts(src_fc->security);
+ struct selinux_mnt_opts *dst;

if (!src)
return 0;
@@ -2813,7 +2828,8 @@ static int selinux_fs_context_dup(struct fs_context *fc,
if (!fc->security)
return -ENOMEM;

- memcpy(fc->security, src, sizeof(*src));
+ dst = selinux_mnt_opts(fc->security);
+ memcpy(dst, src, sizeof(*src));
return 0;
}

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b273e94028bb..61bd3f626e7d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -560,6 +560,7 @@ static int smack_sb_alloc_security(struct super_block *sb)
}

struct smack_mnt_opts {
+ bool initialized;
const char *fsdefault;
const char *fsfloor;
const char *fshat;
@@ -567,24 +568,37 @@ struct smack_mnt_opts {
const char *fstransmute;
};

+static inline struct smack_mnt_opts *smack_mnt_opts(void *mnt_opts)
+{
+ if (mnt_opts)
+ return mnt_opts + smack_blob_sizes.lbs_mnt_opts;
+ return NULL;
+}
+
static void smack_free_mnt_opts(void *mnt_opts)
{
- kfree(mnt_opts);
+ struct smack_mnt_opts *opts;
+
+ if (mnt_opts) {
+ opts = smack_mnt_opts(mnt_opts);
+ opts->initialized = false;
+ }
}

static int smack_add_opt(int token, const char *s, void **mnt_opts)
{
- struct smack_mnt_opts *opts = *mnt_opts;
+ struct smack_mnt_opts *opts;
struct smack_known *skp;

- if (!opts) {
- opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
- if (!opts)
+ if (!s)
+ return -EINVAL;
+
+ if (!*mnt_opts) {
+ *mnt_opts = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!*mnt_opts)
return -ENOMEM;
- *mnt_opts = opts;
}
- if (!s)
- return -ENOMEM;
+ opts = smack_mnt_opts(*mnt_opts);

skp = smk_import_entry(s, 0);
if (IS_ERR(skp))
@@ -617,6 +631,7 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts)
opts->fstransmute = skp->smk_known;
break;
}
+ opts->initialized = true;
return 0;

out_opt_err:
@@ -638,10 +653,12 @@ static int smack_fs_context_submount(struct fs_context *fc,
struct smack_mnt_opts *ctx;
struct inode_smack *isp;

- ctx = lsm_mnt_opts_alloc(GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
- fc->security = ctx;
+ if (!fc->security) {
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ }
+ ctx = smack_mnt_opts(fc->security);

sbsp = smack_superblock(reference);
isp = smack_inode(reference->s_root->d_inode);
@@ -671,6 +688,7 @@ static int smack_fs_context_submount(struct fs_context *fc,
return -ENOMEM;
}
}
+ ctx->initialized = true;
return 0;
}

@@ -684,16 +702,21 @@ static int smack_fs_context_submount(struct fs_context *fc,
static int smack_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
- struct smack_mnt_opts *dst, *src = src_fc->security;
+ struct smack_mnt_opts *src;
+ struct smack_mnt_opts *dst;

+ src = smack_mnt_opts(src_fc->security);
if (!src)
return 0;

- fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
- if (!fc->security)
- return -ENOMEM;
+ if (!fc->security) {
+ fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ }

- dst = fc->security;
+ dst = smack_mnt_opts(fc->security);
+ dst->initialized = src->initialized;
dst->fsdefault = src->fsdefault;
dst->fsfloor = src->fsfloor;
dst->fshat = src->fshat;
@@ -803,7 +826,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
struct superblock_smack *sp = smack_superblock(sb);
struct inode_smack *isp;
struct smack_known *skp;
- struct smack_mnt_opts *opts = mnt_opts;
+ struct smack_mnt_opts *opts = smack_mnt_opts(mnt_opts);
bool transmute = false;

if (sp->smk_flags & SMK_SB_INITIALIZED)
@@ -836,7 +859,7 @@ static int smack_set_mnt_opts(struct super_block *sb,

sp->smk_flags |= SMK_SB_INITIALIZED;

- if (opts) {
+ if (opts && opts->initialized) {
if (opts->fsdefault) {
skp = smk_import_entry(opts->fsdefault, 0);
if (IS_ERR(skp))
--
2.41.0


2023-12-15 22:45:46

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 36/42] LSM: Infrastructure management of the key security blob

Move management of the key->security blob out of the
individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/security.c | 41 +++++++++++++++++++++++++++++--
security/selinux/hooks.c | 23 +++++------------
security/selinux/include/objsec.h | 7 ++++++
security/smack/smack.h | 7 ++++++
security/smack/smack_lsm.c | 33 +++++++++++--------------
6 files changed, 75 insertions(+), 37 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 24a0f62ec2ac..fdeffa0c8d13 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -78,6 +78,7 @@ struct lsm_blob_sizes {
int lbs_sock;
int lbs_superblock;
int lbs_ipc;
+ int lbs_key;
int lbs_msg_msg;
int lbs_task;
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
diff --git a/security/security.c b/security/security.c
index 7a9fbe706525..092752666fb6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -226,6 +226,9 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+ lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
+#endif
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
@@ -449,6 +452,9 @@ static void __init ordered_lsm_init(void)
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+ init_debug("key blob size = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
@@ -768,6 +774,29 @@ static int lsm_ipc_alloc(struct kern_ipc_perm *kip)
return 0;
}

+#ifdef CONFIG_KEYS
+/**
+ * lsm_key_alloc - allocate a composite key blob
+ * @key: the key that needs a blob
+ *
+ * Allocate the key blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_key_alloc(struct key *key)
+{
+ if (blob_sizes.lbs_key == 0) {
+ key->security = NULL;
+ return 0;
+ }
+
+ key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL);
+ if (key->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+#endif /* CONFIG_KEYS */
+
/**
* lsm_msg_msg_alloc - allocate a composite msg_msg blob
* @mp: the msg_msg that needs a blob
@@ -5390,7 +5419,14 @@ EXPORT_SYMBOL(security_skb_classify_flow);
int security_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
- return call_int_hook(key_alloc, 0, key, cred, flags);
+ int rc = lsm_key_alloc(key);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(key_alloc, 0, key, cred, flags);
+ if (unlikely(rc))
+ security_key_free(key);
+ return rc;
}

/**
@@ -5401,7 +5437,8 @@ int security_key_alloc(struct key *key, const struct cred *cred,
*/
void security_key_free(struct key *key)
{
- call_void_hook(key_free, key);
+ kfree(key->security);
+ key->security = NULL;
}

/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3d046c9d0121..a9af3c848a16 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6672,11 +6672,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
unsigned long flags)
{
const struct task_security_struct *tsec;
- struct key_security_struct *ksec;
-
- ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
- if (!ksec)
- return -ENOMEM;
+ struct key_security_struct *ksec = selinux_key(k);

tsec = selinux_cred(cred);
if (tsec->keycreate_sid)
@@ -6684,18 +6680,9 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
else
ksec->sid = tsec->sid;

- k->security = ksec;
return 0;
}

-static void selinux_key_free(struct key *k)
-{
- struct key_security_struct *ksec = k->security;
-
- k->security = NULL;
- kfree(ksec);
-}
-
static int selinux_key_permission(key_ref_t key_ref,
const struct cred *cred,
enum key_need_perm need_perm)
@@ -6736,14 +6723,14 @@ static int selinux_key_permission(key_ref_t key_ref,

sid = cred_sid(cred);
key = key_ref_to_ptr(key_ref);
- ksec = key->security;
+ ksec = selinux_key(key);

return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}

static int selinux_key_getsecurity(struct key *key, char **_buffer)
{
- struct key_security_struct *ksec = key->security;
+ struct key_security_struct *ksec = selinux_key(key);
char *context = NULL;
unsigned len;
int rc;
@@ -6970,6 +6957,9 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_file = sizeof(struct file_security_struct),
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
+#ifdef CONFIG_KEYS
+ .lbs_key = sizeof(struct key_security_struct),
+#endif /* CONFIG_KEYS */
.lbs_msg_msg = sizeof(struct msg_security_struct),
.lbs_sock = sizeof(struct sk_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
@@ -7310,7 +7300,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
#endif

#ifdef CONFIG_KEYS
- LSM_HOOK_INIT(key_free, selinux_key_free),
LSM_HOOK_INIT(key_permission, selinux_key_permission),
LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
#ifdef CONFIG_KEY_NOTIFICATIONS
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index ca12d4d7cfc6..a76d39528262 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -194,6 +194,13 @@ static inline struct superblock_security_struct *selinux_superblock(
return superblock->s_security + selinux_blob_sizes.lbs_superblock;
}

+#ifdef CONFIG_KEYS
+static inline struct key_security_struct *selinux_key(const struct key *key)
+{
+ return key->security + selinux_blob_sizes.lbs_key;
+}
+#endif /* CONFIG_KEYS */
+
static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
{
return sock->sk_security + selinux_blob_sizes.lbs_sock;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 0f5bc5c03b9e..85ec8141fe70 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -360,6 +360,13 @@ static inline struct socket_smack *smack_sock(const struct sock *sock)
return sock->sk_security + smack_blob_sizes.lbs_sock;
}

+#ifdef CONFIG_KEYS
+static inline struct smack_known **smack_key(const struct key *key)
+{
+ return key->security + smack_blob_sizes.lbs_key;
+}
+#endif /* CONFIG_KEYS */
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 97ffb07797e9..b273e94028bb 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4486,23 +4486,13 @@ static void smack_inet_csk_clone(struct sock *sk,
static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
+ struct smack_known **blob = smack_key(key);
struct smack_known *skp = smk_of_task(smack_cred(cred));

- key->security = skp;
+ *blob = skp;
return 0;
}

-/**
- * smack_key_free - Clear the key security blob
- * @key: the object
- *
- * Clear the blob pointer
- */
-static void smack_key_free(struct key *key)
-{
- key->security = NULL;
-}
-
/**
* smack_key_permission - Smack access on a key
* @key_ref: gets to the object
@@ -4516,6 +4506,8 @@ static int smack_key_permission(key_ref_t key_ref,
const struct cred *cred,
enum key_need_perm need_perm)
{
+ struct smack_known **blob;
+ struct smack_known *skp;
struct key *keyp;
struct smk_audit_info ad;
struct smack_known *tkp = smk_of_task(smack_cred(cred));
@@ -4553,7 +4545,9 @@ static int smack_key_permission(key_ref_t key_ref,
* If the key hasn't been initialized give it access so that
* it may do so.
*/
- if (keyp->security == NULL)
+ blob = smack_key(keyp);
+ skp = *blob;
+ if (skp == NULL)
return 0;
/*
* This should not occur
@@ -4569,8 +4563,8 @@ static int smack_key_permission(key_ref_t key_ref,
ad.a.u.key_struct.key = keyp->serial;
ad.a.u.key_struct.key_desc = keyp->description;
#endif
- rc = smk_access(tkp, keyp->security, request, &ad);
- rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
+ rc = smk_access(tkp, skp, request, &ad);
+ rc = smk_bu_note("key access", tkp, skp, request, rc);
return rc;
}

@@ -4585,11 +4579,12 @@ static int smack_key_permission(key_ref_t key_ref,
*/
static int smack_key_getsecurity(struct key *key, char **_buffer)
{
- struct smack_known *skp = key->security;
+ struct smack_known **blob = smack_key(key);
+ struct smack_known *skp = *blob;
size_t length;
char *copy;

- if (key->security == NULL) {
+ if (skp == NULL) {
*_buffer = NULL;
return 0;
}
@@ -5060,6 +5055,9 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_file = sizeof(struct smack_known *),
.lbs_inode = sizeof(struct inode_smack),
.lbs_ipc = sizeof(struct smack_known *),
+#ifdef CONFIG_KEYS
+ .lbs_key = sizeof(struct smack_known *),
+#endif /* CONFIG_KEYS */
.lbs_msg_msg = sizeof(struct smack_known *),
.lbs_sock = sizeof(struct socket_smack),
.lbs_superblock = sizeof(struct superblock_smack),
@@ -5199,7 +5197,6 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
/* key management security hooks */
#ifdef CONFIG_KEYS
LSM_HOOK_INIT(key_alloc, smack_key_alloc),
- LSM_HOOK_INIT(key_free, smack_key_free),
LSM_HOOK_INIT(key_permission, smack_key_permission),
LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity),
#ifdef CONFIG_KEY_NOTIFICATIONS
--
2.41.0


2023-12-15 22:47:04

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 38/42] LSM: Correct handling of ENOSYS in inode_setxattr

The usual "bail on fail" behavior of LSM hooks doesn't
work for security_inode_setxattr(). Modules are allowed
to return -ENOSYS if the attribute specified isn't one
they manage. Fix the code to accommodate this unusal case.
This requires changes to the hooks in SELinux and Smack.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 29 +++++++++++++++--------------
security/selinux/hooks.c | 7 ++-----
security/smack/smack_lsm.c | 10 +++++-----
3 files changed, 22 insertions(+), 24 deletions(-)

diff --git a/security/security.c b/security/security.c
index 64cdf0e09832..b1a849e8589c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2346,24 +2346,25 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- int ret;
+ struct security_hook_list *hp;
+ int rc = -ENOSYS;

if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- /*
- * SELinux and Smack integrate the cap call,
- * so assume that all LSMs supplying this call do so.
- */
- ret = call_int_hook(inode_setxattr, 1, idmap, dentry, name, value,
- size, flags);

- if (ret == 1)
- ret = cap_inode_setxattr(dentry, name, value, size, flags);
- if (ret)
- return ret;
- ret = ima_inode_setxattr(dentry, name, value, size);
- if (ret)
- return ret;
+ hlist_for_each_entry(hp, &security_hook_heads.inode_setxattr, list) {
+ rc = hp->hook.inode_setxattr(idmap, dentry, name, value, size,
+ flags);
+ if (rc != -ENOSYS)
+ break;
+ }
+ if (rc == -ENOSYS)
+ rc = cap_inode_setxattr(dentry, name, value, size, flags);
+ if (rc)
+ return rc;
+ rc = ima_inode_setxattr(dentry, name, value, size);
+ if (rc)
+ return rc;
return evm_inode_setxattr(idmap, dentry, name, value, size);
}

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 46dee63eec12..4ac4b536c568 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3207,13 +3207,10 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
int rc = 0;

if (strcmp(name, XATTR_NAME_SELINUX)) {
- rc = cap_inode_setxattr(dentry, name, value, size, flags);
- if (rc)
- return rc;
-
/* Not an attribute we recognize, so just check the
ordinary setattr permission. */
- return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+ rc = dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+ return rc ? rc : -ENOSYS;
}

if (!selinux_initialized())
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 61bd3f626e7d..02b9aa200ad4 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1340,7 +1340,7 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
rc = -EINVAL;
} else
- rc = cap_inode_setxattr(dentry, name, value, size, flags);
+ rc = -ENOSYS;

if (check_priv && !smack_privileged(CAP_MAC_ADMIN))
rc = -EPERM;
@@ -1354,11 +1354,11 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
rc = -EINVAL;
}

- smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
- smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
-
if (rc == 0) {
- rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)),
+ MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
}

--
2.41.0


2023-12-15 22:47:13

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 39/42] LSM: Remove lsmblob scaffolding

Remove the scaffold member from the lsmblob. Remove the
remaining places it is being set.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/security.h | 6 ------
security/apparmor/audit.c | 6 +-----
security/apparmor/lsm.c | 4 ----
security/apparmor/secid.c | 6 +-----
security/selinux/hooks.c | 14 --------------
security/selinux/ss/services.c | 4 ----
security/smack/smack_lsm.c | 33 ++++-----------------------------
7 files changed, 6 insertions(+), 67 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 529671a89ce0..f7727bf767e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -143,11 +143,6 @@ enum lockdown_reason {
LOCKDOWN_CONFIDENTIALITY_MAX,
};

-/* stacking scaffolding */
-struct lsmblob_scaffold {
- u32 secid;
-};
-
/*
* A "security context" is the text representation of
* the information used by LSMs.
@@ -168,7 +163,6 @@ struct lsmblob {
struct lsmblob_smack smack;
struct lsmblob_apparmor apparmor;
struct lsmblob_bpf bpf;
- struct lsmblob_scaffold scaffold;
};

extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 72c414d00ba6..d51ab2f1284f 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -279,11 +279,7 @@ int aa_audit_rule_match(struct lsmblob *blob, u32 field, u32 op, void *vrule,
if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
return 0;

- /* stacking scaffolding */
- if (!blob->apparmor.label && blob->scaffold.secid)
- label = aa_secid_to_label(blob->scaffold.secid);
- else
- label = blob->apparmor.label;
+ label = blob->apparmor.label;

if (!label)
return -ENOENT;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index d47816e91bd3..c31d5c008b14 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -984,8 +984,6 @@ static void apparmor_current_getlsmblob_subj(struct lsmblob *blob)
struct aa_label *label = __begin_current_label_crit_section();

blob->apparmor.label = label;
- /* stacking scaffolding */
- blob->scaffold.secid = label->secid;
__end_current_label_crit_section(label);
}

@@ -995,8 +993,6 @@ static void apparmor_task_getlsmblob_obj(struct task_struct *p,
struct aa_label *label = aa_get_task_label(p);

blob->apparmor.label = label;
- /* stacking scaffolding */
- blob->scaffold.secid = label->secid;
aa_put_label(label);
}

diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 1df08372bf1b..e5cfaedf1a9f 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -102,11 +102,7 @@ int apparmor_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)

AA_BUG(!seclen);

- /* stacking scaffolding */
- if (!blob->apparmor.label && blob->scaffold.secid)
- label = aa_secid_to_label(blob->scaffold.secid);
- else
- label = blob->apparmor.label;
+ label = blob->apparmor.label;

if (!label)
return -EINVAL;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4ac4b536c568..113ee3df9b5a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3520,8 +3520,6 @@ static void selinux_inode_getlsmblob(struct inode *inode, struct lsmblob *blob)
struct inode_security_struct *isec = inode_security_novalidate(inode);

blob->selinux.secid = isec->sid;
- /* stacking scaffolding */
- blob->scaffold.secid = isec->sid;
}

static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
@@ -4014,8 +4012,6 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
static void selinux_cred_getlsmblob(const struct cred *c, struct lsmblob *blob)
{
blob->selinux.secid = cred_sid(c);
- /* stacking scaffolding */
- blob->scaffold.secid = blob->selinux.secid;
}

/*
@@ -4156,16 +4152,12 @@ static int selinux_task_getsid(struct task_struct *p)
static void selinux_current_getlsmblob_subj(struct lsmblob *blob)
{
blob->selinux.secid = current_sid();
- /* stacking scaffolding */
- blob->scaffold.secid = blob->selinux.secid;
}

static void selinux_task_getlsmblob_obj(struct task_struct *p,
struct lsmblob *blob)
{
blob->selinux.secid = task_sid_obj(p);
- /* stacking scaffolding */
- blob->scaffold.secid = blob->selinux.secid;
}

static int selinux_task_setnice(struct task_struct *p, int nice)
@@ -6305,8 +6297,6 @@ static void selinux_ipc_getlsmblob(struct kern_ipc_perm *ipcp,
{
struct ipc_security_struct *isec = selinux_ipc(ipcp);
blob->selinux.secid = isec->sid;
- /* stacking scaffolding */
- blob->scaffold.secid = isec->sid;
}

static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
@@ -6609,10 +6599,6 @@ static int selinux_lsmblob_to_secctx(struct lsmblob *blob,
u32 seclen;
u32 ret;

- /* stacking scaffolding */
- if (!secid)
- secid = blob->scaffold.secid;
-
if (cp) {
cp->id = LSM_ID_SELINUX;
ret = security_sid_to_context(secid, &cp->context, &cp->len);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index eef6655f7730..48211352345e 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3656,10 +3656,6 @@ int selinux_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
goto out;
}

- /* stacking scaffolding */
- if (!blob->selinux.secid && blob->scaffold.secid)
- blob->selinux.secid = blob->scaffold.secid;
-
ctxt = sidtab_search(policy->sidtab, blob->selinux.secid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 02b9aa200ad4..a486ac42caac 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1644,11 +1644,7 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
*/
static void smack_inode_getlsmblob(struct inode *inode, struct lsmblob *blob)
{
- struct smack_known *skp = smk_of_inode(inode);
-
- blob->smack.skp = skp;
- /* stacking scaffolding */
- blob->scaffold.secid = skp->smk_secid;
+ blob->smack.skp = smk_of_inode(inode);
}

/*
@@ -2156,8 +2152,6 @@ static void smack_cred_getlsmblob(const struct cred *cred,
{
rcu_read_lock();
blob->smack.skp = smk_of_task(smack_cred(cred));
- /* stacking scaffolding */
- blob->scaffold.secid = blob->smack.skp->smk_secid;
rcu_read_unlock();
}

@@ -2259,11 +2253,7 @@ static int smack_task_getsid(struct task_struct *p)
*/
static void smack_current_getlsmblob_subj(struct lsmblob *blob)
{
- struct smack_known *skp = smk_of_current();
-
- blob->smack.skp = skp;
- /* stacking scaffolding */
- blob->scaffold.secid = skp->smk_secid;
+ blob->smack.skp = smk_of_current();
}

/**
@@ -2276,11 +2266,7 @@ static void smack_current_getlsmblob_subj(struct lsmblob *blob)
static void smack_task_getlsmblob_obj(struct task_struct *p,
struct lsmblob *blob)
{
- struct smack_known *skp = smk_of_task_struct_obj(p);
-
- blob->smack.skp = skp;
- /* stacking scaffolding */
- blob->scaffold.secid = skp->smk_secid;
+ blob->smack.skp = smk_of_task_struct_obj(p);
}

/**
@@ -3451,11 +3437,8 @@ static void smack_ipc_getlsmblob(struct kern_ipc_perm *ipp,
struct lsmblob *blob)
{
struct smack_known **iskpp = smack_ipc(ipp);
- struct smack_known *iskp = *iskpp;

- blob->smack.skp = iskp;
- /* stacking scaffolding */
- blob->scaffold.secid = iskp->smk_secid;
+ blob->smack.skp = *iskpp;
}

/**
@@ -4796,10 +4779,6 @@ static int smack_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return 0;

- /* stacking scaffolding */
- if (!skp && blob->scaffold.secid)
- skp = smack_from_secid(blob->scaffold.secid);
-
/*
* No need to do string comparisons. If a match occurs,
* both pointers will point to the same smack_known
@@ -4862,10 +4841,6 @@ static int smack_lsmblob_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
struct smack_known *skp = blob->smack.skp;
int len;

- /* stacking scaffolding */
- if (!skp && blob->scaffold.secid)
- skp = smack_from_secid(blob->scaffold.secid);
-
len = strlen(skp->smk_known);

if (cp) {
--
2.41.0


2023-12-15 22:48:37

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 41/42] LSM: restrict security_cred_getsecid() to a single LSM

The LSM hook security_cred_getsecid() provides a single secid
that is only used by the binder driver. Provide the first value
available, and abandon any other hooks.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/security/security.c b/security/security.c
index f1bff6b5b076..504dfc6d05fa 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3157,13 +3157,20 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
* @c: credentials
* @secid: secid value
*
- * Retrieve the security identifier of the cred structure @c. In case of
- * failure, @secid will be set to zero.
+ * Retrieve the first available security identifier of the
+ * cred structure @c. In case of failure, @secid will be set to zero.
+ * Currently only used by binder.
*/
void security_cred_getsecid(const struct cred *c, u32 *secid)
{
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.cred_getsecid, list) {
+ hp->hook.cred_getsecid(c, secid);
+ return;
+ }
+
*secid = 0;
- call_void_hook(cred_getsecid, c, secid);
}
EXPORT_SYMBOL(security_cred_getsecid);

--
2.41.0


2023-12-15 22:48:54

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 40/42] LSM: Allow reservation of netlabel

Allow LSMs to request exclusive access to the netlabel facility.
Provide mechanism for LSMs to determine if they have access to
netlabel. Update the current users of netlabel, SELinux and Smack,
to use and respect the exclusive use of netlabel.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/security.c | 6 +++++
security/selinux/hooks.c | 7 +++---
security/selinux/include/netlabel.h | 5 +++++
security/selinux/netlabel.c | 4 ++--
security/smack/smack.h | 5 +++++
security/smack/smack_lsm.c | 35 +++++++++++++++++++++--------
security/smack/smackfs.c | 20 ++++++++++++++++-
8 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index fdeffa0c8d13..da60bf163447 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -84,6 +84,7 @@ struct lsm_blob_sizes {
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
int lbs_mnt_opts;
bool lbs_secmark; /* expressed desire for secmark use */
+ bool lbs_netlabel; /* expressed desire for netlabel use */
};

/**
diff --git a/security/security.c b/security/security.c
index b1a849e8589c..f1bff6b5b076 100644
--- a/security/security.c
+++ b/security/security.c
@@ -242,6 +242,12 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
else
needed->lbs_secmark = false;
}
+ if (needed->lbs_netlabel) {
+ if (!blob_sizes.lbs_netlabel)
+ blob_sizes.lbs_netlabel = true;
+ else
+ needed->lbs_netlabel = false;
+ }
}

/* Prepare LSM for initialization. */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 113ee3df9b5a..6da2e95ad5b7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -182,7 +182,7 @@ static int selinux_secmark_enabled(void)
static int selinux_peerlbl_enabled(void)
{
return (selinux_policycap_alwaysnetwork() ||
- netlbl_enabled() || selinux_xfrm_enabled());
+ selinux_netlbl_enabled() || selinux_xfrm_enabled());
}

static int selinux_netcache_avc_callback(u32 event)
@@ -5673,7 +5673,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;

- if (netlbl_enabled())
+ if (selinux_netlbl_enabled())
/* we do this in the FORWARD path and not the POST_ROUTING
* path because we want to make sure we apply the necessary
* labeling before IPsec is applied so we can leverage AH
@@ -5690,7 +5690,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
struct sock *sk;
u32 sid;

- if (!netlbl_enabled())
+ if (!selinux_netlbl_enabled())
return NF_ACCEPT;

/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
@@ -6965,6 +6965,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
.lbs_mnt_opts = sizeof(struct selinux_mnt_opts),
.lbs_secmark = true,
+ .lbs_netlabel = true,
};

#ifdef CONFIG_PERF_EVENTS
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 4d0456d3d459..189803009d04 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -147,4 +147,9 @@ static inline int selinux_netlbl_socket_connect_locked(struct sock *sk,
}
#endif /* CONFIG_NETLABEL */

+static inline bool selinux_netlbl_enabled(void)
+{
+ return selinux_blob_sizes.lbs_netlabel && netlbl_enabled();
+}
+
#endif
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index e8832726bd86..1242296b5fe1 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -198,7 +198,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
int rc;
struct netlbl_lsm_secattr secattr;

- if (!netlbl_enabled()) {
+ if (!selinux_netlbl_enabled()) {
*type = NETLBL_NLTYPE_NONE;
*sid = SECSID_NULL;
return 0;
@@ -440,7 +440,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
u32 perm;
struct netlbl_lsm_secattr secattr;

- if (!netlbl_enabled())
+ if (!selinux_netlbl_enabled())
return 0;

netlbl_secattr_init(&secattr);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 85ec8141fe70..2191f8304e4f 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -367,6 +367,11 @@ static inline struct smack_known **smack_key(const struct key *key)
}
#endif /* CONFIG_KEYS */

+static inline bool smack_netlabel(void)
+{
+ return smack_blob_sizes.lbs_netlabel;
+}
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a486ac42caac..9f5a37a5b47e 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2584,6 +2584,9 @@ static int smack_netlbl_add(struct sock *sk)
struct smack_known *skp = ssp->smk_out;
int rc;

+ if (!smack_netlabel())
+ return 0;
+
local_bh_disable();
bh_lock_sock_nested(sk);

@@ -2614,6 +2617,9 @@ static void smack_netlbl_delete(struct sock *sk)
{
struct socket_smack *ssp = smack_sock(sk);

+ if (!smack_netlabel())
+ return;
+
/*
* Take the label off the socket if one is set.
*/
@@ -2664,7 +2670,7 @@ static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap)
/*
* Clear the socket netlabel if it's set.
*/
- if (!rc)
+ if (!rc && smack_netlabel())
smack_netlbl_delete(sk);
}
rcu_read_unlock();
@@ -3970,6 +3976,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
int acat;
int kcat;

+ if (!smack_netlabel())
+ return smack_net_ambient;
/*
* Netlabel found it in the cache.
*/
@@ -4126,6 +4134,9 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
struct socket_smack *ssp = NULL;
struct smack_known *skp = NULL;

+ if (!smack_netlabel())
+ return NULL;
+
netlbl_secattr_init(&secattr);

if (sk)
@@ -4196,7 +4207,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
MAY_WRITE, rc);
- if (rc != 0)
+ if (rc != 0 && smack_netlabel())
netlbl_skbuff_err(skb, family, rc, 0);
break;
#if IS_ENABLED(CONFIG_IPV6)
@@ -4407,7 +4418,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
if (skp == NULL) {
skp = smack_from_netlbl(sk, family, skb);
if (skp == NULL)
- skp = &smack_known_huh;
+ skp = smack_net_ambient;
}

#ifdef CONFIG_AUDIT
@@ -4428,8 +4439,11 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
/*
* Save the peer's label in the request_sock so we can later setup
* smk_packet in the child socket so that SO_PEERCRED can report it.
+ *
+ * Only do this if Smack is using netlabel.
*/
- req->peer_secid = skp->smk_secid;
+ if (smack_netlabel())
+ req->peer_secid = skp->smk_secid;

/*
* We need to decide if we want to label the incoming connection here
@@ -4442,10 +4456,12 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
hskp = smack_ipv4host_label(&addr);
rcu_read_unlock();

- if (hskp == NULL)
- rc = netlbl_req_setattr(req, &skp->smk_netlabel);
- else
- netlbl_req_delattr(req);
+ if (smack_netlabel()) {
+ if (hskp == NULL)
+ rc = netlbl_req_setattr(req, &skp->smk_netlabel);
+ else
+ netlbl_req_delattr(req);
+ }

return rc;
}
@@ -4463,7 +4479,7 @@ static void smack_inet_csk_clone(struct sock *sk,
struct socket_smack *ssp = smack_sock(sk);
struct smack_known *skp;

- if (req->peer_secid != 0) {
+ if (smack_netlabel() && req->peer_secid != 0) {
skp = smack_from_secid(req->peer_secid);
ssp->smk_packet = skp;
} else
@@ -5062,6 +5078,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
.lbs_mnt_opts = sizeof(struct smack_mnt_opts),
.lbs_secmark = true,
+ .lbs_netlabel = true,
};

static const struct lsm_id smack_lsmid = {
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 878fe44b662d..f8c0ea18b2fe 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -77,7 +77,7 @@ static DEFINE_MUTEX(smk_net6addr_lock);
* If it isn't somehow marked, use this.
* It can be reset via smackfs/ambient
*/
-struct smack_known *smack_net_ambient;
+struct smack_known *smack_net_ambient = &smack_known_floor;

/*
* This is the level in a CIPSO header that indicates a
@@ -685,6 +685,9 @@ static void smk_cipso_doi(void)
struct cipso_v4_doi *doip;
struct netlbl_audit nai;

+ if (!smack_netlabel())
+ return;
+
smk_netlabel_audit_set(&nai);

rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
@@ -725,6 +728,9 @@ static void smk_unlbl_ambient(char *oldambient)
int rc;
struct netlbl_audit nai;

+ if (!smack_netlabel())
+ return;
+
smk_netlabel_audit_set(&nai);

if (oldambient != NULL) {
@@ -848,6 +854,8 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
*/
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
+ if (!smack_netlabel())
+ return -EINVAL;
if (*ppos != 0)
return -EINVAL;
if (format == SMK_FIXED24_FMT &&
@@ -1178,6 +1186,8 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
*/
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
+ if (!smack_netlabel())
+ return -EINVAL;
if (*ppos != 0)
return -EINVAL;
if (count < SMK_NETLBLADDRMIN || count > PAGE_SIZE - 1)
@@ -1437,6 +1447,8 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
*/
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
+ if (!smack_netlabel())
+ return -EINVAL;
if (*ppos != 0)
return -EINVAL;
if (count < SMK_NETLBLADDRMIN || count > PAGE_SIZE - 1)
@@ -1608,6 +1620,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf,

if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
+ if (!smack_netlabel())
+ return -EINVAL;

if (count >= sizeof(temp) || count == 0)
return -EINVAL;
@@ -1675,6 +1689,8 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf,

if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
+ if (!smack_netlabel())
+ return -EINVAL;

if (count >= sizeof(temp) || count == 0)
return -EINVAL;
@@ -1753,6 +1769,8 @@ static ssize_t smk_write_mapped(struct file *file, const char __user *buf,

if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
+ if (!smack_netlabel())
+ return -EINVAL;

if (count >= sizeof(temp) || count == 0)
return -EINVAL;
--
2.41.0


2023-12-15 22:50:19

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v39 42/42] Smack: Remove LSM_FLAG_EXCLUSIVE

Smack no longer has any behaviors that require LSM_FLAG_EXCLUSIVE.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/smack/smack_lsm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9f5a37a5b47e..7bf2a3fabf33 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5325,7 +5325,7 @@ static __init int smack_init(void)
*/
DEFINE_LSM(smack) = {
.name = "smack",
- .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .flags = LSM_FLAG_LEGACY_MAJOR,
.blobs = &smack_blob_sizes,
.init = smack_init,
};
--
2.41.0


2023-12-18 02:25:43

by Leesoo Ahn

[permalink] [raw]
Subject: Re: [PATCH v39 42/42] Smack: Remove LSM_FLAG_EXCLUSIVE

2023-12-16 오전 7:50에 Casey Schaufler 이(가) 쓴 글:
> Smack no longer has any behaviors that require LSM_FLAG_EXCLUSIVE.

Nice working, thank you!

BR,
Leesoo Ahn

2024-02-02 00:24:29

by John Johansen

[permalink] [raw]
Subject: Re: [PATCH v39 00/42] LSM: General module stacking

On 12/15/23 14:15, Casey Schaufler wrote:
> This patchset provides the changes required to allow arbitrary
> combination of all the existing Linux Security Modules (LSM).
> It does not provide for all possible configurations of all of
> co-existing modules. It does not ensure that the enforcement
> of policy provided by one module does not interfere with the
> behavior of another module.
>
> The bulk of the code change is in support of the audit system.
> Because subjects and objects may have multiple LSM specific
> attributes that are used to make access control decisions it
> was necessary to enhance the audit system to report these
> security attributes. Separate audit records have been added
> to include the additional information for each of the audit
> event subject and object. Providing the required security
> information using 32-bit secids was no longer sufficient. A
> new structure, lsmblob, has been introduced to include the
> data for all relevant modules.
>
> The lsmblob structure has an entry for each of the modules
> that has used secids. Each module provides a structure of
> its own which contains the information it uses. For SELinux
> this is a u32 secid. Smack provides a pointer into the label
> list. Modules that are not configured use conditional compilation
> to have empty structures.
>
> Because audit records may need to include the text representation
> of more than one module's security attributes (commonly referred
> to as the "security context") the interfaces that convert the
> lsmblob into a text representation need to identify which module
> provided the text. An structure lsmcontext has been added that
> contains the text, its length and the identifier of the module
> than created it.
>
> Security attributes for network facilities have provided certain
> challenges. The security information allowed in socket buffers
> and secmarks is limited to a single u32 secid, and there is no
> indication that this will ever be allowed to change. The netlabel
> subsystem, which provides CIPSO and CALIPSO labeling on internet
> packets, supports only one IP packet option at a time. Labeled
> NFS3 also supports only one security module. The existing modules
> have been updated to accept that they may not have access to
> these networking security attributes. The first module to
> register that uses them is given exclusive access.
>
> The issue of multiple modules using the /proc/.../attr interfaces
> has been largely addressed for some time by the inclusion of module
> specific sub-directories. Applications should be using these except
> for the case of SELinux.
>
> Patch 0001 removes an interface dependency on audit from IMA.
> Patch 0002 moves management of socket security blobs out of the
> modules and into the LSM infrastructure.
> Patch 0003 introduces the lsmblob structure.
> Patch 0004 introduces mechanism for the IMA mechanisms to handle
> the possibility of multiple modules that use attributes.
> Patches 0005-0015 add new interfaces and change existing interfaces
> to use the lsmblob to represent security data.
> Patches 0016-0021 replace a the use of string and length pairs to
> use a "security context" with an lsmcontext structure.
> Patches 0022-0026 implement audit records describing the multiple
> security attributes on subjects and objects.
> Patch 0027 removes scaffolding code used in support on lsmcontext.
> Patches 0028-0030 optimize LSM hooks for the networking single
> module user case.
> Patch 0031 implements mechanism to reserve use of network secmarks.
> Patch 0032 limits security_secctx_to_secid() to a single module.
> Patch 0033 removes the exclusive tag from AppArmor.
> Patches 0034-0035 adds mount operation security blobs.
> Patch 0036 moves management of key security blobs out of the
> modules and into the LSM infrastructure.
> Patch 0037 enables management of mount operation security blobs
> in the modules.
> Patches 0038-0039 remove scaffolding for lsmblobs.
> Patch 0040 implements mechanism to reserve use of netlabel.
> Patch 0041 restricts a hook used only by binder to a single module.
> Patch 0042 removes the exclusive tag from Smack.
>
> https://github.com:cschaufler/lsm-stacking.git#stack-6.7-rc1-pcmoore-dev-v39-b
>

This is now in testing on the Ubuntu Unstable 6.8 based kernels
https://launchpad.net/~canonical-kernel-team/+archive/ubuntu/unstable

and if all goes well will get rolled out to the noble (24.04) -proposed kernels
for broader testing soon.

> Casey Schaufler (42):
> integrity: disassociate ima_filter_rule from security_audit_rule
> SM: Infrastructure management of the sock security
> LSM: Add the lsmblob data structure.
> IMA: avoid label collisions with stacked LSMs
> LSM: Use lsmblob in security_audit_rule_match
> LSM: Add lsmblob_to_secctx hook
> Audit: maintain an lsmblob in audit_context
> LSM: Use lsmblob in security_ipc_getsecid
> Audit: Update shutdown LSM data
> LSM: Use lsmblob in security_current_getsecid
> LSM: Use lsmblob in security_inode_getsecid
> Audit: use an lsmblob in audit_names
> LSM: Create new security_cred_getlsmblob LSM hook
> Audit: Change context data from secid to lsmblob
> Netlabel: Use lsmblob for audit data
> LSM: Ensure the correct LSM context releaser
> LSM: Use lsmcontext in security_secid_to_secctx
> LSM: Use lsmcontext in security_lsmblob_to_secctx
> LSM: Use lsmcontext in security_inode_getsecctx
> LSM: Use lsmcontext in security_dentry_init_security
> LSM: security_lsmblob_to_secctx module selection
> Audit: Create audit_stamp structure
> Audit: Allow multiple records in an audit_buffer
> Audit: Add record for multiple task security contexts
> audit: multiple subject lsm values for netlabel
> Audit: Add record for multiple object contexts
> LSM: Remove unused lsmcontext_init()
> LSM: Improve logic in security_getprocattr
> LSM: secctx provider check on release
> LSM: Single calls in socket_getpeersec hooks
> LSM: Exclusive secmark usage
> LSM: Identify which LSM handles the context string
> AppArmor: Remove the exclusive flag
> LSM: Add mount opts blob size tracking
> LSM: allocate mnt_opts blobs instead of module specific data
> LSM: Infrastructure management of the key security blob
> LSM: Infrastructure management of the mnt_opts security blob
> LSM: Correct handling of ENOSYS in inode_setxattr
> LSM: Remove lsmblob scaffolding
> LSM: Allow reservation of netlabel
> LSM: restrict security_cred_getsecid() to a single LSM
> Smack: Remove LSM_FLAG_EXCLUSIVE
>
> Documentation/ABI/testing/ima_policy | 8 +-
> drivers/android/binder.c | 25 +-
> fs/ceph/super.h | 3 +-
> fs/ceph/xattr.c | 15 +-
> fs/fuse/dir.c | 35 +-
> fs/nfs/dir.c | 2 +-
> fs/nfs/inode.c | 17 +-
> fs/nfs/internal.h | 8 +-
> fs/nfs/nfs4proc.c | 16 +-
> fs/nfs/nfs4xdr.c | 22 +-
> fs/nfsd/nfs4xdr.c | 21 +-
> include/linux/audit.h | 13 +
> include/linux/lsm/apparmor.h | 17 +
> include/linux/lsm/bpf.h | 16 +
> include/linux/lsm/selinux.h | 16 +
> include/linux/lsm/smack.h | 17 +
> include/linux/lsm_hook_defs.h | 35 +-
> include/linux/lsm_hooks.h | 8 +
> include/linux/nfs4.h | 8 +-
> include/linux/nfs_fs.h | 2 +-
> include/linux/security.h | 158 +++++++--
> include/net/netlabel.h | 2 +-
> include/net/scm.h | 12 +-
> include/uapi/linux/audit.h | 2 +
> kernel/audit.c | 269 +++++++++++----
> kernel/audit.h | 20 +-
> kernel/auditfilter.c | 9 +-
> kernel/auditsc.c | 142 +++-----
> net/ipv4/ip_sockglue.c | 12 +-
> net/netfilter/nf_conntrack_netlink.c | 16 +-
> net/netfilter/nf_conntrack_standalone.c | 11 +-
> net/netfilter/nfnetlink_queue.c | 22 +-
> net/netlabel/netlabel_unlabeled.c | 46 ++-
> net/netlabel/netlabel_user.c | 10 +-
> net/netlabel/netlabel_user.h | 2 +-
> security/apparmor/audit.c | 19 +-
> security/apparmor/include/audit.h | 8 +-
> security/apparmor/include/net.h | 8 +-
> security/apparmor/include/secid.h | 5 +-
> security/apparmor/lsm.c | 65 +---
> security/apparmor/net.c | 2 +-
> security/apparmor/secid.c | 52 ++-
> security/bpf/hooks.c | 1 +
> security/integrity/ima/ima.h | 32 +-
> security/integrity/ima/ima_api.c | 6 +-
> security/integrity/ima/ima_appraise.c | 6 +-
> security/integrity/ima/ima_main.c | 60 ++--
> security/integrity/ima/ima_policy.c | 91 +++++-
> security/security.c | 415 ++++++++++++++++++------
> security/selinux/hooks.c | 285 +++++++++-------
> security/selinux/include/audit.h | 13 +-
> security/selinux/include/netlabel.h | 5 +
> security/selinux/include/objsec.h | 12 +
> security/selinux/netlabel.c | 27 +-
> security/selinux/ss/services.c | 20 +-
> security/smack/smack.h | 22 ++
> security/smack/smack_lsm.c | 347 ++++++++++++--------
> security/smack/smack_netfilter.c | 12 +-
> security/smack/smackfs.c | 24 +-
> 59 files changed, 1691 insertions(+), 883 deletions(-)
> create mode 100644 include/linux/lsm/apparmor.h
> create mode 100644 include/linux/lsm/bpf.h
> create mode 100644 include/linux/lsm/selinux.h
> create mode 100644 include/linux/lsm/smack.h
>


2024-03-06 09:55:17

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v39 01/42] integrity: disassociate ima_filter_rule from security_audit_rule

On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
> Create real functions for the ima_filter_rule interfaces.
> These replace #defines that obscure the reuse of audit
> interfaces. The new functions are put in security.c because
> they use security module registered hooks that we don't
> want exported.

Beginner question: what makes IMA special, that the audit subsystem
does not need an AUDIT_LSM field to do the same that IMA would do?

In other words, why can't we add the lsm_id parameter to
security_audit_*() functions, so that IMA can just call those?

Thanks

Roberto

> Acked-by: Paul Moore <[email protected]>
> Reviewed-by: John Johansen <[email protected]>
> Signed-off-by: Casey Schaufler <[email protected]>
> To: Mimi Zohar <[email protected]>
> Cc: [email protected]
> ---
> include/linux/security.h | 24 ++++++++++++++++++++++++
> security/integrity/ima/ima.h | 26 --------------------------
> security/security.c | 21 +++++++++++++++++++++
> 3 files changed, 45 insertions(+), 26 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 750130a7b9dd..4790508818ee 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -2009,6 +2009,30 @@ static inline void security_audit_rule_free(void *lsmrule)
> #endif /* CONFIG_SECURITY */
> #endif /* CONFIG_AUDIT */
>
> +#if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
> +void ima_filter_rule_free(void *lsmrule);
> +
> +#else
> +
> +static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
> + void **lsmrule)
> +{
> + return 0;
> +}
> +
> +static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
> + void *lsmrule)
> +{
> + return 0;
> +}
> +
> +static inline void ima_filter_rule_free(void *lsmrule)
> +{ }
> +
> +#endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
> +
> #ifdef CONFIG_SECURITYFS
>
> extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index c29db699c996..560d6104de72 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -420,32 +420,6 @@ static inline void ima_free_modsig(struct modsig *modsig)
> }
> #endif /* CONFIG_IMA_APPRAISE_MODSIG */
>
> -/* LSM based policy rules require audit */
> -#ifdef CONFIG_IMA_LSM_RULES
> -
> -#define ima_filter_rule_init security_audit_rule_init
> -#define ima_filter_rule_free security_audit_rule_free
> -#define ima_filter_rule_match security_audit_rule_match
> -
> -#else
> -
> -static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
> - void **lsmrule)
> -{
> - return -EINVAL;
> -}
> -
> -static inline void ima_filter_rule_free(void *lsmrule)
> -{
> -}
> -
> -static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
> - void *lsmrule)
> -{
> - return -EINVAL;
> -}
> -#endif /* CONFIG_IMA_LSM_RULES */
> -
> #ifdef CONFIG_IMA_READ_POLICY
> #define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
> #else
> diff --git a/security/security.c b/security/security.c
> index d7b15ea67c3f..8e5379a76369 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -5350,6 +5350,27 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> }
> #endif /* CONFIG_AUDIT */
>
> +#ifdef CONFIG_IMA_LSM_RULES
> +/*
> + * The integrity subsystem uses the same hooks as
> + * the audit subsystem.
> + */
> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> +{
> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
> +}
> +
> +void ima_filter_rule_free(void *lsmrule)
> +{
> + call_void_hook(audit_rule_free, lsmrule);
> +}
> +
> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> +{
> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
> +}
> +#endif /* CONFIG_IMA_LSM_RULES */
> +
> #ifdef CONFIG_BPF_SYSCALL
> /**
> * security_bpf() - Check if the bpf syscall operation is allowed


2024-03-06 10:10:35

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v39 04/42] IMA: avoid label collisions with stacked LSMs

On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
> Integrity measurement may filter on security module information
> and needs to be clear in the case of multiple active security
> modules which applies. Provide a boot option ima_rules_lsm= to
> allow the user to specify an active security module to apply
> filters to. If not specified, use the first registered module
> that supports the audit_rule_match() LSM hook. Allow the user
> to specify in the IMA policy an lsm= option to specify the
> security module to use for a particular rule.

I was hoping somehow that we can rely on the concept of default LSM
from the LSM infrastructure, so that the extra option would not be
needed.

Roberto

> This requires adding the LSM of interest as a parameter
> to three of the audit hooks.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> To: Mimi Zohar <[email protected]>
> To: [email protected]
> To: [email protected]
> ---
> Documentation/ABI/testing/ima_policy | 8 +++-
> include/linux/lsm_hook_defs.h | 7 +--
> include/linux/security.h | 26 +++++++---
> security/apparmor/audit.c | 15 ++++--
> security/apparmor/include/audit.h | 7 +--
> security/integrity/ima/ima_policy.c | 71 ++++++++++++++++++++++++----
> security/security.c | 64 +++++++++++++++++++++----
> security/selinux/include/audit.h | 10 ++--
> security/selinux/ss/services.c | 15 ++++--
> security/smack/smack_lsm.c | 12 ++++-
> 10 files changed, 192 insertions(+), 43 deletions(-)
>
> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> index c2385183826c..a59291b97c24 100644
> --- a/Documentation/ABI/testing/ima_policy
> +++ b/Documentation/ABI/testing/ima_policy
> @@ -26,7 +26,7 @@ Description:
> [uid=] [euid=] [gid=] [egid=]
> [fowner=] [fgroup=]]
> lsm: [[subj_user=] [subj_role=] [subj_type=]
> - [obj_user=] [obj_role=] [obj_type=]]
> + [obj_user=] [obj_role=] [obj_type=] [lsm=]]
> option: [digest_type=] [template=] [permit_directio]
> [appraise_type=] [appraise_flag=]
> [appraise_algos=] [keyrings=]
> @@ -138,6 +138,12 @@ Description:
>
> measure subj_user=_ func=FILE_CHECK mask=MAY_READ
>
> + It is possible to explicitly specify which security
> + module a rule applies to using lsm=. If the security
> + module specified is not active on the system the rule
> + will be rejected. If lsm= is not specified the first
> + security module registered on the system will be assumed.
> +
> Example of measure rules using alternate PCRs::
>
> measure func=KEXEC_KERNEL_CHECK pcr=4
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index c925a0d26edf..2159013890aa 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -392,10 +392,11 @@ LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
>
> #ifdef CONFIG_AUDIT
> LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
> - void **lsmrule)
> + void **lsmrule, int lsmid)
> LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
> -LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
> -LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
> +LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
> + int lsmid)
> +LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule, int lsmid)
> #endif /* CONFIG_AUDIT */
>
> #ifdef CONFIG_BPF_SYSCALL
> diff --git a/include/linux/security.h b/include/linux/security.h
> index d4103b6cd3fc..2320ed78c4de 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -286,6 +286,8 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
> extern int security_init(void);
> extern int early_security_init(void);
> extern u64 lsm_name_to_attr(const char *name);
> +extern u64 lsm_name_to_id(const char *name);
> +extern const char *lsm_id_to_name(u64 id);
>
> /* Security operations */
> int security_binder_set_context_mgr(const struct cred *mgr);
> @@ -536,6 +538,16 @@ static inline u64 lsm_name_to_attr(const char *name)
> return LSM_ATTR_UNDEF;
> }
>
> +static inline u64 lsm_name_to_id(const char *name)
> +{
> + return LSM_ID_UNDEF;
> +}
> +
> +static inline const char *lsm_id_to_name(u64 id)
> +{
> + return NULL;
> +}
> +
> static inline void security_free_mnt_opts(void **mnt_opts)
> {
> }
> @@ -2030,25 +2042,27 @@ static inline void security_audit_rule_free(void *lsmrule)
> #endif /* CONFIG_AUDIT */
>
> #if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
> -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
> -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
> -void ima_filter_rule_free(void *lsmrule);
> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
> + int lsmid);
> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
> + int lsmid);
> +void ima_filter_rule_free(void *lsmrule, int lsmid);
>
> #else
>
> static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
> - void **lsmrule)
> + void **lsmrule, int lsmid)
> {
> return 0;
> }
>
> static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
> - void *lsmrule)
> + void *lsmrule, int lsmid)
> {
> return 0;
> }
>
> -static inline void ima_filter_rule_free(void *lsmrule)
> +static inline void ima_filter_rule_free(void *lsmrule, int lsmid)
> { }
>
> #endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
> diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
> index 45beb1c5f747..0a9f0019355a 100644
> --- a/security/apparmor/audit.c
> +++ b/security/apparmor/audit.c
> @@ -206,10 +206,12 @@ struct aa_audit_rule {
> struct aa_label *label;
> };
>
> -void aa_audit_rule_free(void *vrule)
> +void aa_audit_rule_free(void *vrule, int lsmid)
> {
> struct aa_audit_rule *rule = vrule;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
> + return;
> if (rule) {
> if (!IS_ERR(rule->label))
> aa_put_label(rule->label);
> @@ -217,10 +219,13 @@ void aa_audit_rule_free(void *vrule)
> }
> }
>
> -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> + int lsmid)
> {
> struct aa_audit_rule *rule;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
> + return 0;
> switch (field) {
> case AUDIT_SUBJ_ROLE:
> if (op != Audit_equal && op != Audit_not_equal)
> @@ -240,7 +245,7 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> GFP_KERNEL, true, false);
> if (IS_ERR(rule->label)) {
> int err = PTR_ERR(rule->label);
> - aa_audit_rule_free(rule);
> + aa_audit_rule_free(rule, LSM_ID_APPARMOR);
> return err;
> }
>
> @@ -264,12 +269,14 @@ int aa_audit_rule_known(struct audit_krule *rule)
> return 0;
> }
>
> -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
> +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
> {
> struct aa_audit_rule *rule = vrule;
> struct aa_label *label;
> int found = 0;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
> + return 0;
> label = aa_secid_to_label(sid);
>
> if (!label)
> diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
> index acbb03b9bd25..a75c45dd059f 100644
> --- a/security/apparmor/include/audit.h
> +++ b/security/apparmor/include/audit.h
> @@ -199,9 +199,10 @@ static inline int complain_error(int error)
> return error;
> }
>
> -void aa_audit_rule_free(void *vrule);
> -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
> +void aa_audit_rule_free(void *vrule, int lsmid);
> +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> + int lsmid);
> int aa_audit_rule_known(struct audit_krule *rule);
> -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
> +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid);
>
> #endif /* __AA_AUDIT_H */
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index f69062617754..a563e0478cc6 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -117,6 +117,8 @@ struct ima_rule_entry {
> void *rule; /* LSM file metadata specific */
> char *args_p; /* audit value */
> int type; /* audit type */
> + int lsm_id; /* which LSM rule applies to */
> + bool lsm_specific; /* true if lsm is specified */
> } lsm[MAX_LSM_RULES];
> char *fsname;
> struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
> @@ -309,6 +311,25 @@ static int __init default_appraise_policy_setup(char *str)
> }
> __setup("ima_appraise_tcb", default_appraise_policy_setup);
>
> +static int default_rules_lsm __ro_after_init = LSM_ID_UNDEF;
> +
> +static int __init ima_rules_lsm_init(char *str)
> +{
> + int newdrl;
> +
> + newdrl = lsm_name_to_id(str);
> + if (newdrl >= 0) {
> + default_rules_lsm = newdrl;
> + return 1;
> + }
> +
> + pr_err("default ima rule lsm \"%s\" not registered, value unchanged.",
> + str);
> +
> + return 1;
> +}
> +__setup("ima_rules_lsm=", ima_rules_lsm_init);
> +
> static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
> {
> struct ima_rule_opt_list *opt_list;
> @@ -380,7 +401,8 @@ static void ima_lsm_free_rule(struct ima_rule_entry *entry)
> int i;
>
> for (i = 0; i < MAX_LSM_RULES; i++) {
> - ima_filter_rule_free(entry->lsm[i].rule);
> + ima_filter_rule_free(entry->lsm[i].rule,
> + entry->lsm[i].lsm_id);
> kfree(entry->lsm[i].args_p);
> }
> }
> @@ -425,7 +447,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
>
> ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
> nentry->lsm[i].args_p,
> - &nentry->lsm[i].rule);
> + &nentry->lsm[i].rule,
> + entry->lsm[i].lsm_id);
> if (!nentry->lsm[i].rule)
> pr_warn("rule for LSM \'%s\' is undefined\n",
> nentry->lsm[i].args_p);
> @@ -451,7 +474,8 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
> * be owned by nentry.
> */
> for (i = 0; i < MAX_LSM_RULES; i++)
> - ima_filter_rule_free(entry->lsm[i].rule);
> + ima_filter_rule_free(entry->lsm[i].rule,
> + entry->lsm[i].lsm_id);
> kfree(entry);
>
> return 0;
> @@ -650,14 +674,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
> security_inode_getsecid(inode, &osid);
> rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
> Audit_equal,
> - lsm_rule->lsm[i].rule);
> + lsm_rule->lsm[i].rule,
> + lsm_rule->lsm[i].lsm_id);
> break;
> case LSM_SUBJ_USER:
> case LSM_SUBJ_ROLE:
> case LSM_SUBJ_TYPE:
> rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
> Audit_equal,
> - lsm_rule->lsm[i].rule);
> + lsm_rule->lsm[i].rule,
> + lsm_rule->lsm[i].lsm_id);
> break;
> default:
> break;
> @@ -680,7 +706,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
> out:
> if (rule_reinitialized) {
> for (i = 0; i < MAX_LSM_RULES; i++)
> - ima_filter_rule_free(lsm_rule->lsm[i].rule);
> + ima_filter_rule_free(lsm_rule->lsm[i].rule,
> + lsm_rule->lsm[i].lsm_id);
> kfree(lsm_rule);
> }
> return result;
> @@ -1073,7 +1100,7 @@ enum policy_opt {
> Opt_digest_type,
> Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
> Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
> - Opt_label, Opt_err
> + Opt_lsm, Opt_label, Opt_err
> };
>
> static const match_table_t policy_tokens = {
> @@ -1121,6 +1148,7 @@ static const match_table_t policy_tokens = {
> {Opt_pcr, "pcr=%s"},
> {Opt_template, "template=%s"},
> {Opt_keyrings, "keyrings=%s"},
> + {Opt_lsm, "lsm=%s"},
> {Opt_label, "label=%s"},
> {Opt_err, NULL}
> };
> @@ -1140,7 +1168,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
> entry->lsm[lsm_rule].type = audit_type;
> result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal,
> entry->lsm[lsm_rule].args_p,
> - &entry->lsm[lsm_rule].rule);
> + &entry->lsm[lsm_rule].rule,
> + entry->lsm[lsm_rule].lsm_id);
> if (!entry->lsm[lsm_rule].rule) {
> pr_warn("rule for LSM \'%s\' is undefined\n",
> entry->lsm[lsm_rule].args_p);
> @@ -1878,6 +1907,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
> &(template_desc->num_fields));
> entry->template = template_desc;
> break;
> + case Opt_lsm: {
> + int i;
> +
> + result = lsm_name_to_id(args[0].from);
> + if (result < 0) {
> + for (i = 0; i < MAX_LSM_RULES; i++)
> + entry->lsm[i].args_p = NULL;
> + result = -EINVAL;
> + break;
> + }
> + for (i = 0; i < MAX_LSM_RULES; i++) {
> + entry->lsm[i].lsm_id = result;
> + entry->lsm[i].lsm_specific = true;
> + }
> + result = 0;
> + break;
> + }
> case Opt_err:
> ima_log_string(ab, "UNKNOWN", p);
> result = -EINVAL;
> @@ -1923,6 +1969,7 @@ ssize_t ima_parse_add_rule(char *rule)
> struct ima_rule_entry *entry;
> ssize_t result, len;
> int audit_info = 0;
> + int i;
>
> p = strsep(&rule, "\n");
> len = strlen(p) + 1;
> @@ -1940,6 +1987,11 @@ ssize_t ima_parse_add_rule(char *rule)
>
> INIT_LIST_HEAD(&entry->list);
>
> + for (i = 0; i < MAX_LSM_RULES; i++) {
> + entry->lsm[i].lsm_id = default_rules_lsm;
> + entry->lsm[i].lsm_specific = false;
> + }
> +
> result = ima_parse_rule(p, entry);
> if (result) {
> ima_free_rule(entry);
> @@ -2251,6 +2303,9 @@ int ima_policy_show(struct seq_file *m, void *v)
> entry->lsm[i].args_p);
> break;
> }
> + if (entry->lsm[i].lsm_specific)
> + seq_printf(m, pt(Opt_lsm),
> + lsm_id_to_name(entry->lsm[i].lsm_id));
> seq_puts(m, " ");
> }
> }
> diff --git a/security/security.c b/security/security.c
> index 0a51e3d23570..cdf9ee12b064 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -271,6 +271,46 @@ static void __init initialize_lsm(struct lsm_info *lsm)
> u32 lsm_active_cnt __ro_after_init;
> const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT];
>
> +/**
> + * lsm_name_to_id - get the LSM ID for a registered LSM
> + * @name: the name of the LSM
> + *
> + * Returns the LSM ID associated with the named LSM or
> + * LSM_ID_UNDEF if the name isn't recongnized.
> + */
> +u64 lsm_name_to_id(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
> + if (!lsm_idlist[i]->name)
> + return LSM_ID_UNDEF;
> + if (!strcmp(name, lsm_idlist[i]->name))
> + return lsm_idlist[i]->id;
> + }
> + return LSM_ID_UNDEF;
> +}
> +
> +/**
> + * lsm_id_to_name - get the LSM name for a registered LSM ID
> + * @id: the ID of the LSM
> + *
> + * Returns the LSM name associated with the LSM ID or
> + * NULL if the ID isn't recongnized.
> + */
> +const char *lsm_id_to_name(u64 id)
> +{
> + int i;
> +
> + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
> + if (!lsm_idlist[i]->name)
> + return NULL;
> + if (id == lsm_idlist[i]->id)
> + return lsm_idlist[i]->name;
> + }
> + return NULL;
> +}
> +
> /* Populate ordered LSMs list from comma-separated LSM name list. */
> static void __init ordered_lsm_parse(const char *order, const char *origin)
> {
> @@ -5336,7 +5376,8 @@ int security_key_getsecurity(struct key *key, char **buffer)
> */
> int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> {
> - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
> + LSM_ID_UNDEF);
> }
>
> /**
> @@ -5362,7 +5403,7 @@ int security_audit_rule_known(struct audit_krule *krule)
> */
> void security_audit_rule_free(void *lsmrule)
> {
> - call_void_hook(audit_rule_free, lsmrule);
> + call_void_hook(audit_rule_free, lsmrule, LSM_ID_UNDEF);
> }
>
> /**
> @@ -5380,7 +5421,8 @@ void security_audit_rule_free(void *lsmrule)
> */
> int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> {
> - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
> + LSM_ID_UNDEF);
> }
> #endif /* CONFIG_AUDIT */
>
> @@ -5389,19 +5431,23 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> * The integrity subsystem uses the same hooks as
> * the audit subsystem.
> */
> -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
> + int lsmid)
> {
> - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
> + lsmid);
> }
>
> -void ima_filter_rule_free(void *lsmrule)
> +void ima_filter_rule_free(void *lsmrule, int lsmid)
> {
> - call_void_hook(audit_rule_free, lsmrule);
> + call_void_hook(audit_rule_free, lsmrule, lsmid);
> }
>
> -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
> + int lsmid)
> {
> - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
> + lsmid);
> }
> #endif /* CONFIG_IMA_LSM_RULES */
>
> diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
> index d5495134a5b9..59468baf0c91 100644
> --- a/security/selinux/include/audit.h
> +++ b/security/selinux/include/audit.h
> @@ -21,21 +21,24 @@
> * @op: the operator the rule uses
> * @rulestr: the text "target" of the rule
> * @rule: pointer to the new rule structure returned via this
> + * @lsmid: the relevant LSM
> *
> * Returns 0 if successful, -errno if not. On success, the rule structure
> * will be allocated internally. The caller must free this structure with
> * selinux_audit_rule_free() after use.
> */
> -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
> +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
> + int lsmid);
>
> /**
> * selinux_audit_rule_free - free an selinux audit rule structure.
> * @rule: pointer to the audit rule to be freed
> + * @lsmid: which LSM this rule relates to
> *
> * This will free all memory associated with the given rule.
> * If @rule is NULL, no operation is performed.
> */
> -void selinux_audit_rule_free(void *rule);
> +void selinux_audit_rule_free(void *rule, int lsmid);
>
> /**
> * selinux_audit_rule_match - determine if a context ID matches a rule.
> @@ -43,11 +46,12 @@ void selinux_audit_rule_free(void *rule);
> * @field: the field this rule refers to
> * @op: the operator the rule uses
> * @rule: pointer to the audit rule to check against
> + * @lsmid: the relevant LSM
> *
> * Returns 1 if the context id matches the rule, 0 if it does not, and
> * -errno on failure.
> */
> -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
> +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, int lsmid);
>
> /**
> * selinux_audit_rule_known - check to see if rule contains selinux fields.
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index 1eeffc66ea7d..a9fe8d85acae 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -3487,17 +3487,20 @@ struct selinux_audit_rule {
> struct context au_ctxt;
> };
>
> -void selinux_audit_rule_free(void *vrule)
> +void selinux_audit_rule_free(void *vrule, int lsmid)
> {
> struct selinux_audit_rule *rule = vrule;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
> + return;
> if (rule) {
> context_destroy(&rule->au_ctxt);
> kfree(rule);
> }
> }
>
> -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> + int lsmid)
> {
> struct selinux_state *state = &selinux_state;
> struct selinux_policy *policy;
> @@ -3511,6 +3514,8 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>
> *rule = NULL;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
> + return 0;
> if (!selinux_initialized())
> return -EOPNOTSUPP;
>
> @@ -3592,7 +3597,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>
> err:
> rcu_read_unlock();
> - selinux_audit_rule_free(tmprule);
> + selinux_audit_rule_free(tmprule, LSM_ID_SELINUX);
> *rule = NULL;
> return rc;
> }
> @@ -3622,7 +3627,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
> return 0;
> }
>
> -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
> +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
> {
> struct selinux_state *state = &selinux_state;
> struct selinux_policy *policy;
> @@ -3631,6 +3636,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
> struct selinux_audit_rule *rule = vrule;
> int match = 0;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
> + return 0;
> if (unlikely(!rule)) {
> WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
> return -ENOENT;
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index cd44f7f3f393..4342947f51d8 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -4672,16 +4672,20 @@ static int smack_post_notification(const struct cred *w_cred,
> * @op: required testing operator (=, !=, >, <, ...)
> * @rulestr: smack label to be audited
> * @vrule: pointer to save our own audit rule representation
> + * @lsmid: the relevant LSM
> *
> * Prepare to audit cases where (@field @op @rulestr) is true.
> * The label to be audited is created if necessay.
> */
> -static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> +static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> + int lsmid)
> {
> struct smack_known *skp;
> char **rule = (char **)vrule;
> *rule = NULL;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
> + return 0;
> if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
> return -EINVAL;
>
> @@ -4726,15 +4730,19 @@ static int smack_audit_rule_known(struct audit_krule *krule)
> * @field: audit rule flags given from user-space
> * @op: required testing operator
> * @vrule: smack internal rule presentation
> + * @lsmid: the relevant LSM
> *
> * The core Audit hook. It's used to take the decision of
> * whether to audit or not to audit a given object.
> */
> -static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
> +static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
> + int lsmid)
> {
> struct smack_known *skp;
> char *rule = vrule;
>
> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
> + return 0;
> if (unlikely(!rule)) {
> WARN_ONCE(1, "Smack: missing rule\n");
> return -ENOENT;


2024-03-06 16:57:14

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v39 01/42] integrity: disassociate ima_filter_rule from security_audit_rule

On 3/6/2024 1:54 AM, Roberto Sassu wrote:
> On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
>> Create real functions for the ima_filter_rule interfaces.
>> These replace #defines that obscure the reuse of audit
>> interfaces. The new functions are put in security.c because
>> they use security module registered hooks that we don't
>> want exported.
> Beginner question: what makes IMA special, that the audit subsystem
> does not need an AUDIT_LSM field to do the same that IMA would do?
>
> In other words, why can't we add the lsm_id parameter to
> security_audit_*() functions, so that IMA can just call those?

I have never liked the reuse of the audit filter functions, especially
the way that they're hidden behind #define. The assumption that the
two facilities (audit and IMA) are going to use them the same way, and
that they will never diverge in their requirements, has always seemed
questionable.

In most cases audit needs an lsmblob rather than a secid+lsm_id pair,
as there is information required about all the LSMs, not just the one
actively involved.

>
> Thanks
>
> Roberto
>
>> Acked-by: Paul Moore <[email protected]>
>> Reviewed-by: John Johansen <[email protected]>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> To: Mimi Zohar <[email protected]>
>> Cc: [email protected]
>> ---
>> include/linux/security.h | 24 ++++++++++++++++++++++++
>> security/integrity/ima/ima.h | 26 --------------------------
>> security/security.c | 21 +++++++++++++++++++++
>> 3 files changed, 45 insertions(+), 26 deletions(-)
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 750130a7b9dd..4790508818ee 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -2009,6 +2009,30 @@ static inline void security_audit_rule_free(void *lsmrule)
>> #endif /* CONFIG_SECURITY */
>> #endif /* CONFIG_AUDIT */
>>
>> +#if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
>> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
>> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
>> +void ima_filter_rule_free(void *lsmrule);
>> +
>> +#else
>> +
>> +static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
>> + void **lsmrule)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
>> + void *lsmrule)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline void ima_filter_rule_free(void *lsmrule)
>> +{ }
>> +
>> +#endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
>> +
>> #ifdef CONFIG_SECURITYFS
>>
>> extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>> index c29db699c996..560d6104de72 100644
>> --- a/security/integrity/ima/ima.h
>> +++ b/security/integrity/ima/ima.h
>> @@ -420,32 +420,6 @@ static inline void ima_free_modsig(struct modsig *modsig)
>> }
>> #endif /* CONFIG_IMA_APPRAISE_MODSIG */
>>
>> -/* LSM based policy rules require audit */
>> -#ifdef CONFIG_IMA_LSM_RULES
>> -
>> -#define ima_filter_rule_init security_audit_rule_init
>> -#define ima_filter_rule_free security_audit_rule_free
>> -#define ima_filter_rule_match security_audit_rule_match
>> -
>> -#else
>> -
>> -static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
>> - void **lsmrule)
>> -{
>> - return -EINVAL;
>> -}
>> -
>> -static inline void ima_filter_rule_free(void *lsmrule)
>> -{
>> -}
>> -
>> -static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
>> - void *lsmrule)
>> -{
>> - return -EINVAL;
>> -}
>> -#endif /* CONFIG_IMA_LSM_RULES */
>> -
>> #ifdef CONFIG_IMA_READ_POLICY
>> #define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
>> #else
>> diff --git a/security/security.c b/security/security.c
>> index d7b15ea67c3f..8e5379a76369 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -5350,6 +5350,27 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>> }
>> #endif /* CONFIG_AUDIT */
>>
>> +#ifdef CONFIG_IMA_LSM_RULES
>> +/*
>> + * The integrity subsystem uses the same hooks as
>> + * the audit subsystem.
>> + */
>> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>> +{
>> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
>> +}
>> +
>> +void ima_filter_rule_free(void *lsmrule)
>> +{
>> + call_void_hook(audit_rule_free, lsmrule);
>> +}
>> +
>> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>> +{
>> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
>> +}
>> +#endif /* CONFIG_IMA_LSM_RULES */
>> +
>> #ifdef CONFIG_BPF_SYSCALL
>> /**
>> * security_bpf() - Check if the bpf syscall operation is allowed

2024-03-06 17:04:26

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v39 04/42] IMA: avoid label collisions with stacked LSMs

On 3/6/2024 2:09 AM, Roberto Sassu wrote:
> On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
>> Integrity measurement may filter on security module information
>> and needs to be clear in the case of multiple active security
>> modules which applies. Provide a boot option ima_rules_lsm= to
>> allow the user to specify an active security module to apply
>> filters to. If not specified, use the first registered module
>> that supports the audit_rule_match() LSM hook. Allow the user
>> to specify in the IMA policy an lsm= option to specify the
>> security module to use for a particular rule.
> I was hoping somehow that we can rely on the concept of default LSM
> from the LSM infrastructure, so that the extra option would not be
> needed.

What is the "default LSM"? The first "major LSM"? If you never, ever,
under any circumstances want to allow the rules to match an LSM other
than that, sure, we can eliminate the option. I'll bet a refreshing
beverage that BPF is going to want the option on a system that also
has SELinux. Nonetheless, if IMA doesn't want the option I'm willing
to leave it out.

>
> Roberto
>
>> This requires adding the LSM of interest as a parameter
>> to three of the audit hooks.
>>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> To: Mimi Zohar <[email protected]>
>> To: [email protected]
>> To: [email protected]
>> ---
>> Documentation/ABI/testing/ima_policy | 8 +++-
>> include/linux/lsm_hook_defs.h | 7 +--
>> include/linux/security.h | 26 +++++++---
>> security/apparmor/audit.c | 15 ++++--
>> security/apparmor/include/audit.h | 7 +--
>> security/integrity/ima/ima_policy.c | 71 ++++++++++++++++++++++++----
>> security/security.c | 64 +++++++++++++++++++++----
>> security/selinux/include/audit.h | 10 ++--
>> security/selinux/ss/services.c | 15 ++++--
>> security/smack/smack_lsm.c | 12 ++++-
>> 10 files changed, 192 insertions(+), 43 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
>> index c2385183826c..a59291b97c24 100644
>> --- a/Documentation/ABI/testing/ima_policy
>> +++ b/Documentation/ABI/testing/ima_policy
>> @@ -26,7 +26,7 @@ Description:
>> [uid=] [euid=] [gid=] [egid=]
>> [fowner=] [fgroup=]]
>> lsm: [[subj_user=] [subj_role=] [subj_type=]
>> - [obj_user=] [obj_role=] [obj_type=]]
>> + [obj_user=] [obj_role=] [obj_type=] [lsm=]]
>> option: [digest_type=] [template=] [permit_directio]
>> [appraise_type=] [appraise_flag=]
>> [appraise_algos=] [keyrings=]
>> @@ -138,6 +138,12 @@ Description:
>>
>> measure subj_user=_ func=FILE_CHECK mask=MAY_READ
>>
>> + It is possible to explicitly specify which security
>> + module a rule applies to using lsm=. If the security
>> + module specified is not active on the system the rule
>> + will be rejected. If lsm= is not specified the first
>> + security module registered on the system will be assumed.
>> +
>> Example of measure rules using alternate PCRs::
>>
>> measure func=KEXEC_KERNEL_CHECK pcr=4
>> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
>> index c925a0d26edf..2159013890aa 100644
>> --- a/include/linux/lsm_hook_defs.h
>> +++ b/include/linux/lsm_hook_defs.h
>> @@ -392,10 +392,11 @@ LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
>>
>> #ifdef CONFIG_AUDIT
>> LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
>> - void **lsmrule)
>> + void **lsmrule, int lsmid)
>> LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
>> -LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
>> -LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
>> +LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
>> + int lsmid)
>> +LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule, int lsmid)
>> #endif /* CONFIG_AUDIT */
>>
>> #ifdef CONFIG_BPF_SYSCALL
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index d4103b6cd3fc..2320ed78c4de 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -286,6 +286,8 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
>> extern int security_init(void);
>> extern int early_security_init(void);
>> extern u64 lsm_name_to_attr(const char *name);
>> +extern u64 lsm_name_to_id(const char *name);
>> +extern const char *lsm_id_to_name(u64 id);
>>
>> /* Security operations */
>> int security_binder_set_context_mgr(const struct cred *mgr);
>> @@ -536,6 +538,16 @@ static inline u64 lsm_name_to_attr(const char *name)
>> return LSM_ATTR_UNDEF;
>> }
>>
>> +static inline u64 lsm_name_to_id(const char *name)
>> +{
>> + return LSM_ID_UNDEF;
>> +}
>> +
>> +static inline const char *lsm_id_to_name(u64 id)
>> +{
>> + return NULL;
>> +}
>> +
>> static inline void security_free_mnt_opts(void **mnt_opts)
>> {
>> }
>> @@ -2030,25 +2042,27 @@ static inline void security_audit_rule_free(void *lsmrule)
>> #endif /* CONFIG_AUDIT */
>>
>> #if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
>> -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
>> -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
>> -void ima_filter_rule_free(void *lsmrule);
>> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
>> + int lsmid);
>> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
>> + int lsmid);
>> +void ima_filter_rule_free(void *lsmrule, int lsmid);
>>
>> #else
>>
>> static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
>> - void **lsmrule)
>> + void **lsmrule, int lsmid)
>> {
>> return 0;
>> }
>>
>> static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
>> - void *lsmrule)
>> + void *lsmrule, int lsmid)
>> {
>> return 0;
>> }
>>
>> -static inline void ima_filter_rule_free(void *lsmrule)
>> +static inline void ima_filter_rule_free(void *lsmrule, int lsmid)
>> { }
>>
>> #endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
>> diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
>> index 45beb1c5f747..0a9f0019355a 100644
>> --- a/security/apparmor/audit.c
>> +++ b/security/apparmor/audit.c
>> @@ -206,10 +206,12 @@ struct aa_audit_rule {
>> struct aa_label *label;
>> };
>>
>> -void aa_audit_rule_free(void *vrule)
>> +void aa_audit_rule_free(void *vrule, int lsmid)
>> {
>> struct aa_audit_rule *rule = vrule;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
>> + return;
>> if (rule) {
>> if (!IS_ERR(rule->label))
>> aa_put_label(rule->label);
>> @@ -217,10 +219,13 @@ void aa_audit_rule_free(void *vrule)
>> }
>> }
>>
>> -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>> +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>> + int lsmid)
>> {
>> struct aa_audit_rule *rule;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
>> + return 0;
>> switch (field) {
>> case AUDIT_SUBJ_ROLE:
>> if (op != Audit_equal && op != Audit_not_equal)
>> @@ -240,7 +245,7 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>> GFP_KERNEL, true, false);
>> if (IS_ERR(rule->label)) {
>> int err = PTR_ERR(rule->label);
>> - aa_audit_rule_free(rule);
>> + aa_audit_rule_free(rule, LSM_ID_APPARMOR);
>> return err;
>> }
>>
>> @@ -264,12 +269,14 @@ int aa_audit_rule_known(struct audit_krule *rule)
>> return 0;
>> }
>>
>> -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>> +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
>> {
>> struct aa_audit_rule *rule = vrule;
>> struct aa_label *label;
>> int found = 0;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
>> + return 0;
>> label = aa_secid_to_label(sid);
>>
>> if (!label)
>> diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
>> index acbb03b9bd25..a75c45dd059f 100644
>> --- a/security/apparmor/include/audit.h
>> +++ b/security/apparmor/include/audit.h
>> @@ -199,9 +199,10 @@ static inline int complain_error(int error)
>> return error;
>> }
>>
>> -void aa_audit_rule_free(void *vrule);
>> -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
>> +void aa_audit_rule_free(void *vrule, int lsmid);
>> +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>> + int lsmid);
>> int aa_audit_rule_known(struct audit_krule *rule);
>> -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
>> +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid);
>>
>> #endif /* __AA_AUDIT_H */
>> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
>> index f69062617754..a563e0478cc6 100644
>> --- a/security/integrity/ima/ima_policy.c
>> +++ b/security/integrity/ima/ima_policy.c
>> @@ -117,6 +117,8 @@ struct ima_rule_entry {
>> void *rule; /* LSM file metadata specific */
>> char *args_p; /* audit value */
>> int type; /* audit type */
>> + int lsm_id; /* which LSM rule applies to */
>> + bool lsm_specific; /* true if lsm is specified */
>> } lsm[MAX_LSM_RULES];
>> char *fsname;
>> struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
>> @@ -309,6 +311,25 @@ static int __init default_appraise_policy_setup(char *str)
>> }
>> __setup("ima_appraise_tcb", default_appraise_policy_setup);
>>
>> +static int default_rules_lsm __ro_after_init = LSM_ID_UNDEF;
>> +
>> +static int __init ima_rules_lsm_init(char *str)
>> +{
>> + int newdrl;
>> +
>> + newdrl = lsm_name_to_id(str);
>> + if (newdrl >= 0) {
>> + default_rules_lsm = newdrl;
>> + return 1;
>> + }
>> +
>> + pr_err("default ima rule lsm \"%s\" not registered, value unchanged.",
>> + str);
>> +
>> + return 1;
>> +}
>> +__setup("ima_rules_lsm=", ima_rules_lsm_init);
>> +
>> static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
>> {
>> struct ima_rule_opt_list *opt_list;
>> @@ -380,7 +401,8 @@ static void ima_lsm_free_rule(struct ima_rule_entry *entry)
>> int i;
>>
>> for (i = 0; i < MAX_LSM_RULES; i++) {
>> - ima_filter_rule_free(entry->lsm[i].rule);
>> + ima_filter_rule_free(entry->lsm[i].rule,
>> + entry->lsm[i].lsm_id);
>> kfree(entry->lsm[i].args_p);
>> }
>> }
>> @@ -425,7 +447,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
>>
>> ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
>> nentry->lsm[i].args_p,
>> - &nentry->lsm[i].rule);
>> + &nentry->lsm[i].rule,
>> + entry->lsm[i].lsm_id);
>> if (!nentry->lsm[i].rule)
>> pr_warn("rule for LSM \'%s\' is undefined\n",
>> nentry->lsm[i].args_p);
>> @@ -451,7 +474,8 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
>> * be owned by nentry.
>> */
>> for (i = 0; i < MAX_LSM_RULES; i++)
>> - ima_filter_rule_free(entry->lsm[i].rule);
>> + ima_filter_rule_free(entry->lsm[i].rule,
>> + entry->lsm[i].lsm_id);
>> kfree(entry);
>>
>> return 0;
>> @@ -650,14 +674,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
>> security_inode_getsecid(inode, &osid);
>> rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
>> Audit_equal,
>> - lsm_rule->lsm[i].rule);
>> + lsm_rule->lsm[i].rule,
>> + lsm_rule->lsm[i].lsm_id);
>> break;
>> case LSM_SUBJ_USER:
>> case LSM_SUBJ_ROLE:
>> case LSM_SUBJ_TYPE:
>> rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
>> Audit_equal,
>> - lsm_rule->lsm[i].rule);
>> + lsm_rule->lsm[i].rule,
>> + lsm_rule->lsm[i].lsm_id);
>> break;
>> default:
>> break;
>> @@ -680,7 +706,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
>> out:
>> if (rule_reinitialized) {
>> for (i = 0; i < MAX_LSM_RULES; i++)
>> - ima_filter_rule_free(lsm_rule->lsm[i].rule);
>> + ima_filter_rule_free(lsm_rule->lsm[i].rule,
>> + lsm_rule->lsm[i].lsm_id);
>> kfree(lsm_rule);
>> }
>> return result;
>> @@ -1073,7 +1100,7 @@ enum policy_opt {
>> Opt_digest_type,
>> Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
>> Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
>> - Opt_label, Opt_err
>> + Opt_lsm, Opt_label, Opt_err
>> };
>>
>> static const match_table_t policy_tokens = {
>> @@ -1121,6 +1148,7 @@ static const match_table_t policy_tokens = {
>> {Opt_pcr, "pcr=%s"},
>> {Opt_template, "template=%s"},
>> {Opt_keyrings, "keyrings=%s"},
>> + {Opt_lsm, "lsm=%s"},
>> {Opt_label, "label=%s"},
>> {Opt_err, NULL}
>> };
>> @@ -1140,7 +1168,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
>> entry->lsm[lsm_rule].type = audit_type;
>> result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal,
>> entry->lsm[lsm_rule].args_p,
>> - &entry->lsm[lsm_rule].rule);
>> + &entry->lsm[lsm_rule].rule,
>> + entry->lsm[lsm_rule].lsm_id);
>> if (!entry->lsm[lsm_rule].rule) {
>> pr_warn("rule for LSM \'%s\' is undefined\n",
>> entry->lsm[lsm_rule].args_p);
>> @@ -1878,6 +1907,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>> &(template_desc->num_fields));
>> entry->template = template_desc;
>> break;
>> + case Opt_lsm: {
>> + int i;
>> +
>> + result = lsm_name_to_id(args[0].from);
>> + if (result < 0) {
>> + for (i = 0; i < MAX_LSM_RULES; i++)
>> + entry->lsm[i].args_p = NULL;
>> + result = -EINVAL;
>> + break;
>> + }
>> + for (i = 0; i < MAX_LSM_RULES; i++) {
>> + entry->lsm[i].lsm_id = result;
>> + entry->lsm[i].lsm_specific = true;
>> + }
>> + result = 0;
>> + break;
>> + }
>> case Opt_err:
>> ima_log_string(ab, "UNKNOWN", p);
>> result = -EINVAL;
>> @@ -1923,6 +1969,7 @@ ssize_t ima_parse_add_rule(char *rule)
>> struct ima_rule_entry *entry;
>> ssize_t result, len;
>> int audit_info = 0;
>> + int i;
>>
>> p = strsep(&rule, "\n");
>> len = strlen(p) + 1;
>> @@ -1940,6 +1987,11 @@ ssize_t ima_parse_add_rule(char *rule)
>>
>> INIT_LIST_HEAD(&entry->list);
>>
>> + for (i = 0; i < MAX_LSM_RULES; i++) {
>> + entry->lsm[i].lsm_id = default_rules_lsm;
>> + entry->lsm[i].lsm_specific = false;
>> + }
>> +
>> result = ima_parse_rule(p, entry);
>> if (result) {
>> ima_free_rule(entry);
>> @@ -2251,6 +2303,9 @@ int ima_policy_show(struct seq_file *m, void *v)
>> entry->lsm[i].args_p);
>> break;
>> }
>> + if (entry->lsm[i].lsm_specific)
>> + seq_printf(m, pt(Opt_lsm),
>> + lsm_id_to_name(entry->lsm[i].lsm_id));
>> seq_puts(m, " ");
>> }
>> }
>> diff --git a/security/security.c b/security/security.c
>> index 0a51e3d23570..cdf9ee12b064 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -271,6 +271,46 @@ static void __init initialize_lsm(struct lsm_info *lsm)
>> u32 lsm_active_cnt __ro_after_init;
>> const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT];
>>
>> +/**
>> + * lsm_name_to_id - get the LSM ID for a registered LSM
>> + * @name: the name of the LSM
>> + *
>> + * Returns the LSM ID associated with the named LSM or
>> + * LSM_ID_UNDEF if the name isn't recongnized.
>> + */
>> +u64 lsm_name_to_id(const char *name)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
>> + if (!lsm_idlist[i]->name)
>> + return LSM_ID_UNDEF;
>> + if (!strcmp(name, lsm_idlist[i]->name))
>> + return lsm_idlist[i]->id;
>> + }
>> + return LSM_ID_UNDEF;
>> +}
>> +
>> +/**
>> + * lsm_id_to_name - get the LSM name for a registered LSM ID
>> + * @id: the ID of the LSM
>> + *
>> + * Returns the LSM name associated with the LSM ID or
>> + * NULL if the ID isn't recongnized.
>> + */
>> +const char *lsm_id_to_name(u64 id)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
>> + if (!lsm_idlist[i]->name)
>> + return NULL;
>> + if (id == lsm_idlist[i]->id)
>> + return lsm_idlist[i]->name;
>> + }
>> + return NULL;
>> +}
>> +
>> /* Populate ordered LSMs list from comma-separated LSM name list. */
>> static void __init ordered_lsm_parse(const char *order, const char *origin)
>> {
>> @@ -5336,7 +5376,8 @@ int security_key_getsecurity(struct key *key, char **buffer)
>> */
>> int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>> {
>> - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
>> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
>> + LSM_ID_UNDEF);
>> }
>>
>> /**
>> @@ -5362,7 +5403,7 @@ int security_audit_rule_known(struct audit_krule *krule)
>> */
>> void security_audit_rule_free(void *lsmrule)
>> {
>> - call_void_hook(audit_rule_free, lsmrule);
>> + call_void_hook(audit_rule_free, lsmrule, LSM_ID_UNDEF);
>> }
>>
>> /**
>> @@ -5380,7 +5421,8 @@ void security_audit_rule_free(void *lsmrule)
>> */
>> int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>> {
>> - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
>> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
>> + LSM_ID_UNDEF);
>> }
>> #endif /* CONFIG_AUDIT */
>>
>> @@ -5389,19 +5431,23 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>> * The integrity subsystem uses the same hooks as
>> * the audit subsystem.
>> */
>> -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
>> + int lsmid)
>> {
>> - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
>> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
>> + lsmid);
>> }
>>
>> -void ima_filter_rule_free(void *lsmrule)
>> +void ima_filter_rule_free(void *lsmrule, int lsmid)
>> {
>> - call_void_hook(audit_rule_free, lsmrule);
>> + call_void_hook(audit_rule_free, lsmrule, lsmid);
>> }
>>
>> -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
>> + int lsmid)
>> {
>> - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
>> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
>> + lsmid);
>> }
>> #endif /* CONFIG_IMA_LSM_RULES */
>>
>> diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
>> index d5495134a5b9..59468baf0c91 100644
>> --- a/security/selinux/include/audit.h
>> +++ b/security/selinux/include/audit.h
>> @@ -21,21 +21,24 @@
>> * @op: the operator the rule uses
>> * @rulestr: the text "target" of the rule
>> * @rule: pointer to the new rule structure returned via this
>> + * @lsmid: the relevant LSM
>> *
>> * Returns 0 if successful, -errno if not. On success, the rule structure
>> * will be allocated internally. The caller must free this structure with
>> * selinux_audit_rule_free() after use.
>> */
>> -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
>> +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
>> + int lsmid);
>>
>> /**
>> * selinux_audit_rule_free - free an selinux audit rule structure.
>> * @rule: pointer to the audit rule to be freed
>> + * @lsmid: which LSM this rule relates to
>> *
>> * This will free all memory associated with the given rule.
>> * If @rule is NULL, no operation is performed.
>> */
>> -void selinux_audit_rule_free(void *rule);
>> +void selinux_audit_rule_free(void *rule, int lsmid);
>>
>> /**
>> * selinux_audit_rule_match - determine if a context ID matches a rule.
>> @@ -43,11 +46,12 @@ void selinux_audit_rule_free(void *rule);
>> * @field: the field this rule refers to
>> * @op: the operator the rule uses
>> * @rule: pointer to the audit rule to check against
>> + * @lsmid: the relevant LSM
>> *
>> * Returns 1 if the context id matches the rule, 0 if it does not, and
>> * -errno on failure.
>> */
>> -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
>> +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, int lsmid);
>>
>> /**
>> * selinux_audit_rule_known - check to see if rule contains selinux fields.
>> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
>> index 1eeffc66ea7d..a9fe8d85acae 100644
>> --- a/security/selinux/ss/services.c
>> +++ b/security/selinux/ss/services.c
>> @@ -3487,17 +3487,20 @@ struct selinux_audit_rule {
>> struct context au_ctxt;
>> };
>>
>> -void selinux_audit_rule_free(void *vrule)
>> +void selinux_audit_rule_free(void *vrule, int lsmid)
>> {
>> struct selinux_audit_rule *rule = vrule;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
>> + return;
>> if (rule) {
>> context_destroy(&rule->au_ctxt);
>> kfree(rule);
>> }
>> }
>>
>> -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>> +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>> + int lsmid)
>> {
>> struct selinux_state *state = &selinux_state;
>> struct selinux_policy *policy;
>> @@ -3511,6 +3514,8 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>
>> *rule = NULL;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
>> + return 0;
>> if (!selinux_initialized())
>> return -EOPNOTSUPP;
>>
>> @@ -3592,7 +3597,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>
>> err:
>> rcu_read_unlock();
>> - selinux_audit_rule_free(tmprule);
>> + selinux_audit_rule_free(tmprule, LSM_ID_SELINUX);
>> *rule = NULL;
>> return rc;
>> }
>> @@ -3622,7 +3627,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
>> return 0;
>> }
>>
>> -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>> +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
>> {
>> struct selinux_state *state = &selinux_state;
>> struct selinux_policy *policy;
>> @@ -3631,6 +3636,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>> struct selinux_audit_rule *rule = vrule;
>> int match = 0;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
>> + return 0;
>> if (unlikely(!rule)) {
>> WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
>> return -ENOENT;
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index cd44f7f3f393..4342947f51d8 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -4672,16 +4672,20 @@ static int smack_post_notification(const struct cred *w_cred,
>> * @op: required testing operator (=, !=, >, <, ...)
>> * @rulestr: smack label to be audited
>> * @vrule: pointer to save our own audit rule representation
>> + * @lsmid: the relevant LSM
>> *
>> * Prepare to audit cases where (@field @op @rulestr) is true.
>> * The label to be audited is created if necessay.
>> */
>> -static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>> +static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>> + int lsmid)
>> {
>> struct smack_known *skp;
>> char **rule = (char **)vrule;
>> *rule = NULL;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
>> + return 0;
>> if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
>> return -EINVAL;
>>
>> @@ -4726,15 +4730,19 @@ static int smack_audit_rule_known(struct audit_krule *krule)
>> * @field: audit rule flags given from user-space
>> * @op: required testing operator
>> * @vrule: smack internal rule presentation
>> + * @lsmid: the relevant LSM
>> *
>> * The core Audit hook. It's used to take the decision of
>> * whether to audit or not to audit a given object.
>> */
>> -static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
>> +static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
>> + int lsmid)
>> {
>> struct smack_known *skp;
>> char *rule = vrule;
>>
>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
>> + return 0;
>> if (unlikely(!rule)) {
>> WARN_ONCE(1, "Smack: missing rule\n");
>> return -ENOENT;

2024-03-07 07:56:41

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v39 01/42] integrity: disassociate ima_filter_rule from security_audit_rule

On Wed, 2024-03-06 at 08:56 -0800, Casey Schaufler wrote:
> On 3/6/2024 1:54 AM, Roberto Sassu wrote:
> > On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
> > > Create real functions for the ima_filter_rule interfaces.
> > > These replace #defines that obscure the reuse of audit
> > > interfaces. The new functions are put in security.c because
> > > they use security module registered hooks that we don't
> > > want exported.
> > Beginner question: what makes IMA special, that the audit subsystem
> > does not need an AUDIT_LSM field to do the same that IMA would do?
> >
> > In other words, why can't we add the lsm_id parameter to
> > security_audit_*() functions, so that IMA can just call those?
>
> I have never liked the reuse of the audit filter functions, especially
> the way that they're hidden behind #define. The assumption that the
> two facilities (audit and IMA) are going to use them the same way, and
> that they will never diverge in their requirements, has always seemed
> questionable.
>
> In most cases audit needs an lsmblob rather than a secid+lsm_id pair,
> as there is information required about all the LSMs, not just the one
> actively involved.

Fair enough.

Thanks

Roberto

> >
> > Thanks
> >
> > Roberto
> >
> > > Acked-by: Paul Moore <[email protected]>
> > > Reviewed-by: John Johansen <[email protected]>
> > > Signed-off-by: Casey Schaufler <[email protected]>
> > > To: Mimi Zohar <[email protected]>
> > > Cc: [email protected]
> > > ---
> > > include/linux/security.h | 24 ++++++++++++++++++++++++
> > > security/integrity/ima/ima.h | 26 --------------------------
> > > security/security.c | 21 +++++++++++++++++++++
> > > 3 files changed, 45 insertions(+), 26 deletions(-)
> > >
> > > diff --git a/include/linux/security.h b/include/linux/security.h
> > > index 750130a7b9dd..4790508818ee 100644
> > > --- a/include/linux/security.h
> > > +++ b/include/linux/security.h
> > > @@ -2009,6 +2009,30 @@ static inline void security_audit_rule_free(void *lsmrule)
> > > #endif /* CONFIG_SECURITY */
> > > #endif /* CONFIG_AUDIT */
> > >
> > > +#if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
> > > +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
> > > +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
> > > +void ima_filter_rule_free(void *lsmrule);
> > > +
> > > +#else
> > > +
> > > +static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
> > > + void **lsmrule)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > > +static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
> > > + void *lsmrule)
> > > +{
> > > + return 0;
> > > +}
> > > +
> > > +static inline void ima_filter_rule_free(void *lsmrule)
> > > +{ }
> > > +
> > > +#endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
> > > +
> > > #ifdef CONFIG_SECURITYFS
> > >
> > > extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
> > > diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> > > index c29db699c996..560d6104de72 100644
> > > --- a/security/integrity/ima/ima.h
> > > +++ b/security/integrity/ima/ima.h
> > > @@ -420,32 +420,6 @@ static inline void ima_free_modsig(struct modsig *modsig)
> > > }
> > > #endif /* CONFIG_IMA_APPRAISE_MODSIG */
> > >
> > > -/* LSM based policy rules require audit */
> > > -#ifdef CONFIG_IMA_LSM_RULES
> > > -
> > > -#define ima_filter_rule_init security_audit_rule_init
> > > -#define ima_filter_rule_free security_audit_rule_free
> > > -#define ima_filter_rule_match security_audit_rule_match
> > > -
> > > -#else
> > > -
> > > -static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
> > > - void **lsmrule)
> > > -{
> > > - return -EINVAL;
> > > -}
> > > -
> > > -static inline void ima_filter_rule_free(void *lsmrule)
> > > -{
> > > -}
> > > -
> > > -static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
> > > - void *lsmrule)
> > > -{
> > > - return -EINVAL;
> > > -}
> > > -#endif /* CONFIG_IMA_LSM_RULES */
> > > -
> > > #ifdef CONFIG_IMA_READ_POLICY
> > > #define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
> > > #else
> > > diff --git a/security/security.c b/security/security.c
> > > index d7b15ea67c3f..8e5379a76369 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -5350,6 +5350,27 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> > > }
> > > #endif /* CONFIG_AUDIT */
> > >
> > > +#ifdef CONFIG_IMA_LSM_RULES
> > > +/*
> > > + * The integrity subsystem uses the same hooks as
> > > + * the audit subsystem.
> > > + */
> > > +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> > > +{
> > > + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
> > > +}
> > > +
> > > +void ima_filter_rule_free(void *lsmrule)
> > > +{
> > > + call_void_hook(audit_rule_free, lsmrule);
> > > +}
> > > +
> > > +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> > > +{
> > > + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
> > > +}
> > > +#endif /* CONFIG_IMA_LSM_RULES */
> > > +
> > > #ifdef CONFIG_BPF_SYSCALL
> > > /**
> > > * security_bpf() - Check if the bpf syscall operation is allowed


2024-03-07 08:17:13

by Roberto Sassu

[permalink] [raw]
Subject: Re: [PATCH v39 04/42] IMA: avoid label collisions with stacked LSMs

On Wed, 2024-03-06 at 09:04 -0800, Casey Schaufler wrote:
> On 3/6/2024 2:09 AM, Roberto Sassu wrote:
> > On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
> > > Integrity measurement may filter on security module information
> > > and needs to be clear in the case of multiple active security
> > > modules which applies. Provide a boot option ima_rules_lsm= to
> > > allow the user to specify an active security module to apply
> > > filters to. If not specified, use the first registered module
> > > that supports the audit_rule_match() LSM hook. Allow the user
> > > to specify in the IMA policy an lsm= option to specify the
> > > security module to use for a particular rule.
> > I was hoping somehow that we can rely on the concept of default LSM
> > from the LSM infrastructure, so that the extra option would not be
> > needed.
>
> What is the "default LSM"? The first "major LSM"? If you never, ever,
> under any circumstances want to allow the rules to match an LSM other
> than that, sure, we can eliminate the option. I'll bet a refreshing
> beverage that BPF is going to want the option on a system that also
> has SELinux. Nonetheless, if IMA doesn't want the option I'm willing
> to leave it out.

I was more thinking that for existing IMA policies, that would be the
behavior. New policies would always specify lsm=.

If we want to provide more flexibility, I'm fine with that.

Roberto

> >
> > Roberto
> >
> > > This requires adding the LSM of interest as a parameter
> > > to three of the audit hooks.
> > >
> > > Signed-off-by: Casey Schaufler <[email protected]>
> > > To: Mimi Zohar <[email protected]>
> > > To: [email protected]
> > > To: [email protected]
> > > ---
> > > Documentation/ABI/testing/ima_policy | 8 +++-
> > > include/linux/lsm_hook_defs.h | 7 +--
> > > include/linux/security.h | 26 +++++++---
> > > security/apparmor/audit.c | 15 ++++--
> > > security/apparmor/include/audit.h | 7 +--
> > > security/integrity/ima/ima_policy.c | 71 ++++++++++++++++++++++++----
> > > security/security.c | 64 +++++++++++++++++++++----
> > > security/selinux/include/audit.h | 10 ++--
> > > security/selinux/ss/services.c | 15 ++++--
> > > security/smack/smack_lsm.c | 12 ++++-
> > > 10 files changed, 192 insertions(+), 43 deletions(-)
> > >
> > > diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
> > > index c2385183826c..a59291b97c24 100644
> > > --- a/Documentation/ABI/testing/ima_policy
> > > +++ b/Documentation/ABI/testing/ima_policy
> > > @@ -26,7 +26,7 @@ Description:
> > > [uid=] [euid=] [gid=] [egid=]
> > > [fowner=] [fgroup=]]
> > > lsm: [[subj_user=] [subj_role=] [subj_type=]
> > > - [obj_user=] [obj_role=] [obj_type=]]
> > > + [obj_user=] [obj_role=] [obj_type=] [lsm=]]
> > > option: [digest_type=] [template=] [permit_directio]
> > > [appraise_type=] [appraise_flag=]
> > > [appraise_algos=] [keyrings=]
> > > @@ -138,6 +138,12 @@ Description:
> > >
> > > measure subj_user=_ func=FILE_CHECK mask=MAY_READ
> > >
> > > + It is possible to explicitly specify which security
> > > + module a rule applies to using lsm=. If the security
> > > + module specified is not active on the system the rule
> > > + will be rejected. If lsm= is not specified the first
> > > + security module registered on the system will be assumed.
> > > +
> > > Example of measure rules using alternate PCRs::
> > >
> > > measure func=KEXEC_KERNEL_CHECK pcr=4
> > > diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> > > index c925a0d26edf..2159013890aa 100644
> > > --- a/include/linux/lsm_hook_defs.h
> > > +++ b/include/linux/lsm_hook_defs.h
> > > @@ -392,10 +392,11 @@ LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
> > >
> > > #ifdef CONFIG_AUDIT
> > > LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
> > > - void **lsmrule)
> > > + void **lsmrule, int lsmid)
> > > LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
> > > -LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
> > > -LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
> > > +LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
> > > + int lsmid)
> > > +LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule, int lsmid)
> > > #endif /* CONFIG_AUDIT */
> > >
> > > #ifdef CONFIG_BPF_SYSCALL
> > > diff --git a/include/linux/security.h b/include/linux/security.h
> > > index d4103b6cd3fc..2320ed78c4de 100644
> > > --- a/include/linux/security.h
> > > +++ b/include/linux/security.h
> > > @@ -286,6 +286,8 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
> > > extern int security_init(void);
> > > extern int early_security_init(void);
> > > extern u64 lsm_name_to_attr(const char *name);
> > > +extern u64 lsm_name_to_id(const char *name);
> > > +extern const char *lsm_id_to_name(u64 id);
> > >
> > > /* Security operations */
> > > int security_binder_set_context_mgr(const struct cred *mgr);
> > > @@ -536,6 +538,16 @@ static inline u64 lsm_name_to_attr(const char *name)
> > > return LSM_ATTR_UNDEF;
> > > }
> > >
> > > +static inline u64 lsm_name_to_id(const char *name)
> > > +{
> > > + return LSM_ID_UNDEF;
> > > +}
> > > +
> > > +static inline const char *lsm_id_to_name(u64 id)
> > > +{
> > > + return NULL;
> > > +}
> > > +
> > > static inline void security_free_mnt_opts(void **mnt_opts)
> > > {
> > > }
> > > @@ -2030,25 +2042,27 @@ static inline void security_audit_rule_free(void *lsmrule)
> > > #endif /* CONFIG_AUDIT */
> > >
> > > #if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
> > > -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
> > > -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
> > > -void ima_filter_rule_free(void *lsmrule);
> > > +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
> > > + int lsmid);
> > > +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
> > > + int lsmid);
> > > +void ima_filter_rule_free(void *lsmrule, int lsmid);
> > >
> > > #else
> > >
> > > static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
> > > - void **lsmrule)
> > > + void **lsmrule, int lsmid)
> > > {
> > > return 0;
> > > }
> > >
> > > static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
> > > - void *lsmrule)
> > > + void *lsmrule, int lsmid)
> > > {
> > > return 0;
> > > }
> > >
> > > -static inline void ima_filter_rule_free(void *lsmrule)
> > > +static inline void ima_filter_rule_free(void *lsmrule, int lsmid)
> > > { }
> > >
> > > #endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
> > > diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
> > > index 45beb1c5f747..0a9f0019355a 100644
> > > --- a/security/apparmor/audit.c
> > > +++ b/security/apparmor/audit.c
> > > @@ -206,10 +206,12 @@ struct aa_audit_rule {
> > > struct aa_label *label;
> > > };
> > >
> > > -void aa_audit_rule_free(void *vrule)
> > > +void aa_audit_rule_free(void *vrule, int lsmid)
> > > {
> > > struct aa_audit_rule *rule = vrule;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
> > > + return;
> > > if (rule) {
> > > if (!IS_ERR(rule->label))
> > > aa_put_label(rule->label);
> > > @@ -217,10 +219,13 @@ void aa_audit_rule_free(void *vrule)
> > > }
> > > }
> > >
> > > -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> > > +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> > > + int lsmid)
> > > {
> > > struct aa_audit_rule *rule;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
> > > + return 0;
> > > switch (field) {
> > > case AUDIT_SUBJ_ROLE:
> > > if (op != Audit_equal && op != Audit_not_equal)
> > > @@ -240,7 +245,7 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> > > GFP_KERNEL, true, false);
> > > if (IS_ERR(rule->label)) {
> > > int err = PTR_ERR(rule->label);
> > > - aa_audit_rule_free(rule);
> > > + aa_audit_rule_free(rule, LSM_ID_APPARMOR);
> > > return err;
> > > }
> > >
> > > @@ -264,12 +269,14 @@ int aa_audit_rule_known(struct audit_krule *rule)
> > > return 0;
> > > }
> > >
> > > -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
> > > +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
> > > {
> > > struct aa_audit_rule *rule = vrule;
> > > struct aa_label *label;
> > > int found = 0;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
> > > + return 0;
> > > label = aa_secid_to_label(sid);
> > >
> > > if (!label)
> > > diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
> > > index acbb03b9bd25..a75c45dd059f 100644
> > > --- a/security/apparmor/include/audit.h
> > > +++ b/security/apparmor/include/audit.h
> > > @@ -199,9 +199,10 @@ static inline int complain_error(int error)
> > > return error;
> > > }
> > >
> > > -void aa_audit_rule_free(void *vrule);
> > > -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
> > > +void aa_audit_rule_free(void *vrule, int lsmid);
> > > +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> > > + int lsmid);
> > > int aa_audit_rule_known(struct audit_krule *rule);
> > > -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
> > > +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid);
> > >
> > > #endif /* __AA_AUDIT_H */
> > > diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> > > index f69062617754..a563e0478cc6 100644
> > > --- a/security/integrity/ima/ima_policy.c
> > > +++ b/security/integrity/ima/ima_policy.c
> > > @@ -117,6 +117,8 @@ struct ima_rule_entry {
> > > void *rule; /* LSM file metadata specific */
> > > char *args_p; /* audit value */
> > > int type; /* audit type */
> > > + int lsm_id; /* which LSM rule applies to */
> > > + bool lsm_specific; /* true if lsm is specified */
> > > } lsm[MAX_LSM_RULES];
> > > char *fsname;
> > > struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
> > > @@ -309,6 +311,25 @@ static int __init default_appraise_policy_setup(char *str)
> > > }
> > > __setup("ima_appraise_tcb", default_appraise_policy_setup);
> > >
> > > +static int default_rules_lsm __ro_after_init = LSM_ID_UNDEF;
> > > +
> > > +static int __init ima_rules_lsm_init(char *str)
> > > +{
> > > + int newdrl;
> > > +
> > > + newdrl = lsm_name_to_id(str);
> > > + if (newdrl >= 0) {
> > > + default_rules_lsm = newdrl;
> > > + return 1;
> > > + }
> > > +
> > > + pr_err("default ima rule lsm \"%s\" not registered, value unchanged",
> > > + str);
> > > +
> > > + return 1;
> > > +}
> > > +__setup("ima_rules_lsm=", ima_rules_lsm_init);
> > > +
> > > static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
> > > {
> > > struct ima_rule_opt_list *opt_list;
> > > @@ -380,7 +401,8 @@ static void ima_lsm_free_rule(struct ima_rule_entry *entry)
> > > int i;
> > >
> > > for (i = 0; i < MAX_LSM_RULES; i++) {
> > > - ima_filter_rule_free(entry->lsm[i].rule);
> > > + ima_filter_rule_free(entry->lsm[i].rule,
> > > + entry->lsm[i].lsm_id);
> > > kfree(entry->lsm[i].args_p);
> > > }
> > > }
> > > @@ -425,7 +447,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
> > >
> > > ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
> > > nentry->lsm[i].args_p,
> > > - &nentry->lsm[i].rule);
> > > + &nentry->lsm[i].rule,
> > > + entry->lsm[i].lsm_id);
> > > if (!nentry->lsm[i].rule)
> > > pr_warn("rule for LSM \'%s\' is undefined\n",
> > > nentry->lsm[i].args_p);
> > > @@ -451,7 +474,8 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
> > > * be owned by nentry.
> > > */
> > > for (i = 0; i < MAX_LSM_RULES; i++)
> > > - ima_filter_rule_free(entry->lsm[i].rule);
> > > + ima_filter_rule_free(entry->lsm[i].rule,
> > > + entry->lsm[i].lsm_id);
> > > kfree(entry);
> > >
> > > return 0;
> > > @@ -650,14 +674,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
> > > security_inode_getsecid(inode, &osid);
> > > rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
> > > Audit_equal,
> > > - lsm_rule->lsm[i].rule);
> > > + lsm_rule->lsm[i].rule,
> > > + lsm_rule->lsm[i].lsm_id);
> > > break;
> > > case LSM_SUBJ_USER:
> > > case LSM_SUBJ_ROLE:
> > > case LSM_SUBJ_TYPE:
> > > rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
> > > Audit_equal,
> > > - lsm_rule->lsm[i].rule);
> > > + lsm_rule->lsm[i].rule,
> > > + lsm_rule->lsm[i].lsm_id);
> > > break;
> > > default:
> > > break;
> > > @@ -680,7 +706,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
> > > out:
> > > if (rule_reinitialized) {
> > > for (i = 0; i < MAX_LSM_RULES; i++)
> > > - ima_filter_rule_free(lsm_rule->lsm[i].rule);
> > > + ima_filter_rule_free(lsm_rule->lsm[i].rule,
> > > + lsm_rule->lsm[i].lsm_id);
> > > kfree(lsm_rule);
> > > }
> > > return result;
> > > @@ -1073,7 +1100,7 @@ enum policy_opt {
> > > Opt_digest_type,
> > > Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
> > > Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
> > > - Opt_label, Opt_err
> > > + Opt_lsm, Opt_label, Opt_err
> > > };
> > >
> > > static const match_table_t policy_tokens = {
> > > @@ -1121,6 +1148,7 @@ static const match_table_t policy_tokens = {
> > > {Opt_pcr, "pcr=%s"},
> > > {Opt_template, "template=%s"},
> > > {Opt_keyrings, "keyrings=%s"},
> > > + {Opt_lsm, "lsm=%s"},
> > > {Opt_label, "label=%s"},
> > > {Opt_err, NULL}
> > > };
> > > @@ -1140,7 +1168,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
> > > entry->lsm[lsm_rule].type = audit_type;
> > > result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal,
> > > entry->lsm[lsm_rule].args_p,
> > > - &entry->lsm[lsm_rule].rule);
> > > + &entry->lsm[lsm_rule].rule,
> > > + entry->lsm[lsm_rule].lsm_id);
> > > if (!entry->lsm[lsm_rule].rule) {
> > > pr_warn("rule for LSM \'%s\' is undefined\n",
> > > entry->lsm[lsm_rule].args_p);
> > > @@ -1878,6 +1907,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
> > > &(template_desc->num_fields));
> > > entry->template = template_desc;
> > > break;
> > > + case Opt_lsm: {
> > > + int i;
> > > +
> > > + result = lsm_name_to_id(args[0].from);
> > > + if (result < 0) {
> > > + for (i = 0; i < MAX_LSM_RULES; i++)
> > > + entry->lsm[i].args_p = NULL;
> > > + result = -EINVAL;
> > > + break;
> > > + }
> > > + for (i = 0; i < MAX_LSM_RULES; i++) {
> > > + entry->lsm[i].lsm_id = result;
> > > + entry->lsm[i].lsm_specific = true;
> > > + }
> > > + result = 0;
> > > + break;
> > > + }
> > > case Opt_err:
> > > ima_log_string(ab, "UNKNOWN", p);
> > > result = -EINVAL;
> > > @@ -1923,6 +1969,7 @@ ssize_t ima_parse_add_rule(char *rule)
> > > struct ima_rule_entry *entry;
> > > ssize_t result, len;
> > > int audit_info = 0;
> > > + int i;
> > >
> > > p = strsep(&rule, "\n");
> > > len = strlen(p) + 1;
> > > @@ -1940,6 +1987,11 @@ ssize_t ima_parse_add_rule(char *rule)
> > >
> > > INIT_LIST_HEAD(&entry->list);
> > >
> > > + for (i = 0; i < MAX_LSM_RULES; i++) {
> > > + entry->lsm[i].lsm_id = default_rules_lsm;
> > > + entry->lsm[i].lsm_specific = false;
> > > + }
> > > +
> > > result = ima_parse_rule(p, entry);
> > > if (result) {
> > > ima_free_rule(entry);
> > > @@ -2251,6 +2303,9 @@ int ima_policy_show(struct seq_file *m, void *v)
> > > entry->lsm[i].args_p);
> > > break;
> > > }
> > > + if (entry->lsm[i].lsm_specific)
> > > + seq_printf(m, pt(Opt_lsm),
> > > + lsm_id_to_name(entry->lsm[i].lsm_id));
> > > seq_puts(m, " ");
> > > }
> > > }
> > > diff --git a/security/security.c b/security/security.c
> > > index 0a51e3d23570..cdf9ee12b064 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -271,6 +271,46 @@ static void __init initialize_lsm(struct lsm_info *lsm)
> > > u32 lsm_active_cnt __ro_after_init;
> > > const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT];
> > >
> > > +/**
> > > + * lsm_name_to_id - get the LSM ID for a registered LSM
> > > + * @name: the name of the LSM
> > > + *
> > > + * Returns the LSM ID associated with the named LSM or
> > > + * LSM_ID_UNDEF if the name isn't recongnized.
> > > + */
> > > +u64 lsm_name_to_id(const char *name)
> > > +{
> > > + int i;
> > > +
> > > + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
> > > + if (!lsm_idlist[i]->name)
> > > + return LSM_ID_UNDEF;
> > > + if (!strcmp(name, lsm_idlist[i]->name))
> > > + return lsm_idlist[i]->id;
> > > + }
> > > + return LSM_ID_UNDEF;
> > > +}
> > > +
> > > +/**
> > > + * lsm_id_to_name - get the LSM name for a registered LSM ID
> > > + * @id: the ID of the LSM
> > > + *
> > > + * Returns the LSM name associated with the LSM ID or
> > > + * NULL if the ID isn't recongnized.
> > > + */
> > > +const char *lsm_id_to_name(u64 id)
> > > +{
> > > + int i;
> > > +
> > > + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
> > > + if (!lsm_idlist[i]->name)
> > > + return NULL;
> > > + if (id == lsm_idlist[i]->id)
> > > + return lsm_idlist[i]->name;
> > > + }
> > > + return NULL;
> > > +}
> > > +
> > > /* Populate ordered LSMs list from comma-separated LSM name list. */
> > > static void __init ordered_lsm_parse(const char *order, const char *origin)
> > > {
> > > @@ -5336,7 +5376,8 @@ int security_key_getsecurity(struct key *key, char **buffer)
> > > */
> > > int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> > > {
> > > - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
> > > + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
> > > + LSM_ID_UNDEF);
> > > }
> > >
> > > /**
> > > @@ -5362,7 +5403,7 @@ int security_audit_rule_known(struct audit_krule *krule)
> > > */
> > > void security_audit_rule_free(void *lsmrule)
> > > {
> > > - call_void_hook(audit_rule_free, lsmrule);
> > > + call_void_hook(audit_rule_free, lsmrule, LSM_ID_UNDEF);
> > > }
> > >
> > > /**
> > > @@ -5380,7 +5421,8 @@ void security_audit_rule_free(void *lsmrule)
> > > */
> > > int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> > > {
> > > - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
> > > + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
> > > + LSM_ID_UNDEF);
> > > }
> > > #endif /* CONFIG_AUDIT */
> > >
> > > @@ -5389,19 +5431,23 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> > > * The integrity subsystem uses the same hooks as
> > > * the audit subsystem.
> > > */
> > > -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
> > > +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
> > > + int lsmid)
> > > {
> > > - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
> > > + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
> > > + lsmid);
> > > }
> > >
> > > -void ima_filter_rule_free(void *lsmrule)
> > > +void ima_filter_rule_free(void *lsmrule, int lsmid)
> > > {
> > > - call_void_hook(audit_rule_free, lsmrule);
> > > + call_void_hook(audit_rule_free, lsmrule, lsmid);
> > > }
> > >
> > > -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
> > > +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
> > > + int lsmid)
> > > {
> > > - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
> > > + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
> > > + lsmid);
> > > }
> > > #endif /* CONFIG_IMA_LSM_RULES */
> > >
> > > diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
> > > index d5495134a5b9..59468baf0c91 100644
> > > --- a/security/selinux/include/audit.h
> > > +++ b/security/selinux/include/audit.h
> > > @@ -21,21 +21,24 @@
> > > * @op: the operator the rule uses
> > > * @rulestr: the text "target" of the rule
> > > * @rule: pointer to the new rule structure returned via this
> > > + * @lsmid: the relevant LSM
> > > *
> > > * Returns 0 if successful, -errno if not. On success, the rule structure
> > > * will be allocated internally. The caller must free this structure with
> > > * selinux_audit_rule_free() after use.
> > > */
> > > -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
> > > +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
> > > + int lsmid);
> > >
> > > /**
> > > * selinux_audit_rule_free - free an selinux audit rule structure.
> > > * @rule: pointer to the audit rule to be freed
> > > + * @lsmid: which LSM this rule relates to
> > > *
> > > * This will free all memory associated with the given rule.
> > > * If @rule is NULL, no operation is performed.
> > > */
> > > -void selinux_audit_rule_free(void *rule);
> > > +void selinux_audit_rule_free(void *rule, int lsmid);
> > >
> > > /**
> > > * selinux_audit_rule_match - determine if a context ID matches a rule.
> > > @@ -43,11 +46,12 @@ void selinux_audit_rule_free(void *rule);
> > > * @field: the field this rule refers to
> > > * @op: the operator the rule uses
> > > * @rule: pointer to the audit rule to check against
> > > + * @lsmid: the relevant LSM
> > > *
> > > * Returns 1 if the context id matches the rule, 0 if it does not, and
> > > * -errno on failure.
> > > */
> > > -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
> > > +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, int lsmid);
> > >
> > > /**
> > > * selinux_audit_rule_known - check to see if rule contains selinux fields.
> > > diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> > > index 1eeffc66ea7d..a9fe8d85acae 100644
> > > --- a/security/selinux/ss/services.c
> > > +++ b/security/selinux/ss/services.c
> > > @@ -3487,17 +3487,20 @@ struct selinux_audit_rule {
> > > struct context au_ctxt;
> > > };
> > >
> > > -void selinux_audit_rule_free(void *vrule)
> > > +void selinux_audit_rule_free(void *vrule, int lsmid)
> > > {
> > > struct selinux_audit_rule *rule = vrule;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
> > > + return;
> > > if (rule) {
> > > context_destroy(&rule->au_ctxt);
> > > kfree(rule);
> > > }
> > > }
> > >
> > > -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> > > +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> > > + int lsmid)
> > > {
> > > struct selinux_state *state = &selinux_state;
> > > struct selinux_policy *policy;
> > > @@ -3511,6 +3514,8 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> > >
> > > *rule = NULL;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
> > > + return 0;
> > > if (!selinux_initialized())
> > > return -EOPNOTSUPP;
> > >
> > > @@ -3592,7 +3597,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> > >
> > > err:
> > > rcu_read_unlock();
> > > - selinux_audit_rule_free(tmprule);
> > > + selinux_audit_rule_free(tmprule, LSM_ID_SELINUX);
> > > *rule = NULL;
> > > return rc;
> > > }
> > > @@ -3622,7 +3627,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
> > > return 0;
> > > }
> > >
> > > -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
> > > +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
> > > {
> > > struct selinux_state *state = &selinux_state;
> > > struct selinux_policy *policy;
> > > @@ -3631,6 +3636,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
> > > struct selinux_audit_rule *rule = vrule;
> > > int match = 0;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
> > > + return 0;
> > > if (unlikely(!rule)) {
> > > WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
> > > return -ENOENT;
> > > diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> > > index cd44f7f3f393..4342947f51d8 100644
> > > --- a/security/smack/smack_lsm.c
> > > +++ b/security/smack/smack_lsm.c
> > > @@ -4672,16 +4672,20 @@ static int smack_post_notification(const struct cred *w_cred,
> > > * @op: required testing operator (=, !=, >, <, ...)
> > > * @rulestr: smack label to be audited
> > > * @vrule: pointer to save our own audit rule representation
> > > + * @lsmid: the relevant LSM
> > > *
> > > * Prepare to audit cases where (@field @op @rulestr) is true.
> > > * The label to be audited is created if necessay.
> > > */
> > > -static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
> > > +static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
> > > + int lsmid)
> > > {
> > > struct smack_known *skp;
> > > char **rule = (char **)vrule;
> > > *rule = NULL;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
> > > + return 0;
> > > if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
> > > return -EINVAL;
> > >
> > > @@ -4726,15 +4730,19 @@ static int smack_audit_rule_known(struct audit_krule *krule)
> > > * @field: audit rule flags given from user-space
> > > * @op: required testing operator
> > > * @vrule: smack internal rule presentation
> > > + * @lsmid: the relevant LSM
> > > *
> > > * The core Audit hook. It's used to take the decision of
> > > * whether to audit or not to audit a given object.
> > > */
> > > -static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
> > > +static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
> > > + int lsmid)
> > > {
> > > struct smack_known *skp;
> > > char *rule = vrule;
> > >
> > > + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
> > > + return 0;
> > > if (unlikely(!rule)) {
> > > WARN_ONCE(1, "Smack: missing rule\n");
> > > return -ENOENT;


2024-03-07 18:07:35

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v39 04/42] IMA: avoid label collisions with stacked LSMs

On 3/7/2024 12:15 AM, Roberto Sassu wrote:
> On Wed, 2024-03-06 at 09:04 -0800, Casey Schaufler wrote:
>> On 3/6/2024 2:09 AM, Roberto Sassu wrote:
>>> On Fri, 2023-12-15 at 14:15 -0800, Casey Schaufler wrote:
>>>> Integrity measurement may filter on security module information
>>>> and needs to be clear in the case of multiple active security
>>>> modules which applies. Provide a boot option ima_rules_lsm= to
>>>> allow the user to specify an active security module to apply
>>>> filters to. If not specified, use the first registered module
>>>> that supports the audit_rule_match() LSM hook. Allow the user
>>>> to specify in the IMA policy an lsm= option to specify the
>>>> security module to use for a particular rule.
>>> I was hoping somehow that we can rely on the concept of default LSM
>>> from the LSM infrastructure, so that the extra option would not be
>>> needed.
>> What is the "default LSM"? The first "major LSM"? If you never, ever,
>> under any circumstances want to allow the rules to match an LSM other
>> than that, sure, we can eliminate the option. I'll bet a refreshing
>> beverage that BPF is going to want the option on a system that also
>> has SELinux. Nonetheless, if IMA doesn't want the option I'm willing
>> to leave it out.
> I was more thinking that for existing IMA policies, that would be the
> behavior. New policies would always specify lsm=.
>
> If we want to provide more flexibility, I'm fine with that.

I'm not wedded to providing the ima_rules_lsm= option if you don't
think it's necessary. We could always add it later if it turns out
to be something that actually comes up. Less work for me (and the
reviewers). :) If you really don't care, I'm happy to leave it off.

>
> Roberto
>
>>> Roberto
>>>
>>>> This requires adding the LSM of interest as a parameter
>>>> to three of the audit hooks.
>>>>
>>>> Signed-off-by: Casey Schaufler <[email protected]>
>>>> To: Mimi Zohar <[email protected]>
>>>> To: [email protected]
>>>> To: [email protected]
>>>> ---
>>>> Documentation/ABI/testing/ima_policy | 8 +++-
>>>> include/linux/lsm_hook_defs.h | 7 +--
>>>> include/linux/security.h | 26 +++++++---
>>>> security/apparmor/audit.c | 15 ++++--
>>>> security/apparmor/include/audit.h | 7 +--
>>>> security/integrity/ima/ima_policy.c | 71 ++++++++++++++++++++++++----
>>>> security/security.c | 64 +++++++++++++++++++++----
>>>> security/selinux/include/audit.h | 10 ++--
>>>> security/selinux/ss/services.c | 15 ++++--
>>>> security/smack/smack_lsm.c | 12 ++++-
>>>> 10 files changed, 192 insertions(+), 43 deletions(-)
>>>>
>>>> diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
>>>> index c2385183826c..a59291b97c24 100644
>>>> --- a/Documentation/ABI/testing/ima_policy
>>>> +++ b/Documentation/ABI/testing/ima_policy
>>>> @@ -26,7 +26,7 @@ Description:
>>>> [uid=] [euid=] [gid=] [egid=]
>>>> [fowner=] [fgroup=]]
>>>> lsm: [[subj_user=] [subj_role=] [subj_type=]
>>>> - [obj_user=] [obj_role=] [obj_type=]]
>>>> + [obj_user=] [obj_role=] [obj_type=] [lsm=]]
>>>> option: [digest_type=] [template=] [permit_directio]
>>>> [appraise_type=] [appraise_flag=]
>>>> [appraise_algos=] [keyrings=]
>>>> @@ -138,6 +138,12 @@ Description:
>>>>
>>>> measure subj_user=_ func=FILE_CHECK mask=MAY_READ
>>>>
>>>> + It is possible to explicitly specify which security
>>>> + module a rule applies to using lsm=. If the security
>>>> + module specified is not active on the system the rule
>>>> + will be rejected. If lsm= is not specified the first
>>>> + security module registered on the system will be assumed.
>>>> +
>>>> Example of measure rules using alternate PCRs::
>>>>
>>>> measure func=KEXEC_KERNEL_CHECK pcr=4
>>>> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
>>>> index c925a0d26edf..2159013890aa 100644
>>>> --- a/include/linux/lsm_hook_defs.h
>>>> +++ b/include/linux/lsm_hook_defs.h
>>>> @@ -392,10 +392,11 @@ LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
>>>>
>>>> #ifdef CONFIG_AUDIT
>>>> LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
>>>> - void **lsmrule)
>>>> + void **lsmrule, int lsmid)
>>>> LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
>>>> -LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
>>>> -LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
>>>> +LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule,
>>>> + int lsmid)
>>>> +LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule, int lsmid)
>>>> #endif /* CONFIG_AUDIT */
>>>>
>>>> #ifdef CONFIG_BPF_SYSCALL
>>>> diff --git a/include/linux/security.h b/include/linux/security.h
>>>> index d4103b6cd3fc..2320ed78c4de 100644
>>>> --- a/include/linux/security.h
>>>> +++ b/include/linux/security.h
>>>> @@ -286,6 +286,8 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb);
>>>> extern int security_init(void);
>>>> extern int early_security_init(void);
>>>> extern u64 lsm_name_to_attr(const char *name);
>>>> +extern u64 lsm_name_to_id(const char *name);
>>>> +extern const char *lsm_id_to_name(u64 id);
>>>>
>>>> /* Security operations */
>>>> int security_binder_set_context_mgr(const struct cred *mgr);
>>>> @@ -536,6 +538,16 @@ static inline u64 lsm_name_to_attr(const char *name)
>>>> return LSM_ATTR_UNDEF;
>>>> }
>>>>
>>>> +static inline u64 lsm_name_to_id(const char *name)
>>>> +{
>>>> + return LSM_ID_UNDEF;
>>>> +}
>>>> +
>>>> +static inline const char *lsm_id_to_name(u64 id)
>>>> +{
>>>> + return NULL;
>>>> +}
>>>> +
>>>> static inline void security_free_mnt_opts(void **mnt_opts)
>>>> {
>>>> }
>>>> @@ -2030,25 +2042,27 @@ static inline void security_audit_rule_free(void *lsmrule)
>>>> #endif /* CONFIG_AUDIT */
>>>>
>>>> #if defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY)
>>>> -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
>>>> -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
>>>> -void ima_filter_rule_free(void *lsmrule);
>>>> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
>>>> + int lsmid);
>>>> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
>>>> + int lsmid);
>>>> +void ima_filter_rule_free(void *lsmrule, int lsmid);
>>>>
>>>> #else
>>>>
>>>> static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
>>>> - void **lsmrule)
>>>> + void **lsmrule, int lsmid)
>>>> {
>>>> return 0;
>>>> }
>>>>
>>>> static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
>>>> - void *lsmrule)
>>>> + void *lsmrule, int lsmid)
>>>> {
>>>> return 0;
>>>> }
>>>>
>>>> -static inline void ima_filter_rule_free(void *lsmrule)
>>>> +static inline void ima_filter_rule_free(void *lsmrule, int lsmid)
>>>> { }
>>>>
>>>> #endif /* defined(CONFIG_IMA_LSM_RULES) && defined(CONFIG_SECURITY) */
>>>> diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
>>>> index 45beb1c5f747..0a9f0019355a 100644
>>>> --- a/security/apparmor/audit.c
>>>> +++ b/security/apparmor/audit.c
>>>> @@ -206,10 +206,12 @@ struct aa_audit_rule {
>>>> struct aa_label *label;
>>>> };
>>>>
>>>> -void aa_audit_rule_free(void *vrule)
>>>> +void aa_audit_rule_free(void *vrule, int lsmid)
>>>> {
>>>> struct aa_audit_rule *rule = vrule;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
>>>> + return;
>>>> if (rule) {
>>>> if (!IS_ERR(rule->label))
>>>> aa_put_label(rule->label);
>>>> @@ -217,10 +219,13 @@ void aa_audit_rule_free(void *vrule)
>>>> }
>>>> }
>>>>
>>>> -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>>> +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>>>> + int lsmid)
>>>> {
>>>> struct aa_audit_rule *rule;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
>>>> + return 0;
>>>> switch (field) {
>>>> case AUDIT_SUBJ_ROLE:
>>>> if (op != Audit_equal && op != Audit_not_equal)
>>>> @@ -240,7 +245,7 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>>> GFP_KERNEL, true, false);
>>>> if (IS_ERR(rule->label)) {
>>>> int err = PTR_ERR(rule->label);
>>>> - aa_audit_rule_free(rule);
>>>> + aa_audit_rule_free(rule, LSM_ID_APPARMOR);
>>>> return err;
>>>> }
>>>>
>>>> @@ -264,12 +269,14 @@ int aa_audit_rule_known(struct audit_krule *rule)
>>>> return 0;
>>>> }
>>>>
>>>> -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>>>> +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
>>>> {
>>>> struct aa_audit_rule *rule = vrule;
>>>> struct aa_label *label;
>>>> int found = 0;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_APPARMOR)
>>>> + return 0;
>>>> label = aa_secid_to_label(sid);
>>>>
>>>> if (!label)
>>>> diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
>>>> index acbb03b9bd25..a75c45dd059f 100644
>>>> --- a/security/apparmor/include/audit.h
>>>> +++ b/security/apparmor/include/audit.h
>>>> @@ -199,9 +199,10 @@ static inline int complain_error(int error)
>>>> return error;
>>>> }
>>>>
>>>> -void aa_audit_rule_free(void *vrule);
>>>> -int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
>>>> +void aa_audit_rule_free(void *vrule, int lsmid);
>>>> +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>>>> + int lsmid);
>>>> int aa_audit_rule_known(struct audit_krule *rule);
>>>> -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
>>>> +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid);
>>>>
>>>> #endif /* __AA_AUDIT_H */
>>>> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
>>>> index f69062617754..a563e0478cc6 100644
>>>> --- a/security/integrity/ima/ima_policy.c
>>>> +++ b/security/integrity/ima/ima_policy.c
>>>> @@ -117,6 +117,8 @@ struct ima_rule_entry {
>>>> void *rule; /* LSM file metadata specific */
>>>> char *args_p; /* audit value */
>>>> int type; /* audit type */
>>>> + int lsm_id; /* which LSM rule applies to */
>>>> + bool lsm_specific; /* true if lsm is specified */
>>>> } lsm[MAX_LSM_RULES];
>>>> char *fsname;
>>>> struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */
>>>> @@ -309,6 +311,25 @@ static int __init default_appraise_policy_setup(char *str)
>>>> }
>>>> __setup("ima_appraise_tcb", default_appraise_policy_setup);
>>>>
>>>> +static int default_rules_lsm __ro_after_init = LSM_ID_UNDEF;
>>>> +
>>>> +static int __init ima_rules_lsm_init(char *str)
>>>> +{
>>>> + int newdrl;
>>>> +
>>>> + newdrl = lsm_name_to_id(str);
>>>> + if (newdrl >= 0) {
>>>> + default_rules_lsm = newdrl;
>>>> + return 1;
>>>> + }
>>>> +
>>>> + pr_err("default ima rule lsm \"%s\" not registered, value unchanged.",
>>>> + str);
>>>> +
>>>> + return 1;
>>>> +}
>>>> +__setup("ima_rules_lsm=", ima_rules_lsm_init);
>>>> +
>>>> static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
>>>> {
>>>> struct ima_rule_opt_list *opt_list;
>>>> @@ -380,7 +401,8 @@ static void ima_lsm_free_rule(struct ima_rule_entry *entry)
>>>> int i;
>>>>
>>>> for (i = 0; i < MAX_LSM_RULES; i++) {
>>>> - ima_filter_rule_free(entry->lsm[i].rule);
>>>> + ima_filter_rule_free(entry->lsm[i].rule,
>>>> + entry->lsm[i].lsm_id);
>>>> kfree(entry->lsm[i].args_p);
>>>> }
>>>> }
>>>> @@ -425,7 +447,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
>>>>
>>>> ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
>>>> nentry->lsm[i].args_p,
>>>> - &nentry->lsm[i].rule);
>>>> + &nentry->lsm[i].rule,
>>>> + entry->lsm[i].lsm_id);
>>>> if (!nentry->lsm[i].rule)
>>>> pr_warn("rule for LSM \'%s\' is undefined\n",
>>>> nentry->lsm[i].args_p);
>>>> @@ -451,7 +474,8 @@ static int ima_lsm_update_rule(struct ima_rule_entry *entry)
>>>> * be owned by nentry.
>>>> */
>>>> for (i = 0; i < MAX_LSM_RULES; i++)
>>>> - ima_filter_rule_free(entry->lsm[i].rule);
>>>> + ima_filter_rule_free(entry->lsm[i].rule,
>>>> + entry->lsm[i].lsm_id);
>>>> kfree(entry);
>>>>
>>>> return 0;
>>>> @@ -650,14 +674,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
>>>> security_inode_getsecid(inode, &osid);
>>>> rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type,
>>>> Audit_equal,
>>>> - lsm_rule->lsm[i].rule);
>>>> + lsm_rule->lsm[i].rule,
>>>> + lsm_rule->lsm[i].lsm_id);
>>>> break;
>>>> case LSM_SUBJ_USER:
>>>> case LSM_SUBJ_ROLE:
>>>> case LSM_SUBJ_TYPE:
>>>> rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type,
>>>> Audit_equal,
>>>> - lsm_rule->lsm[i].rule);
>>>> + lsm_rule->lsm[i].rule,
>>>> + lsm_rule->lsm[i].lsm_id);
>>>> break;
>>>> default:
>>>> break;
>>>> @@ -680,7 +706,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
>>>> out:
>>>> if (rule_reinitialized) {
>>>> for (i = 0; i < MAX_LSM_RULES; i++)
>>>> - ima_filter_rule_free(lsm_rule->lsm[i].rule);
>>>> + ima_filter_rule_free(lsm_rule->lsm[i].rule,
>>>> + lsm_rule->lsm[i].lsm_id);
>>>> kfree(lsm_rule);
>>>> }
>>>> return result;
>>>> @@ -1073,7 +1100,7 @@ enum policy_opt {
>>>> Opt_digest_type,
>>>> Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
>>>> Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
>>>> - Opt_label, Opt_err
>>>> + Opt_lsm, Opt_label, Opt_err
>>>> };
>>>>
>>>> static const match_table_t policy_tokens = {
>>>> @@ -1121,6 +1148,7 @@ static const match_table_t policy_tokens = {
>>>> {Opt_pcr, "pcr=%s"},
>>>> {Opt_template, "template=%s"},
>>>> {Opt_keyrings, "keyrings=%s"},
>>>> + {Opt_lsm, "lsm=%s"},
>>>> {Opt_label, "label=%s"},
>>>> {Opt_err, NULL}
>>>> };
>>>> @@ -1140,7 +1168,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
>>>> entry->lsm[lsm_rule].type = audit_type;
>>>> result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal,
>>>> entry->lsm[lsm_rule].args_p,
>>>> - &entry->lsm[lsm_rule].rule);
>>>> + &entry->lsm[lsm_rule].rule,
>>>> + entry->lsm[lsm_rule].lsm_id);
>>>> if (!entry->lsm[lsm_rule].rule) {
>>>> pr_warn("rule for LSM \'%s\' is undefined\n",
>>>> entry->lsm[lsm_rule].args_p);
>>>> @@ -1878,6 +1907,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
>>>> &(template_desc->num_fields));
>>>> entry->template = template_desc;
>>>> break;
>>>> + case Opt_lsm: {
>>>> + int i;
>>>> +
>>>> + result = lsm_name_to_id(args[0].from);
>>>> + if (result < 0) {
>>>> + for (i = 0; i < MAX_LSM_RULES; i++)
>>>> + entry->lsm[i].args_p = NULL;
>>>> + result = -EINVAL;
>>>> + break;
>>>> + }
>>>> + for (i = 0; i < MAX_LSM_RULES; i++) {
>>>> + entry->lsm[i].lsm_id = result;
>>>> + entry->lsm[i].lsm_specific = true;
>>>> + }
>>>> + result = 0;
>>>> + break;
>>>> + }
>>>> case Opt_err:
>>>> ima_log_string(ab, "UNKNOWN", p);
>>>> result = -EINVAL;
>>>> @@ -1923,6 +1969,7 @@ ssize_t ima_parse_add_rule(char *rule)
>>>> struct ima_rule_entry *entry;
>>>> ssize_t result, len;
>>>> int audit_info = 0;
>>>> + int i;
>>>>
>>>> p = strsep(&rule, "\n");
>>>> len = strlen(p) + 1;
>>>> @@ -1940,6 +1987,11 @@ ssize_t ima_parse_add_rule(char *rule)
>>>>
>>>> INIT_LIST_HEAD(&entry->list);
>>>>
>>>> + for (i = 0; i < MAX_LSM_RULES; i++) {
>>>> + entry->lsm[i].lsm_id = default_rules_lsm;
>>>> + entry->lsm[i].lsm_specific = false;
>>>> + }
>>>> +
>>>> result = ima_parse_rule(p, entry);
>>>> if (result) {
>>>> ima_free_rule(entry);
>>>> @@ -2251,6 +2303,9 @@ int ima_policy_show(struct seq_file *m, void *v)
>>>> entry->lsm[i].args_p);
>>>> break;
>>>> }
>>>> + if (entry->lsm[i].lsm_specific)
>>>> + seq_printf(m, pt(Opt_lsm),
>>>> + lsm_id_to_name(entry->lsm[i].lsm_id));
>>>> seq_puts(m, " ");
>>>> }
>>>> }
>>>> diff --git a/security/security.c b/security/security.c
>>>> index 0a51e3d23570..cdf9ee12b064 100644
>>>> --- a/security/security.c
>>>> +++ b/security/security.c
>>>> @@ -271,6 +271,46 @@ static void __init initialize_lsm(struct lsm_info *lsm)
>>>> u32 lsm_active_cnt __ro_after_init;
>>>> const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT];
>>>>
>>>> +/**
>>>> + * lsm_name_to_id - get the LSM ID for a registered LSM
>>>> + * @name: the name of the LSM
>>>> + *
>>>> + * Returns the LSM ID associated with the named LSM or
>>>> + * LSM_ID_UNDEF if the name isn't recongnized.
>>>> + */
>>>> +u64 lsm_name_to_id(const char *name)
>>>> +{
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
>>>> + if (!lsm_idlist[i]->name)
>>>> + return LSM_ID_UNDEF;
>>>> + if (!strcmp(name, lsm_idlist[i]->name))
>>>> + return lsm_idlist[i]->id;
>>>> + }
>>>> + return LSM_ID_UNDEF;
>>>> +}
>>>> +
>>>> +/**
>>>> + * lsm_id_to_name - get the LSM name for a registered LSM ID
>>>> + * @id: the ID of the LSM
>>>> + *
>>>> + * Returns the LSM name associated with the LSM ID or
>>>> + * NULL if the ID isn't recongnized.
>>>> + */
>>>> +const char *lsm_id_to_name(u64 id)
>>>> +{
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < LSM_CONFIG_COUNT; i++) {
>>>> + if (!lsm_idlist[i]->name)
>>>> + return NULL;
>>>> + if (id == lsm_idlist[i]->id)
>>>> + return lsm_idlist[i]->name;
>>>> + }
>>>> + return NULL;
>>>> +}
>>>> +
>>>> /* Populate ordered LSMs list from comma-separated LSM name list. */
>>>> static void __init ordered_lsm_parse(const char *order, const char *origin)
>>>> {
>>>> @@ -5336,7 +5376,8 @@ int security_key_getsecurity(struct key *key, char **buffer)
>>>> */
>>>> int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>>>> {
>>>> - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
>>>> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
>>>> + LSM_ID_UNDEF);
>>>> }
>>>>
>>>> /**
>>>> @@ -5362,7 +5403,7 @@ int security_audit_rule_known(struct audit_krule *krule)
>>>> */
>>>> void security_audit_rule_free(void *lsmrule)
>>>> {
>>>> - call_void_hook(audit_rule_free, lsmrule);
>>>> + call_void_hook(audit_rule_free, lsmrule, LSM_ID_UNDEF);
>>>> }
>>>>
>>>> /**
>>>> @@ -5380,7 +5421,8 @@ void security_audit_rule_free(void *lsmrule)
>>>> */
>>>> int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>>>> {
>>>> - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
>>>> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
>>>> + LSM_ID_UNDEF);
>>>> }
>>>> #endif /* CONFIG_AUDIT */
>>>>
>>>> @@ -5389,19 +5431,23 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>>>> * The integrity subsystem uses the same hooks as
>>>> * the audit subsystem.
>>>> */
>>>> -int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>>>> +int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
>>>> + int lsmid)
>>>> {
>>>> - return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
>>>> + return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule,
>>>> + lsmid);
>>>> }
>>>>
>>>> -void ima_filter_rule_free(void *lsmrule)
>>>> +void ima_filter_rule_free(void *lsmrule, int lsmid)
>>>> {
>>>> - call_void_hook(audit_rule_free, lsmrule);
>>>> + call_void_hook(audit_rule_free, lsmrule, lsmid);
>>>> }
>>>>
>>>> -int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
>>>> +int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
>>>> + int lsmid)
>>>> {
>>>> - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
>>>> + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
>>>> + lsmid);
>>>> }
>>>> #endif /* CONFIG_IMA_LSM_RULES */
>>>>
>>>> diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
>>>> index d5495134a5b9..59468baf0c91 100644
>>>> --- a/security/selinux/include/audit.h
>>>> +++ b/security/selinux/include/audit.h
>>>> @@ -21,21 +21,24 @@
>>>> * @op: the operator the rule uses
>>>> * @rulestr: the text "target" of the rule
>>>> * @rule: pointer to the new rule structure returned via this
>>>> + * @lsmid: the relevant LSM
>>>> *
>>>> * Returns 0 if successful, -errno if not. On success, the rule structure
>>>> * will be allocated internally. The caller must free this structure with
>>>> * selinux_audit_rule_free() after use.
>>>> */
>>>> -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
>>>> +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
>>>> + int lsmid);
>>>>
>>>> /**
>>>> * selinux_audit_rule_free - free an selinux audit rule structure.
>>>> * @rule: pointer to the audit rule to be freed
>>>> + * @lsmid: which LSM this rule relates to
>>>> *
>>>> * This will free all memory associated with the given rule.
>>>> * If @rule is NULL, no operation is performed.
>>>> */
>>>> -void selinux_audit_rule_free(void *rule);
>>>> +void selinux_audit_rule_free(void *rule, int lsmid);
>>>>
>>>> /**
>>>> * selinux_audit_rule_match - determine if a context ID matches a rule.
>>>> @@ -43,11 +46,12 @@ void selinux_audit_rule_free(void *rule);
>>>> * @field: the field this rule refers to
>>>> * @op: the operator the rule uses
>>>> * @rule: pointer to the audit rule to check against
>>>> + * @lsmid: the relevant LSM
>>>> *
>>>> * Returns 1 if the context id matches the rule, 0 if it does not, and
>>>> * -errno on failure.
>>>> */
>>>> -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
>>>> +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, int lsmid);
>>>>
>>>> /**
>>>> * selinux_audit_rule_known - check to see if rule contains selinux fields.
>>>> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
>>>> index 1eeffc66ea7d..a9fe8d85acae 100644
>>>> --- a/security/selinux/ss/services.c
>>>> +++ b/security/selinux/ss/services.c
>>>> @@ -3487,17 +3487,20 @@ struct selinux_audit_rule {
>>>> struct context au_ctxt;
>>>> };
>>>>
>>>> -void selinux_audit_rule_free(void *vrule)
>>>> +void selinux_audit_rule_free(void *vrule, int lsmid)
>>>> {
>>>> struct selinux_audit_rule *rule = vrule;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
>>>> + return;
>>>> if (rule) {
>>>> context_destroy(&rule->au_ctxt);
>>>> kfree(rule);
>>>> }
>>>> }
>>>>
>>>> -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>>> +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>>>> + int lsmid)
>>>> {
>>>> struct selinux_state *state = &selinux_state;
>>>> struct selinux_policy *policy;
>>>> @@ -3511,6 +3514,8 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>>>
>>>> *rule = NULL;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
>>>> + return 0;
>>>> if (!selinux_initialized())
>>>> return -EOPNOTSUPP;
>>>>
>>>> @@ -3592,7 +3597,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>>>
>>>> err:
>>>> rcu_read_unlock();
>>>> - selinux_audit_rule_free(tmprule);
>>>> + selinux_audit_rule_free(tmprule, LSM_ID_SELINUX);
>>>> *rule = NULL;
>>>> return rc;
>>>> }
>>>> @@ -3622,7 +3627,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
>>>> return 0;
>>>> }
>>>>
>>>> -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>>>> +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int lsmid)
>>>> {
>>>> struct selinux_state *state = &selinux_state;
>>>> struct selinux_policy *policy;
>>>> @@ -3631,6 +3636,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>>>> struct selinux_audit_rule *rule = vrule;
>>>> int match = 0;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SELINUX)
>>>> + return 0;
>>>> if (unlikely(!rule)) {
>>>> WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
>>>> return -ENOENT;
>>>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>>>> index cd44f7f3f393..4342947f51d8 100644
>>>> --- a/security/smack/smack_lsm.c
>>>> +++ b/security/smack/smack_lsm.c
>>>> @@ -4672,16 +4672,20 @@ static int smack_post_notification(const struct cred *w_cred,
>>>> * @op: required testing operator (=, !=, >, <, ...)
>>>> * @rulestr: smack label to be audited
>>>> * @vrule: pointer to save our own audit rule representation
>>>> + * @lsmid: the relevant LSM
>>>> *
>>>> * Prepare to audit cases where (@field @op @rulestr) is true.
>>>> * The label to be audited is created if necessay.
>>>> */
>>>> -static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>>>> +static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
>>>> + int lsmid)
>>>> {
>>>> struct smack_known *skp;
>>>> char **rule = (char **)vrule;
>>>> *rule = NULL;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
>>>> + return 0;
>>>> if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
>>>> return -EINVAL;
>>>>
>>>> @@ -4726,15 +4730,19 @@ static int smack_audit_rule_known(struct audit_krule *krule)
>>>> * @field: audit rule flags given from user-space
>>>> * @op: required testing operator
>>>> * @vrule: smack internal rule presentation
>>>> + * @lsmid: the relevant LSM
>>>> *
>>>> * The core Audit hook. It's used to take the decision of
>>>> * whether to audit or not to audit a given object.
>>>> */
>>>> -static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
>>>> +static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
>>>> + int lsmid)
>>>> {
>>>> struct smack_known *skp;
>>>> char *rule = vrule;
>>>>
>>>> + if (lsmid != LSM_ID_UNDEF || lsmid != LSM_ID_SMACK)
>>>> + return 0;
>>>> if (unlikely(!rule)) {
>>>> WARN_ONCE(1, "Smack: missing rule\n");
>>>> return -ENOENT;
>