int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested) { int rc = NET_RX_SUCCESS; if (sk_filter(sk, skb)) goto discard_and_relse; skb->dev = NULL; if (nested) bh_lock_sock_nested(sk); else bh_lock_sock(sk); if (!sock_owned_by_user(sk)) { /* * trylock + unlock semantics: */ mutex_acquire(&sk->sk_lock.dep_map, 0, 1, _RET_IP_); rc = sk->sk_backlog_rcv(sk, skb); mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); } else sk_add_backlog(sk, skb); bh_unlock_sock(sk); out: sock_put(sk); return rc; discard_and_relse: kfree_skb(skb); goto out; }
/** * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled * @inode: the file descriptor's inode * @mask: the permission mask * * Description: * Looks at a file's inode and if it is marked as a socket protected by * NetLabel then verify that the socket has been labeled, if not try to label * the socket now with the inode's SID. Returns zero on success, negative * values on failure. * */ int selinux_netlbl_inode_permission(struct inode *inode, int mask) { int rc; struct sock *sk; struct socket *sock; struct sk_security_struct *sksec; if (!S_ISSOCK(inode->i_mode) || ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) return 0; sock = SOCKET_I(inode); sk = sock->sk; sksec = sk->sk_security; if (sksec->nlbl_state != NLBL_REQUIRE) return 0; local_bh_disable(); bh_lock_sock_nested(sk); if (likely(sksec->nlbl_state == NLBL_REQUIRE)) rc = selinux_netlbl_sock_setsid(sk); else rc = 0; bh_unlock_sock(sk); local_bh_enable(); return rc; }
/** * 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; local_bh_disable(); bh_lock_sock_nested(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: bh_unlock_sock(sk); local_bh_enable(); return rc; }