summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Morris <jmorris@intercode.com.au>2003-02-06 09:51:56 -0800
committerJames Morris <jmorris@intercode.com.au>2003-02-06 09:51:56 -0800
commitd5a9256003294d65d6cd9d162cf29fb852f6569a (patch)
treed73c28b196643383a056dba95bb99953c538a765
parent73880d9f50dd54d301c95d8d793404f5bf3e08c6 (diff)
[LSM]: Networking netlink socket capability hooks.
-rw-r--r--include/linux/security.h65
-rw-r--r--net/core/rtnetlink.c3
-rw-r--r--net/ipv4/netfilter/ip_queue.c3
-rw-r--r--net/ipv4/xfrm_user.c3
-rw-r--r--net/ipv6/netfilter/ip6_queue.c6
-rw-r--r--net/netlink/af_netlink.c8
-rw-r--r--security/capability.c2
-rw-r--r--security/dummy.c18
8 files changed, 95 insertions, 13 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index c04fc8ceec06..d2873ec35117 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,7 +31,8 @@
#include <linux/shm.h>
#include <linux/msg.h>
#include <linux/sched.h>
-
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
/*
* These functions are in security/capability.c and are used
@@ -48,6 +49,20 @@ extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
extern void cap_task_kmod_set_label (void);
extern void cap_task_reparent_to_init (struct task_struct *p);
+static inline int cap_netlink_send (struct sk_buff *skb)
+{
+ NETLINK_CB (skb).eff_cap = current->cap_effective;
+ return 0;
+}
+
+static inline int cap_netlink_recv (struct sk_buff *skb)
+{
+ if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
+
/*
* Values used in the task_security_ops calls
*/
@@ -64,11 +79,6 @@ extern void cap_task_reparent_to_init (struct task_struct *p);
#define LSM_SETID_FS 8
/* forward declares to avoid warnings */
-struct sock;
-struct socket;
-struct sockaddr;
-struct msghdr;
-struct sk_buff;
struct nfsctl_arg;
struct sched_param;
struct swap_info_struct;
@@ -588,6 +598,21 @@ struct swap_info_struct;
* is being reparented to the init task.
* @p contains the task_struct for the kernel thread.
*
+ * Security hooks for Netlink messaging.
+ *
+ * @netlink_send:
+ * Save security information for a netlink message so that permission
+ * checking can be performed when the message is processed. The security
+ * information can be saved using the eff_cap field of the
+ * netlink_skb_parms structure.
+ * @skb contains the sk_buff structure for the netlink message.
+ * Return 0 if the information was successfully saved.
+ * @netlink_recv:
+ * Check permission before processing the received netlink message in
+ * @skb.
+ * @skb contains the sk_buff structure for the netlink message.
+ * Return 0 if permission is granted.
+ *
* Security hooks for Unix domain networking.
*
* @unix_stream_connect:
@@ -1077,6 +1102,9 @@ struct security_operations {
int (*sem_semop) (struct sem_array * sma,
struct sembuf * sops, unsigned nsops, int alter);
+ int (*netlink_send) (struct sk_buff * skb);
+ int (*netlink_recv) (struct sk_buff * skb);
+
/* allow module stacking */
int (*register_security) (const char *name,
struct security_operations *ops);
@@ -1701,6 +1729,16 @@ static inline int security_sem_semop (struct sem_array * sma,
return security_ops->sem_semop(sma, sops, nsops, alter);
}
+static inline int security_netlink_send(struct sk_buff * skb)
+{
+ return security_ops->netlink_send(skb);
+}
+
+static inline int security_netlink_recv(struct sk_buff * skb)
+{
+ return security_ops->netlink_recv(skb);
+}
+
/* prototypes */
extern int security_scaffolding_startup (void);
extern int register_security (struct security_operations *ops);
@@ -2262,6 +2300,21 @@ static inline int security_sem_semop (struct sem_array * sma,
return 0;
}
+/*
+ * The netlink capability defaults need to be used inline by default
+ * (rather than hooking into the capability module) to reduce overhead
+ * in the networking code.
+ */
+static inline int security_netlink_send (struct sk_buff *skb)
+{
+ return cap_netlink_send (skb);
+}
+
+static inline int security_netlink_recv (struct sk_buff *skb)
+{
+ return cap_netlink_recv (skb);
+}
+
#endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index eac888a5e82e..2e2f9c1e9aee 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -34,6 +34,7 @@
#include <linux/capability.h>
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -363,7 +364,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
sz_idx = type>>2;
kind = type&3;
- if (kind != 2 && !cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+ if (kind != 2 && security_netlink_recv(skb)) {
*errp = -EPERM;
return -1;
}
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 080c3d1efdd4..d832d2d98d3b 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -26,6 +26,7 @@
#include <linux/brlock.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
+#include <linux/security.h>
#include <net/sock.h>
#include <net/route.h>
@@ -496,7 +497,7 @@ ipq_rcv_skb(struct sk_buff *skb)
if (type <= IPQM_BASE)
return;
- if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ if (security_netlink_recv(skb))
RCV_SKB_FAIL(-EPERM);
write_lock_bh(&queue_lock);
diff --git a/net/ipv4/xfrm_user.c b/net/ipv4/xfrm_user.c
index 72a667a2f1be..05738783a11d 100644
--- a/net/ipv4/xfrm_user.c
+++ b/net/ipv4/xfrm_user.c
@@ -16,6 +16,7 @@
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
#include <linux/init.h>
+#include <linux/security.h>
#include <net/sock.h>
#include <net/xfrm.h>
@@ -774,7 +775,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */
- if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+ if (security_netlink_recv(skb)) {
*errp = -EPERM;
return -1;
}
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 5e02b47050e9..aa87c34de72a 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -538,10 +538,10 @@ ipq_rcv_skb(struct sk_buff *skb)
if (type <= IPQM_BASE)
return;
-
- if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
- RCV_SKB_FAIL(-EPERM);
+ if (security_netlink_recv(skb))
+ RCV_SKB_FAIL(-EPERM);
+
write_lock_bh(&queue_lock);
if (peer_pid) {
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 499a8c9a9c99..9249dddc9001 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -42,6 +42,7 @@
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
+#include <linux/security.h>
#include <net/sock.h>
#include <net/scm.h>
@@ -636,7 +637,12 @@ static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock,
check them, when this message will be delivered
to corresponding kernel module. --ANK (980802)
*/
- NETLINK_CB(skb).eff_cap = current->cap_effective;
+
+ err = security_netlink_send(skb);
+ if (err) {
+ kfree_skb(skb);
+ goto out;
+ }
err = -EFAULT;
if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) {
diff --git a/security/capability.c b/security/capability.c
index cf6d2440a21d..221f185ca380 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -282,6 +282,8 @@ static struct security_operations capability_ops = {
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
.capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
.bprm_compute_creds = cap_bprm_compute_creds,
.bprm_set_security = cap_bprm_set_security,
diff --git a/security/dummy.c b/security/dummy.c
index 46cfb0d00aa6..9b450c740bfa 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -597,6 +597,22 @@ static int dummy_sem_semop (struct sem_array *sma,
return 0;
}
+static int dummy_netlink_send (struct sk_buff *skb)
+{
+ if (current->euid == 0)
+ cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
+ else
+ NETLINK_CB (skb).eff_cap = 0;
+ return 0;
+}
+
+static int dummy_netlink_recv (struct sk_buff *skb)
+{
+ if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
#ifdef CONFIG_SECURITY_NETWORK
static int dummy_unix_stream_connect (struct socket *sock,
struct socket *other,
@@ -819,6 +835,8 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, sem_associate);
set_to_dummy_if_null(ops, sem_semctl);
set_to_dummy_if_null(ops, sem_semop);
+ set_to_dummy_if_null(ops, netlink_send);
+ set_to_dummy_if_null(ops, netlink_recv);
set_to_dummy_if_null(ops, register_security);
set_to_dummy_if_null(ops, unregister_security);
#ifdef CONFIG_SECURITY_NETWORK