diff options
| author | James Morris <jmorris@intercode.com.au> | 2003-02-06 09:51:56 -0800 |
|---|---|---|
| committer | James Morris <jmorris@intercode.com.au> | 2003-02-06 09:51:56 -0800 |
| commit | d5a9256003294d65d6cd9d162cf29fb852f6569a (patch) | |
| tree | d73c28b196643383a056dba95bb99953c538a765 | |
| parent | 73880d9f50dd54d301c95d8d793404f5bf3e08c6 (diff) | |
[LSM]: Networking netlink socket capability hooks.
| -rw-r--r-- | include/linux/security.h | 65 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 3 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 3 | ||||
| -rw-r--r-- | net/ipv4/xfrm_user.c | 3 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 6 | ||||
| -rw-r--r-- | net/netlink/af_netlink.c | 8 | ||||
| -rw-r--r-- | security/capability.c | 2 | ||||
| -rw-r--r-- | security/dummy.c | 18 |
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 |
