* [RFC PATCH 0/3] Shrink sk_buff and add a security blob
@ 2013-04-16 20:39 Paul Moore
2013-04-16 20:39 ` [RFC PATCH 1/3] skb: wrap skb_shared_info->destructor_arg access with set and get functions Paul Moore
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Paul Moore @ 2013-04-16 20:39 UTC (permalink / raw)
To: netdev, linux-security-module, selinux
This patchset is a follow-up to the recent discussion around sk_buff
size and the desire to add a LSM security blob to the sk_buff. The
patches proposed here do indeed shrink the size of the sk_buff from
256 bytes down to 248 bytes on my x86_64 system while adding a LSM
security blob, but there is a tradeoff in that the patches overload
the skb_shared_info->destructor_arg field (more info/detail in the
description of patch 3/3). The overloading only takes place for LSMs
which make use of the blob, all other cases behave as they currently
do. I wouldn't say this solution is perfect, but it does both shrink
the sk_buff and add a security blob through what I believe to be the
least invasive approach.
I'm posting this to restart the discussion around these changes now
that we have a set of patches to discuss, critique, etc. Hopefully
we can find some middle ground that gets everyone enough of what they
want, if not all.
The standard disclaimers apply. This is a RFC patch; it builds,
boots, and passes the basic unit tests I've thrown at it, but I can't
say I've tested it throughly. This includes building the kernel with
all the different, relevant CONFIG options. YMMV.
---
Paul Moore (3):
skb: wrap skb_shared_info->destructor_arg access with set and get functions
net: wrap skb->secmark access with set and get functions
net: move sk_buff->secmark into a security blob in skb_shared_info
drivers/net/macvtap.c | 2 -
drivers/net/tun.c | 2 -
include/linux/security.h | 91 ++++++++++++++++++++++++++-
include/linux/skbuff.h | 73 ++++++++++++++-------
net/core/skbuff.c | 28 +++++++-
net/ipv4/ip_output.c | 2 -
net/ipv6/ip6_output.c | 2 -
net/netfilter/xt_AUDIT.c | 8 +-
net/netfilter/xt_CONNSECMARK.c | 10 ++-
net/netfilter/xt_SECMARK.c | 2 -
net/packet/af_packet.c | 4 +
security/capability.c | 38 +++++++++++
security/security.c | 63 +++++++++++++++++++
security/selinux/hooks.c | 126 +++++++++++++++++++++++++++++++++----
security/selinux/include/objsec.h | 6 ++
15 files changed, 397 insertions(+), 60 deletions(-)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC PATCH 1/3] skb: wrap skb_shared_info->destructor_arg access with set and get functions
2013-04-16 20:39 [RFC PATCH 0/3] Shrink sk_buff and add a security blob Paul Moore
@ 2013-04-16 20:39 ` Paul Moore
2013-04-16 20:39 ` [RFC PATCH 2/3] net: wrap skb->secmark " Paul Moore
2013-04-16 20:39 ` [RFC PATCH 3/3] net: move sk_buff->secmark into a security blob in skb_shared_info Paul Moore
2 siblings, 0 replies; 4+ messages in thread
From: Paul Moore @ 2013-04-16 20:39 UTC (permalink / raw)
To: netdev, linux-security-module, selinux
Abstract away direct access to the "destructor_arg" field in the
skb_shared_info struct via skb_destructor_arg_{set,get}() which is
defined as a static inline in include/linux/skbuff.h.
Signed-off-by: Paul Moore <pmoore@redhat.com>
---
drivers/net/macvtap.c | 2 +-
drivers/net/tun.c | 2 +-
include/linux/skbuff.h | 19 +++++++++++++++++++
net/core/skbuff.c | 6 +++---
net/packet/af_packet.c | 4 ++--
5 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index a449439..8179df0 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -729,7 +729,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
vlan = rcu_dereference_bh(q->vlan);
/* copy skb_ubuf_info for callback when skb has no error */
if (zerocopy) {
- skb_shinfo(skb)->destructor_arg = m->msg_control;
+ skb_destructor_arg_set(skb, m->msg_control);
skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index b7c457a..3cea09d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1199,7 +1199,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
/* copy skb_ubuf_info for callback when skb has no error */
if (zerocopy) {
- skb_shinfo(skb)->destructor_arg = msg_control;
+ skb_destructor_arg_set(skb, msg_control);
skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index b8292d8..0998af3 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -696,6 +696,25 @@ static inline unsigned int skb_end_offset(const struct sk_buff *skb)
/* Internal */
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
+/**
+ * skb_destructor_arg_set - set the packet's destructor argument
+ * @skb: packet
+ * @ptr: pointer to the destructor argument
+ */
+static inline void skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
+{
+ skb_shinfo(skb)->destructor_arg = ptr;
+}
+
+/**
+ * skb_destructor_arg_get - return the packet's destructor argument
+ * @skb: packet
+ */
+static inline void *skb_destructor_arg_get(const struct sk_buff *skb)
+{
+ return skb_shinfo(skb)->destructor_arg;
+}
+
static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
{
return &skb_shinfo(skb)->hwtstamps;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 33245ef..e4fa549 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -506,7 +506,7 @@ static void skb_release_data(struct sk_buff *skb)
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
struct ubuf_info *uarg;
- uarg = skb_shinfo(skb)->destructor_arg;
+ uarg = skb_destructor_arg_get(skb);
if (uarg->callback)
uarg->callback(uarg, true);
}
@@ -635,7 +635,7 @@ void skb_tx_error(struct sk_buff *skb)
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
struct ubuf_info *uarg;
- uarg = skb_shinfo(skb)->destructor_arg;
+ uarg = skb_destructor_arg_get(skb);
if (uarg->callback)
uarg->callback(uarg, false);
skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
@@ -782,7 +782,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
int i;
int num_frags = skb_shinfo(skb)->nr_frags;
struct page *page, *head = NULL;
- struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
+ struct ubuf_info *uarg = skb_destructor_arg_get(skb);
for (i = 0; i < num_frags; i++) {
u8 *vaddr;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 1d6793d..32f186b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1833,7 +1833,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
void *ph;
if (likely(po->tx_ring.pg_vec)) {
- ph = skb_shinfo(skb)->destructor_arg;
+ ph = skb_destructor_arg_get(skb);
BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
atomic_dec(&po->tx_ring.pending);
__packet_set_status(po, ph, TP_STATUS_AVAILABLE);
@@ -1863,7 +1863,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb->dev = dev;
skb->priority = po->sk.sk_priority;
skb->mark = po->sk.sk_mark;
- skb_shinfo(skb)->destructor_arg = ph.raw;
+ skb_destructor_arg_set(skb, ph.raw);
switch (po->tp_version) {
case TPACKET_V2:
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [RFC PATCH 2/3] net: wrap skb->secmark access with set and get functions
2013-04-16 20:39 [RFC PATCH 0/3] Shrink sk_buff and add a security blob Paul Moore
2013-04-16 20:39 ` [RFC PATCH 1/3] skb: wrap skb_shared_info->destructor_arg access with set and get functions Paul Moore
@ 2013-04-16 20:39 ` Paul Moore
2013-04-16 20:39 ` [RFC PATCH 3/3] net: move sk_buff->secmark into a security blob in skb_shared_info Paul Moore
2 siblings, 0 replies; 4+ messages in thread
From: Paul Moore @ 2013-04-16 20:39 UTC (permalink / raw)
To: netdev, linux-security-module, selinux
Abstract away direct access to the "secmark" field in the sk_buff
struct via the LSM hooks security_skb_secmark_{get,set}().
Signed-off-by: Paul Moore <pmoore@redhat.com>
---
include/linux/security.h | 20 +++++++++++++++++++-
net/netfilter/xt_CONNSECMARK.c | 10 ++++++----
net/netfilter/xt_SECMARK.c | 2 +-
security/capability.c | 10 ++++++++++
security/security.c | 11 +++++++++++
security/selinux/hooks.c | 22 +++++++++++++++++-----
6 files changed, 64 insertions(+), 11 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 032c366..464f123 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1016,6 +1016,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* This hook sets the packet's owning sock.
* @skb is the packet.
* @sk the sock which owns the packet.
+ * @skb_secmark_set:
+ * This hook sets the secmark on a packet.
+ * @skb the packet.
+ * @secmark the secmark value.
+ * @skb_secmark_get:
+ * This hook returns the packet's secmark.
+ * @skb the packet.
*
* Security hooks for XFRM operations.
*
@@ -1643,6 +1650,8 @@ struct security_operations {
int (*tun_dev_attach) (struct sock *sk, void *security);
int (*tun_dev_open) (void *security);
void (*skb_owned_by) (struct sk_buff *skb, struct sock *sk);
+ void (*skb_secmark_set) (struct sk_buff *skb, u32 secmark);
+ u32 (*skb_secmark_get) (const struct sk_buff *skb);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -2592,8 +2601,9 @@ int security_tun_dev_create(void);
int security_tun_dev_attach_queue(void *security);
int security_tun_dev_attach(struct sock *sk, void *security);
int security_tun_dev_open(void *security);
-
void security_skb_owned_by(struct sk_buff *skb, struct sock *sk);
+void security_skb_secmark_set(struct sk_buff *skb, u32 secmark);
+u32 security_skb_secmark_get(const struct sk_buff *skb);
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct sock *sock,
@@ -2791,6 +2801,14 @@ static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
}
+static inline void security_skb_secmark_set(struct sk_buff *skb, u32 secmark)
+{
+}
+
+static inline u32 security_skb_secmark_get(const struct sk_buff *skb)
+{
+ return 0;
+}
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index e04dc28..2201c1b 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -35,13 +35,15 @@ MODULE_ALIAS("ip6t_CONNSECMARK");
*/
static void secmark_save(const struct sk_buff *skb)
{
- if (skb->secmark) {
+ u32 secmark = security_skb_secmark_get(skb);
+
+ if (secmark) {
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
ct = nf_ct_get(skb, &ctinfo);
if (ct && !ct->secmark) {
- ct->secmark = skb->secmark;
+ ct->secmark = secmark;
nf_conntrack_event_cache(IPCT_SECMARK, ct);
}
}
@@ -53,13 +55,13 @@ static void secmark_save(const struct sk_buff *skb)
*/
static void secmark_restore(struct sk_buff *skb)
{
- if (!skb->secmark) {
+ if (!security_skb_secmark_get(skb)) {
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
ct = nf_ct_get(skb, &ctinfo);
if (ct && ct->secmark)
- skb->secmark = ct->secmark;
+ security_skb_secmark_set(skb, ct->secmark);
}
}
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index 9faf5e0..ed20d8e 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -45,7 +45,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
BUG();
}
- skb->secmark = secmark;
+ security_skb_secmark_set(skb, secmark);
return XT_CONTINUE;
}
diff --git a/security/capability.c b/security/capability.c
index 6783c3e..b7c0ef2 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -742,6 +742,14 @@ static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
}
+static void cap_skb_secmark_set(struct sk_buff *skb, u32 secmark)
+{
+}
+
+static u32 cap_skb_secmark_get(const struct sk_buff *skb)
+{
+ return 0;
+}
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1077,6 +1085,8 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, tun_dev_attach_queue);
set_to_cap_if_null(ops, tun_dev_attach);
set_to_cap_if_null(ops, skb_owned_by);
+ set_to_cap_if_null(ops, skb_secmark_set);
+ set_to_cap_if_null(ops, skb_secmark_get);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_cap_if_null(ops, xfrm_policy_alloc_security);
diff --git a/security/security.c b/security/security.c
index 03f248b..7e2b7c7 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1295,6 +1295,17 @@ void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
security_ops->skb_owned_by(skb, sk);
}
+void security_skb_secmark_set(struct sk_buff *skb, u32 secmark)
+{
+ security_ops->skb_secmark_set(skb, secmark);
+}
+EXPORT_SYMBOL(security_skb_secmark_set);
+
+u32 security_skb_secmark_get(const struct sk_buff *skb)
+{
+ return security_ops->skb_secmark_get(skb);
+}
+EXPORT_SYMBOL(security_skb_secmark_get);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7171a95..5021cf7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3473,6 +3473,21 @@ static void selinux_task_to_inode(struct task_struct *p,
isec->initialized = 1;
}
+static void selinux_skb_owned_by(struct sk_buff *skb, struct sock *sk)
+{
+ skb_set_owner_w(skb, sk);
+}
+
+static void selinux_skb_secmark_set(struct sk_buff *skb, u32 secmark)
+{
+ skb->secmark = secmark;
+}
+
+static u32 selinux_skb_secmark_get(const struct sk_buff *skb)
+{
+ return skb->secmark;
+}
+
/* Returns error only if unable to parse addresses */
static int selinux_parse_skb_ipv4(struct sk_buff *skb,
struct common_audit_data *ad, u8 *proto)
@@ -4364,11 +4379,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
}
-static void selinux_skb_owned_by(struct sk_buff *skb, struct sock *sk)
-{
- skb_set_owner_w(skb, sk);
-}
-
static int selinux_secmark_relabel_packet(u32 sid)
{
const struct task_security_struct *__tsec;
@@ -5671,6 +5681,8 @@ static struct security_operations selinux_ops = {
.tun_dev_attach = selinux_tun_dev_attach,
.tun_dev_open = selinux_tun_dev_open,
.skb_owned_by = selinux_skb_owned_by,
+ .skb_secmark_set = selinux_skb_secmark_set,
+ .skb_secmark_get = selinux_skb_secmark_get,
#ifdef CONFIG_SECURITY_NETWORK_XFRM
.xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [RFC PATCH 3/3] net: move sk_buff->secmark into a security blob in skb_shared_info
2013-04-16 20:39 [RFC PATCH 0/3] Shrink sk_buff and add a security blob Paul Moore
2013-04-16 20:39 ` [RFC PATCH 1/3] skb: wrap skb_shared_info->destructor_arg access with set and get functions Paul Moore
2013-04-16 20:39 ` [RFC PATCH 2/3] net: wrap skb->secmark " Paul Moore
@ 2013-04-16 20:39 ` Paul Moore
2 siblings, 0 replies; 4+ messages in thread
From: Paul Moore @ 2013-04-16 20:39 UTC (permalink / raw)
To: netdev, linux-security-module, selinux
This patch moves the "secmark" field from where it currently lives
in the sk_buff struct to a newly overloaded field in the
skb_shared_info struct. There are two main reasons for making this
change 1) we shrink sk_buff from 256 bytes to 248 bytes (on x86_64)
(the sk_buff breakdown is shown below) and 2) we gain a LSM security
blob.
There are two catches to this change 1) the secmark value is now the
same for a sk_buff and all its associated clones and 2) we overload
the "destructor_arg" field in the skb_shared_info struct. The
secmark/clone issue is not a problem as SELinux, the only user, keeps
the secmark value consistent across clone calls and it seems
reasonable that any other LSM using secmark would do the same as the
LSM security attributes are generally tied to the packet's data and
not the sk_buff metadata. The overloading issue is a bit more
awkward, but with the sk_buff and skb_shared_info structures already
carefully pruned for size, adding a new field is not an option (so
says DaveM) make replacement or overloading of an existing field the
only viable options. Not finding a field suitable for replacement,
this patch opts for the overloading option and choose the
"destructor_arg" field due to its size and usage within the core
network stack.
The "destructor_arg" overloading is done in such a way that there
should be no impact when the LSM is disabled at compile time, and
only an additional function call when the LSM is enabled but the
hooks are not in use by the active LSM. When the LSM is enabled and
the active LSM is making use of the new hooks there will be some
additional overhead, but that is to be expected.
For reference, here is the breakdown of the sk_buff struct:
BEFORE:
struct sk_buff {
struct sk_buff * next; /* 0 8 */
struct sk_buff * prev; /* 8 8 */
ktime_t tstamp; /* 16 8 */
struct sock * sk; /* 24 8 */
struct net_device * dev; /* 32 8 */
char cb[48]; /* 40 48 */
/* --- cacheline 1 boundary (64 bytes) was 24 bytes ago --- */
long unsigned int _skb_refdst; /* 88 8 */
struct sec_path * sp; /* 96 8 */
unsigned int len; /* 104 4 */
unsigned int data_len; /* 108 4 */
__u16 mac_len; /* 112 2 */
__u16 hdr_len; /* 114 2 */
union {
__wsum csum; /* 4 */
struct {
__u16 csum_start; /* 116 2 */
__u16 csum_offset; /* 118 2 */
}; /* 4 */
}; /* 116 4 */
__u32 priority; /* 120 4 */
int flags1_begin[0]; /* 124 0 */
__u8 local_df:1; /* 124: 7 1 */
__u8 cloned:1; /* 124: 6 1 */
__u8 ip_summed:2; /* 124: 4 1 */
__u8 nohdr:1; /* 124: 3 1 */
__u8 nfctinfo:3; /* 124: 0 1 */
__u8 pkt_type:3; /* 125: 5 1 */
__u8 fclone:2; /* 125: 3 1 */
__u8 ipvs_property:1; /* 125: 2 1 */
__u8 peeked:1; /* 125: 1 1 */
__u8 nf_trace:1; /* 125: 0 1 */
/* XXX 2 bytes hole, try to pack */
/* --- cacheline 2 boundary (128 bytes) --- */
int flags1_end[0]; /* 128 0 */
__be16 protocol; /* 128 2 */
/* XXX 6 bytes hole, try to pack */
void (*destructor)(struct sk_buff *);
/* 136 8 */
struct nf_conntrack * nfct; /* 144 8 */
struct sk_buff * nfct_reasm; /* 152 8 */
struct nf_bridge_info * nf_bridge; /* 160 8 */
int skb_iif; /* 168 4 */
__u32 rxhash; /* 172 4 */
__u16 vlan_tci; /* 176 2 */
__u16 tc_index; /* 178 2 */
__u16 tc_verd; /* 180 2 */
__u16 queue_mapping; /* 182 2 */
int flags2_begin[0]; /* 184 0 */
__u8 ndisc_nodetype:2; /* 184: 6 1 */
__u8 pfmemalloc:1; /* 184: 5 1 */
__u8 ooo_okay:1; /* 184: 4 1 */
__u8 l4_rxhash:1; /* 184: 3 1 */
__u8 wifi_acked_valid:1; /* 184: 2 1 */
__u8 wifi_acked:1; /* 184: 1 1 */
__u8 no_fcs:1; /* 184: 0 1 */
__u8 head_frag:1; /* 185: 7 1 */
__u8 encapsulation:1; /* 185: 6 1 */
/* XXX 6 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int flags2_end[0]; /* 188 0 */
dma_cookie_t dma_cookie; /* 188 4 */
/* --- cacheline 3 boundary (192 bytes) --- */
__u32 secmark; /* 192 4 */
union {
__u32 mark; /* 4 */
__u32 dropcount; /* 4 */
__u32 reserved_tailroom; /* 4 */
}; /* 196 4 */
sk_buff_data_t inner_transport_header; /* 200 4 */
sk_buff_data_t inner_network_header; /* 204 4 */
sk_buff_data_t transport_header; /* 208 4 */
sk_buff_data_t network_header; /* 212 4 */
sk_buff_data_t mac_header; /* 216 4 */
sk_buff_data_t tail; /* 220 4 */
sk_buff_data_t end; /* 224 4 */
/* XXX 4 bytes hole, try to pack */
unsigned char * head; /* 232 8 */
unsigned char * data; /* 240 8 */
unsigned int truesize; /* 248 4 */
atomic_t users; /* 252 4 */
/* --- cacheline 4 boundary (256 bytes) --- */
/* size: 256, cachelines: 4, members: 62 */
/* sum members: 242, holes: 4, sum holes: 14 */
/* bit holes: 1, sum bit holes: 6 bits */
};
AFTER:
struct sk_buff_test {
struct sk_buff * next; /* 0 8 */
struct sk_buff * prev; /* 8 8 */
ktime_t tstamp; /* 16 8 */
struct sock * sk; /* 24 8 */
struct net_device * dev; /* 32 8 */
char cb[48]; /* 40 48 */
/* --- cacheline 1 boundary (64 bytes) was 24 bytes ago --- */
long unsigned int _skb_refdst; /* 88 8 */
struct sec_path * sp; /* 96 8 */
unsigned int len; /* 104 4 */
unsigned int data_len; /* 108 4 */
__u16 mac_len; /* 112 2 */
__u16 hdr_len; /* 114 2 */
union {
__wsum csum; /* 4 */
struct {
__u16 csum_start; /* 116 2 */
__u16 csum_offset; /* 118 2 */
}; /* 4 */
}; /* 116 4 */
__u32 priority; /* 120 4 */
int flags1_begin[0]; /* 124 0 */
__u8 local_df:1; /* 124: 7 1 */
__u8 cloned:1; /* 124: 6 1 */
__u8 ip_summed:2; /* 124: 4 1 */
__u8 nohdr:1; /* 124: 3 1 */
__u8 nfctinfo:3; /* 124: 0 1 */
__u8 pkt_type:3; /* 125: 5 1 */
__u8 fclone:2; /* 125: 3 1 */
__u8 ipvs_property:1; /* 125: 2 1 */
__u8 peeked:1; /* 125: 1 1 */
__u8 nf_trace:1; /* 125: 0 1 */
/* XXX 2 bytes hole, try to pack */
/* --- cacheline 2 boundary (128 bytes) --- */
int flags1_end[0]; /* 128 0 */
__be16 protocol; /* 128 2 */
/* XXX 6 bytes hole, try to pack */
void (*destructor)(struct sk_buff *);
/* 136 8 */
struct nf_conntrack * nfct; /* 144 8 */
struct sk_buff * nfct_reasm; /* 152 8 */
struct nf_bridge_info * nf_bridge; /* 160 8 */
int skb_iif; /* 168 4 */
__u32 rxhash; /* 172 4 */
__u16 vlan_tci; /* 176 2 */
__u16 tc_index; /* 178 2 */
__u16 tc_verd; /* 180 2 */
__u16 queue_mapping; /* 182 2 */
int flags2_begin[0]; /* 184 0 */
__u8 ndisc_nodetype:2; /* 184: 6 1 */
__u8 pfmemalloc:1; /* 184: 5 1 */
__u8 ooo_okay:1; /* 184: 4 1 */
__u8 l4_rxhash:1; /* 184: 3 1 */
__u8 wifi_acked_valid:1; /* 184: 2 1 */
__u8 wifi_acked:1; /* 184: 1 1 */
__u8 no_fcs:1; /* 184: 0 1 */
__u8 head_frag:1; /* 185: 7 1 */
__u8 encapsulation:1; /* 185: 6 1 */
/* XXX 6 bits hole, try to pack */
/* XXX 2 bytes hole, try to pack */
int flags2_end[0]; /* 188 0 */
dma_cookie_t dma_cookie; /* 188 4 */
/* --- cacheline 3 boundary (192 bytes) --- */
union {
__u32 mark; /* 4 */
__u32 dropcount; /* 4 */
__u32 reserved_tailroom; /* 4 */
}; /* 192 4 */
sk_buff_data_t inner_transport_header; /* 196 4 */
sk_buff_data_t inner_network_header; /* 200 4 */
sk_buff_data_t transport_header; /* 204 4 */
sk_buff_data_t network_header; /* 208 4 */
sk_buff_data_t mac_header; /* 212 4 */
sk_buff_data_t tail; /* 216 4 */
sk_buff_data_t end; /* 220 4 */
unsigned char * head; /* 224 8 */
unsigned char * data; /* 232 8 */
unsigned int truesize; /* 240 4 */
atomic_t users; /* 244 4 */
/* size: 248, cachelines: 4, members: 61 */
/* sum members: 238, holes: 3, sum holes: 10 */
/* bit holes: 1, sum bit holes: 6 bits */
/* last cacheline: 56 bytes */
};
Signed-off-by: Paul Moore <pmoore@redhat.com>
---
include/linux/security.h | 71 ++++++++++++++++++++++++
include/linux/skbuff.h | 58 ++++++++++----------
net/core/skbuff.c | 22 +++++++-
net/ipv4/ip_output.c | 2 -
net/ipv6/ip6_output.c | 2 -
net/netfilter/xt_AUDIT.c | 8 +--
security/capability.c | 28 ++++++++++
security/security.c | 52 ++++++++++++++++++
security/selinux/hooks.c | 108 ++++++++++++++++++++++++++++++++++---
security/selinux/include/objsec.h | 6 ++
10 files changed, 311 insertions(+), 46 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 464f123..53484af 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -19,6 +19,10 @@
*
*/
+/* We include linux/skbuff.h at the very top to prevent problems with both
+ * linux/skbuff.h and linux/security.h including each other */
+#include <linux/skbuff.h>
+
#ifndef __LINUX_SECURITY_H
#define __LINUX_SECURITY_H
@@ -98,7 +102,6 @@ extern int cap_task_setnice(struct task_struct *p, int nice);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
struct msghdr;
-struct sk_buff;
struct sock;
struct sockaddr;
struct socket;
@@ -1012,10 +1015,32 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* This hook can be used by the module to update any security state
* associated with the TUN device's security structure.
* @security pointer to the TUN devices's security structure.
+ * @skb_alloc:
+ * This hook is called when a new packet is allocated and should be used
+ * to allocate any per-packet security state.
+ * @skb the packet
+ * @gfp_mask allocation mask.
+ * @flags the flags passed to __alloc_skb().
+ * @node NUMA node, set to -1 if NUMA information is not available.
+ * @skb_free:
+ * This hook is called when a packet is freed and should be used to
+ * release any per-packet security state.
+ * @skb the packet.
+ * @skb_security_copy:
+ * This hook copies the security metadata from one packet to another.
+ * @dst the destination packet.
+ * @src the source packet.
* @skb_owned_by:
* This hook sets the packet's owning sock.
* @skb is the packet.
* @sk the sock which owns the packet.
+ * @skb_destructor_arg_set:
+ * This hook sets the packet's destructor argument.
+ * @skb packet.
+ * @ptr pointer to the destructor argument.
+ * @skb_destructor_arg_get:
+ * This hook returns the packet's destructor argument.
+ * @skb the packet.
* @skb_secmark_set:
* This hook sets the secmark on a packet.
* @skb the packet.
@@ -1649,7 +1674,12 @@ struct security_operations {
int (*tun_dev_attach_queue) (void *security);
int (*tun_dev_attach) (struct sock *sk, void *security);
int (*tun_dev_open) (void *security);
+ int (*skb_alloc) (struct sk_buff *skb, gfp_t gfp_mask, int flags, int node);
+ void (*skb_free) (struct sk_buff *skb);
+ void (*skb_security_copy) (struct sk_buff *dst, const struct sk_buff *src);
void (*skb_owned_by) (struct sk_buff *skb, struct sock *sk);
+ void (*skb_destructor_arg_set) (struct sk_buff *skb, void *ptr);
+ void *(*skb_destructor_arg_get) (const struct sk_buff *skb);
void (*skb_secmark_set) (struct sk_buff *skb, u32 secmark);
u32 (*skb_secmark_get) (const struct sk_buff *skb);
#endif /* CONFIG_SECURITY_NETWORK */
@@ -2601,6 +2631,13 @@ int security_tun_dev_create(void);
int security_tun_dev_attach_queue(void *security);
int security_tun_dev_attach(struct sock *sk, void *security);
int security_tun_dev_open(void *security);
+int security_skb_alloc(struct sk_buff *skb, gfp_t gfp_mask, int flags, int node);
+void security_skb_free(struct sk_buff *skb);
+void security_skb_ref(struct sk_buff *skb);
+void security_skb_unref(struct sk_buff *skb);
+void security_skb_security_copy(struct sk_buff *dst, const struct sk_buff *src);
+void security_skb_destructor_arg_set(struct sk_buff *skb, void *ptr);
+void *security_skb_destructor_arg_get(const struct sk_buff *skb);
void security_skb_owned_by(struct sk_buff *skb, struct sock *sk);
void security_skb_secmark_set(struct sk_buff *skb, u32 secmark);
u32 security_skb_secmark_get(const struct sk_buff *skb);
@@ -2797,10 +2834,42 @@ static inline int security_tun_dev_open(void *security)
return 0;
}
+static inline int security_skb_alloc(struct sk_buff *skb, gfp_t gfp_mask, int flags, int node)
+{
+ return 0;
+}
+
+static inline void security_skb_free(struct sk_buff *skb)
+{
+}
+
+static inline void security_skb_ref(struct sk_buff *skb)
+{
+}
+
+static inline void security_skb_unref(struct sk_buff *skb)
+{
+}
+
+static inline void security_skb_security_copy(struct sk_buff *dst,
+ const struct sk_buff *src)
+{
+}
+
static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
}
+static inline void security_skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
+{
+ skb_shinfo(skb)->destructor_arg = ptr;
+}
+
+static inline void *security_skb_destructor_arg_get(const struct sk_buff *skb)
+{
+ return skb_shinfo(skb)->destructor_arg;
+}
+
static inline void security_skb_secmark_set(struct sk_buff *skb, u32 secmark)
{
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 0998af3..58c559e9 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -253,6 +253,25 @@ struct ubuf_info {
unsigned long desc;
};
+/* Used by skb_shared_info->opt_data when the LSM is using the security blob,
+ * otherwise the destructor_arg pointer is stored directly in
+ * skb_shared_info->destructor_arg. Only the LSMs should ever use this struct
+ * directly, the network stack should use the skb_destructor_arg_{set,get}()
+ * helper functions. */
+struct skb_opt_info {
+ void *destructor_arg;
+
+ /* Used to keep track of the security pointer below; not the
+ * destructor_arg field above which is covered by the
+ * skb_shared_info protections. */
+ atomic_t sec_refcnt;
+
+ /* This must always be the last element so the LSM can allocate the
+ * skb_opt_info struct and their own state struct with a single
+ * allocation. */
+ unsigned char security[0];
+};
+
/* This data is invariant across clones and lives at
* the end of the header data, ie. at skb->end.
*/
@@ -272,9 +291,12 @@ struct skb_shared_info {
*/
atomic_t dataref;
- /* Intermediate layers must ensure that destructor_arg
- * remains valid until skb destructor */
- void * destructor_arg;
+ /* Intermediate layers must ensure that the union fields remain valid
+ * until the skb is freed. See the comments for skb_opt_info above. */
+ union {
+ void * destructor_arg;
+ struct skb_opt_info * opt_data;
+ };
/* must be last field, see pskb_expand_head() */
skb_frag_t frags[MAX_SKB_FRAGS];
@@ -381,7 +403,6 @@ typedef unsigned char *sk_buff_data_t;
* @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS
* @dma_cookie: a cookie to one of several possible DMA operations
* done by skb DMA functions
- * @secmark: security marking
* @mark: Generic packet mark
* @dropcount: total number of sk_receive_queue overflows
* @vlan_tci: vlan tag control information
@@ -494,9 +515,6 @@ struct sk_buff {
#ifdef CONFIG_NET_DMA
dma_cookie_t dma_cookie;
#endif
-#ifdef CONFIG_NETWORK_SECMARK
- __u32 secmark;
-#endif
union {
__u32 mark;
__u32 dropcount;
@@ -523,7 +541,6 @@ struct sk_buff {
*/
#include <linux/slab.h>
-
#define SKB_ALLOC_FCLONE 0x01
#define SKB_ALLOC_RX 0x02
@@ -695,6 +712,9 @@ static inline unsigned int skb_end_offset(const struct sk_buff *skb)
/* Internal */
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
+#define skb_optinfo(SKB) (skb_shinfo(SKB)->opt_data)
+
+#include <linux/security.h>
/**
* skb_destructor_arg_set - set the packet's destructor argument
@@ -703,7 +723,7 @@ static inline unsigned int skb_end_offset(const struct sk_buff *skb)
*/
static inline void skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
{
- skb_shinfo(skb)->destructor_arg = ptr;
+ security_skb_destructor_arg_set(skb, ptr);
}
/**
@@ -712,7 +732,7 @@ static inline void skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
*/
static inline void *skb_destructor_arg_get(const struct sk_buff *skb)
{
- return skb_shinfo(skb)->destructor_arg;
+ return security_skb_destructor_arg_get(skb);
}
static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
@@ -2701,24 +2721,6 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
__nf_copy(dst, src);
}
-#ifdef CONFIG_NETWORK_SECMARK
-static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from)
-{
- to->secmark = from->secmark;
-}
-
-static inline void skb_init_secmark(struct sk_buff *skb)
-{
- skb->secmark = 0;
-}
-#else
-static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from)
-{ }
-
-static inline void skb_init_secmark(struct sk_buff *skb)
-{ }
-#endif
-
static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
{
skb->queue_mapping = queue_mapping;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e4fa549..9d4ea5f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -70,6 +70,7 @@
#include <asm/uaccess.h>
#include <trace/events/skb.h>
#include <linux/highmem.h>
+#include <linux/security.h>
struct kmem_cache *skbuff_head_cache __read_mostly;
static struct kmem_cache *skbuff_fclone_cache __read_mostly;
@@ -271,12 +272,20 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
child->fclone = SKB_FCLONE_UNAVAILABLE;
child->pfmemalloc = pfmemalloc;
}
+
+ if (security_skb_alloc(skb, gfp_mask, flags, node) < 0)
+ goto data;
+
out:
return skb;
nodata:
kmem_cache_free(cache, skb);
skb = NULL;
goto out;
+data:
+ kfree_skb(skb);
+ skb = NULL;
+ goto out;
}
EXPORT_SYMBOL(__alloc_skb);
@@ -328,7 +337,14 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size)
atomic_set(&shinfo->dataref, 1);
kmemcheck_annotate_variable(shinfo->destructor_arg);
+ if (security_skb_alloc(skb, GFP_ATOMIC, 0, -1) < 0)
+ goto free_skb;
+
return skb;
+
+free_skb:
+ kmem_cache_free(skbuff_head_cache, skb);
+ return NULL;
}
EXPORT_SYMBOL(build_skb);
@@ -514,6 +530,8 @@ static void skb_release_data(struct sk_buff *skb)
if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
+ security_skb_free(skb);
+
skb_free_head(skb);
}
}
@@ -707,8 +725,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#endif
#endif
new->vlan_tci = old->vlan_tci;
-
- skb_copy_secmark(new, old);
}
/*
@@ -1062,6 +1078,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
if (skb_has_frag_list(skb))
skb_clone_fraglist(skb);
+ security_skb_ref(skb);
+
skb_release_data(skb);
} else {
skb_free_head(skb);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 5e12dca..c2fb026 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -437,7 +437,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
to->ipvs_property = from->ipvs_property;
#endif
- skb_copy_secmark(to, from);
+ security_skb_security_copy(to, from);
}
/*
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 155eccf..4d176b7 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -520,7 +520,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
to->nf_trace = from->nf_trace;
#endif
- skb_copy_secmark(to, from);
+ security_skb_security_copy(to, from);
}
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c
index 3228d7f..4fa6d27 100644
--- a/net/netfilter/xt_AUDIT.c
+++ b/net/netfilter/xt_AUDIT.c
@@ -123,6 +123,7 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_audit_info *info = par->targinfo;
struct audit_buffer *ab;
+ u32 secmark;
if (audit_enabled == 0)
goto errout;
@@ -167,10 +168,9 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par)
break;
}
-#ifdef CONFIG_NETWORK_SECMARK
- if (skb->secmark)
- audit_log_secctx(ab, skb->secmark);
-#endif
+ secmark = security_skb_secmark_get(skb);
+ if (secmark)
+ audit_log_secctx(ab, secmark);
audit_log_end(ab);
diff --git a/security/capability.c b/security/capability.c
index b7c0ef2..1ff3b6f 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -738,10 +738,33 @@ static int cap_tun_dev_open(void *security)
return 0;
}
+static int cap_skb_alloc(struct sk_buff *skb, gfp_t gfp_mask, int flags, int node)
+{
+ return 0;
+}
+
+static void cap_skb_free(struct sk_buff *skb)
+{
+}
+
+static void cap_skb_security_copy(struct sk_buff *dst, const struct sk_buff *src)
+{
+}
+
static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
}
+static void cap_skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
+{
+ skb_shinfo(skb)->destructor_arg = ptr;
+}
+
+static void *cap_skb_destructor_arg_get(const struct sk_buff *skb)
+{
+ return skb_shinfo(skb)->destructor_arg;
+}
+
static void cap_skb_secmark_set(struct sk_buff *skb, u32 secmark)
{
}
@@ -1084,7 +1107,12 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, tun_dev_open);
set_to_cap_if_null(ops, tun_dev_attach_queue);
set_to_cap_if_null(ops, tun_dev_attach);
+ set_to_cap_if_null(ops, skb_alloc);
+ set_to_cap_if_null(ops, skb_free);
+ set_to_cap_if_null(ops, skb_security_copy);
set_to_cap_if_null(ops, skb_owned_by);
+ set_to_cap_if_null(ops, skb_destructor_arg_set);
+ set_to_cap_if_null(ops, skb_destructor_arg_get);
set_to_cap_if_null(ops, skb_secmark_set);
set_to_cap_if_null(ops, skb_secmark_get);
#endif /* CONFIG_SECURITY_NETWORK */
diff --git a/security/security.c b/security/security.c
index 7e2b7c7..11aa73b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -24,6 +24,7 @@
#include <linux/mount.h>
#include <linux/personality.h>
#include <linux/backing-dev.h>
+#include <linux/skbuff.h>
#include <net/flow.h>
#define MAX_LSM_EVM_XATTR 2
@@ -1290,11 +1291,62 @@ int security_tun_dev_open(void *security)
}
EXPORT_SYMBOL(security_tun_dev_open);
+int security_skb_alloc(struct sk_buff *skb, gfp_t gfp_mask, int flags, int node)
+{
+ int rc;
+
+ rc = security_ops->skb_alloc(skb, gfp_mask, flags, node);
+ if (rc == 0)
+ atomic_set(&skb_optinfo(skb)->sec_refcnt, 1);
+ return rc;
+}
+
+void security_skb_free(struct sk_buff *skb)
+{
+ struct skb_opt_info *skb_opt = skb_optinfo(skb);
+
+ BUG_ON(skb_opt == NULL);
+
+ if (atomic_dec_and_test(&skb_opt->sec_refcnt))
+ security_ops->skb_free(skb);
+ else
+ /* we keep the security data we need to reset the rest */
+ skb_opt->destructor_arg = NULL;
+}
+
+void security_skb_ref(struct sk_buff *skb)
+{
+ atomic_inc(&skb_optinfo(skb)->sec_refcnt);
+}
+
+void security_skb_unref(struct sk_buff *skb)
+{
+ atomic_dec(&skb_optinfo(skb)->sec_refcnt);
+}
+
+void security_skb_security_copy(struct sk_buff *dst, const struct sk_buff *src)
+{
+ security_ops->skb_security_copy(dst, src);
+}
+EXPORT_SYMBOL(security_skb_security_copy);
+
void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
security_ops->skb_owned_by(skb, sk);
}
+void security_skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
+{
+ security_ops->skb_destructor_arg_set(skb, ptr);
+}
+EXPORT_SYMBOL(security_skb_destructor_arg_set);
+
+void *security_skb_destructor_arg_get(const struct sk_buff *skb)
+{
+ return security_ops->skb_destructor_arg_get(skb);
+}
+EXPORT_SYMBOL(security_skb_destructor_arg_get);
+
void security_skb_secmark_set(struct sk_buff *skb, u32 secmark)
{
security_ops->skb_secmark_set(skb, secmark);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5021cf7..2b60493 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -131,6 +131,8 @@ int selinux_enabled = 1;
static struct kmem_cache *sel_inode_cache;
+static struct kmem_cache *sel_skb_cache;
+
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
*
@@ -3473,19 +3475,97 @@ static void selinux_task_to_inode(struct task_struct *p,
isec->initialized = 1;
}
+static int selinux_skb_alloc(struct sk_buff *skb,
+ gfp_t gfp_mask, int flags, int node)
+{
+ struct skb_opt_info *skb_opt;
+ gfp_t gfp = gfp_mask & ~__GFP_DMA;
+
+ if (node < 0)
+ skb_opt = kmem_cache_alloc(sel_skb_cache, gfp);
+ else
+ skb_opt = kmem_cache_alloc_node(sel_skb_cache, gfp, node);
+ if (skb_opt == NULL)
+ return -ENOMEM;
+ memset(skb_opt, 0,
+ sizeof(struct skb_opt_info)+sizeof(struct skb_security_struct));
+ skb_optinfo(skb) = skb_opt;
+
+ return 0;
+}
+
+static void selinux_skb_free(struct sk_buff *skb)
+{
+ struct skb_opt_info *skb_opt = skb_optinfo(skb);
+
+ BUG_ON(skb_opt == NULL);
+
+ skb_optinfo(skb) = NULL;
+ kmem_cache_free(sel_skb_cache, skb_opt);
+}
+
+static void selinux_skb_security_copy(struct sk_buff *dst,
+ const struct sk_buff *src)
+{
+ struct skb_security_struct *skbsec_dst;
+ struct skb_security_struct *skbsec_src;
+
+ BUG_ON(skb_optinfo(dst) == NULL || skb_optinfo(src) == NULL);
+ if (skb_optinfo(dst) == NULL || skb_optinfo(src) == NULL)
+ return;
+
+ /* NOTE: skb_security(x) can't be NULL if skb_optinfo(x) is valid */
+ skbsec_src = skb_security(src);
+ skbsec_dst = skb_security(dst);
+
+ /* check if we are copying the security metadata between clones, we
+ * may not need this check, but it is cheap insurance */
+ if (skbsec_dst == skbsec_src)
+ return;
+
+ /* copy the security metadata */
+ skbsec_dst->secmark = skbsec_src->secmark;
+}
+
static void selinux_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
skb_set_owner_w(skb, sk);
}
+static void selinux_skb_destructor_arg_set(struct sk_buff *skb, void *ptr)
+{
+ struct skb_opt_info *skb_opt = skb_optinfo(skb);
+
+ BUG_ON(skb_opt == NULL);
+ if (skb_opt == NULL)
+ return;
+
+ skb_opt->destructor_arg = ptr;
+}
+
+static void *selinux_skb_destructor_arg_get(const struct sk_buff *skb)
+{
+ struct skb_opt_info *skb_opt = skb_optinfo(skb);
+
+ BUG_ON(skb_opt == NULL);
+ if (skb_opt == NULL)
+ return NULL;
+
+ return skb_opt->destructor_arg;
+}
+
static void selinux_skb_secmark_set(struct sk_buff *skb, u32 secmark)
{
- skb->secmark = secmark;
+ BUG_ON(skb_optinfo(skb) == NULL);
+
+ skb_security(skb)->secmark = secmark;
}
static u32 selinux_skb_secmark_get(const struct sk_buff *skb)
{
- return skb->secmark;
+ BUG_ON(skb_optinfo(skb) == NULL);
+
+ return skb_security(skb)->secmark;
}
/* Returns error only if unable to parse addresses */
@@ -4120,8 +4200,8 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
if (selinux_secmark_enabled()) {
- err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
- PACKET__RECV, &ad);
+ err = avc_has_perm(sk_sid, selinux_skb_secmark_get(skb),
+ SECCLASS_PACKET, PACKET__RECV, &ad);
if (err)
return err;
}
@@ -4192,8 +4272,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
if (secmark_active) {
- err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
- PACKET__RECV, &ad);
+ err = avc_has_perm(sk_sid, selinux_skb_secmark_get(skb),
+ SECCLASS_PACKET, PACKET__RECV, &ad);
if (err)
return err;
}
@@ -4562,7 +4642,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
}
if (secmark_active)
- if (avc_has_perm(peer_sid, skb->secmark,
+ if (avc_has_perm(peer_sid, selinux_skb_secmark_get(skb),
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
@@ -4651,7 +4731,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP;
if (selinux_secmark_enabled())
- if (avc_has_perm(sksec->sid, skb->secmark,
+ if (avc_has_perm(sksec->sid, selinux_skb_secmark_get(skb),
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -4722,7 +4802,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
return NF_DROP;
if (secmark_active)
- if (avc_has_perm(peer_sid, skb->secmark,
+ if (avc_has_perm(peer_sid, selinux_skb_secmark_get(skb),
SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -5680,7 +5760,12 @@ static struct security_operations selinux_ops = {
.tun_dev_attach_queue = selinux_tun_dev_attach_queue,
.tun_dev_attach = selinux_tun_dev_attach,
.tun_dev_open = selinux_tun_dev_open,
+ .skb_alloc = selinux_skb_alloc,
+ .skb_free = selinux_skb_free,
+ .skb_security_copy = selinux_skb_security_copy,
.skb_owned_by = selinux_skb_owned_by,
+ .skb_destructor_arg_set = selinux_skb_destructor_arg_set,
+ .skb_destructor_arg_get = selinux_skb_destructor_arg_get,
.skb_secmark_set = selinux_skb_secmark_set,
.skb_secmark_get = selinux_skb_secmark_get,
@@ -5734,6 +5819,11 @@ static __init int selinux_init(void)
sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
0, SLAB_PANIC, NULL);
+ sel_skb_cache = kmem_cache_create("selinux_skb_security",
+ sizeof(struct skb_opt_info) +
+ sizeof(struct skb_security_struct),
+ 0, SLAB_PANIC, NULL);
+
avc_init();
if (register_security(&selinux_ops))
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index aa47bca..7ec3623 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -110,6 +110,12 @@ struct sk_security_struct {
u16 sclass; /* sock security class */
};
+#define skb_security(SKB) \
+ ((struct skb_security_struct *)(&(skb_optinfo(SKB)->security)))
+struct skb_security_struct {
+ int secmark;
+};
+
struct tun_security_struct {
u32 sid; /* SID for the tun device sockets */
};
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-04-16 20:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-16 20:39 [RFC PATCH 0/3] Shrink sk_buff and add a security blob Paul Moore
2013-04-16 20:39 ` [RFC PATCH 1/3] skb: wrap skb_shared_info->destructor_arg access with set and get functions Paul Moore
2013-04-16 20:39 ` [RFC PATCH 2/3] net: wrap skb->secmark " Paul Moore
2013-04-16 20:39 ` [RFC PATCH 3/3] net: move sk_buff->secmark into a security blob in skb_shared_info Paul Moore
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).