Skip to content

Commit

Permalink
Smack: secmark support for netfilter
Browse files Browse the repository at this point in the history
Smack uses CIPSO to label internet packets and thus provide
for access control on delivery of packets. The netfilter facility
was not used to allow for Smack to work properly without netfilter
configuration. Smack does not need netfilter, however there are
cases where it would be handy.

As a side effect, the labeling of local IPv4 packets can be optimized
and the handling of local IPv6 packets is just all out better.

The best part is that the netfilter tools use "contexts" that
are just strings, and they work just as well for Smack as they
do for SELinux.

All of the conditional compilation for IPv6 was implemented
by Rafal Krypa <[email protected]>

Signed-off-by: Casey Schaufler <[email protected]>
  • Loading branch information
cschaufler committed Jan 21, 2015
1 parent 5e7270a commit 69f287a
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 8 deletions.
12 changes: 12 additions & 0 deletions security/smack/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,15 @@ config SECURITY_SMACK_BRINGUP
access rule set once the behavior is well understood.
This is a superior mechanism to the oft abused
"permissive" mode of other systems.
If you are unsure how to answer this question, answer N.

config SECURITY_SMACK_NETFILTER
bool "Packet marking using secmarks for netfilter"
depends on SECURITY_SMACK
depends on NETWORK_SECMARK
depends on NETFILTER
default n
help
This enables security marking of network packets using
Smack labels.
If you are unsure how to answer this question, answer N.
1 change: 1 addition & 0 deletions security/smack/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
obj-$(CONFIG_SECURITY_SMACK) := smack.o

smack-y := smack_lsm.o smack_access.o smackfs.o
smack-$(CONFIG_NETFILTER) += smack_netfilter.o
1 change: 1 addition & 0 deletions security/smack/smack.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ struct smack_known *smk_find_entry(const char *);
/*
* Shared data.
*/
extern int smack_enabled;
extern int smack_cipso_direct;
extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient;
Expand Down
94 changes: 86 additions & 8 deletions security/smack/smack_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@
#define SMK_RECEIVING 1
#define SMK_SENDING 2

#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
LIST_HEAD(smk_ipv6_port_list);
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
static struct kmem_cache *smack_inode_cache;
int smack_enabled;

#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static void smk_bu_mode(int mode, char *s)
Expand Down Expand Up @@ -2213,6 +2216,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
return smack_netlabel(sk, sk_lbl);
}

#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
/**
* smk_ipv6_port_label - Smack port access table management
* @sock: socket
Expand Down Expand Up @@ -2362,6 +2366,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
return rc;
}
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */

/**
* smack_inode_setsecurity - set smack xattrs
Expand Down Expand Up @@ -2422,8 +2427,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
} else
return -EOPNOTSUPP;

#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
if (sock->sk->sk_family == PF_INET6)
smk_ipv6_port_label(sock, NULL);
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */

return 0;
}
Expand Down Expand Up @@ -2451,6 +2458,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
}

#ifndef CONFIG_SECURITY_SMACK_NETFILTER
/**
* smack_socket_bind - record port binding information.
* @sock: the socket
Expand All @@ -2464,11 +2472,14 @@ static int smack_socket_post_create(struct socket *sock, int family,
static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
int addrlen)
{
#if IS_ENABLED(CONFIG_IPV6)
if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
smk_ipv6_port_label(sock, address);
#endif

return 0;
}
#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */

/**
* smack_socket_connect - connect access check
Expand Down Expand Up @@ -2497,8 +2508,10 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
case PF_INET6:
if (addrlen < sizeof(struct sockaddr_in6))
return -EINVAL;
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
SMK_CONNECTING);
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
break;
}
return rc;
Expand Down Expand Up @@ -3381,7 +3394,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
int rc = 0;

/*
Expand All @@ -3395,7 +3410,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
rc = smack_netlabel_send(sock->sk, sip);
break;
case AF_INET6:
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
break;
}
return rc;
Expand Down Expand Up @@ -3486,6 +3503,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
return smack_net_ambient;
}

#if IS_ENABLED(CONFIG_IPV6)
static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
{
u8 nexthdr;
Expand Down Expand Up @@ -3532,6 +3550,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
}
return proto;
}
#endif /* CONFIG_IPV6 */

/**
* smack_socket_sock_rcv_skb - Smack packet delivery access check
Expand All @@ -3544,15 +3563,30 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct netlbl_lsm_secattr secattr;
struct socket_smack *ssp = sk->sk_security;
struct smack_known *skp;
struct sockaddr_in6 sadd;
struct smack_known *skp = NULL;
int rc = 0;
struct smk_audit_info ad;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
#endif
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 sadd;
int proto;
#endif /* CONFIG_IPV6 */

switch (sk->sk_family) {
case PF_INET:
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
/*
* If there is a secmark use it rather than the CIPSO label.
* If there is no secmark fall back to CIPSO.
* The secmark is assumed to reflect policy better.
*/
if (skb && skb->secmark != 0) {
skp = smack_from_secid(skb->secmark);
goto access_check;
}
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
/*
* Translate what netlabel gave us.
*/
Expand All @@ -3566,6 +3600,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)

