Hello,
This is an updated patch to collect the SID of a user process sending
audit messages while running in its context and then converting it into
the corresponding security label once the audit message is received in a
kernel context for logging purposes.
This patch:
1) Augments the LSM interface to retrieve a task's SID and scraps the
incorrect usage of security_task_getsid (Thanks Stephen ;)).
2) Uses a portion of the James Morris' SELinux API to give the ability
to easily convert a SID into a security label / SELinux context.
http://people.redhat.com/jmorris/selinux/skfilter/kernel/12-skfilter-seli...
Thanks. Comments and feedback welcome.
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 6a2ccf7..ccd5905 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -143,6 +143,7 @@ struct netlink_skb_parms
__u32 dst_group;
kernel_cap_t eff_cap;
__u32 loginuid; /* Login (audit) uid */
+ __u32 secid; /* SELinux security id */
};
#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))
diff --git a/include/linux/security.h b/include/linux/security.h
index b4fe8aa..bed528c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -625,6 +625,11 @@ struct swap_info_struct;
* @p contains the task_struct for the task.
* @inode contains the inode structure for the inode.
*
+ * @task_getsecid:
+ * Get the SID (security id) of a task.
+ * @tsk contains the task_struct for the task
+ * @sid is storage for task SID
+ *
* Security hooks for Netlink messaging.
*
* @netlink_send:
@@ -1169,6 +1174,7 @@ struct security_operations {
unsigned long arg5);
void (*task_reparent_to_init) (struct task_struct * p);
void (*task_to_inode)(struct task_struct *p, struct inode *inode);
+ int (*task_getsecid)(struct task_struct *tsk, __u32 *sid);
int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
@@ -1817,6 +1823,11 @@ static inline void security_task_to_inod
security_ops->task_to_inode(p, inode);
}
+static inline int security_task_getsecid(struct task_struct *tsk, __u32 *sid)
+{
+ return security_ops->task_getsecid(tsk, sid);
+}
+
static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
short flag)
{
@@ -2457,6 +2468,11 @@ static inline void security_task_reparen
static inline void security_task_to_inode(struct task_struct *p, struct inode *inode)
{ }
+static inline int security_task_getsecid(struct task_struct *tsk, __u32 *sid)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
short flag)
{
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
new file mode 100644
index 0000000..7da2da3
--- /dev/null
+++ b/include/linux/selinux.h
@@ -0,0 +1,70 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris(a)redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_SELINUX_H
+#define _LINUX_SELINUX_H
+
+#ifdef CONFIG_SECURITY_SELINUX
+
+struct sock;
+
+/**
+ * selinux_available - check if SELinux is available for use.
+ *
+ * Returns true if configured, enabled, not disabled and policy loaded.
+ */
+int selinux_available(void);
+
+/**
+ * selinux_ctx_to_id - map a security context string to an ID
+ * @ctx: the security context string to be mapped
+ * @ctxid: ID value returned via this.
+ *
+ * Returns 0 if successful, with the ID stored in ctxid. A value
+ * of zero for the ctxid indicates no ID could be determined (but
+ * no error occurred). Otherwise, this value should only be used
+ * opaquely (e.g. compare with value from selinux_sk_ctxid())
+ */
+int selinux_ctx_to_id(const char *ctx, u32 *ctxid);
+
+/**
+ * selinux_id_to_ctx - map a security context ID to a string
+ * @ctxid: security context ID to be converted.
+ * @ctx: address of context string to be returned
+ * @ctxlen: length of returned context string.
+ *
+ * Returns 0 if successful, -errno if not. On success, the context
+ * string will be allocated internally, and the caller must call
+ * kfree() on it after use.
+ */
+int selinux_id_to_ctx(u32 ctxid, char **ctx, u32 *ctxlen);
+
+#else
+
+static inline int selinux_available(void)
+{
+ return 0;
+}
+
+static inline int selinux_ctx_to_id(const char *ctx, u32 *ctxid)
+{
+ *ctxid = 0;
+ return 0;
+}
+
+static inline int selinux_id_to_ctx(u32 ctxid, char **ctx, u32 *ctxlen)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SECURITY_SELINUX */
+
+#endif /* _LINUX_SELINUX_H */
diff --git a/kernel/audit.c b/kernel/audit.c
index d95efd6..129b3da 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -50,6 +50,7 @@
#include <linux/kthread.h>
#include <linux/audit.h>
+#include <linux/selinux.h>
#include <net/sock.h>
#include <linux/skbuff.h>
@@ -383,7 +384,7 @@ static int audit_netlink_ok(kernel_cap_t
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
- u32 uid, pid, seq;
+ u32 uid, pid, sid, seq;
void *data;
struct audit_status *status_get, status_set;
int err;
@@ -391,6 +392,8 @@ static int audit_receive_msg(struct sk_b
u16 msg_type = nlh->nlmsg_type;
uid_t loginuid; /* loginuid of sender */
struct audit_sig_info sig_data;
+ char * ctx = NULL;
+ u32 len;
err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);
if (err)
@@ -409,6 +412,7 @@ static int audit_receive_msg(struct sk_b
pid = NETLINK_CREDS(skb)->pid;
uid = NETLINK_CREDS(skb)->uid;
loginuid = NETLINK_CB(skb).loginuid;
+ sid = NETLINK_CB(skb).secid;
seq = nlh->nlmsg_seq;
data = NLMSG_DATA(nlh);
@@ -460,11 +464,17 @@ static int audit_receive_msg(struct sk_b
err = 0;
ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
if (ab) {
+ if (selinux_available()) {
+ err = selinux_id_to_ctx(sid, &ctx, &len);
+ if (err < 0)
+ return err;
+ }
audit_log_format(ab,
- "user pid=%d uid=%u auid=%u msg='%.1024s'",
- pid, uid, loginuid, (char *)data);
+ "user pid=%d uid=%u auid=%u subj=%s msg='%.1024s'",
+ pid, uid, loginuid, ctx ? ctx : "null", (char *)data);
audit_set_pid(ab, pid);
audit_log_end(ab);
+ kfree(ctx);
}
}
break;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 96020d7..8b9eff4 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1120,6 +1120,9 @@ static int netlink_sendmsg(struct kiocb
NETLINK_CB(skb).dst_pid = dst_pid;
NETLINK_CB(skb).dst_group = dst_group;
NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
+ err = security_task_getsecid(current, &NETLINK_CB(skb).secid);
+ if (err < 0 && err != -EOPNOTSUPP)
+ goto out;
memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
/* What can I do? Netlink is asynchronous, so that
diff --git a/security/dummy.c b/security/dummy.c
index 75e7c4a..ef32c87 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -557,6 +557,11 @@ static void dummy_task_reparent_to_init
static void dummy_task_to_inode(struct task_struct *p, struct inode *inode)
{ }
+static int dummy_task_getsecid(struct task_struct *tsk, __u32 *sid)
+{
+ return -EOPNOTSUPP;
+}
+
static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
{
return 0;
@@ -934,6 +939,7 @@ void security_fixup_ops (struct security
set_to_dummy_if_null(ops, task_prctl);
set_to_dummy_if_null(ops, task_reparent_to_init);
set_to_dummy_if_null(ops, task_to_inode);
+ set_to_dummy_if_null(ops, task_getsecid);
set_to_dummy_if_null(ops, ipc_permission);
set_to_dummy_if_null(ops, ipc_getsecurity);
set_to_dummy_if_null(ops, msg_msg_alloc_security);
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index b038cd0..3e3d4eb 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
-selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o
+selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o exports.o
selinux-$(CONFIG_SECURITY_NETWORK) += netif.o
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
new file mode 100644
index 0000000..4dc7405
--- /dev/null
+++ b/security/selinux/exports.c
@@ -0,0 +1,38 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris(a)redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/selinux.h>
+
+#include "security.h"
+
+extern int ss_initialized;
+
+int selinux_available(void)
+{
+ return ss_initialized;
+}
+
+int selinux_ctx_to_id(const char *ctx, u32 *ctxid)
+{
+ return security_context_to_sid(ctx, strlen(ctx), ctxid);
+}
+
+int selinux_id_to_ctx(u32 ctxid, char **ctx, u32 *ctxlen)
+{
+ return security_sid_to_context(ctxid, ctx, ctxlen);
+}
+
+EXPORT_SYMBOL_GPL(selinux_available);
+EXPORT_SYMBOL_GPL(selinux_ctx_to_id);
+EXPORT_SYMBOL_GPL(selinux_id_to_ctx);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 21c8aa6..ae9b097 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2769,6 +2769,13 @@ static void selinux_task_to_inode(struct
return;
}
+static int selinux_task_getsecid(struct task_struct *tsk)
+{
+ struct task_security_struct *tsec = tsk->security;
+
+ return tsec->sid;
+}
+
#ifdef CONFIG_SECURITY_NETWORK
/* Returns error only if unable to parse addresses */
@@ -4319,6 +4326,7 @@ static struct security_operations selinu
.task_prctl = selinux_task_prctl,
.task_reparent_to_init = selinux_task_reparent_to_init,
.task_to_inode = selinux_task_to_inode,
+ .task_getsecid = selinux_task_getsecid,
.ipc_permission = selinux_ipc_permission,
.ipc_getsecurity = selinux_ipc_getsecurity,
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 5f016c9..a2e5bb0 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -63,7 +63,7 @@ int security_change_sid(u32 ssid, u32 ts
int security_sid_to_context(u32 sid, char **scontext,
u32 *scontext_len);
-int security_context_to_sid(char *scontext, u32 scontext_len,
+int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid);
int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sid, u32
def_sid);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 2311255..c66f765 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -617,7 +617,7 @@ out:
}
-static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32
def_sid)
+static int security_context_to_sid_core(const char *scontext, u32 scontext_len, u32 *sid,
u32 def_sid)
{
char *scontext2;
struct context context;
@@ -743,7 +743,7 @@ out:
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
sid, SECSID_NULL);