xref: /openbmc/linux/net/netfilter/xt_SECMARK.c (revision d621d35e)
15e6874cdSJames Morris /*
25e6874cdSJames Morris  * Module for modifying the secmark field of the skb, for use by
35e6874cdSJames Morris  * security subsystems.
45e6874cdSJames Morris  *
55e6874cdSJames Morris  * Based on the nfmark match by:
65e6874cdSJames Morris  * (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
75e6874cdSJames Morris  *
85e6874cdSJames Morris  * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
95e6874cdSJames Morris  *
105e6874cdSJames Morris  * This program is free software; you can redistribute it and/or modify
115e6874cdSJames Morris  * it under the terms of the GNU General Public License version 2 as
125e6874cdSJames Morris  * published by the Free Software Foundation.
135e6874cdSJames Morris  *
145e6874cdSJames Morris  */
155e6874cdSJames Morris #include <linux/module.h>
165e6874cdSJames Morris #include <linux/skbuff.h>
175e6874cdSJames Morris #include <linux/selinux.h>
185e6874cdSJames Morris #include <linux/netfilter/x_tables.h>
195e6874cdSJames Morris #include <linux/netfilter/xt_SECMARK.h>
205e6874cdSJames Morris 
215e6874cdSJames Morris MODULE_LICENSE("GPL");
225e6874cdSJames Morris MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
232ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: packet security mark modification");
245e6874cdSJames Morris MODULE_ALIAS("ipt_SECMARK");
255e6874cdSJames Morris MODULE_ALIAS("ip6t_SECMARK");
265e6874cdSJames Morris 
275e6874cdSJames Morris #define PFX "SECMARK: "
285e6874cdSJames Morris 
295e6874cdSJames Morris static u8 mode;
305e6874cdSJames Morris 
31d3c5ee6dSJan Engelhardt static unsigned int
32d3c5ee6dSJan Engelhardt secmark_tg(struct sk_buff *skb, const struct net_device *in,
335e6874cdSJames Morris            const struct net_device *out, unsigned int hooknum,
34d3c5ee6dSJan Engelhardt            const struct xt_target *target, const void *targinfo)
355e6874cdSJames Morris {
365e6874cdSJames Morris 	u32 secmark = 0;
375e6874cdSJames Morris 	const struct xt_secmark_target_info *info = targinfo;
385e6874cdSJames Morris 
395e6874cdSJames Morris 	BUG_ON(info->mode != mode);
405e6874cdSJames Morris 
415e6874cdSJames Morris 	switch (mode) {
425e6874cdSJames Morris 	case SECMARK_MODE_SEL:
435e6874cdSJames Morris 		secmark = info->u.sel.selsid;
445e6874cdSJames Morris 		break;
455e6874cdSJames Morris 
465e6874cdSJames Morris 	default:
475e6874cdSJames Morris 		BUG();
485e6874cdSJames Morris 	}
495e6874cdSJames Morris 
503db05feaSHerbert Xu 	skb->secmark = secmark;
515e6874cdSJames Morris 	return XT_CONTINUE;
525e6874cdSJames Morris }
535e6874cdSJames Morris 
54e1931b78SJan Engelhardt static bool checkentry_selinux(struct xt_secmark_target_info *info)
555e6874cdSJames Morris {
565e6874cdSJames Morris 	int err;
575e6874cdSJames Morris 	struct xt_secmark_target_selinux_info *sel = &info->u.sel;
58a280b899SJames Morris 
59a280b899SJames Morris 	sel->selctx[SECMARK_SELCTX_MAX - 1] = '\0';
605e6874cdSJames Morris 
615e6874cdSJames Morris 	err = selinux_string_to_sid(sel->selctx, &sel->selsid);
625e6874cdSJames Morris 	if (err) {
635e6874cdSJames Morris 		if (err == -EINVAL)
645e6874cdSJames Morris 			printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n",
655e6874cdSJames Morris 			       sel->selctx);
66e1931b78SJan Engelhardt 		return false;
675e6874cdSJames Morris 	}
685e6874cdSJames Morris 
695e6874cdSJames Morris 	if (!sel->selsid) {
705e6874cdSJames Morris 		printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n",
715e6874cdSJames Morris 		       sel->selctx);
72e1931b78SJan Engelhardt 		return false;
735e6874cdSJames Morris 	}
745e6874cdSJames Morris 
75d621d35eSPaul Moore 	err = selinux_secmark_relabel_packet_permission(sel->selsid);
765e6874cdSJames Morris 	if (err) {
775e6874cdSJames Morris 		printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
78e1931b78SJan Engelhardt 		return false;
795e6874cdSJames Morris 	}
805e6874cdSJames Morris 
81d621d35eSPaul Moore 	selinux_secmark_refcount_inc();
82e1931b78SJan Engelhardt 	return true;
835e6874cdSJames Morris }
845e6874cdSJames Morris 
85d3c5ee6dSJan Engelhardt static bool
86d3c5ee6dSJan Engelhardt secmark_tg_check(const char *tablename, const void *entry,
875e6874cdSJames Morris                  const struct xt_target *target, void *targinfo,
88efa74165SPatrick McHardy                  unsigned int hook_mask)
895e6874cdSJames Morris {
905e6874cdSJames Morris 	struct xt_secmark_target_info *info = targinfo;
915e6874cdSJames Morris 
925e6874cdSJames Morris 	if (mode && mode != info->mode) {
935e6874cdSJames Morris 		printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
945e6874cdSJames Morris 		       "rules for mode %hu\n", mode, info->mode);
95e1931b78SJan Engelhardt 		return false;
965e6874cdSJames Morris 	}
975e6874cdSJames Morris 
985e6874cdSJames Morris 	switch (info->mode) {
995e6874cdSJames Morris 	case SECMARK_MODE_SEL:
1005e6874cdSJames Morris 		if (!checkentry_selinux(info))
101e1931b78SJan Engelhardt 			return false;
1025e6874cdSJames Morris 		break;
1035e6874cdSJames Morris 
1045e6874cdSJames Morris 	default:
1055e6874cdSJames Morris 		printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
106e1931b78SJan Engelhardt 		return false;
1075e6874cdSJames Morris 	}
1085e6874cdSJames Morris 
1095e6874cdSJames Morris 	if (!mode)
1105e6874cdSJames Morris 		mode = info->mode;
111e1931b78SJan Engelhardt 	return true;
1125e6874cdSJames Morris }
1135e6874cdSJames Morris 
114d621d35eSPaul Moore void secmark_tg_destroy(const struct xt_target *target, void *targinfo)
115d621d35eSPaul Moore {
116d621d35eSPaul Moore 	switch (mode) {
117d621d35eSPaul Moore 	case SECMARK_MODE_SEL:
118d621d35eSPaul Moore 		selinux_secmark_refcount_dec();
119d621d35eSPaul Moore 	}
120d621d35eSPaul Moore }
121d621d35eSPaul Moore 
122d3c5ee6dSJan Engelhardt static struct xt_target secmark_tg_reg[] __read_mostly = {
1234470bbc7SPatrick McHardy 	{
1245e6874cdSJames Morris 		.name		= "SECMARK",
1255e6874cdSJames Morris 		.family		= AF_INET,
126d3c5ee6dSJan Engelhardt 		.checkentry	= secmark_tg_check,
127d621d35eSPaul Moore 		.destroy	= secmark_tg_destroy,
128d3c5ee6dSJan Engelhardt 		.target		= secmark_tg,
1295e6874cdSJames Morris 		.targetsize	= sizeof(struct xt_secmark_target_info),
1305e6874cdSJames Morris 		.table		= "mangle",
1315e6874cdSJames Morris 		.me		= THIS_MODULE,
1324470bbc7SPatrick McHardy 	},
1334470bbc7SPatrick McHardy 	{
1344470bbc7SPatrick McHardy 		.name		= "SECMARK",
1355e6874cdSJames Morris 		.family		= AF_INET6,
136d3c5ee6dSJan Engelhardt 		.checkentry	= secmark_tg_check,
137d621d35eSPaul Moore 		.destroy	= secmark_tg_destroy,
138d3c5ee6dSJan Engelhardt 		.target		= secmark_tg,
1394470bbc7SPatrick McHardy 		.targetsize	= sizeof(struct xt_secmark_target_info),
1404470bbc7SPatrick McHardy 		.table		= "mangle",
1414470bbc7SPatrick McHardy 		.me		= THIS_MODULE,
1424470bbc7SPatrick McHardy 	},
1435e6874cdSJames Morris };
1445e6874cdSJames Morris 
145d3c5ee6dSJan Engelhardt static int __init secmark_tg_init(void)
1465e6874cdSJames Morris {
147d3c5ee6dSJan Engelhardt 	return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
1485e6874cdSJames Morris }
1495e6874cdSJames Morris 
150d3c5ee6dSJan Engelhardt static void __exit secmark_tg_exit(void)
1515e6874cdSJames Morris {
152d3c5ee6dSJan Engelhardt 	xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
1535e6874cdSJames Morris }
1545e6874cdSJames Morris 
155d3c5ee6dSJan Engelhardt module_init(secmark_tg_init);
156d3c5ee6dSJan Engelhardt module_exit(secmark_tg_exit);
157