[RFC PATCH 13/17] calipso: Allow request sockets to be relabelled by the lsm.

2015-12-22 Thread Huw Davies
Request sockets need to have a label that takes into account the
incoming connection as well as their parent's label.  This is used
for the outgoing SYN-ACK and for their child full-socket.

Signed-off-by: Huw Davies 
---
 include/net/netlabel.h  |  6 
 net/ipv6/calipso.c  | 78 +
 net/ipv6/exthdrs.c  | 16 ++---
 net/netlabel/netlabel_calipso.c | 40 +
 net/netlabel/netlabel_calipso.h |  4 +++
 net/netlabel/netlabel_kapi.c| 39 -
 security/selinux/netlabel.c |  2 +-
 7 files changed, 171 insertions(+), 14 deletions(-)

diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index b7ec76c..771a11c 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -229,6 +229,8 @@ struct netlbl_lsm_secattr {
  * @sock_getattr: retrieve the socket's attr
  * @sock_setattr: set the socket's attr
  * @sock_delattr: remove the socket's attr
+ * @req_setattr: set the req socket's attr
+ * @req_delattr: remove the req socket's attr
  *
  * Description:
  * This structure is filled out by the CALIPSO engine and passed
@@ -252,6 +254,10 @@ struct netlbl_calipso_ops {
const struct calipso_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
void (*sock_delattr)(struct sock *sk);
+   int (*req_setattr)(struct request_sock *req,
+  const struct calipso_doi *doi_def,
+  const struct netlbl_lsm_secattr *secattr);
+   void (*req_delattr)(struct request_sock *req);
 };
 
 /*
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
index ce803e2..5d72669 100644
--- a/net/ipv6/calipso.c
+++ b/net/ipv6/calipso.c
@@ -886,6 +886,82 @@ done:
txopt_put(txopts);
 }
 
+/* request sock functions.
+ */
+
+/**
+ * calipso_req_setattr - Add a CALIPSO option to a connection request socket
+ * @req: the connection request socket
+ * @doi_def: the CALIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CALIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function.  Returns zero on success and
+ * negative values on failure.
+ *
+ */
+static int calipso_req_setattr(struct request_sock *req,
+  const struct calipso_doi *doi_def,
+  const struct netlbl_lsm_secattr *secattr)
+{
+   struct ipv6_txoptions *txopts;
+   struct inet_request_sock *req_inet = inet_rsk(req);
+   struct ipv6_opt_hdr *old, *new;
+
+   if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
+   old = req_inet->ipv6_opt->hopopt;
+   else
+   old = NULL;
+
+   new = calipso_opt_insert(old, doi_def, secattr);
+   if (IS_ERR(new))
+   return PTR_ERR(new);
+
+   txopts = ipv6_renew_options_kern(NULL, req_inet->ipv6_opt, IPV6_HOPOPTS,
+new, new ? ipv6_optlen(new) : 0);
+
+   kfree(new);
+
+   if (IS_ERR(txopts))
+   return PTR_ERR(txopts);
+
+   txopts = xchg(_inet->ipv6_opt, txopts);
+   txopt_put(txopts);
+
+   return 0;
+}
+
+/**
+ * calipso_req_delattr - Delete the CALIPSO option from a request socket
+ * @reg: the request socket
+ *
+ * Description:
+ * Removes the CALIPSO option from a request socket, if present.
+ *
+ */
+static void calipso_req_delattr(struct request_sock *req)
+{
+   struct inet_request_sock *req_inet = inet_rsk(req);
+   struct ipv6_opt_hdr *new;
+   struct ipv6_txoptions *txopts;
+
+   if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
+   return;
+
+   if (calipso_opt_del(req_inet->ipv6_opt->hopopt, ))
+   return; /* Nothing to do */
+
+   txopts = ipv6_renew_options_kern(NULL, req_inet->ipv6_opt, IPV6_HOPOPTS,
+new, new ? ipv6_optlen(new) : 0);
+
+   if (!IS_ERR(txopts)) {
+   txopts = xchg(_inet->ipv6_opt, txopts);
+   txopt_put(txopts);
+   }
+   kfree(new);
+}
+
 static const struct netlbl_calipso_ops ops = {
.doi_add  = calipso_doi_add,
.doi_free = calipso_doi_free,
@@ -896,6 +972,8 @@ static const struct netlbl_calipso_ops ops = {
.sock_getattr = calipso_sock_getattr,
.sock_setattr = calipso_sock_setattr,
.sock_delattr = calipso_sock_delattr,
+   .req_setattr  = calipso_req_setattr,
+   .req_delattr  = calipso_req_delattr,
 };
 
 /**
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 9426b26..e87c89b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -793,7 +793,7 @@ static int ipv6_renew_option(void *ohdr,
  * specified option type is not copied into the new set of options.
  *
  * The new set of options is allocated from the socket option 

Re: [RFC PATCH 13/17] calipso: Allow request sockets to be relabelled by the lsm.

2015-12-22 Thread Hannes Frederic Sowa
On 22.12.2015 12:46, Huw Davies wrote:
>   tot_len += sizeof(*opt2);
> - opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
> + if (sk)
> + opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
> + else
> + opt2 = kmalloc(tot_len, GFP_ATOMIC);
>   if (!opt2)
>   return ERR_PTR(-ENOBUFS);

This change looks dangerous to me in terms of control of memory
depletion from a remote host. Could you use sk_to_full_sk and account
options towards the listener socket?

--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html