Commit d5a92560 authored by James Morris's avatar James Morris

[LSM]: Networking netlink socket capability hooks.

parent 73880d9f
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/msg.h> #include <linux/msg.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
/* /*
* These functions are in security/capability.c and are used * 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, ...@@ -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_kmod_set_label (void);
extern void cap_task_reparent_to_init (struct task_struct *p); 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 * Values used in the task_security_ops calls
*/ */
...@@ -64,11 +79,6 @@ extern void cap_task_reparent_to_init (struct task_struct *p); ...@@ -64,11 +79,6 @@ extern void cap_task_reparent_to_init (struct task_struct *p);
#define LSM_SETID_FS 8 #define LSM_SETID_FS 8
/* forward declares to avoid warnings */ /* forward declares to avoid warnings */
struct sock;
struct socket;
struct sockaddr;
struct msghdr;
struct sk_buff;
struct nfsctl_arg; struct nfsctl_arg;
struct sched_param; struct sched_param;
struct swap_info_struct; struct swap_info_struct;
...@@ -588,6 +598,21 @@ struct swap_info_struct; ...@@ -588,6 +598,21 @@ struct swap_info_struct;
* is being reparented to the init task. * is being reparented to the init task.
* @p contains the task_struct for the kernel thread. * @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. * Security hooks for Unix domain networking.
* *
* @unix_stream_connect: * @unix_stream_connect:
...@@ -1077,6 +1102,9 @@ struct security_operations { ...@@ -1077,6 +1102,9 @@ struct security_operations {
int (*sem_semop) (struct sem_array * sma, int (*sem_semop) (struct sem_array * sma,
struct sembuf * sops, unsigned nsops, int alter); struct sembuf * sops, unsigned nsops, int alter);
int (*netlink_send) (struct sk_buff * skb);
int (*netlink_recv) (struct sk_buff * skb);
/* allow module stacking */ /* allow module stacking */
int (*register_security) (const char *name, int (*register_security) (const char *name,
struct security_operations *ops); struct security_operations *ops);
...@@ -1701,6 +1729,16 @@ static inline int security_sem_semop (struct sem_array * sma, ...@@ -1701,6 +1729,16 @@ static inline int security_sem_semop (struct sem_array * sma,
return security_ops->sem_semop(sma, sops, nsops, alter); 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 */ /* prototypes */
extern int security_scaffolding_startup (void); extern int security_scaffolding_startup (void);
extern int register_security (struct security_operations *ops); extern int register_security (struct security_operations *ops);
...@@ -2262,6 +2300,21 @@ static inline int security_sem_semop (struct sem_array * sma, ...@@ -2262,6 +2300,21 @@ static inline int security_sem_semop (struct sem_array * sma,
return 0; 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 */ #endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK #ifdef CONFIG_SECURITY_NETWORK
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -363,7 +364,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) ...@@ -363,7 +364,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
sz_idx = type>>2; sz_idx = type>>2;
kind = type&3; 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; *errp = -EPERM;
return -1; return -1;
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/brlock.h> #include <linux/brlock.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/route.h> #include <net/route.h>
...@@ -496,7 +497,7 @@ ipq_rcv_skb(struct sk_buff *skb) ...@@ -496,7 +497,7 @@ ipq_rcv_skb(struct sk_buff *skb)
if (type <= IPQM_BASE) if (type <= IPQM_BASE)
return; return;
if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) if (security_netlink_recv(skb))
RCV_SKB_FAIL(-EPERM); RCV_SKB_FAIL(-EPERM);
write_lock_bh(&queue_lock); write_lock_bh(&queue_lock);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/pfkeyv2.h> #include <linux/pfkeyv2.h>
#include <linux/ipsec.h> #include <linux/ipsec.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/xfrm.h> #include <net/xfrm.h>
...@@ -774,7 +775,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err ...@@ -774,7 +775,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
link = &xfrm_dispatch[type]; link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */ /* All operations require privileges, even GET */
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { if (security_netlink_recv(skb)) {
*errp = -EPERM; *errp = -EPERM;
return -1; return -1;
} }
......
...@@ -538,10 +538,10 @@ ipq_rcv_skb(struct sk_buff *skb) ...@@ -538,10 +538,10 @@ ipq_rcv_skb(struct sk_buff *skb)
if (type <= IPQM_BASE) if (type <= IPQM_BASE)
return; 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); write_lock_bh(&queue_lock);
if (peer_pid) { if (peer_pid) {
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/scm.h> #include <net/scm.h>
...@@ -636,7 +637,12 @@ static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -636,7 +637,12 @@ static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock,
check them, when this message will be delivered check them, when this message will be delivered
to corresponding kernel module. --ANK (980802) 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; err = -EFAULT;
if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) { if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) {
......
...@@ -282,6 +282,8 @@ static struct security_operations capability_ops = { ...@@ -282,6 +282,8 @@ static struct security_operations capability_ops = {
.capset_check = cap_capset_check, .capset_check = cap_capset_check,
.capset_set = cap_capset_set, .capset_set = cap_capset_set,
.capable = cap_capable, .capable = cap_capable,
.netlink_send = cap_netlink_send,
.netlink_recv = cap_netlink_recv,
.bprm_compute_creds = cap_bprm_compute_creds, .bprm_compute_creds = cap_bprm_compute_creds,
.bprm_set_security = cap_bprm_set_security, .bprm_set_security = cap_bprm_set_security,
......
...@@ -597,6 +597,22 @@ static int dummy_sem_semop (struct sem_array *sma, ...@@ -597,6 +597,22 @@ static int dummy_sem_semop (struct sem_array *sma,
return 0; 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 #ifdef CONFIG_SECURITY_NETWORK
static int dummy_unix_stream_connect (struct socket *sock, static int dummy_unix_stream_connect (struct socket *sock,
struct socket *other, struct socket *other,
...@@ -819,6 +835,8 @@ void security_fixup_ops (struct security_operations *ops) ...@@ -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_associate);
set_to_dummy_if_null(ops, sem_semctl); set_to_dummy_if_null(ops, sem_semctl);
set_to_dummy_if_null(ops, sem_semop); 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, register_security);
set_to_dummy_if_null(ops, unregister_security); set_to_dummy_if_null(ops, unregister_security);
#ifdef CONFIG_SECURITY_NETWORK #ifdef CONFIG_SECURITY_NETWORK
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment