]> git.hungrycats.org Git - linux/commitdiff
[LSM]: Networking netlink socket capability hooks.
authorJames Morris <jmorris@intercode.com.au>
Thu, 6 Feb 2003 17:51:56 +0000 (09:51 -0800)
committerJames Morris <jmorris@intercode.com.au>
Thu, 6 Feb 2003 17:51:56 +0000 (09:51 -0800)
include/linux/security.h
net/core/rtnetlink.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/xfrm_user.c
net/ipv6/netfilter/ip6_queue.c
net/netlink/af_netlink.c
security/capability.c
security/dummy.c

index c04fc8ceec06e417f2641ba92a4fe4208e1097b7..d2873ec35117d07c5f142b0197ae2f3a707a51a1 100644 (file)
@@ -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
index eac888a5e82e04977002a498ce6ebca5952d314f..2e2f9c1e9aee7223ba669d11e98ca61c738fcaa2 100644 (file)
@@ -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;
        }
index 080c3d1efdd4bd928861eec36b7a0cecbfcf9567..d832d2d98d3b15ebda2ecca7c8c66a9c1451929e 100644 (file)
@@ -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);
index 72a667a2f1be0e91152688ef16aa93ec18fe112a..05738783a11dd4d73015289995f22a232597c63c 100644 (file)
@@ -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;
        }
index 5e02b47050e948d0d7f10bf722de02075d187a83..aa87c34de72aeaaea50cbb095e87b8989a162dda 100644 (file)
@@ -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) {
index 499a8c9a9c99ce38567264327801a550c6062166..9249dddc9001d8bcb0cd08703dc1b83bf1616ba6 100644 (file)
@@ -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)) {
index cf6d2440a21d218102c5a4fbbf281a7e54601bb1..221f185ca3809fe88719fbb2398a46db27ff2f5f 100644 (file)
@@ -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,
index 46cfb0d00aa6888d86c5ff84181d75f56fb8a16b..9b450c740bfa6f137b0c47a64afc33bdf26e853f 100644 (file)
@@ -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