Merge to Fedora kernel-2.6.7-1.441
[linux-2.6.git] / security / selinux / hooks.c
index 35d779a..b2a1418 100644 (file)
@@ -71,6 +71,9 @@
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 
+extern int policydb_loaded_version;
+extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
+
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing = 0;
 
@@ -627,7 +630,7 @@ static inline u16 inode_mode_to_security_class(umode_t mode)
        return SECCLASS_FILE;
 }
 
-static inline u16 socket_type_to_security_class(int family, int type)
+static inline u16 socket_type_to_security_class(int family, int type, int protocol)
 {
        switch (family) {
        case PF_UNIX:
@@ -648,7 +651,28 @@ static inline u16 socket_type_to_security_class(int family, int type)
                        return SECCLASS_RAWIP_SOCKET;
                }
        case PF_NETLINK:
-               return SECCLASS_NETLINK_SOCKET;
+               switch (protocol) {
+               case NETLINK_ROUTE:
+                       return SECCLASS_NETLINK_ROUTE_SOCKET;
+               case NETLINK_FIREWALL:
+                       return SECCLASS_NETLINK_FIREWALL_SOCKET;
+               case NETLINK_TCPDIAG:
+                       return SECCLASS_NETLINK_TCPDIAG_SOCKET;
+               case NETLINK_NFLOG:
+                       return SECCLASS_NETLINK_NFLOG_SOCKET;
+               case NETLINK_XFRM:
+                       return SECCLASS_NETLINK_XFRM_SOCKET;
+               case NETLINK_SELINUX:
+                       return SECCLASS_NETLINK_SELINUX_SOCKET;
+               case NETLINK_AUDIT:
+                       return SECCLASS_NETLINK_AUDIT_SOCKET;
+               case NETLINK_IP6_FW:
+                       return SECCLASS_NETLINK_IP6FW_SOCKET;
+               case NETLINK_DNRTMSG:
+                       return SECCLASS_NETLINK_DNRT_SOCKET;
+               default:
+                       return SECCLASS_NETLINK_SOCKET;
+               }
        case PF_PACKET:
                return SECCLASS_PACKET_SOCKET;
        case PF_KEY:
@@ -853,7 +877,8 @@ out:
                struct socket *sock = SOCKET_I(inode);
                if (sock->sk) {
                        isec->sclass = socket_type_to_security_class(sock->sk->sk_family,
-                                                                    sock->sk->sk_type);
+                                                                    sock->sk->sk_type,
+                                                                    sock->sk->sk_protocol);
                } else {
                        isec->sclass = SECCLASS_SOCKET;
                }
@@ -1380,7 +1405,7 @@ static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effecti
        if (error)
                return;
 
-       return secondary_ops->capset_set(target, effective, inheritable, permitted);
+       secondary_ops->capset_set(target, effective, inheritable, permitted);
 }
 
 static int selinux_capable(struct task_struct *tsk, int cap)
@@ -1567,22 +1592,6 @@ static int selinux_vm_enough_memory(long pages)
        return -ENOMEM;
 }
 
-static int selinux_netlink_send(struct sk_buff *skb)
-{
-       if (capable(CAP_NET_ADMIN))
-               cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
-       else
-               NETLINK_CB(skb).eff_cap = 0;
-       return 0;
-}
-
-static int selinux_netlink_recv(struct sk_buff *skb)
-{
-       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
-               return -EPERM;
-       return 0;
-}
-
 /* binprm security operations */
 
 static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
@@ -2918,8 +2927,8 @@ static int selinux_socket_create(int family, int type,
 
        tsec = current->security;
        err = avc_has_perm(tsec->sid, tsec->sid,
-                          socket_type_to_security_class(family, type),
-                          SOCKET__CREATE, NULL, NULL);
+                          socket_type_to_security_class(family, type,
+                          protocol), SOCKET__CREATE, NULL, NULL);
 
 out:
        return err;
@@ -2938,7 +2947,7 @@ static void selinux_socket_post_create(struct socket *sock, int family,
        isec = SOCK_INODE(sock)->i_security;
 
        tsec = current->security;
-       isec->sclass = socket_type_to_security_class(family, type);
+       isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
 
        return;
@@ -3327,6 +3336,55 @@ static void selinux_sk_free_security(struct sock *sk)
        sk_free_security(sk);
 }
 
+static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
+{
+       int err = 0;
+       u32 perm;
+       struct nlmsghdr *nlh;
+       struct socket *sock = sk->sk_socket;
+       struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+       
+       if (skb->len < NLMSG_SPACE(0)) {
+               err = -EINVAL;
+               goto out;
+       }
+       nlh = (struct nlmsghdr *)skb->data;
+       
+       err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+       if (err) {
+               /* Ignore */
+               if (err == -ENOENT)
+                       err = 0;
+               goto out;
+       }
+
+       err = socket_has_perm(current, sock, perm);
+out:
+       return err;
+}
+
+static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+       int err = 0;
+       
+       if (capable(CAP_NET_ADMIN))
+               cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
+       else
+               NETLINK_CB(skb).eff_cap = 0;
+       
+       if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
+               err = selinux_nlmsg_perm(sk, skb);
+       
+       return err;
+}
+
+static int selinux_netlink_recv(struct sk_buff *skb)
+{
+       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+               return -EPERM;
+       return 0;
+}
+
 #ifdef CONFIG_NETFILTER
 
 static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
@@ -3550,7 +3608,7 @@ static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
 
 static void selinux_msg_msg_free_security(struct msg_msg *msg)
 {
-       return msg_msg_free_security(msg);
+       msg_msg_free_security(msg);
 }
 
 /* message queue security operations */
@@ -3786,7 +3844,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
 }
 
 static int selinux_shm_shmat(struct shmid_kernel *shp,
-                            char *shmaddr, int shmflg)
+                            char __user *shmaddr, int shmflg)
 {
        u32 perms;