Skip to content

Commit

Permalink
selinux: Set socket NetLabel based on connection endpoint
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: James Morris <[email protected]>
  • Loading branch information
pcmoore committed Oct 10, 2008
1 parent 948bf85 commit 014ab19
Show file tree
Hide file tree
Showing 8 changed files with 311 additions and 37 deletions.
5 changes: 5 additions & 0 deletions include/net/cipso_ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
int cipso_v4_sock_setattr(struct sock *sk,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
void cipso_v4_sock_delattr(struct sock *sk);
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
int cipso_v4_skbuff_setattr(struct sk_buff *skb,
const struct cipso_v4_doi *doi_def,
Expand All @@ -230,6 +231,10 @@ static inline int cipso_v4_sock_setattr(struct sock *sk,
return -ENOSYS;
}

static inline void cipso_v4_sock_delattr(struct sock *sk)
{
}

static inline int cipso_v4_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
Expand Down
13 changes: 13 additions & 0 deletions include/net/netlabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,12 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
int netlbl_enabled(void);
int netlbl_sock_setattr(struct sock *sk,
const struct netlbl_lsm_secattr *secattr);
void netlbl_sock_delattr(struct sock *sk);
int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr);
int netlbl_conn_setattr(struct sock *sk,
struct sockaddr *addr,
const struct netlbl_lsm_secattr *secattr);
int netlbl_skbuff_setattr(struct sk_buff *skb,
u16 family,
const struct netlbl_lsm_secattr *secattr);
Expand Down Expand Up @@ -449,11 +453,20 @@ static inline int netlbl_sock_setattr(struct sock *sk,
{
return -ENOSYS;
}
static inline void netlbl_sock_delattr(struct sock *sk)
{
}
static inline int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int netlbl_conn_setattr(struct sock *sk,
struct sockaddr *addr,
const struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
u16 family,
const struct netlbl_lsm_secattr *secattr)
Expand Down
74 changes: 74 additions & 0 deletions net/ipv4/cipso_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1809,6 +1809,80 @@ int cipso_v4_sock_setattr(struct sock *sk,
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
Expand Down
78 changes: 77 additions & 1 deletion net/netlabel/netlabel_kapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/

/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -455,6 +455,20 @@ int netlbl_sock_setattr(struct sock *sk,
return ret_val;
}

/**
* netlbl_sock_delattr - Delete all the NetLabel labels on a socket
* @sk: the socket
*
* Description:
* Remove all the NetLabel labeling from @sk. The caller is responsible for
* ensuring that @sk is locked.
*
*/
void netlbl_sock_delattr(struct sock *sk)
{
cipso_v4_sock_delattr(sk);
}

/**
* netlbl_sock_getattr - Determine the security attributes of a sock
* @sk: the sock
Expand All @@ -472,6 +486,68 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
return cipso_v4_sock_getattr(sk, secattr);
}

/**
* netlbl_conn_setattr - Label a connected socket using the correct protocol
* @sk: the socket to label
* @addr: the destination address
* @secattr: the security attributes
*
* Description:
* Attach the correct label to the given connected socket using the security
* attributes specified in @secattr. The caller is responsible for ensuring
* that @sk is locked. Returns zero on success, negative values on failure.
*
*/
int netlbl_conn_setattr(struct sock *sk,
struct sockaddr *addr,
const struct netlbl_lsm_secattr *secattr)
{
int ret_val;
struct sockaddr_in *addr4;
struct netlbl_domaddr4_map *af4_entry;

rcu_read_lock();
switch (addr->sa_family) {
case AF_INET:
addr4 = (struct sockaddr_in *)addr;
af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
addr4->sin_addr.s_addr);
if (af4_entry == NULL) {
ret_val = -ENOENT;
goto conn_setattr_return;
}
switch (af4_entry->type) {
case NETLBL_NLTYPE_CIPSOV4:
ret_val = cipso_v4_sock_setattr(sk,
af4_entry->type_def.cipsov4,
secattr);
break;
case NETLBL_NLTYPE_UNLABELED:
/* just delete the protocols we support for right now
* but we could remove other protocols if needed */
cipso_v4_sock_delattr(sk);
ret_val = 0;
break;
default:
ret_val = -ENOENT;
}
break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
/* since we don't support any IPv6 labeling protocols right
* now we can optimize everything away until we do */
ret_val = 0;
break;
#endif /* IPv6 */
default:
ret_val = 0;
}

conn_setattr_return:
rcu_read_unlock();
return ret_val;
}

/**
* netlbl_skbuff_setattr - Label a packet using the correct protocol
* @skb: the packet
Expand Down
11 changes: 6 additions & 5 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -3794,6 +3794,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in

static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
struct inode_security_struct *isec;
int err;

Expand All @@ -3807,7 +3808,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
isec = SOCK_INODE(sock)->i_security;
if (isec->sclass == SECCLASS_TCP_SOCKET ||
isec->sclass == SECCLASS_DCCP_SOCKET) {
struct sock *sk = sock->sk;
struct avc_audit_data ad;
struct sockaddr_in *addr4 = NULL;
struct sockaddr_in6 *addr6 = NULL;
Expand Down Expand Up @@ -3841,6 +3841,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
goto out;
}

err = selinux_netlbl_socket_connect(sk, address);

out:
return err;
}
Expand Down Expand Up @@ -4290,8 +4292,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
sk->sk_family == PF_UNIX)
isec->sid = sksec->sid;
sksec->sclass = isec->sclass;

selinux_netlbl_sock_graft(sk, parent);
}

static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
Expand Down Expand Up @@ -4342,8 +4342,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
}

static void selinux_inet_conn_established(struct sock *sk,
struct sk_buff *skb)
static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
{
u16 family = sk->sk_family;
struct sk_security_struct *sksec = sk->sk_security;
Expand All @@ -4353,6 +4352,8 @@ static void selinux_inet_conn_established(struct sock *sk,
family = PF_INET;

selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);

selinux_netlbl_inet_conn_established(sk, family);
}

static void selinux_req_classify_flow(const struct request_sock *req,
Expand Down
19 changes: 16 additions & 3 deletions security/selinux/include/netlabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
u16 family,
u32 sid);

void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
int selinux_netlbl_socket_post_create(struct socket *sock);
int selinux_netlbl_inode_permission(struct inode *inode, int mask);
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
Expand All @@ -62,6 +62,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
int selinux_netlbl_socket_setsockopt(struct socket *sock,
int level,
int optname);
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);

#else
static inline void selinux_netlbl_cache_invalidate(void)
{
Expand Down Expand Up @@ -98,8 +100,14 @@ static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
return 0;
}

static inline void selinux_netlbl_sock_graft(struct sock *sk,
struct socket *sock)
static inline int selinux_netlbl_conn_setsid(struct sock *sk,
struct sockaddr *addr)
{
return 0;
}

static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
u16 family)
{
return;
}
Expand All @@ -125,6 +133,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
{
return 0;
}
static inline int selinux_netlbl_socket_connect(struct sock *sk,
struct sockaddr *addr)
{
return 0;
}
#endif /* CONFIG_NETLABEL */

#endif
1 change: 1 addition & 0 deletions security/selinux/include/objsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ struct sk_security_struct {
NLBL_REQUIRE,
NLBL_LABELED,
NLBL_REQSKB,
NLBL_CONNLABELED,
} nlbl_state;
#endif
};
Expand Down
Loading

0 comments on commit 014ab19

Please sign in to comment.