Inter-revision diff: patch 25

Comparing v5 (message) to v33 (message)

--- v5
+++ v33
@@ -1,412 +1,142 @@
-The getsockopt SO_PEERSEC provides the LSM based security
-information for a single module, but for reasons of backward
-compatibility cannot include the information for multiple
-modules. A new option SO_PEERCONTEXT is added to report the
-security "context" of multiple modules using a "compound" format
+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.
 
-	lsm1\0value\0lsm2\0value\0
-
-This is expected to be used by system services, including dbus-daemon.
-
+Suggested-by: Paul Moore <paul@paul-moore.com>
 Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
 ---
- arch/alpha/include/uapi/asm/socket.h  |  1 +
- arch/mips/include/uapi/asm/socket.h   |  1 +
- arch/parisc/include/uapi/asm/socket.h |  1 +
- arch/sparc/include/uapi/asm/socket.h  |  1 +
- include/linux/lsm_hooks.h             |  9 ++-
- include/linux/security.h              | 10 ++-
- include/uapi/asm-generic/socket.h     |  1 +
- net/core/sock.c                       |  7 +-
- security/apparmor/lsm.c               | 20 ++----
- security/security.c                   | 94 ++++++++++++++++++++++++---
- security/selinux/hooks.c              | 20 ++----
- security/smack/smack_lsm.c            | 31 ++++-----
- 12 files changed, 134 insertions(+), 62 deletions(-)
+ kernel/audit.c | 53 +++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 35 insertions(+), 18 deletions(-)
 
-diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
-index 976e89b116e5..019e5fa8bcda 100644
---- a/arch/alpha/include/uapi/asm/socket.h
-+++ b/arch/alpha/include/uapi/asm/socket.h
-@@ -121,6 +121,7 @@
+diff --git a/kernel/audit.c b/kernel/audit.c
+index f012c3786264..4713e66a12af 100644
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -197,8 +197,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;
+ };
  
- #define SO_RCVTIMEO_NEW         66
- #define SO_SNDTIMEO_NEW         67
-+#define SO_PEERCONTEXT          68
+@@ -1744,7 +1746,6 @@ static void audit_buffer_free(struct audit_buffer *ab)
+ 	if (!ab)
+ 		return;
  
- #if !defined(__KERNEL__)
+-	kfree_skb(ab->skb);
+ 	kmem_cache_free(audit_buffer_cache, ab);
+ }
  
-diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
-index d41765cfbc6e..df8d984d76ed 100644
---- a/arch/mips/include/uapi/asm/socket.h
-+++ b/arch/mips/include/uapi/asm/socket.h
-@@ -132,6 +132,7 @@
+@@ -1760,11 +1761,15 @@ static struct audit_buffer *audit_buffer_alloc(struct audit_context *ctx,
+ 	ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
+ 	if (!ab->skb)
+ 		goto err;
+-	if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
++	if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0)) {
++		kfree_skb(ab->skb);
+ 		goto err;
++	}
  
- #define SO_RCVTIMEO_NEW         66
- #define SO_SNDTIMEO_NEW         67
-+#define SO_PEERCONTEXT          68
+ 	ab->ctx = ctx;
+ 	ab->gfp_mask = gfp_mask;
++	skb_queue_head_init(&ab->skb_list);
++	skb_queue_tail(&ab->skb_list, ab->skb);
  
- #if !defined(__KERNEL__)
+ 	return ab;
  
-diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
-index 66c5dd245ac7..9ae358309f46 100644
---- a/arch/parisc/include/uapi/asm/socket.h
-+++ b/arch/parisc/include/uapi/asm/socket.h
-@@ -113,6 +113,7 @@
+@@ -1825,7 +1830,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;
  
- #define SO_RCVTIMEO_NEW         0x4040
- #define SO_SNDTIMEO_NEW         0x4041
-+#define SO_PEERCONTEXT          0x4042
+ 	if (audit_initialized != AUDIT_INITIALIZED)
+ 		return NULL;
+@@ -1880,14 +1884,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
+ 		return NULL;
+ 	}
  
- #if !defined(__KERNEL__)
+-	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);
  
-diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
-index 9265a9eece15..e8a53ef65210 100644
---- a/arch/sparc/include/uapi/asm/socket.h
-+++ b/arch/sparc/include/uapi/asm/socket.h
-@@ -114,6 +114,7 @@
- 
- #define SO_RCVTIMEO_NEW          0x0044
- #define SO_SNDTIMEO_NEW          0x0045
-+#define SO_PEERCONTEXT           0x0046
- 
- #if !defined(__KERNEL__)
- 
-diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
-index 33e5ab4af9f8..b0f788bf82b6 100644
---- a/include/linux/lsm_hooks.h
-+++ b/include/linux/lsm_hooks.h
-@@ -864,8 +864,8 @@
-  *	SO_GETPEERSEC.  For tcp sockets this can be meaningful if the
-  *	socket is associated with an ipsec SA.
-  *	@sock is the local socket.
-- *	@optval userspace memory where the security state is to be copied.
-- *	@optlen userspace int where the module should copy the actual length
-+ *	@optval memory where the security state is to be copied.
-+ *	@optlen int where the module should copy the actual length
-  *	of the security state.
-  *	@len as input is the maximum length to copy to userspace provided
-  *	by the caller.
-@@ -1697,9 +1697,8 @@ union security_list_options {
- 	int (*socket_setsockopt)(struct socket *sock, int level, int optname);
- 	int (*socket_shutdown)(struct socket *sock, int how);
- 	int (*socket_sock_rcv_skb)(struct sock *sk, struct sk_buff *skb);
--	int (*socket_getpeersec_stream)(struct socket *sock,
--					char __user *optval,
--					int __user *optlen, unsigned len);
-+	int (*socket_getpeersec_stream)(struct socket *sock, char **optval,
-+					int *optlen, unsigned len);
- 	int (*socket_getpeersec_dgram)(struct socket *sock,
- 					struct sk_buff *skb, u32 *secid);
- 	int (*sk_alloc_security)(struct sock *sk, int family, gfp_t priority);
-diff --git a/include/linux/security.h b/include/linux/security.h
-index 12f6d5fcbf6a..0665a27a2891 100644
---- a/include/linux/security.h
-+++ b/include/linux/security.h
-@@ -130,6 +130,7 @@ struct lsmblob {
- #define LSMBLOB_NOT_NEEDED	-3	/* Slot not requested */
- #define LSMBLOB_DISPLAY		-4	/* Use the "display" slot */
- #define LSMBLOB_FIRST		-5	/* Use the default "display" slot */
-+#define LSMBLOB_COMPOUND	-6	/* A compound "display" */
+ 	return ab;
+ }
+@@ -2378,26 +2382,19 @@ int audit_signal_info(int sig, struct task_struct *t)
+ }
  
  /**
-  * lsmblob_init - initialize an lsmblob structure.
-@@ -1324,7 +1325,8 @@ int security_socket_setsockopt(struct socket *sock, int level, int optname);
- int security_socket_shutdown(struct socket *sock, int how);
- int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
- int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
--				      int __user *optlen, unsigned len);
-+				      int __user *optlen, unsigned len,
-+				      int display);
- int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
- 				     struct lsmblob *blob);
- int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
-@@ -1458,8 +1460,10 @@ static inline int security_sock_rcv_skb(struct sock *sk,
- 	return 0;
- }
+- * audit_log_end - end one audit record
+- * @ab: the audit_buffer
++ * __audit_log_end - end one audit record
++ * @skb: the buffer to send
+  *
+  * 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)
++static void __audit_log_end(struct sk_buff *skb)
+ {
+-	struct sk_buff *skb;
+ 	struct nlmsghdr *nlh;
  
--static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
--						    int __user *optlen, unsigned len)
-+static inline int security_socket_getpeersec_stream(struct socket *sock,
-+						    char __user *optval,
-+						    int __user *optlen,
-+						    unsigned len, int display)
- {
- 	return -ENOPROTOOPT;
- }
-diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
-index 8c1391c89171..b38d080c2802 100644
---- a/include/uapi/asm-generic/socket.h
-+++ b/include/uapi/asm-generic/socket.h
-@@ -116,6 +116,7 @@
+-	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);
+@@ -2408,6 +2405,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);
  
- #define SO_RCVTIMEO_NEW         66
- #define SO_SNDTIMEO_NEW         67
-+#define SO_PEERCONTEXT          68
- 
- #if !defined(__KERNEL__)
- 
-diff --git a/net/core/sock.c b/net/core/sock.c
-index 782343bb925b..b0955a34167c 100644
---- a/net/core/sock.c
-+++ b/net/core/sock.c
-@@ -1412,7 +1412,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
- 		break;
- 
- 	case SO_PEERSEC:
--		return security_socket_getpeersec_stream(sock, optval, optlen, len);
-+		return security_socket_getpeersec_stream(sock, optval, optlen,
-+							 len, LSMBLOB_DISPLAY);
-+
-+	case SO_PEERCONTEXT:
-+		return security_socket_getpeersec_stream(sock, optval, optlen,
-+							 len, LSMBLOB_COMPOUND);
- 
- 	case SO_MARK:
- 		v.val = sk->sk_mark;
-diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
-index ec2e39aa9a84..5d25959610f9 100644
---- a/security/apparmor/lsm.c
-+++ b/security/apparmor/lsm.c
-@@ -1037,10 +1037,8 @@ static struct aa_label *sk_peer_label(struct sock *sk)
-  *
-  * Note: for tcp only valid if using ipsec or cipso on lan
-  */
--static int apparmor_socket_getpeersec_stream(struct socket *sock,
--					     char __user *optval,
--					     int __user *optlen,
--					     unsigned int len)
-+static int apparmor_socket_getpeersec_stream(struct socket *sock, char **optval,
-+					     int *optlen, unsigned int len)
- {
- 	char *name;
- 	int slen, error = 0;
-@@ -1060,17 +1058,11 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
- 	if (slen < 0) {
- 		error = -ENOMEM;
- 	} else {
--		if (slen > len) {
-+		if (slen > len)
- 			error = -ERANGE;
--		} else if (copy_to_user(optval, name, slen)) {
--			error = -EFAULT;
--			goto out;
--		}
--		if (put_user(slen, optlen))
--			error = -EFAULT;
--out:
--		kfree(name);
--
-+		else
-+			*optval = name;
-+		*optlen = slen;
- 	}
- 
- done:
-diff --git a/security/security.c b/security/security.c
-index 9e5e3ebd169d..5551c146c035 100644
---- a/security/security.c
-+++ b/security/security.c
-@@ -2126,8 +2126,8 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
- 	hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
- 		if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
- 			continue;
--		if (lsm == NULL && *display != LSMBLOB_INVALID &&
--		    *display != hp->lsmid->slot)
-+		if (lsm == NULL && display != NULL &&
-+		    *display != LSMBLOB_INVALID && *display != hp->lsmid->slot)
- 			continue;
- 		return hp->hook.setprocattr(name, value, size);
- 	}
-@@ -2351,17 +2351,91 @@ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
- EXPORT_SYMBOL(security_sock_rcv_skb);
- 
- int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
--				      int __user *optlen, unsigned len)
-+				      int __user *optlen, unsigned len,
-+				      int display)
- {
--	int display = lsm_task_display(current);
- 	struct security_hook_list *hp;
-+	char *final = NULL;
-+	char *cp;
-+	char *tp;
-+	int rc = 0;
-+	unsigned finallen = 0;
-+	unsigned llen;
-+	unsigned clen = 0;
-+	unsigned tlen;
-+
-+	switch (display) {
-+	case LSMBLOB_DISPLAY:
-+		rc = -ENOPROTOOPT;
-+		display = lsm_task_display(current);
-+		hlist_for_each_entry(hp,
-+				&security_hook_heads.socket_getpeersec_stream,
-+				list)
-+			if (display == LSMBLOB_INVALID ||
-+			    display == hp->lsmid->slot) {
-+				rc = hp->hook.socket_getpeersec_stream(sock,
-+							&final, &finallen, len);
-+				break;
-+			}
-+		break;
-+	case LSMBLOB_COMPOUND:
-+		/*
-+		 * A compound context, in the form lsm='value'[,lsm='value']...
-+		 */
-+		hlist_for_each_entry(hp,
-+				&security_hook_heads.socket_getpeersec_stream,
-+				list) {
-+			rc = hp->hook.socket_getpeersec_stream(sock, &cp, &clen,
-+							       len);
-+			if (rc == -EINVAL || rc == -ENOPROTOOPT) {
-+				rc = 0;
-+				continue;
-+			}
-+			if (rc) {
-+				kfree(final);
-+				return rc;
-+			}
-+			/*
-+			 * Don't propogate trailing nul bytes.
-+			 */
-+			clen = strnlen(cp, clen) + 1;
-+			llen = strlen(hp->lsmid->lsm) + 1;
-+			tlen = llen + clen;
-+			if (final)
-+				tlen += finallen;
-+			tp = kzalloc(tlen, GFP_KERNEL);
-+			if (tp == NULL) {
-+				kfree(cp);
-+				kfree(final);
-+				return -ENOMEM;
-+			}
-+			if (final)
-+				memcpy(tp, final, finallen);
-+			memcpy(tp + finallen, hp->lsmid->lsm, llen);
-+			memcpy(tp + finallen + llen, cp, clen);
-+			kfree(cp);
-+			if (final)
-+				kfree(final);
-+			final = tp;
-+			finallen = tlen;
-+		}
-+		if (final == NULL)
-+			return -EINVAL;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
- 
--	hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream,
--			     list)
--		if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
--			return hp->hook.socket_getpeersec_stream(sock, optval,
--								 optlen, len);
--	return -ENOPROTOOPT;
-+	if (finallen > len)
-+		rc = -ERANGE;
-+	else if (copy_to_user(optval, final, finallen))
-+		rc = -EFAULT;
-+
-+	if (put_user(finallen, optlen))
-+		rc = -EFAULT;
-+
-+	kfree(final);
-+	return rc;
- }
- 
- int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
-diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
-index fcad2e3432d2..5e7d61754798 100644
---- a/security/selinux/hooks.c
-+++ b/security/selinux/hooks.c
-@@ -4923,10 +4923,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
- 	return err;
- }
- 
--static int selinux_socket_getpeersec_stream(struct socket *sock,
--					    char __user *optval,
--					    int __user *optlen,
--					    unsigned int len)
-+static int selinux_socket_getpeersec_stream(struct socket *sock, char **optval,
-+					    int *optlen, unsigned int len)
- {
- 	int err = 0;
- 	char *scontext;
-@@ -4946,18 +4944,12 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
- 	if (err)
- 		return err;
- 
--	if (scontext_len > len) {
-+	if (scontext_len > len)
- 		err = -ERANGE;
--		goto out_len;
--	}
--
--	if (copy_to_user(optval, scontext, scontext_len))
--		err = -EFAULT;
-+	else
-+		*optval = scontext;
- 
--out_len:
--	if (put_user(scontext_len, optlen))
--		err = -EFAULT;
--	kfree(scontext);
-+	*optlen = scontext_len;
- 	return err;
- }
- 
-diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
-index 7a30b8692b1e..40c75205a914 100644
---- a/security/smack/smack_lsm.c
-+++ b/security/smack/smack_lsm.c
-@@ -3919,28 +3919,29 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
-  *
-  * returns zero on success, an error code otherwise
-  */
--static int smack_socket_getpeersec_stream(struct socket *sock,
--					  char __user *optval,
--					  int __user *optlen, unsigned len)
-+static int smack_socket_getpeersec_stream(struct socket *sock, char **optval,
-+					  int *optlen, unsigned len)
- {
--	struct socket_smack *ssp;
--	char *rcp = "";
--	int slen = 1;
-+	struct socket_smack *ssp = smack_sock(sock->sk);
-+	char *rcp;
-+	int slen;
- 	int rc = 0;
- 
--	ssp = smack_sock(sock->sk);
--	if (ssp->smk_packet != NULL) {
--		rcp = ssp->smk_packet->smk_known;
--		slen = strlen(rcp) + 1;
-+	if (ssp->smk_packet == NULL) {
-+		*optlen = 0;
-+		return -EINVAL;
- 	}
- 
-+	rcp = ssp->smk_packet->smk_known;
-+	slen = strlen(rcp) + 1;
- 	if (slen > len)
- 		rc = -ERANGE;
--	else if (copy_to_user(optval, rcp, slen) != 0)
--		rc = -EFAULT;
--
--	if (put_user(slen, optlen) != 0)
--		rc = -EFAULT;
-+	else {
-+		*optval = kstrdup(rcp, GFP_KERNEL);
-+		if (*optval == NULL)
-+			rc = -ENOMEM;
-+	}
-+	*optlen = slen;
- 
- 	return rc;
+ 	audit_buffer_free(ab);
  }
 -- 
-2.20.1
+2.31.1
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help