/** * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection * @sk: the new connection * * Description: * A new connection has been established on @sk so make sure it is labeled * correctly with the NetLabel susbsystem. * */ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) { int rc; struct sk_security_struct *sksec = sk->sk_security; struct netlbl_lsm_secattr *secattr; struct inet_sock *sk_inet = inet_sk(sk); struct sockaddr_in addr; if (sksec->nlbl_state != NLBL_REQUIRE) return; secattr = selinux_netlbl_sock_genattr(sk); if (secattr == NULL) return; rc = netlbl_sock_setattr(sk, secattr); switch (rc) { case 0: sksec->nlbl_state = NLBL_LABELED; break; case -EDESTADDRREQ: /* no PF_INET6 support yet because we don't support any IPv6 * labeling protocols */ if (family != PF_INET) { sksec->nlbl_state = NLBL_UNSET; return; } addr.sin_family = family; addr.sin_addr.s_addr = sk_inet->daddr; if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, secattr) != 0) { /* we failed to label the connected socket (could be * for a variety of reasons, the actual "why" isn't * important here) so we have to go to our backup plan, * labeling the packets individually in the netfilter * local output hook. this is okay but we need to * adjust the MSS of the connection to take into * account any labeling overhead, since we don't know * the exact overhead at this point we'll use the worst * case value which is 40 bytes for IPv4 */ struct inet_connection_sock *sk_conn = inet_csk(sk); sk_conn->icsk_ext_hdr_len += 40 - (sk_inet->opt ? sk_inet->opt->optlen : 0); sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); sksec->nlbl_state = NLBL_REQSKB; } else sksec->nlbl_state = NLBL_CONNLABELED; break; default: /* note that we are failing to label the socket which could be * a bad thing since it means traffic could leave the system * without the desired labeling, however, all is not lost as * we have a check in selinux_netlbl_inode_permission() to * pick up the pieces that we might drop here because we can't * return an error code */ break; } }
/** * selinux_netlbl_socket_connect - Label a client-side socket on connect * @sk: the socket to label * @addr: the destination address * * Description: * Attempt to label a connected socket with NetLabel using the given address. * Returns zero values on success, negative values on failure. * */ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) { int rc; struct sk_security_struct *sksec = sk->sk_security; struct netlbl_lsm_secattr *secattr; if (sksec->nlbl_state != NLBL_REQSKB && sksec->nlbl_state != NLBL_CONNLABELED) return 0; lock_sock(sk); /* connected sockets are allowed to disconnect when the address family * is set to AF_UNSPEC, if that is what is happening we want to reset * the socket */ if (addr->sa_family == AF_UNSPEC) { netlbl_sock_delattr(sk); sksec->nlbl_state = NLBL_REQSKB; rc = 0; goto socket_connect_return; } secattr = selinux_netlbl_sock_genattr(sk); if (secattr == NULL) { rc = -ENOMEM; goto socket_connect_return; } rc = netlbl_conn_setattr(sk, addr, secattr); if (rc == 0) sksec->nlbl_state = NLBL_CONNLABELED; socket_connect_return: release_sock(sk); return rc; }