Browse Source

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [CIPSO]: Fix several unaligned kernel accesses in the CIPSO engine.
  [NetLabel]: consolidate the struct socket/sock handling to just struct sock
  [IPV4]: Do not remove idev when addresses are cleared
Linus Torvalds 18 years ago
parent
commit
81d84a94be
6 changed files with 61 additions and 122 deletions
  1. 6 14
      include/net/cipso_ipv4.h
  2. 3 11
      include/net/netlabel.h
  3. 21 43
      net/ipv4/cipso_ipv4.c
  4. 1 5
      net/ipv4/devinet.c
  5. 9 34
      net/netlabel/netlabel_kapi.c
  6. 21 15
      security/selinux/netlabel.c

+ 6 - 14
include/net/cipso_ipv4.h

@@ -203,12 +203,10 @@ static inline int cipso_v4_cache_add(const struct sk_buff *skb,
 
 #ifdef CONFIG_NETLABEL
 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
-int cipso_v4_socket_setattr(const struct socket *sock,
-			    const struct cipso_v4_doi *doi_def,
-			    const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_sock_setattr(struct sock *sk,
+			  const struct cipso_v4_doi *doi_def,
+			  const struct netlbl_lsm_secattr *secattr);
 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
-int cipso_v4_socket_getattr(const struct socket *sock,
-			    struct netlbl_lsm_secattr *secattr);
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 			    struct netlbl_lsm_secattr *secattr);
 int cipso_v4_validate(unsigned char **option);
@@ -220,9 +218,9 @@ static inline void cipso_v4_error(struct sk_buff *skb,
 	return;
 }
 
-static inline int cipso_v4_socket_setattr(const struct socket *sock,
-				  const struct cipso_v4_doi *doi_def,
-				  const struct netlbl_lsm_secattr *secattr)
+static inline int cipso_v4_sock_setattr(struct sock *sk,
+				      const struct cipso_v4_doi *doi_def,
+				      const struct netlbl_lsm_secattr *secattr)
 {
 	return -ENOSYS;
 }
@@ -233,12 +231,6 @@ static inline int cipso_v4_sock_getattr(struct sock *sk,
 	return -ENOSYS;
 }
 
-static inline int cipso_v4_socket_getattr(const struct socket *sock,
-					  struct netlbl_lsm_secattr *secattr)
-{
-	return -ENOSYS;
-}
-
 static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 					  struct netlbl_lsm_secattr *secattr)
 {

+ 3 - 11
include/net/netlabel.h

@@ -332,17 +332,15 @@ static inline int netlbl_secattr_catmap_setrng(
  */
 
 #ifdef CONFIG_NETLABEL
-int netlbl_socket_setattr(const struct socket *sock,
-			  const struct netlbl_lsm_secattr *secattr);
+int netlbl_sock_setattr(struct sock *sk,
+			const struct netlbl_lsm_secattr *secattr);
 int netlbl_sock_getattr(struct sock *sk,
 			struct netlbl_lsm_secattr *secattr);
-int netlbl_socket_getattr(const struct socket *sock,
-			  struct netlbl_lsm_secattr *secattr);
 int netlbl_skbuff_getattr(const struct sk_buff *skb,
 			  struct netlbl_lsm_secattr *secattr);
 void netlbl_skbuff_err(struct sk_buff *skb, int error);
 #else
-static inline int netlbl_socket_setattr(const struct socket *sock,
+static inline int netlbl_sock_setattr(struct sock *sk,
 				     const struct netlbl_lsm_secattr *secattr)
 {
 	return -ENOSYS;
@@ -354,12 +352,6 @@ static inline int netlbl_sock_getattr(struct sock *sk,
 	return -ENOSYS;
 }
 
-static inline int netlbl_socket_getattr(const struct socket *sock,
-					struct netlbl_lsm_secattr *secattr)
-{
-	return -ENOSYS;
-}
-
 static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
 					struct netlbl_lsm_secattr *secattr)
 {

+ 21 - 43
net/ipv4/cipso_ipv4.c

@@ -45,6 +45,7 @@
 #include <net/cipso_ipv4.h>
 #include <asm/atomic.h>
 #include <asm/bug.h>
+#include <asm/unaligned.h>
 
 struct cipso_v4_domhsh_entry {
 	char *domain;
@@ -1000,7 +1001,7 @@ static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def,
 		return -EFAULT;
 
 	for (iter = 0; iter < enumcat_len; iter += 2) {
-		cat = ntohs(*((__be16 *)&enumcat[iter]));
+		cat = ntohs(get_unaligned((__be16 *)&enumcat[iter]));
 		if (cat <= cat_prev)
 			return -EFAULT;
 		cat_prev = cat;
@@ -1068,8 +1069,8 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
 
 	for (iter = 0; iter < net_cat_len; iter += 2) {
 		ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat,
-					    ntohs(*((__be16 *)&net_cat[iter])),
-					    GFP_ATOMIC);
+				ntohs(get_unaligned((__be16 *)&net_cat[iter])),
+				GFP_ATOMIC);
 		if (ret_val != 0)
 			return ret_val;
 	}
@@ -1102,9 +1103,10 @@ static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def,
 		return -EFAULT;
 
 	for (iter = 0; iter < rngcat_len; iter += 4) {
-		cat_high = ntohs(*((__be16 *)&rngcat[iter]));
+		cat_high = ntohs(get_unaligned((__be16 *)&rngcat[iter]));
 		if ((iter + 4) <= rngcat_len)
-			cat_low = ntohs(*((__be16 *)&rngcat[iter + 2]));
+			cat_low = ntohs(
+				get_unaligned((__be16 *)&rngcat[iter + 2]));
 		else
 			cat_low = 0;
 
@@ -1201,9 +1203,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
 	u16 cat_high;
 
 	for (net_iter = 0; net_iter < net_cat_len; net_iter += 4) {
-		cat_high = ntohs(*((__be16 *)&net_cat[net_iter]));
+		cat_high = ntohs(get_unaligned((__be16 *)&net_cat[net_iter]));
 		if ((net_iter + 4) <= net_cat_len)
-			cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2]));
+			cat_low = ntohs(
+			      get_unaligned((__be16 *)&net_cat[net_iter + 2]));
 		else
 			cat_low = 0;
 
@@ -1565,7 +1568,7 @@ int cipso_v4_validate(unsigned char **option)
 	}
 
 	rcu_read_lock();
-	doi_def = cipso_v4_doi_search(ntohl(*((__be32 *)&opt[2])));
+	doi_def = cipso_v4_doi_search(ntohl(get_unaligned((__be32 *)&opt[2])));
 	if (doi_def == NULL) {
 		err_offset = 2;
 		goto validate_return_locked;
@@ -1709,22 +1712,22 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 }
 
 /**
- * cipso_v4_socket_setattr - Add a CIPSO option to a socket
- * @sock: the socket
+ * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+ * @sk: the socket
  * @doi_def: the CIPSO DOI to use
  * @secattr: the specific security attributes of the socket
  *
  * Description:
  * Set the CIPSO option on the given socket using the DOI definition and
  * security attributes passed to the function.  This function requires
- * exclusive access to @sock->sk, which means it either needs to be in the
- * process of being created or locked via lock_sock(sock->sk).  Returns zero on
- * success and negative values on failure.
+ * exclusive access to @sk, which means it either needs to be in the
+ * process of being created or locked.  Returns zero on success and negative
+ * values on failure.
  *
  */
-int cipso_v4_socket_setattr(const struct socket *sock,
-			    const struct cipso_v4_doi *doi_def,
-			    const struct netlbl_lsm_secattr *secattr)
+int cipso_v4_sock_setattr(struct sock *sk,
+			  const struct cipso_v4_doi *doi_def,
+			  const struct netlbl_lsm_secattr *secattr)
 {
 	int ret_val = -EPERM;
 	u32 iter;
@@ -1732,7 +1735,6 @@ int cipso_v4_socket_setattr(const struct socket *sock,
 	u32 buf_len = 0;
 	u32 opt_len;
 	struct ip_options *opt = NULL;
-	struct sock *sk;
 	struct inet_sock *sk_inet;
 	struct inet_connection_sock *sk_conn;
 
@@ -1740,7 +1742,6 @@ int cipso_v4_socket_setattr(const struct socket *sock,
 	 * defined yet but it is not a problem as the only users of these
 	 * "lite" PF_INET sockets are functions which do an accept() call
 	 * afterwards so we will label the socket as part of the accept(). */
-	sk = sock->sk;
 	if (sk == NULL)
 		return 0;
 
@@ -1858,7 +1859,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
 	if (ret_val == 0)
 		return ret_val;
 
-	doi = ntohl(*(__be32 *)&cipso_ptr[2]);
+	doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2]));
 	rcu_read_lock();
 	doi_def = cipso_v4_doi_search(doi);
 	if (doi_def == NULL) {
@@ -1891,29 +1892,6 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
 	return ret_val;
 }
 
-/**
- * cipso_v4_socket_getattr - Get the security attributes from a socket
- * @sock: the socket
- * @secattr: the security attributes
- *
- * Description:
- * Query @sock to see if there is a CIPSO option attached to the socket and if
- * there is return the CIPSO security attributes in @secattr.  Returns zero on
- * success and negative values on failure.
- *
- */
-int cipso_v4_socket_getattr(const struct socket *sock,
-			    struct netlbl_lsm_secattr *secattr)
-{
-	int ret_val;
-
-	lock_sock(sock->sk);
-	ret_val = cipso_v4_sock_getattr(sock->sk, secattr);
-	release_sock(sock->sk);
-
-	return ret_val;
-}
-
 /**
  * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
  * @skb: the packet
@@ -1936,7 +1914,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 	if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0)
 		return 0;
 
-	doi = ntohl(*(__be32 *)&cipso_ptr[2]);
+	doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2]));
 	rcu_read_lock();
 	doi_def = cipso_v4_doi_search(doi);
 	if (doi_def == NULL)

+ 1 - 5
net/ipv4/devinet.c

@@ -327,12 +327,8 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 		}
 
 	}
-	if (destroy) {
+	if (destroy)
 		inet_free_ifa(ifa1);
-
-		if (!in_dev->ifa_list)
-			inetdev_destroy(in_dev);
-	}
 }
 
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,

+ 9 - 34
net/netlabel/netlabel_kapi.c

@@ -246,19 +246,18 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
 
 /**
  * netlbl_socket_setattr - Label a socket using the correct protocol
- * @sock: the socket to label
+ * @sk: the socket to label
  * @secattr: the security attributes
  *
  * Description:
  * Attach the correct label to the given socket using the security attributes
- * specified in @secattr.  This function requires exclusive access to
- * @sock->sk, which means it either needs to be in the process of being
- * created or locked via lock_sock(sock->sk).  Returns zero on success,
- * negative values on failure.
+ * specified in @secattr.  This function requires exclusive access to @sk,
+ * which means it either needs to be in the process of being created or locked.
+ * Returns zero on success, negative values on failure.
  *
  */
-int netlbl_socket_setattr(const struct socket *sock,
-			  const struct netlbl_lsm_secattr *secattr)
+int netlbl_sock_setattr(struct sock *sk,
+			const struct netlbl_lsm_secattr *secattr)
 {
 	int ret_val = -ENOENT;
 	struct netlbl_dom_map *dom_entry;
@@ -269,9 +268,9 @@ int netlbl_socket_setattr(const struct socket *sock,
 		goto socket_setattr_return;
 	switch (dom_entry->type) {
 	case NETLBL_NLTYPE_CIPSOV4:
-		ret_val = cipso_v4_socket_setattr(sock,
-						  dom_entry->type_def.cipsov4,
-						  secattr);
+		ret_val = cipso_v4_sock_setattr(sk,
+						dom_entry->type_def.cipsov4,
+						secattr);
 		break;
 	case NETLBL_NLTYPE_UNLABELED:
 		ret_val = 0;
@@ -308,30 +307,6 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
 	return netlbl_unlabel_getattr(secattr);
 }
 
-/**
- * netlbl_socket_getattr - Determine the security attributes of a socket
- * @sock: the socket
- * @secattr: the security attributes
- *
- * Description:
- * Examines the given socket to see any NetLabel style labeling has been
- * applied to the socket, if so it parses the socket label and returns the
- * security attributes in @secattr.  Returns zero on success, negative values
- * on failure.
- *
- */
-int netlbl_socket_getattr(const struct socket *sock,
-			  struct netlbl_lsm_secattr *secattr)
-{
-	int ret_val;
-
-	ret_val = cipso_v4_socket_getattr(sock, secattr);
-	if (ret_val == 0)
-		return 0;
-
-	return netlbl_unlabel_getattr(secattr);
-}
-
 /**
  * netlbl_skbuff_getattr - Determine the security attributes of a packet
  * @skb: the packet

+ 21 - 15
security/selinux/netlabel.c

@@ -36,8 +36,8 @@
 #include "security.h"
 
 /**
- * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
- * @sock: the socket to label
+ * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
+ * @sk: the socket to label
  * @sid: the SID to use
  *
  * Description:
@@ -47,17 +47,17 @@
  * this function and rcu_read_unlock() after this function returns.
  *
  */
-static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
+static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
 {
 	int rc;
-	struct sk_security_struct *sksec = sock->sk->sk_security;
+	struct sk_security_struct *sksec = sk->sk_security;
 	struct netlbl_lsm_secattr secattr;
 
 	rc = security_netlbl_sid_to_secattr(sid, &secattr);
 	if (rc != 0)
 		return rc;
 
-	rc = netlbl_socket_setattr(sock, &secattr);
+	rc = netlbl_sock_setattr(sk, &secattr);
 	if (rc == 0) {
 		spin_lock_bh(&sksec->nlbl_lock);
 		sksec->nlbl_state = NLBL_LABELED;
@@ -206,7 +206,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
 	/* Try to set the NetLabel on the socket to save time later, if we fail
 	 * here we will pick up the pieces in later calls to
 	 * selinux_netlbl_inode_permission(). */
-	selinux_netlbl_socket_setsid(sock, sksec->sid);
+	selinux_netlbl_sock_setsid(sk, sksec->sid);
 
 	rcu_read_unlock();
 }
@@ -223,14 +223,15 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
 int selinux_netlbl_socket_post_create(struct socket *sock)
 {
 	int rc = 0;
+	struct sock *sk = sock->sk;
 	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
-	struct sk_security_struct *sksec = sock->sk->sk_security;
+	struct sk_security_struct *sksec = sk->sk_security;
 
 	sksec->sclass = isec->sclass;
 
 	rcu_read_lock();
 	if (sksec->nlbl_state == NLBL_REQUIRE)
-		rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
+		rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
 	rcu_read_unlock();
 
 	return rc;
@@ -251,14 +252,16 @@ int selinux_netlbl_socket_post_create(struct socket *sock)
 int selinux_netlbl_inode_permission(struct inode *inode, int mask)
 {
 	int rc;
-	struct sk_security_struct *sksec;
+	struct sock *sk;
 	struct socket *sock;
+	struct sk_security_struct *sksec;
 
 	if (!S_ISSOCK(inode->i_mode) ||
 	    ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
 		return 0;
 	sock = SOCKET_I(inode);
-	sksec = sock->sk->sk_security;
+	sk = sock->sk;
+	sksec = sk->sk_security;
 
 	rcu_read_lock();
 	if (sksec->nlbl_state != NLBL_REQUIRE) {
@@ -266,9 +269,9 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
 		return 0;
 	}
 	local_bh_disable();
-	bh_lock_sock_nested(sock->sk);
-	rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
-	bh_unlock_sock(sock->sk);
+	bh_lock_sock_nested(sk);
+	rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+	bh_unlock_sock(sk);
 	local_bh_enable();
 	rcu_read_unlock();
 
@@ -345,14 +348,17 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
 				     int optname)
 {
 	int rc = 0;
-	struct sk_security_struct *sksec = sock->sk->sk_security;
+	struct sock *sk = sock->sk;
+	struct sk_security_struct *sksec = sk->sk_security;
 	struct netlbl_lsm_secattr secattr;
 
 	rcu_read_lock();
 	if (level == IPPROTO_IP && optname == IP_OPTIONS &&
 	    sksec->nlbl_state == NLBL_LABELED) {
 		netlbl_secattr_init(&secattr);
-		rc = netlbl_socket_getattr(sock, &secattr);
+		lock_sock(sk);
+		rc = netlbl_sock_getattr(sk, &secattr);
+		release_sock(sk);
 		if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
 			rc = -EACCES;
 		netlbl_secattr_destroy(&secattr);