#include "objsec.h"
#include "security.h"
+/**
+ * selinux_netlbl_sidlookup_cached - Cache a SID lookup
+ * @skb: the packet
+ * @secattr: the NetLabel security attributes
+ * @sid: the SID
+ *
+ * Description:
+ * Query the SELinux security server to lookup the correct SID for the given
+ * security attributes. If the query is successful, cache the result to speed
+ * up future lookups. Returns zero on success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr,
+ u32 *sid)
+{
+ int rc;
+
+ rc = security_netlbl_secattr_to_sid(secattr, sid);
+ if (rc == 0 &&
+ (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
+ (secattr->flags & NETLBL_SECATTR_CACHE))
+ netlbl_cache_add(skb, secattr);
+
+ return rc;
+}
+
/**
* selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
* @sk: the socket to label
struct sk_security_struct *sksec = sk->sk_security;
struct netlbl_lsm_secattr secattr;
+ netlbl_secattr_init(&secattr);
+
rc = security_netlbl_sid_to_secattr(sid, &secattr);
if (rc != 0)
- return rc;
-
+ goto sock_setsid_return;
rc = netlbl_sock_setattr(sk, &secattr);
if (rc == 0) {
spin_lock_bh(&sksec->nlbl_lock);
spin_unlock_bh(&sksec->nlbl_lock);
}
+sock_setsid_return:
+ netlbl_secattr_destroy(&secattr);
return rc;
}
* lock as other threads could have access to ssec */
rcu_read_lock();
selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
- newssec->sclass = ssec->sclass;
rcu_read_unlock();
}
/**
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
* @skb: the packet
- * @base_sid: the SELinux SID to use as a context for MLS only attributes
+ * @family: protocol family
+ * @type: NetLabel labeling protocol type
* @sid: the SID
*
* Description:
* assign to the packet. Returns zero on success, negative values on failure.
*
*/
-int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
+int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
+ u16 family,
+ u32 *type,
+ u32 *sid)
{
int rc;
struct netlbl_lsm_secattr secattr;
+ if (!netlbl_enabled()) {
+ *sid = SECSID_NULL;
+ return 0;
+ }
+
netlbl_secattr_init(&secattr);
- rc = netlbl_skbuff_getattr(skb, &secattr);
+ rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
- rc = security_netlbl_secattr_to_sid(&secattr,
- base_sid,
- sid);
+ rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
else
*sid = SECSID_NULL;
+ *type = secattr.type;
netlbl_secattr_destroy(&secattr);
return rc;
*/
void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
{
- struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec = sk->sk_security;
struct netlbl_lsm_secattr secattr;
u32 nlbl_peer_sid;
- sksec->sclass = isec->sclass;
-
rcu_read_lock();
if (sksec->nlbl_state != NLBL_REQUIRE) {
netlbl_secattr_init(&secattr);
if (netlbl_sock_getattr(sk, &secattr) == 0 &&
secattr.flags != NETLBL_SECATTR_NONE &&
- security_netlbl_secattr_to_sid(&secattr,
- SECINITSID_UNLABELED,
- &nlbl_peer_sid) == 0)
+ security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
sksec->peer_sid = nlbl_peer_sid;
netlbl_secattr_destroy(&secattr);
{
int rc = 0;
struct sock *sk = sock->sk;
- struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec = sk->sk_security;
- sksec->sclass = isec->sclass;
-
rcu_read_lock();
if (sksec->nlbl_state == NLBL_REQUIRE)
rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
* selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
* @sksec: the sock's sk_security_struct
* @skb: the packet
+ * @family: protocol family
* @ad: the audit data
*
* Description:
*/
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct sk_buff *skb,
+ u16 family,
struct avc_audit_data *ad)
{
int rc;
- u32 netlbl_sid;
- u32 recv_perm;
+ u32 nlbl_sid;
+ u32 perm;
+ struct netlbl_lsm_secattr secattr;
- rc = selinux_netlbl_skbuff_getsid(skb,
- SECINITSID_UNLABELED,
- &netlbl_sid);
+ if (!netlbl_enabled())
+ return 0;
+
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_skbuff_getattr(skb, family, &secattr);
+ if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
+ rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
+ else
+ nlbl_sid = SECINITSID_UNLABELED;
+ netlbl_secattr_destroy(&secattr);
if (rc != 0)
return rc;
- if (netlbl_sid == SECSID_NULL)
- return 0;
-
switch (sksec->sclass) {
case SECCLASS_UDP_SOCKET:
- recv_perm = UDP_SOCKET__RECVFROM;
+ perm = UDP_SOCKET__RECVFROM;
break;
case SECCLASS_TCP_SOCKET:
- recv_perm = TCP_SOCKET__RECVFROM;
+ perm = TCP_SOCKET__RECVFROM;
break;
default:
- recv_perm = RAWIP_SOCKET__RECVFROM;
+ perm = RAWIP_SOCKET__RECVFROM;
}
- rc = avc_has_perm(sksec->sid,
- netlbl_sid,
- sksec->sclass,
- recv_perm,
- ad);
+ rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
if (rc == 0)
return 0;
- netlbl_skbuff_err(skb, rc);
+ if (nlbl_sid != SECINITSID_UNLABELED)
+ netlbl_skbuff_err(skb, rc);
return rc;
}