selinux: Set socket NetLabel based on connection endpoint

Previous work enabled the use of address based NetLabel selectors, which while
highly useful, brought the potential for additional per-packet overhead when
used.  This patch attempts to solve that by applying NetLabel socket labels
when sockets are connect()'d.  This should alleviate the per-packet NetLabel
labeling for all connected sockets (yes, it even works for connected DGRAM
sockets).

Signed-off-by: Paul Moore <paul.moore@hp.com>
Reviewed-by: James Morris <jmorris@namei.org>
This commit is contained in:
Paul Moore
2008-10-10 10:16:33 -04:00
parent 948bf85c1b
commit 014ab19a69
8 changed files with 311 additions and 37 deletions

View 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