netlbl_secattr_destroy(&secattr);

#ifdef CONFIG_SECURITY_SMACK_NETFILTER
access_check:
#endif
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = sk->sk_family;
Expand All @@ -3584,14 +3621,32 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (rc != 0)
netlbl_skbuff_err(skb, rc, 0);
break;
#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
rc = smk_skb_to_addr_ipv6(skb, &sadd);
if (rc == IPPROTO_UDP || rc == IPPROTO_TCP)
rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
proto = smk_skb_to_addr_ipv6(skb, &sadd);
if (proto != IPPROTO_UDP && proto != IPPROTO_TCP)
break;
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
if (skb && skb->secmark != 0)
skp = smack_from_secid(skb->secmark);
else
rc = 0;
skp = smack_net_ambient;
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
ad.a.u.net->family = sk->sk_family;
ad.a.u.net->netif = skb->skb_iif;
ipv6_skb_to_auditdata(skb, &ad.a, NULL);
#endif /* CONFIG_AUDIT */
rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in,
MAY_WRITE, rc);
#else /* CONFIG_SECURITY_SMACK_NETFILTER */
rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
break;
#endif /* CONFIG_IPV6 */
}

return rc;
}

Expand Down Expand Up @@ -3653,16 +3708,25 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
if (skb != NULL) {
if (skb->protocol == htons(ETH_P_IP))
family = PF_INET;
#if IS_ENABLED(CONFIG_IPV6)
else if (skb->protocol == htons(ETH_P_IPV6))
family = PF_INET6;
#endif /* CONFIG_IPV6 */
}
if (family == PF_UNSPEC && sock != NULL)
family = sock->sk->sk_family;

if (family == PF_UNIX) {
switch (family) {
case PF_UNIX:
ssp = sock->sk->sk_security;
s = ssp->smk_out->smk_secid;
} else if (family == PF_INET || family == PF_INET6) {
break;
case PF_INET:
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
s = skb->secmark;
if (s != 0)
break;
#endif
/*
* Translate what netlabel gave us.
*/
Expand All @@ -3675,6 +3739,14 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
s = skp->smk_secid;
}
netlbl_secattr_destroy(&secattr);
break;
#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
s = skb->secmark;
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
break;
#endif /* CONFIG_IPV6 */
}
*secid = s;
if (s == 0)
Expand Down Expand Up @@ -3730,6 +3802,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct lsm_network_audit net;
#endif

#if IS_ENABLED(CONFIG_IPV6)
if (family == PF_INET6) {
/*
* Handle mapped IPv4 packets arriving
Expand All @@ -3741,6 +3814,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
else
return 0;
}
#endif /* CONFIG_IPV6 */

netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr);
Expand Down Expand Up @@ -4199,7 +4273,9 @@ struct security_operations smack_ops = {
.unix_may_send = smack_unix_may_send,

.socket_post_create = smack_socket_post_create,
#ifndef CONFIG_SECURITY_SMACK_NETFILTER
.socket_bind = smack_socket_bind,
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
.socket_connect = smack_socket_connect,
.socket_sendmsg = smack_socket_sendmsg,
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
Expand Down Expand Up @@ -4280,6 +4356,8 @@ static __init int smack_init(void)
if (!security_module_enable(&smack_ops))
return 0;

smack_enabled = 1;

smack_inode_cache = KMEM_CACHE(inode_smack, 0);
if (!smack_inode_cache)
return -ENOMEM;
Expand Down
96 changes: 96 additions & 0 deletions security/smack/smack_netfilter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Simplified MAC Kernel (smack) security module
*
* This file contains the Smack netfilter implementation
*
* Author:
* Casey Schaufler <[email protected]>
*
* Copyright (C) 2014 Casey Schaufler <[email protected]>
* Copyright (C) 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/

#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netdevice.h>
#include "smack.h"

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)

static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct socket_smack *ssp;
struct smack_known *skp;

if (skb && skb->sk && skb->sk->sk_security) {
ssp = skb->sk->sk_security;
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
}

return NF_ACCEPT;
}
#endif /* IPV6 */

static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct socket_smack *ssp;
struct smack_known *skp;

if (skb && skb->sk && skb->sk->sk_security) {
ssp = skb->sk->sk_security;
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
}

return NF_ACCEPT;
}

static struct nf_hook_ops smack_nf_ops[] = {
{
.hook = smack_ipv4_output,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SELINUX_FIRST,
},
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
{
.hook = smack_ipv6_output,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_SELINUX_FIRST,
},
#endif /* IPV6 */
};

static int __init smack_nf_ip_init(void)
{
int err;

if (smack_enabled == 0)
return 0;

printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");

err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
if (err)
pr_info("Smack: nf_register_hooks: error %d\n", err);

return 0;
}

__initcall(smack_nf_ip_init);

0 comments on commit 69f287a

Please sign in to comment.