xref: /openbmc/linux/net/netfilter/xt_SECMARK.c (revision c7d13358)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25e6874cdSJames Morris /*
35e6874cdSJames Morris  * Module for modifying the secmark field of the skb, for use by
45e6874cdSJames Morris  * security subsystems.
55e6874cdSJames Morris  *
65e6874cdSJames Morris  * Based on the nfmark match by:
75e6874cdSJames Morris  * (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
85e6874cdSJames Morris  *
9560ee653SJames Morris  * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
105e6874cdSJames Morris  */
118bee4badSJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
125e6874cdSJames Morris #include <linux/module.h>
132606fd1fSEric Paris #include <linux/security.h>
145e6874cdSJames Morris #include <linux/skbuff.h>
155e6874cdSJames Morris #include <linux/netfilter/x_tables.h>
165e6874cdSJames Morris #include <linux/netfilter/xt_SECMARK.h>
175e6874cdSJames Morris 
185e6874cdSJames Morris MODULE_LICENSE("GPL");
195e6874cdSJames Morris MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
202ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: packet security mark modification");
215e6874cdSJames Morris MODULE_ALIAS("ipt_SECMARK");
225e6874cdSJames Morris MODULE_ALIAS("ip6t_SECMARK");
235e6874cdSJames Morris 
245e6874cdSJames Morris static u8 mode;
255e6874cdSJames Morris 
26d3c5ee6dSJan Engelhardt static unsigned int
secmark_tg(struct sk_buff * skb,const struct xt_secmark_target_info_v1 * info)27*c7d13358SPablo Neira Ayuso secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
285e6874cdSJames Morris {
295e6874cdSJames Morris 	u32 secmark = 0;
305e6874cdSJames Morris 
315e6874cdSJames Morris 	switch (mode) {
325e6874cdSJames Morris 	case SECMARK_MODE_SEL:
332606fd1fSEric Paris 		secmark = info->secid;
345e6874cdSJames Morris 		break;
355e6874cdSJames Morris 	default:
365e6874cdSJames Morris 		BUG();
375e6874cdSJames Morris 	}
385e6874cdSJames Morris 
393db05feaSHerbert Xu 	skb->secmark = secmark;
405e6874cdSJames Morris 	return XT_CONTINUE;
415e6874cdSJames Morris }
425e6874cdSJames Morris 
checkentry_lsm(struct xt_secmark_target_info_v1 * info)43*c7d13358SPablo Neira Ayuso static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
445e6874cdSJames Morris {
455e6874cdSJames Morris 	int err;
46a280b899SJames Morris 
472606fd1fSEric Paris 	info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
482606fd1fSEric Paris 	info->secid = 0;
495e6874cdSJames Morris 
502606fd1fSEric Paris 	err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
512606fd1fSEric Paris 				       &info->secid);
525e6874cdSJames Morris 	if (err) {
535e6874cdSJames Morris 		if (err == -EINVAL)
54b2606644SFlorian Westphal 			pr_info_ratelimited("invalid security context \'%s\'\n",
55b2606644SFlorian Westphal 					    info->secctx);
564a5a5c73SJan Engelhardt 		return err;
575e6874cdSJames Morris 	}
585e6874cdSJames Morris 
592606fd1fSEric Paris 	if (!info->secid) {
60b2606644SFlorian Westphal 		pr_info_ratelimited("unable to map security context \'%s\'\n",
61b2606644SFlorian Westphal 				    info->secctx);
624a5a5c73SJan Engelhardt 		return -ENOENT;
635e6874cdSJames Morris 	}
645e6874cdSJames Morris 
652606fd1fSEric Paris 	err = security_secmark_relabel_packet(info->secid);
665e6874cdSJames Morris 	if (err) {
67b2606644SFlorian Westphal 		pr_info_ratelimited("unable to obtain relabeling permission\n");
684a5a5c73SJan Engelhardt 		return err;
695e6874cdSJames Morris 	}
705e6874cdSJames Morris 
712606fd1fSEric Paris 	security_secmark_refcount_inc();
724a5a5c73SJan Engelhardt 	return 0;
735e6874cdSJames Morris }
745e6874cdSJames Morris 
75*c7d13358SPablo Neira Ayuso static int
secmark_tg_check(const char * table,struct xt_secmark_target_info_v1 * info)76*c7d13358SPablo Neira Ayuso secmark_tg_check(const char *table, struct xt_secmark_target_info_v1 *info)
775e6874cdSJames Morris {
784a5a5c73SJan Engelhardt 	int err;
795e6874cdSJames Morris 
80*c7d13358SPablo Neira Ayuso 	if (strcmp(table, "mangle") != 0 &&
81*c7d13358SPablo Neira Ayuso 	    strcmp(table, "security") != 0) {
82cc48baefSFlorian Westphal 		pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
83*c7d13358SPablo Neira Ayuso 				    table);
84d6b00a53SJan Engelhardt 		return -EINVAL;
85560ee653SJames Morris 	}
86560ee653SJames Morris 
875e6874cdSJames Morris 	if (mode && mode != info->mode) {
88b2606644SFlorian Westphal 		pr_info_ratelimited("mode already set to %hu cannot mix with rules for mode %hu\n",
89b2606644SFlorian Westphal 				    mode, info->mode);
90d6b00a53SJan Engelhardt 		return -EINVAL;
915e6874cdSJames Morris 	}
925e6874cdSJames Morris 
935e6874cdSJames Morris 	switch (info->mode) {
945e6874cdSJames Morris 	case SECMARK_MODE_SEL:
955e6874cdSJames Morris 		break;
965e6874cdSJames Morris 	default:
97b2606644SFlorian Westphal 		pr_info_ratelimited("invalid mode: %hu\n", info->mode);
98d6b00a53SJan Engelhardt 		return -EINVAL;
995e6874cdSJames Morris 	}
1005e6874cdSJames Morris 
1012606fd1fSEric Paris 	err = checkentry_lsm(info);
1022606fd1fSEric Paris 	if (err)
1032606fd1fSEric Paris 		return err;
1042606fd1fSEric Paris 
1055e6874cdSJames Morris 	if (!mode)
1065e6874cdSJames Morris 		mode = info->mode;
107d6b00a53SJan Engelhardt 	return 0;
1085e6874cdSJames Morris }
1095e6874cdSJames Morris 
secmark_tg_destroy(const struct xt_tgdtor_param * par)110a2df1648SJan Engelhardt static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
111d621d35eSPaul Moore {
112d621d35eSPaul Moore 	switch (mode) {
113d621d35eSPaul Moore 	case SECMARK_MODE_SEL:
1142606fd1fSEric Paris 		security_secmark_refcount_dec();
115d621d35eSPaul Moore 	}
116d621d35eSPaul Moore }
117d621d35eSPaul Moore 
secmark_tg_check_v0(const struct xt_tgchk_param * par)118*c7d13358SPablo Neira Ayuso static int secmark_tg_check_v0(const struct xt_tgchk_param *par)
119*c7d13358SPablo Neira Ayuso {
120*c7d13358SPablo Neira Ayuso 	struct xt_secmark_target_info *info = par->targinfo;
121*c7d13358SPablo Neira Ayuso 	struct xt_secmark_target_info_v1 newinfo = {
122*c7d13358SPablo Neira Ayuso 		.mode	= info->mode,
123*c7d13358SPablo Neira Ayuso 	};
124*c7d13358SPablo Neira Ayuso 	int ret;
125*c7d13358SPablo Neira Ayuso 
126*c7d13358SPablo Neira Ayuso 	memcpy(newinfo.secctx, info->secctx, SECMARK_SECCTX_MAX);
127*c7d13358SPablo Neira Ayuso 
128*c7d13358SPablo Neira Ayuso 	ret = secmark_tg_check(par->table, &newinfo);
129*c7d13358SPablo Neira Ayuso 	info->secid = newinfo.secid;
130*c7d13358SPablo Neira Ayuso 
131*c7d13358SPablo Neira Ayuso 	return ret;
132*c7d13358SPablo Neira Ayuso }
133*c7d13358SPablo Neira Ayuso 
134*c7d13358SPablo Neira Ayuso static unsigned int
secmark_tg_v0(struct sk_buff * skb,const struct xt_action_param * par)135*c7d13358SPablo Neira Ayuso secmark_tg_v0(struct sk_buff *skb, const struct xt_action_param *par)
136*c7d13358SPablo Neira Ayuso {
137*c7d13358SPablo Neira Ayuso 	const struct xt_secmark_target_info *info = par->targinfo;
138*c7d13358SPablo Neira Ayuso 	struct xt_secmark_target_info_v1 newinfo = {
139*c7d13358SPablo Neira Ayuso 		.secid	= info->secid,
140*c7d13358SPablo Neira Ayuso 	};
141*c7d13358SPablo Neira Ayuso 
142*c7d13358SPablo Neira Ayuso 	return secmark_tg(skb, &newinfo);
143*c7d13358SPablo Neira Ayuso }
144*c7d13358SPablo Neira Ayuso 
secmark_tg_check_v1(const struct xt_tgchk_param * par)145*c7d13358SPablo Neira Ayuso static int secmark_tg_check_v1(const struct xt_tgchk_param *par)
146*c7d13358SPablo Neira Ayuso {
147*c7d13358SPablo Neira Ayuso 	return secmark_tg_check(par->table, par->targinfo);
148*c7d13358SPablo Neira Ayuso }
149*c7d13358SPablo Neira Ayuso 
150*c7d13358SPablo Neira Ayuso static unsigned int
secmark_tg_v1(struct sk_buff * skb,const struct xt_action_param * par)151*c7d13358SPablo Neira Ayuso secmark_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
152*c7d13358SPablo Neira Ayuso {
153*c7d13358SPablo Neira Ayuso 	return secmark_tg(skb, par->targinfo);
154*c7d13358SPablo Neira Ayuso }
155*c7d13358SPablo Neira Ayuso 
156*c7d13358SPablo Neira Ayuso static struct xt_target secmark_tg_reg[] __read_mostly = {
157*c7d13358SPablo Neira Ayuso 	{
1585e6874cdSJames Morris 		.name		= "SECMARK",
15955b69e91SJan Engelhardt 		.revision	= 0,
16055b69e91SJan Engelhardt 		.family		= NFPROTO_UNSPEC,
161*c7d13358SPablo Neira Ayuso 		.checkentry	= secmark_tg_check_v0,
162d621d35eSPaul Moore 		.destroy	= secmark_tg_destroy,
163*c7d13358SPablo Neira Ayuso 		.target		= secmark_tg_v0,
1645e6874cdSJames Morris 		.targetsize	= sizeof(struct xt_secmark_target_info),
1655e6874cdSJames Morris 		.me		= THIS_MODULE,
166*c7d13358SPablo Neira Ayuso 	},
167*c7d13358SPablo Neira Ayuso 	{
168*c7d13358SPablo Neira Ayuso 		.name		= "SECMARK",
169*c7d13358SPablo Neira Ayuso 		.revision	= 1,
170*c7d13358SPablo Neira Ayuso 		.family		= NFPROTO_UNSPEC,
171*c7d13358SPablo Neira Ayuso 		.checkentry	= secmark_tg_check_v1,
172*c7d13358SPablo Neira Ayuso 		.destroy	= secmark_tg_destroy,
173*c7d13358SPablo Neira Ayuso 		.target		= secmark_tg_v1,
174*c7d13358SPablo Neira Ayuso 		.targetsize	= sizeof(struct xt_secmark_target_info_v1),
175*c7d13358SPablo Neira Ayuso 		.usersize	= offsetof(struct xt_secmark_target_info_v1, secid),
176*c7d13358SPablo Neira Ayuso 		.me		= THIS_MODULE,
177*c7d13358SPablo Neira Ayuso 	},
1785e6874cdSJames Morris };
1795e6874cdSJames Morris 
secmark_tg_init(void)180d3c5ee6dSJan Engelhardt static int __init secmark_tg_init(void)
1815e6874cdSJames Morris {
182*c7d13358SPablo Neira Ayuso 	return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
1835e6874cdSJames Morris }
1845e6874cdSJames Morris 
secmark_tg_exit(void)185d3c5ee6dSJan Engelhardt static void __exit secmark_tg_exit(void)
1865e6874cdSJames Morris {
187*c7d13358SPablo Neira Ayuso 	xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
1885e6874cdSJames Morris }
1895e6874cdSJames Morris 
190d3c5ee6dSJan Engelhardt module_init(secmark_tg_init);
191d3c5ee6dSJan Engelhardt module_exit(secmark_tg_exit);
192