selinux: Set socket NetLabel based on connection endpoint
[pandora-kernel.git] / net / ipv4 / cipso_ipv4.c
index e13d6db..23768b9 100644 (file)
@@ -1809,6 +1809,80 @@ socket_setattr_failure:
        return ret_val;
 }
 
+/**
+ * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Removes the CIPSO option from a socket, if present.
+ *
+ */
+void cipso_v4_sock_delattr(struct sock *sk)
+{
+       u8 hdr_delta;
+       struct ip_options *opt;
+       struct inet_sock *sk_inet;
+
+       sk_inet = inet_sk(sk);
+       opt = sk_inet->opt;
+       if (opt == NULL || opt->cipso == 0)
+               return;
+
+       if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
+               u8 cipso_len;
+               u8 cipso_off;
+               unsigned char *cipso_ptr;
+               int iter;
+               int optlen_new;
+
+               cipso_off = opt->cipso - sizeof(struct iphdr);
+               cipso_ptr = &opt->__data[cipso_off];
+               cipso_len = cipso_ptr[1];
+
+               if (opt->srr > opt->cipso)
+                       opt->srr -= cipso_len;
+               if (opt->rr > opt->cipso)
+                       opt->rr -= cipso_len;
+               if (opt->ts > opt->cipso)
+                       opt->ts -= cipso_len;
+               if (opt->router_alert > opt->cipso)
+                       opt->router_alert -= cipso_len;
+               opt->cipso = 0;
+
+               memmove(cipso_ptr, cipso_ptr + cipso_len,
+                       opt->optlen - cipso_off - cipso_len);
+
+               /* determining the new total option length is tricky because of
+                * the padding necessary, the only thing i can think to do at
+                * this point is walk the options one-by-one, skipping the
+                * padding at the end to determine the actual option size and
+                * from there we can determine the new total option length */
+               iter = 0;
+               optlen_new = 0;
+               while (iter < opt->optlen)
+                       if (opt->__data[iter] != IPOPT_NOP) {
+                               iter += opt->__data[iter + 1];
+                               optlen_new = iter;
+                       } else
+                               iter++;
+               hdr_delta = opt->optlen;
+               opt->optlen = (optlen_new + 3) & ~3;
+               hdr_delta -= opt->optlen;
+       } else {
+               /* only the cipso option was present on the socket so we can
+                * remove the entire option struct */
+               sk_inet->opt = NULL;
+               hdr_delta = opt->optlen;
+               kfree(opt);
+       }
+
+       if (sk_inet->is_icsk && hdr_delta > 0) {
+               struct inet_connection_sock *sk_conn = inet_csk(sk);
+               sk_conn->icsk_ext_hdr_len -= hdr_delta;
+               sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+       }
+}
+
 /**
  * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
  * @cipso: the CIPSO v4 option