1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This module is used to copy security markings from packets
4  * to connections, and restore security markings from connections
5  * back to packets.  This would normally be performed in conjunction
6  * with the SECMARK target and state match.
7  *
8  * Based somewhat on CONNMARK:
9  *   Copyright (C) 2002,2004 MARA Systems AB <https://www.marasystems.com>
10  *    by Henrik Nordstrom <hno@marasystems.com>
11  *
12  * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
13  */
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/module.h>
16 #include <linux/skbuff.h>
17 #include <linux/netfilter/x_tables.h>
18 #include <linux/netfilter/xt_CONNSECMARK.h>
19 #include <net/netfilter/nf_conntrack.h>
20 #include <net/netfilter/nf_conntrack_ecache.h>
21 
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
24 MODULE_DESCRIPTION("Xtables: target for copying between connection and security mark");
25 MODULE_ALIAS("ipt_CONNSECMARK");
26 MODULE_ALIAS("ip6t_CONNSECMARK");
27 
28 /*
29  * If the packet has a security mark and the connection does not, copy
30  * the security mark from the packet to the connection.
31  */
secmark_save(const struct sk_buff * skb)32 static void secmark_save(const struct sk_buff *skb)
33 {
34 	if (skb->secmark) {
35 		struct nf_conn *ct;
36 		enum ip_conntrack_info ctinfo;
37 
38 		ct = nf_ct_get(skb, &ctinfo);
39 		if (ct && !ct->secmark) {
40 			ct->secmark = skb->secmark;
41 			nf_conntrack_event_cache(IPCT_SECMARK, ct);
42 		}
43 	}
44 }
45 
46 /*
47  * If packet has no security mark, and the connection does, restore the
48  * security mark from the connection to the packet.
49  */
secmark_restore(struct sk_buff * skb)50 static void secmark_restore(struct sk_buff *skb)
51 {
52 	if (!skb->secmark) {
53 		const struct nf_conn *ct;
54 		enum ip_conntrack_info ctinfo;
55 
56 		ct = nf_ct_get(skb, &ctinfo);
57 		if (ct && ct->secmark)
58 			skb->secmark = ct->secmark;
59 	}
60 }
61 
62 static unsigned int
connsecmark_tg(struct sk_buff * skb,const struct xt_action_param * par)63 connsecmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
64 {
65 	const struct xt_connsecmark_target_info *info = par->targinfo;
66 
67 	switch (info->mode) {
68 	case CONNSECMARK_SAVE:
69 		secmark_save(skb);
70 		break;
71 
72 	case CONNSECMARK_RESTORE:
73 		secmark_restore(skb);
74 		break;
75 
76 	default:
77 		BUG();
78 	}
79 
80 	return XT_CONTINUE;
81 }
82 
connsecmark_tg_check(const struct xt_tgchk_param * par)83 static int connsecmark_tg_check(const struct xt_tgchk_param *par)
84 {
85 	const struct xt_connsecmark_target_info *info = par->targinfo;
86 	int ret;
87 
88 	if (strcmp(par->table, "mangle") != 0 &&
89 	    strcmp(par->table, "security") != 0) {
90 		pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
91 				    par->table);
92 		return -EINVAL;
93 	}
94 
95 	switch (info->mode) {
96 	case CONNSECMARK_SAVE:
97 	case CONNSECMARK_RESTORE:
98 		break;
99 
100 	default:
101 		pr_info_ratelimited("invalid mode: %hu\n", info->mode);
102 		return -EINVAL;
103 	}
104 
105 	ret = nf_ct_netns_get(par->net, par->family);
106 	if (ret < 0)
107 		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
108 				    par->family);
109 	return ret;
110 }
111 
connsecmark_tg_destroy(const struct xt_tgdtor_param * par)112 static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
113 {
114 	nf_ct_netns_put(par->net, par->family);
115 }
116 
117 static struct xt_target connsecmark_tg_reg[] __read_mostly = {
118 	{
119 		.name       = "CONNSECMARK",
120 		.revision   = 0,
121 		.family     = NFPROTO_IPV4,
122 		.checkentry = connsecmark_tg_check,
123 		.destroy    = connsecmark_tg_destroy,
124 		.target     = connsecmark_tg,
125 		.targetsize = sizeof(struct xt_connsecmark_target_info),
126 		.me         = THIS_MODULE,
127 	},
128 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
129 	{
130 		.name       = "CONNSECMARK",
131 		.revision   = 0,
132 		.family     = NFPROTO_IPV6,
133 		.checkentry = connsecmark_tg_check,
134 		.destroy    = connsecmark_tg_destroy,
135 		.target     = connsecmark_tg,
136 		.targetsize = sizeof(struct xt_connsecmark_target_info),
137 		.me         = THIS_MODULE,
138 	},
139 #endif
140 };
141 
connsecmark_tg_init(void)142 static int __init connsecmark_tg_init(void)
143 {
144 	return xt_register_targets(connsecmark_tg_reg, ARRAY_SIZE(connsecmark_tg_reg));
145 }
146 
connsecmark_tg_exit(void)147 static void __exit connsecmark_tg_exit(void)
148 {
149 	xt_unregister_targets(connsecmark_tg_reg, ARRAY_SIZE(connsecmark_tg_reg));
150 }
151 
152 module_init(connsecmark_tg_init);
153 module_exit(connsecmark_tg_exit);
154