diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-29 20:38:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-29 20:38:46 -0400 |
commit | 7a1e8b80fb1e8ead4cec15d1fc494ed290e4d2e9 (patch) | |
tree | 55a36d4256f1ae793b5c8e88c0f158737447193f /net/netlabel | |
parent | a867d7349e94b6409b08629886a819f802377e91 (diff) | |
parent | 7616ac70d1bb4f2e9d25c1a82d283f3368a7b632 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Highlights:
- TPM core and driver updates/fixes
- IPv6 security labeling (CALIPSO)
- Lots of Apparmor fixes
- Seccomp: remove 2-phase API, close hole where ptrace can change
syscall #"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (156 commits)
apparmor: fix SECURITY_APPARMOR_HASH_DEFAULT parameter handling
tpm: Add TPM 2.0 support to the Nuvoton i2c driver (NPCT6xx family)
tpm: Factor out common startup code
tpm: use devm_add_action_or_reset
tpm2_i2c_nuvoton: add irq validity check
tpm: read burstcount from TPM_STS in one 32-bit transaction
tpm: fix byte-order for the value read by tpm2_get_tpm_pt
tpm_tis_core: convert max timeouts from msec to jiffies
apparmor: fix arg_size computation for when setprocattr is null terminated
apparmor: fix oops, validate buffer size in apparmor_setprocattr()
apparmor: do not expose kernel stack
apparmor: fix module parameters can be changed after policy is locked
apparmor: fix oops in profile_unpack() when policy_db is not present
apparmor: don't check for vmalloc_addr if kvzalloc() failed
apparmor: add missing id bounds check on dfa verification
apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task
apparmor: use list_next_entry instead of list_entry_next
apparmor: fix refcount race when finding a child profile
apparmor: fix ref count leak when profile sha1 hash is read
apparmor: check that xindex is in trans_table bounds
...
Diffstat (limited to 'net/netlabel')
-rw-r--r-- | net/netlabel/Kconfig | 1 | ||||
-rw-r--r-- | net/netlabel/Makefile | 2 | ||||
-rw-r--r-- | net/netlabel/netlabel_calipso.c | 740 | ||||
-rw-r--r-- | net/netlabel/netlabel_calipso.h | 151 | ||||
-rw-r--r-- | net/netlabel/netlabel_domainhash.c | 293 | ||||
-rw-r--r-- | net/netlabel/netlabel_domainhash.h | 17 | ||||
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 394 | ||||
-rw-r--r-- | net/netlabel/netlabel_mgmt.c | 85 | ||||
-rw-r--r-- | net/netlabel/netlabel_mgmt.h | 27 | ||||
-rw-r--r-- | net/netlabel/netlabel_unlabeled.c | 5 | ||||
-rw-r--r-- | net/netlabel/netlabel_user.c | 5 |
11 files changed, 1619 insertions, 101 deletions
diff --git a/net/netlabel/Kconfig b/net/netlabel/Kconfig index 56958c85f2b4..d9eaa30ffe3f 100644 --- a/net/netlabel/Kconfig +++ b/net/netlabel/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | config NETLABEL | 5 | config NETLABEL |
6 | bool "NetLabel subsystem support" | 6 | bool "NetLabel subsystem support" |
7 | depends on SECURITY | 7 | depends on SECURITY |
8 | select CRC_CCITT if IPV6 | ||
8 | default n | 9 | default n |
9 | ---help--- | 10 | ---help--- |
10 | NetLabel provides support for explicit network packet labeling | 11 | NetLabel provides support for explicit network packet labeling |
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile index d2732fc952e2..d341ede0dca5 100644 --- a/net/netlabel/Makefile +++ b/net/netlabel/Makefile | |||
@@ -12,4 +12,4 @@ obj-y += netlabel_mgmt.o | |||
12 | # protocol modules | 12 | # protocol modules |
13 | obj-y += netlabel_unlabeled.o | 13 | obj-y += netlabel_unlabeled.o |
14 | obj-y += netlabel_cipso_v4.o | 14 | obj-y += netlabel_cipso_v4.o |
15 | 15 | obj-$(subst m,y,$(CONFIG_IPV6)) += netlabel_calipso.o | |
diff --git a/net/netlabel/netlabel_calipso.c b/net/netlabel/netlabel_calipso.c new file mode 100644 index 000000000000..2ec93c5e77bb --- /dev/null +++ b/net/netlabel/netlabel_calipso.c | |||
@@ -0,0 +1,740 @@ | |||
1 | /* | ||
2 | * NetLabel CALIPSO/IPv6 Support | ||
3 | * | ||
4 | * This file defines the CALIPSO/IPv6 functions for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and CALIPSO. | ||
7 | * | ||
8 | * Authors: Paul Moore <paul@paul-moore.com> | ||
9 | * Huw Davies <huw@codeweavers.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/socket.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/skbuff.h> | ||
35 | #include <linux/audit.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <net/sock.h> | ||
38 | #include <net/netlink.h> | ||
39 | #include <net/genetlink.h> | ||
40 | #include <net/netlabel.h> | ||
41 | #include <net/calipso.h> | ||
42 | #include <linux/atomic.h> | ||
43 | |||
44 | #include "netlabel_user.h" | ||
45 | #include "netlabel_calipso.h" | ||
46 | #include "netlabel_mgmt.h" | ||
47 | #include "netlabel_domainhash.h" | ||
48 | |||
49 | /* Argument struct for calipso_doi_walk() */ | ||
50 | struct netlbl_calipso_doiwalk_arg { | ||
51 | struct netlink_callback *nl_cb; | ||
52 | struct sk_buff *skb; | ||
53 | u32 seq; | ||
54 | }; | ||
55 | |||
56 | /* Argument struct for netlbl_domhsh_walk() */ | ||
57 | struct netlbl_domhsh_walk_arg { | ||
58 | struct netlbl_audit *audit_info; | ||
59 | u32 doi; | ||
60 | }; | ||
61 | |||
62 | /* NetLabel Generic NETLINK CALIPSO family */ | ||
63 | static struct genl_family netlbl_calipso_gnl_family = { | ||
64 | .id = GENL_ID_GENERATE, | ||
65 | .hdrsize = 0, | ||
66 | .name = NETLBL_NLTYPE_CALIPSO_NAME, | ||
67 | .version = NETLBL_PROTO_VERSION, | ||
68 | .maxattr = NLBL_CALIPSO_A_MAX, | ||
69 | }; | ||
70 | |||
71 | /* NetLabel Netlink attribute policy */ | ||
72 | static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = { | ||
73 | [NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 }, | ||
74 | [NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 }, | ||
75 | }; | ||
76 | |||
77 | /* NetLabel Command Handlers | ||
78 | */ | ||
79 | /** | ||
80 | * netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition | ||
81 | * @info: the Generic NETLINK info block | ||
82 | * @audit_info: NetLabel audit information | ||
83 | * | ||
84 | * Description: | ||
85 | * Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message | ||
86 | * and add it to the CALIPSO engine. Return zero on success and non-zero on | ||
87 | * error. | ||
88 | * | ||
89 | */ | ||
90 | static int netlbl_calipso_add_pass(struct genl_info *info, | ||
91 | struct netlbl_audit *audit_info) | ||
92 | { | ||
93 | int ret_val; | ||
94 | struct calipso_doi *doi_def = NULL; | ||
95 | |||
96 | doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); | ||
97 | if (!doi_def) | ||
98 | return -ENOMEM; | ||
99 | doi_def->type = CALIPSO_MAP_PASS; | ||
100 | doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]); | ||
101 | ret_val = calipso_doi_add(doi_def, audit_info); | ||
102 | if (ret_val != 0) | ||
103 | calipso_doi_free(doi_def); | ||
104 | |||
105 | return ret_val; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * netlbl_calipso_add - Handle an ADD message | ||
110 | * @skb: the NETLINK buffer | ||
111 | * @info: the Generic NETLINK info block | ||
112 | * | ||
113 | * Description: | ||
114 | * Create a new DOI definition based on the given ADD message and add it to the | ||
115 | * CALIPSO engine. Returns zero on success, negative values on failure. | ||
116 | * | ||
117 | */ | ||
118 | static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info) | ||
119 | |||
120 | { | ||
121 | int ret_val = -EINVAL; | ||
122 | struct netlbl_audit audit_info; | ||
123 | |||
124 | if (!info->attrs[NLBL_CALIPSO_A_DOI] || | ||
125 | !info->attrs[NLBL_CALIPSO_A_MTYPE]) | ||
126 | return -EINVAL; | ||
127 | |||
128 | netlbl_netlink_auditinfo(skb, &audit_info); | ||
129 | switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) { | ||
130 | case CALIPSO_MAP_PASS: | ||
131 | ret_val = netlbl_calipso_add_pass(info, &audit_info); | ||
132 | break; | ||
133 | } | ||
134 | if (ret_val == 0) | ||
135 | atomic_inc(&netlabel_mgmt_protocount); | ||
136 | |||
137 | return ret_val; | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * netlbl_calipso_list - Handle a LIST message | ||
142 | * @skb: the NETLINK buffer | ||
143 | * @info: the Generic NETLINK info block | ||
144 | * | ||
145 | * Description: | ||
146 | * Process a user generated LIST message and respond accordingly. | ||
147 | * Returns zero on success and negative values on error. | ||
148 | * | ||
149 | */ | ||
150 | static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info) | ||
151 | { | ||
152 | int ret_val; | ||
153 | struct sk_buff *ans_skb = NULL; | ||
154 | void *data; | ||
155 | u32 doi; | ||
156 | struct calipso_doi *doi_def; | ||
157 | |||
158 | if (!info->attrs[NLBL_CALIPSO_A_DOI]) { | ||
159 | ret_val = -EINVAL; | ||
160 | goto list_failure; | ||
161 | } | ||
162 | |||
163 | doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]); | ||
164 | |||
165 | doi_def = calipso_doi_getdef(doi); | ||
166 | if (!doi_def) { | ||
167 | ret_val = -EINVAL; | ||
168 | goto list_failure; | ||
169 | } | ||
170 | |||
171 | ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
172 | if (!ans_skb) { | ||
173 | ret_val = -ENOMEM; | ||
174 | goto list_failure_put; | ||
175 | } | ||
176 | data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family, | ||
177 | 0, NLBL_CALIPSO_C_LIST); | ||
178 | if (!data) { | ||
179 | ret_val = -ENOMEM; | ||
180 | goto list_failure_put; | ||
181 | } | ||
182 | |||
183 | ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type); | ||
184 | if (ret_val != 0) | ||
185 | goto list_failure_put; | ||
186 | |||
187 | calipso_doi_putdef(doi_def); | ||
188 | |||
189 | genlmsg_end(ans_skb, data); | ||
190 | return genlmsg_reply(ans_skb, info); | ||
191 | |||
192 | list_failure_put: | ||
193 | calipso_doi_putdef(doi_def); | ||
194 | list_failure: | ||
195 | kfree_skb(ans_skb); | ||
196 | return ret_val; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL | ||
201 | * @doi_def: the CALIPSO DOI definition | ||
202 | * @arg: the netlbl_calipso_doiwalk_arg structure | ||
203 | * | ||
204 | * Description: | ||
205 | * This function is designed to be used as a callback to the | ||
206 | * calipso_doi_walk() function for use in generating a response for a LISTALL | ||
207 | * message. Returns the size of the message on success, negative values on | ||
208 | * failure. | ||
209 | * | ||
210 | */ | ||
211 | static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg) | ||
212 | { | ||
213 | int ret_val = -ENOMEM; | ||
214 | struct netlbl_calipso_doiwalk_arg *cb_arg = arg; | ||
215 | void *data; | ||
216 | |||
217 | data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, | ||
218 | cb_arg->seq, &netlbl_calipso_gnl_family, | ||
219 | NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL); | ||
220 | if (!data) | ||
221 | goto listall_cb_failure; | ||
222 | |||
223 | ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi); | ||
224 | if (ret_val != 0) | ||
225 | goto listall_cb_failure; | ||
226 | ret_val = nla_put_u32(cb_arg->skb, | ||
227 | NLBL_CALIPSO_A_MTYPE, | ||
228 | doi_def->type); | ||
229 | if (ret_val != 0) | ||
230 | goto listall_cb_failure; | ||
231 | |||
232 | genlmsg_end(cb_arg->skb, data); | ||
233 | return 0; | ||
234 | |||
235 | listall_cb_failure: | ||
236 | genlmsg_cancel(cb_arg->skb, data); | ||
237 | return ret_val; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * netlbl_calipso_listall - Handle a LISTALL message | ||
242 | * @skb: the NETLINK buffer | ||
243 | * @cb: the NETLINK callback | ||
244 | * | ||
245 | * Description: | ||
246 | * Process a user generated LISTALL message and respond accordingly. Returns | ||
247 | * zero on success and negative values on error. | ||
248 | * | ||
249 | */ | ||
250 | static int netlbl_calipso_listall(struct sk_buff *skb, | ||
251 | struct netlink_callback *cb) | ||
252 | { | ||
253 | struct netlbl_calipso_doiwalk_arg cb_arg; | ||
254 | u32 doi_skip = cb->args[0]; | ||
255 | |||
256 | cb_arg.nl_cb = cb; | ||
257 | cb_arg.skb = skb; | ||
258 | cb_arg.seq = cb->nlh->nlmsg_seq; | ||
259 | |||
260 | calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg); | ||
261 | |||
262 | cb->args[0] = doi_skip; | ||
263 | return skb->len; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * netlbl_calipso_remove_cb - netlbl_calipso_remove() callback for REMOVE | ||
268 | * @entry: LSM domain mapping entry | ||
269 | * @arg: the netlbl_domhsh_walk_arg structure | ||
270 | * | ||
271 | * Description: | ||
272 | * This function is intended for use by netlbl_calipso_remove() as the callback | ||
273 | * for the netlbl_domhsh_walk() function; it removes LSM domain map entries | ||
274 | * which are associated with the CALIPSO DOI specified in @arg. Returns zero on | ||
275 | * success, negative values on failure. | ||
276 | * | ||
277 | */ | ||
278 | static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg) | ||
279 | { | ||
280 | struct netlbl_domhsh_walk_arg *cb_arg = arg; | ||
281 | |||
282 | if (entry->def.type == NETLBL_NLTYPE_CALIPSO && | ||
283 | entry->def.calipso->doi == cb_arg->doi) | ||
284 | return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * netlbl_calipso_remove - Handle a REMOVE message | ||
291 | * @skb: the NETLINK buffer | ||
292 | * @info: the Generic NETLINK info block | ||
293 | * | ||
294 | * Description: | ||
295 | * Process a user generated REMOVE message and respond accordingly. Returns | ||
296 | * zero on success, negative values on failure. | ||
297 | * | ||
298 | */ | ||
299 | static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info) | ||
300 | { | ||
301 | int ret_val = -EINVAL; | ||
302 | struct netlbl_domhsh_walk_arg cb_arg; | ||
303 | struct netlbl_audit audit_info; | ||
304 | u32 skip_bkt = 0; | ||
305 | u32 skip_chain = 0; | ||
306 | |||
307 | if (!info->attrs[NLBL_CALIPSO_A_DOI]) | ||
308 | return -EINVAL; | ||
309 | |||
310 | netlbl_netlink_auditinfo(skb, &audit_info); | ||
311 | cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]); | ||
312 | cb_arg.audit_info = &audit_info; | ||
313 | ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, | ||
314 | netlbl_calipso_remove_cb, &cb_arg); | ||
315 | if (ret_val == 0 || ret_val == -ENOENT) { | ||
316 | ret_val = calipso_doi_remove(cb_arg.doi, &audit_info); | ||
317 | if (ret_val == 0) | ||
318 | atomic_dec(&netlabel_mgmt_protocount); | ||
319 | } | ||
320 | |||
321 | return ret_val; | ||
322 | } | ||
323 | |||
324 | /* NetLabel Generic NETLINK Command Definitions | ||
325 | */ | ||
326 | |||
327 | static const struct genl_ops netlbl_calipso_ops[] = { | ||
328 | { | ||
329 | .cmd = NLBL_CALIPSO_C_ADD, | ||
330 | .flags = GENL_ADMIN_PERM, | ||
331 | .policy = calipso_genl_policy, | ||
332 | .doit = netlbl_calipso_add, | ||
333 | .dumpit = NULL, | ||
334 | }, | ||
335 | { | ||
336 | .cmd = NLBL_CALIPSO_C_REMOVE, | ||
337 | .flags = GENL_ADMIN_PERM, | ||
338 | .policy = calipso_genl_policy, | ||
339 | .doit = netlbl_calipso_remove, | ||
340 | .dumpit = NULL, | ||
341 | }, | ||
342 | { | ||
343 | .cmd = NLBL_CALIPSO_C_LIST, | ||
344 | .flags = 0, | ||
345 | .policy = calipso_genl_policy, | ||
346 | .doit = netlbl_calipso_list, | ||
347 | .dumpit = NULL, | ||
348 | }, | ||
349 | { | ||
350 | .cmd = NLBL_CALIPSO_C_LISTALL, | ||
351 | .flags = 0, | ||
352 | .policy = calipso_genl_policy, | ||
353 | .doit = NULL, | ||
354 | .dumpit = netlbl_calipso_listall, | ||
355 | }, | ||
356 | }; | ||
357 | |||
358 | /* NetLabel Generic NETLINK Protocol Functions | ||
359 | */ | ||
360 | |||
361 | /** | ||
362 | * netlbl_calipso_genl_init - Register the CALIPSO NetLabel component | ||
363 | * | ||
364 | * Description: | ||
365 | * Register the CALIPSO packet NetLabel component with the Generic NETLINK | ||
366 | * mechanism. Returns zero on success, negative values on failure. | ||
367 | * | ||
368 | */ | ||
369 | int __init netlbl_calipso_genl_init(void) | ||
370 | { | ||
371 | return genl_register_family_with_ops(&netlbl_calipso_gnl_family, | ||
372 | netlbl_calipso_ops); | ||
373 | } | ||
374 | |||
375 | static const struct netlbl_calipso_ops *calipso_ops; | ||
376 | |||
377 | /** | ||
378 | * netlbl_calipso_ops_register - Register the CALIPSO operations | ||
379 | * | ||
380 | * Description: | ||
381 | * Register the CALIPSO packet engine operations. | ||
382 | * | ||
383 | */ | ||
384 | const struct netlbl_calipso_ops * | ||
385 | netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops) | ||
386 | { | ||
387 | return xchg(&calipso_ops, ops); | ||
388 | } | ||
389 | EXPORT_SYMBOL(netlbl_calipso_ops_register); | ||
390 | |||
391 | static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void) | ||
392 | { | ||
393 | return ACCESS_ONCE(calipso_ops); | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine | ||
398 | * @doi_def: the DOI structure | ||
399 | * @audit_info: NetLabel audit information | ||
400 | * | ||
401 | * Description: | ||
402 | * The caller defines a new DOI for use by the CALIPSO engine and calls this | ||
403 | * function to add it to the list of acceptable domains. The caller must | ||
404 | * ensure that the mapping table specified in @doi_def->map meets all of the | ||
405 | * requirements of the mapping type (see calipso.h for details). Returns | ||
406 | * zero on success and non-zero on failure. | ||
407 | * | ||
408 | */ | ||
409 | int calipso_doi_add(struct calipso_doi *doi_def, | ||
410 | struct netlbl_audit *audit_info) | ||
411 | { | ||
412 | int ret_val = -ENOMSG; | ||
413 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
414 | |||
415 | if (ops) | ||
416 | ret_val = ops->doi_add(doi_def, audit_info); | ||
417 | return ret_val; | ||
418 | } | ||
419 | |||
420 | /** | ||
421 | * calipso_doi_free - Frees a DOI definition | ||
422 | * @doi_def: the DOI definition | ||
423 | * | ||
424 | * Description: | ||
425 | * This function frees all of the memory associated with a DOI definition. | ||
426 | * | ||
427 | */ | ||
428 | void calipso_doi_free(struct calipso_doi *doi_def) | ||
429 | { | ||
430 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
431 | |||
432 | if (ops) | ||
433 | ops->doi_free(doi_def); | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine | ||
438 | * @doi: the DOI value | ||
439 | * @audit_secid: the LSM secid to use in the audit message | ||
440 | * | ||
441 | * Description: | ||
442 | * Removes a DOI definition from the CALIPSO engine. The NetLabel routines will | ||
443 | * be called to release their own LSM domain mappings as well as our own | ||
444 | * domain list. Returns zero on success and negative values on failure. | ||
445 | * | ||
446 | */ | ||
447 | int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info) | ||
448 | { | ||
449 | int ret_val = -ENOMSG; | ||
450 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
451 | |||
452 | if (ops) | ||
453 | ret_val = ops->doi_remove(doi, audit_info); | ||
454 | return ret_val; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * calipso_doi_getdef - Returns a reference to a valid DOI definition | ||
459 | * @doi: the DOI value | ||
460 | * | ||
461 | * Description: | ||
462 | * Searches for a valid DOI definition and if one is found it is returned to | ||
463 | * the caller. Otherwise NULL is returned. The caller must ensure that | ||
464 | * calipso_doi_putdef() is called when the caller is done. | ||
465 | * | ||
466 | */ | ||
467 | struct calipso_doi *calipso_doi_getdef(u32 doi) | ||
468 | { | ||
469 | struct calipso_doi *ret_val = NULL; | ||
470 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
471 | |||
472 | if (ops) | ||
473 | ret_val = ops->doi_getdef(doi); | ||
474 | return ret_val; | ||
475 | } | ||
476 | |||
477 | /** | ||
478 | * calipso_doi_putdef - Releases a reference for the given DOI definition | ||
479 | * @doi_def: the DOI definition | ||
480 | * | ||
481 | * Description: | ||
482 | * Releases a DOI definition reference obtained from calipso_doi_getdef(). | ||
483 | * | ||
484 | */ | ||
485 | void calipso_doi_putdef(struct calipso_doi *doi_def) | ||
486 | { | ||
487 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
488 | |||
489 | if (ops) | ||
490 | ops->doi_putdef(doi_def); | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * calipso_doi_walk - Iterate through the DOI definitions | ||
495 | * @skip_cnt: skip past this number of DOI definitions, updated | ||
496 | * @callback: callback for each DOI definition | ||
497 | * @cb_arg: argument for the callback function | ||
498 | * | ||
499 | * Description: | ||
500 | * Iterate over the DOI definition list, skipping the first @skip_cnt entries. | ||
501 | * For each entry call @callback, if @callback returns a negative value stop | ||
502 | * 'walking' through the list and return. Updates the value in @skip_cnt upon | ||
503 | * return. Returns zero on success, negative values on failure. | ||
504 | * | ||
505 | */ | ||
506 | int calipso_doi_walk(u32 *skip_cnt, | ||
507 | int (*callback)(struct calipso_doi *doi_def, void *arg), | ||
508 | void *cb_arg) | ||
509 | { | ||
510 | int ret_val = -ENOMSG; | ||
511 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
512 | |||
513 | if (ops) | ||
514 | ret_val = ops->doi_walk(skip_cnt, callback, cb_arg); | ||
515 | return ret_val; | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * calipso_sock_getattr - Get the security attributes from a sock | ||
520 | * @sk: the sock | ||
521 | * @secattr: the security attributes | ||
522 | * | ||
523 | * Description: | ||
524 | * Query @sk to see if there is a CALIPSO option attached to the sock and if | ||
525 | * there is return the CALIPSO security attributes in @secattr. This function | ||
526 | * requires that @sk be locked, or privately held, but it does not do any | ||
527 | * locking itself. Returns zero on success and negative values on failure. | ||
528 | * | ||
529 | */ | ||
530 | int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | ||
531 | { | ||
532 | int ret_val = -ENOMSG; | ||
533 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
534 | |||
535 | if (ops) | ||
536 | ret_val = ops->sock_getattr(sk, secattr); | ||
537 | return ret_val; | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * calipso_sock_setattr - Add a CALIPSO option to a socket | ||
542 | * @sk: the socket | ||
543 | * @doi_def: the CALIPSO DOI to use | ||
544 | * @secattr: the specific security attributes of the socket | ||
545 | * | ||
546 | * Description: | ||
547 | * Set the CALIPSO option on the given socket using the DOI definition and | ||
548 | * security attributes passed to the function. This function requires | ||
549 | * exclusive access to @sk, which means it either needs to be in the | ||
550 | * process of being created or locked. Returns zero on success and negative | ||
551 | * values on failure. | ||
552 | * | ||
553 | */ | ||
554 | int calipso_sock_setattr(struct sock *sk, | ||
555 | const struct calipso_doi *doi_def, | ||
556 | const struct netlbl_lsm_secattr *secattr) | ||
557 | { | ||
558 | int ret_val = -ENOMSG; | ||
559 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
560 | |||
561 | if (ops) | ||
562 | ret_val = ops->sock_setattr(sk, doi_def, secattr); | ||
563 | return ret_val; | ||
564 | } | ||
565 | |||
566 | /** | ||
567 | * calipso_sock_delattr - Delete the CALIPSO option from a socket | ||
568 | * @sk: the socket | ||
569 | * | ||
570 | * Description: | ||
571 | * Removes the CALIPSO option from a socket, if present. | ||
572 | * | ||
573 | */ | ||
574 | void calipso_sock_delattr(struct sock *sk) | ||
575 | { | ||
576 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
577 | |||
578 | if (ops) | ||
579 | ops->sock_delattr(sk); | ||
580 | } | ||
581 | |||
582 | /** | ||
583 | * calipso_req_setattr - Add a CALIPSO option to a connection request socket | ||
584 | * @req: the connection request socket | ||
585 | * @doi_def: the CALIPSO DOI to use | ||
586 | * @secattr: the specific security attributes of the socket | ||
587 | * | ||
588 | * Description: | ||
589 | * Set the CALIPSO option on the given socket using the DOI definition and | ||
590 | * security attributes passed to the function. Returns zero on success and | ||
591 | * negative values on failure. | ||
592 | * | ||
593 | */ | ||
594 | int calipso_req_setattr(struct request_sock *req, | ||
595 | const struct calipso_doi *doi_def, | ||
596 | const struct netlbl_lsm_secattr *secattr) | ||
597 | { | ||
598 | int ret_val = -ENOMSG; | ||
599 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
600 | |||
601 | if (ops) | ||
602 | ret_val = ops->req_setattr(req, doi_def, secattr); | ||
603 | return ret_val; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * calipso_req_delattr - Delete the CALIPSO option from a request socket | ||
608 | * @reg: the request socket | ||
609 | * | ||
610 | * Description: | ||
611 | * Removes the CALIPSO option from a request socket, if present. | ||
612 | * | ||
613 | */ | ||
614 | void calipso_req_delattr(struct request_sock *req) | ||
615 | { | ||
616 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
617 | |||
618 | if (ops) | ||
619 | ops->req_delattr(req); | ||
620 | } | ||
621 | |||
622 | /** | ||
623 | * calipso_optptr - Find the CALIPSO option in the packet | ||
624 | * @skb: the packet | ||
625 | * | ||
626 | * Description: | ||
627 | * Parse the packet's IP header looking for a CALIPSO option. Returns a pointer | ||
628 | * to the start of the CALIPSO option on success, NULL if one if not found. | ||
629 | * | ||
630 | */ | ||
631 | unsigned char *calipso_optptr(const struct sk_buff *skb) | ||
632 | { | ||
633 | unsigned char *ret_val = NULL; | ||
634 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
635 | |||
636 | if (ops) | ||
637 | ret_val = ops->skbuff_optptr(skb); | ||
638 | return ret_val; | ||
639 | } | ||
640 | |||
641 | /** | ||
642 | * calipso_getattr - Get the security attributes from a memory block. | ||
643 | * @calipso: the CALIPSO option | ||
644 | * @secattr: the security attributes | ||
645 | * | ||
646 | * Description: | ||
647 | * Inspect @calipso and return the security attributes in @secattr. | ||
648 | * Returns zero on success and negative values on failure. | ||
649 | * | ||
650 | */ | ||
651 | int calipso_getattr(const unsigned char *calipso, | ||
652 | struct netlbl_lsm_secattr *secattr) | ||
653 | { | ||
654 | int ret_val = -ENOMSG; | ||
655 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
656 | |||
657 | if (ops) | ||
658 | ret_val = ops->opt_getattr(calipso, secattr); | ||
659 | return ret_val; | ||
660 | } | ||
661 | |||
662 | /** | ||
663 | * calipso_skbuff_setattr - Set the CALIPSO option on a packet | ||
664 | * @skb: the packet | ||
665 | * @doi_def: the CALIPSO DOI to use | ||
666 | * @secattr: the security attributes | ||
667 | * | ||
668 | * Description: | ||
669 | * Set the CALIPSO option on the given packet based on the security attributes. | ||
670 | * Returns a pointer to the IP header on success and NULL on failure. | ||
671 | * | ||
672 | */ | ||
673 | int calipso_skbuff_setattr(struct sk_buff *skb, | ||
674 | const struct calipso_doi *doi_def, | ||
675 | const struct netlbl_lsm_secattr *secattr) | ||
676 | { | ||
677 | int ret_val = -ENOMSG; | ||
678 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
679 | |||
680 | if (ops) | ||
681 | ret_val = ops->skbuff_setattr(skb, doi_def, secattr); | ||
682 | return ret_val; | ||
683 | } | ||
684 | |||
685 | /** | ||
686 | * calipso_skbuff_delattr - Delete any CALIPSO options from a packet | ||
687 | * @skb: the packet | ||
688 | * | ||
689 | * Description: | ||
690 | * Removes any and all CALIPSO options from the given packet. Returns zero on | ||
691 | * success, negative values on failure. | ||
692 | * | ||
693 | */ | ||
694 | int calipso_skbuff_delattr(struct sk_buff *skb) | ||
695 | { | ||
696 | int ret_val = -ENOMSG; | ||
697 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
698 | |||
699 | if (ops) | ||
700 | ret_val = ops->skbuff_delattr(skb); | ||
701 | return ret_val; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * calipso_cache_invalidate - Invalidates the current CALIPSO cache | ||
706 | * | ||
707 | * Description: | ||
708 | * Invalidates and frees any entries in the CALIPSO cache. Returns zero on | ||
709 | * success and negative values on failure. | ||
710 | * | ||
711 | */ | ||
712 | void calipso_cache_invalidate(void) | ||
713 | { | ||
714 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
715 | |||
716 | if (ops) | ||
717 | ops->cache_invalidate(); | ||
718 | } | ||
719 | |||
720 | /** | ||
721 | * calipso_cache_add - Add an entry to the CALIPSO cache | ||
722 | * @calipso_ptr: the CALIPSO option | ||
723 | * @secattr: the packet's security attributes | ||
724 | * | ||
725 | * Description: | ||
726 | * Add a new entry into the CALIPSO label mapping cache. | ||
727 | * Returns zero on success, negative values on failure. | ||
728 | * | ||
729 | */ | ||
730 | int calipso_cache_add(const unsigned char *calipso_ptr, | ||
731 | const struct netlbl_lsm_secattr *secattr) | ||
732 | |||
733 | { | ||
734 | int ret_val = -ENOMSG; | ||
735 | const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); | ||
736 | |||
737 | if (ops) | ||
738 | ret_val = ops->cache_add(calipso_ptr, secattr); | ||
739 | return ret_val; | ||
740 | } | ||
diff --git a/net/netlabel/netlabel_calipso.h b/net/netlabel/netlabel_calipso.h new file mode 100644 index 000000000000..9fd291cd0fc5 --- /dev/null +++ b/net/netlabel/netlabel_calipso.h | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * NetLabel CALIPSO Support | ||
3 | * | ||
4 | * This file defines the CALIPSO functions for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Authors: Paul Moore <paul@paul-moore.com> | ||
9 | * Huw Davies <huw@codeweavers.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef _NETLABEL_CALIPSO | ||
32 | #define _NETLABEL_CALIPSO | ||
33 | |||
34 | #include <net/netlabel.h> | ||
35 | #include <net/calipso.h> | ||
36 | |||
37 | /* The following NetLabel payloads are supported by the CALIPSO subsystem. | ||
38 | * | ||
39 | * o ADD: | ||
40 | * Sent by an application to add a new DOI mapping table. | ||
41 | * | ||
42 | * Required attributes: | ||
43 | * | ||
44 | * NLBL_CALIPSO_A_DOI | ||
45 | * NLBL_CALIPSO_A_MTYPE | ||
46 | * | ||
47 | * If using CALIPSO_MAP_PASS no additional attributes are required. | ||
48 | * | ||
49 | * o REMOVE: | ||
50 | * Sent by an application to remove a specific DOI mapping table from the | ||
51 | * CALIPSO system. | ||
52 | * | ||
53 | * Required attributes: | ||
54 | * | ||
55 | * NLBL_CALIPSO_A_DOI | ||
56 | * | ||
57 | * o LIST: | ||
58 | * Sent by an application to list the details of a DOI definition. On | ||
59 | * success the kernel should send a response using the following format. | ||
60 | * | ||
61 | * Required attributes: | ||
62 | * | ||
63 | * NLBL_CALIPSO_A_DOI | ||
64 | * | ||
65 | * The valid response message format depends on the type of the DOI mapping, | ||
66 | * the defined formats are shown below. | ||
67 | * | ||
68 | * Required attributes: | ||
69 | * | ||
70 | * NLBL_CALIPSO_A_MTYPE | ||
71 | * | ||
72 | * If using CALIPSO_MAP_PASS no additional attributes are required. | ||
73 | * | ||
74 | * o LISTALL: | ||
75 | * This message is sent by an application to list the valid DOIs on the | ||
76 | * system. When sent by an application there is no payload and the | ||
77 | * NLM_F_DUMP flag should be set. The kernel should respond with a series of | ||
78 | * the following messages. | ||
79 | * | ||
80 | * Required attributes: | ||
81 | * | ||
82 | * NLBL_CALIPSO_A_DOI | ||
83 | * NLBL_CALIPSO_A_MTYPE | ||
84 | * | ||
85 | */ | ||
86 | |||
87 | /* NetLabel CALIPSO commands */ | ||
88 | enum { | ||
89 | NLBL_CALIPSO_C_UNSPEC, | ||
90 | NLBL_CALIPSO_C_ADD, | ||
91 | NLBL_CALIPSO_C_REMOVE, | ||
92 | NLBL_CALIPSO_C_LIST, | ||
93 | NLBL_CALIPSO_C_LISTALL, | ||
94 | __NLBL_CALIPSO_C_MAX, | ||
95 | }; | ||
96 | |||
97 | /* NetLabel CALIPSO attributes */ | ||
98 | enum { | ||
99 | NLBL_CALIPSO_A_UNSPEC, | ||
100 | NLBL_CALIPSO_A_DOI, | ||
101 | /* (NLA_U32) | ||
102 | * the DOI value */ | ||
103 | NLBL_CALIPSO_A_MTYPE, | ||
104 | /* (NLA_U32) | ||
105 | * the mapping table type (defined in the calipso.h header as | ||
106 | * CALIPSO_MAP_*) */ | ||
107 | __NLBL_CALIPSO_A_MAX, | ||
108 | }; | ||
109 | |||
110 | #define NLBL_CALIPSO_A_MAX (__NLBL_CALIPSO_A_MAX - 1) | ||
111 | |||
112 | /* NetLabel protocol functions */ | ||
113 | #if IS_ENABLED(CONFIG_IPV6) | ||
114 | int netlbl_calipso_genl_init(void); | ||
115 | #else | ||
116 | static inline int netlbl_calipso_genl_init(void) | ||
117 | { | ||
118 | return 0; | ||
119 | } | ||
120 | #endif | ||
121 | |||
122 | int calipso_doi_add(struct calipso_doi *doi_def, | ||
123 | struct netlbl_audit *audit_info); | ||
124 | void calipso_doi_free(struct calipso_doi *doi_def); | ||
125 | int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info); | ||
126 | struct calipso_doi *calipso_doi_getdef(u32 doi); | ||
127 | void calipso_doi_putdef(struct calipso_doi *doi_def); | ||
128 | int calipso_doi_walk(u32 *skip_cnt, | ||
129 | int (*callback)(struct calipso_doi *doi_def, void *arg), | ||
130 | void *cb_arg); | ||
131 | int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); | ||
132 | int calipso_sock_setattr(struct sock *sk, | ||
133 | const struct calipso_doi *doi_def, | ||
134 | const struct netlbl_lsm_secattr *secattr); | ||
135 | void calipso_sock_delattr(struct sock *sk); | ||
136 | int calipso_req_setattr(struct request_sock *req, | ||
137 | const struct calipso_doi *doi_def, | ||
138 | const struct netlbl_lsm_secattr *secattr); | ||
139 | void calipso_req_delattr(struct request_sock *req); | ||
140 | unsigned char *calipso_optptr(const struct sk_buff *skb); | ||
141 | int calipso_getattr(const unsigned char *calipso, | ||
142 | struct netlbl_lsm_secattr *secattr); | ||
143 | int calipso_skbuff_setattr(struct sk_buff *skb, | ||
144 | const struct calipso_doi *doi_def, | ||
145 | const struct netlbl_lsm_secattr *secattr); | ||
146 | int calipso_skbuff_delattr(struct sk_buff *skb); | ||
147 | void calipso_cache_invalidate(void); | ||
148 | int calipso_cache_add(const unsigned char *calipso_ptr, | ||
149 | const struct netlbl_lsm_secattr *secattr); | ||
150 | |||
151 | #endif | ||
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index ada67422234b..41d0e95d171e 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
@@ -37,10 +37,12 @@ | |||
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <net/netlabel.h> | 38 | #include <net/netlabel.h> |
39 | #include <net/cipso_ipv4.h> | 39 | #include <net/cipso_ipv4.h> |
40 | #include <net/calipso.h> | ||
40 | #include <asm/bug.h> | 41 | #include <asm/bug.h> |
41 | 42 | ||
42 | #include "netlabel_mgmt.h" | 43 | #include "netlabel_mgmt.h" |
43 | #include "netlabel_addrlist.h" | 44 | #include "netlabel_addrlist.h" |
45 | #include "netlabel_calipso.h" | ||
44 | #include "netlabel_domainhash.h" | 46 | #include "netlabel_domainhash.h" |
45 | #include "netlabel_user.h" | 47 | #include "netlabel_user.h" |
46 | 48 | ||
@@ -55,8 +57,9 @@ struct netlbl_domhsh_tbl { | |||
55 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); | 57 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); |
56 | #define netlbl_domhsh_rcu_deref(p) \ | 58 | #define netlbl_domhsh_rcu_deref(p) \ |
57 | rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock)) | 59 | rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock)) |
58 | static struct netlbl_domhsh_tbl *netlbl_domhsh; | 60 | static struct netlbl_domhsh_tbl __rcu *netlbl_domhsh; |
59 | static struct netlbl_dom_map *netlbl_domhsh_def; | 61 | static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv4; |
62 | static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv6; | ||
60 | 63 | ||
61 | /* | 64 | /* |
62 | * Domain Hash Table Helper Functions | 65 | * Domain Hash Table Helper Functions |
@@ -126,18 +129,26 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
126 | return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1); | 129 | return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1); |
127 | } | 130 | } |
128 | 131 | ||
132 | static bool netlbl_family_match(u16 f1, u16 f2) | ||
133 | { | ||
134 | return (f1 == f2) || (f1 == AF_UNSPEC) || (f2 == AF_UNSPEC); | ||
135 | } | ||
136 | |||
129 | /** | 137 | /** |
130 | * netlbl_domhsh_search - Search for a domain entry | 138 | * netlbl_domhsh_search - Search for a domain entry |
131 | * @domain: the domain | 139 | * @domain: the domain |
140 | * @family: the address family | ||
132 | * | 141 | * |
133 | * Description: | 142 | * Description: |
134 | * Searches the domain hash table and returns a pointer to the hash table | 143 | * Searches the domain hash table and returns a pointer to the hash table |
135 | * entry if found, otherwise NULL is returned. The caller is responsible for | 144 | * entry if found, otherwise NULL is returned. @family may be %AF_UNSPEC |
145 | * which matches any address family entries. The caller is responsible for | ||
136 | * ensuring that the hash table is protected with either a RCU read lock or the | 146 | * ensuring that the hash table is protected with either a RCU read lock or the |
137 | * hash table lock. | 147 | * hash table lock. |
138 | * | 148 | * |
139 | */ | 149 | */ |
140 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | 150 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, |
151 | u16 family) | ||
141 | { | 152 | { |
142 | u32 bkt; | 153 | u32 bkt; |
143 | struct list_head *bkt_list; | 154 | struct list_head *bkt_list; |
@@ -147,7 +158,9 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | |||
147 | bkt = netlbl_domhsh_hash(domain); | 158 | bkt = netlbl_domhsh_hash(domain); |
148 | bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt]; | 159 | bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt]; |
149 | list_for_each_entry_rcu(iter, bkt_list, list) | 160 | list_for_each_entry_rcu(iter, bkt_list, list) |
150 | if (iter->valid && strcmp(iter->domain, domain) == 0) | 161 | if (iter->valid && |
162 | netlbl_family_match(iter->family, family) && | ||
163 | strcmp(iter->domain, domain) == 0) | ||
151 | return iter; | 164 | return iter; |
152 | } | 165 | } |
153 | 166 | ||
@@ -157,28 +170,37 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | |||
157 | /** | 170 | /** |
158 | * netlbl_domhsh_search_def - Search for a domain entry | 171 | * netlbl_domhsh_search_def - Search for a domain entry |
159 | * @domain: the domain | 172 | * @domain: the domain |
160 | * @def: return default if no match is found | 173 | * @family: the address family |
161 | * | 174 | * |
162 | * Description: | 175 | * Description: |
163 | * Searches the domain hash table and returns a pointer to the hash table | 176 | * Searches the domain hash table and returns a pointer to the hash table |
164 | * entry if an exact match is found, if an exact match is not present in the | 177 | * entry if an exact match is found, if an exact match is not present in the |
165 | * hash table then the default entry is returned if valid otherwise NULL is | 178 | * hash table then the default entry is returned if valid otherwise NULL is |
166 | * returned. The caller is responsible ensuring that the hash table is | 179 | * returned. @family may be %AF_UNSPEC which matches any address family |
180 | * entries. The caller is responsible ensuring that the hash table is | ||
167 | * protected with either a RCU read lock or the hash table lock. | 181 | * protected with either a RCU read lock or the hash table lock. |
168 | * | 182 | * |
169 | */ | 183 | */ |
170 | static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | 184 | static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain, |
185 | u16 family) | ||
171 | { | 186 | { |
172 | struct netlbl_dom_map *entry; | 187 | struct netlbl_dom_map *entry; |
173 | 188 | ||
174 | entry = netlbl_domhsh_search(domain); | 189 | entry = netlbl_domhsh_search(domain, family); |
175 | if (entry == NULL) { | 190 | if (entry != NULL) |
176 | entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def); | 191 | return entry; |
177 | if (entry != NULL && !entry->valid) | 192 | if (family == AF_INET || family == AF_UNSPEC) { |
178 | entry = NULL; | 193 | entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv4); |
194 | if (entry != NULL && entry->valid) | ||
195 | return entry; | ||
196 | } | ||
197 | if (family == AF_INET6 || family == AF_UNSPEC) { | ||
198 | entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv6); | ||
199 | if (entry != NULL && entry->valid) | ||
200 | return entry; | ||
179 | } | 201 | } |
180 | 202 | ||
181 | return entry; | 203 | return NULL; |
182 | } | 204 | } |
183 | 205 | ||
184 | /** | 206 | /** |
@@ -203,6 +225,7 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, | |||
203 | { | 225 | { |
204 | struct audit_buffer *audit_buf; | 226 | struct audit_buffer *audit_buf; |
205 | struct cipso_v4_doi *cipsov4 = NULL; | 227 | struct cipso_v4_doi *cipsov4 = NULL; |
228 | struct calipso_doi *calipso = NULL; | ||
206 | u32 type; | 229 | u32 type; |
207 | 230 | ||
208 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); | 231 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); |
@@ -221,12 +244,14 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, | |||
221 | struct netlbl_domaddr6_map *map6; | 244 | struct netlbl_domaddr6_map *map6; |
222 | map6 = netlbl_domhsh_addr6_entry(addr6); | 245 | map6 = netlbl_domhsh_addr6_entry(addr6); |
223 | type = map6->def.type; | 246 | type = map6->def.type; |
247 | calipso = map6->def.calipso; | ||
224 | netlbl_af6list_audit_addr(audit_buf, 0, NULL, | 248 | netlbl_af6list_audit_addr(audit_buf, 0, NULL, |
225 | &addr6->addr, &addr6->mask); | 249 | &addr6->addr, &addr6->mask); |
226 | #endif /* IPv6 */ | 250 | #endif /* IPv6 */ |
227 | } else { | 251 | } else { |
228 | type = entry->def.type; | 252 | type = entry->def.type; |
229 | cipsov4 = entry->def.cipso; | 253 | cipsov4 = entry->def.cipso; |
254 | calipso = entry->def.calipso; | ||
230 | } | 255 | } |
231 | switch (type) { | 256 | switch (type) { |
232 | case NETLBL_NLTYPE_UNLABELED: | 257 | case NETLBL_NLTYPE_UNLABELED: |
@@ -238,6 +263,12 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, | |||
238 | " nlbl_protocol=cipsov4 cipso_doi=%u", | 263 | " nlbl_protocol=cipsov4 cipso_doi=%u", |
239 | cipsov4->doi); | 264 | cipsov4->doi); |
240 | break; | 265 | break; |
266 | case NETLBL_NLTYPE_CALIPSO: | ||
267 | BUG_ON(calipso == NULL); | ||
268 | audit_log_format(audit_buf, | ||
269 | " nlbl_protocol=calipso calipso_doi=%u", | ||
270 | calipso->doi); | ||
271 | break; | ||
241 | } | 272 | } |
242 | audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0); | 273 | audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0); |
243 | audit_log_end(audit_buf); | 274 | audit_log_end(audit_buf); |
@@ -264,13 +295,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry) | |||
264 | if (entry == NULL) | 295 | if (entry == NULL) |
265 | return -EINVAL; | 296 | return -EINVAL; |
266 | 297 | ||
298 | if (entry->family != AF_INET && entry->family != AF_INET6 && | ||
299 | (entry->family != AF_UNSPEC || | ||
300 | entry->def.type != NETLBL_NLTYPE_UNLABELED)) | ||
301 | return -EINVAL; | ||
302 | |||
267 | switch (entry->def.type) { | 303 | switch (entry->def.type) { |
268 | case NETLBL_NLTYPE_UNLABELED: | 304 | case NETLBL_NLTYPE_UNLABELED: |
269 | if (entry->def.cipso != NULL || entry->def.addrsel != NULL) | 305 | if (entry->def.cipso != NULL || entry->def.calipso != NULL || |
306 | entry->def.addrsel != NULL) | ||
270 | return -EINVAL; | 307 | return -EINVAL; |
271 | break; | 308 | break; |
272 | case NETLBL_NLTYPE_CIPSOV4: | 309 | case NETLBL_NLTYPE_CIPSOV4: |
273 | if (entry->def.cipso == NULL) | 310 | if (entry->family != AF_INET || |
311 | entry->def.cipso == NULL) | ||
312 | return -EINVAL; | ||
313 | break; | ||
314 | case NETLBL_NLTYPE_CALIPSO: | ||
315 | if (entry->family != AF_INET6 || | ||
316 | entry->def.calipso == NULL) | ||
274 | return -EINVAL; | 317 | return -EINVAL; |
275 | break; | 318 | break; |
276 | case NETLBL_NLTYPE_ADDRSELECT: | 319 | case NETLBL_NLTYPE_ADDRSELECT: |
@@ -294,6 +337,12 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry) | |||
294 | map6 = netlbl_domhsh_addr6_entry(iter6); | 337 | map6 = netlbl_domhsh_addr6_entry(iter6); |
295 | switch (map6->def.type) { | 338 | switch (map6->def.type) { |
296 | case NETLBL_NLTYPE_UNLABELED: | 339 | case NETLBL_NLTYPE_UNLABELED: |
340 | if (map6->def.calipso != NULL) | ||
341 | return -EINVAL; | ||
342 | break; | ||
343 | case NETLBL_NLTYPE_CALIPSO: | ||
344 | if (map6->def.calipso == NULL) | ||
345 | return -EINVAL; | ||
297 | break; | 346 | break; |
298 | default: | 347 | default: |
299 | return -EINVAL; | 348 | return -EINVAL; |
@@ -358,15 +407,18 @@ int __init netlbl_domhsh_init(u32 size) | |||
358 | * | 407 | * |
359 | * Description: | 408 | * Description: |
360 | * Adds a new entry to the domain hash table and handles any updates to the | 409 | * Adds a new entry to the domain hash table and handles any updates to the |
361 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | 410 | * lower level protocol handler (i.e. CIPSO). @entry->family may be set to |
362 | * negative on failure. | 411 | * %AF_UNSPEC which will add an entry that matches all address families. This |
412 | * is only useful for the unlabelled type and will only succeed if there is no | ||
413 | * existing entry for any address family with the same domain. Returns zero | ||
414 | * on success, negative on failure. | ||
363 | * | 415 | * |
364 | */ | 416 | */ |
365 | int netlbl_domhsh_add(struct netlbl_dom_map *entry, | 417 | int netlbl_domhsh_add(struct netlbl_dom_map *entry, |
366 | struct netlbl_audit *audit_info) | 418 | struct netlbl_audit *audit_info) |
367 | { | 419 | { |
368 | int ret_val = 0; | 420 | int ret_val = 0; |
369 | struct netlbl_dom_map *entry_old; | 421 | struct netlbl_dom_map *entry_old, *entry_b; |
370 | struct netlbl_af4list *iter4; | 422 | struct netlbl_af4list *iter4; |
371 | struct netlbl_af4list *tmp4; | 423 | struct netlbl_af4list *tmp4; |
372 | #if IS_ENABLED(CONFIG_IPV6) | 424 | #if IS_ENABLED(CONFIG_IPV6) |
@@ -385,9 +437,10 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, | |||
385 | rcu_read_lock(); | 437 | rcu_read_lock(); |
386 | spin_lock(&netlbl_domhsh_lock); | 438 | spin_lock(&netlbl_domhsh_lock); |
387 | if (entry->domain != NULL) | 439 | if (entry->domain != NULL) |
388 | entry_old = netlbl_domhsh_search(entry->domain); | 440 | entry_old = netlbl_domhsh_search(entry->domain, entry->family); |
389 | else | 441 | else |
390 | entry_old = netlbl_domhsh_search_def(entry->domain); | 442 | entry_old = netlbl_domhsh_search_def(entry->domain, |
443 | entry->family); | ||
391 | if (entry_old == NULL) { | 444 | if (entry_old == NULL) { |
392 | entry->valid = 1; | 445 | entry->valid = 1; |
393 | 446 | ||
@@ -397,7 +450,41 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, | |||
397 | &rcu_dereference(netlbl_domhsh)->tbl[bkt]); | 450 | &rcu_dereference(netlbl_domhsh)->tbl[bkt]); |
398 | } else { | 451 | } else { |
399 | INIT_LIST_HEAD(&entry->list); | 452 | INIT_LIST_HEAD(&entry->list); |
400 | rcu_assign_pointer(netlbl_domhsh_def, entry); | 453 | switch (entry->family) { |
454 | case AF_INET: | ||
455 | rcu_assign_pointer(netlbl_domhsh_def_ipv4, | ||
456 | entry); | ||
457 | break; | ||
458 | case AF_INET6: | ||
459 | rcu_assign_pointer(netlbl_domhsh_def_ipv6, | ||
460 | entry); | ||
461 | break; | ||
462 | case AF_UNSPEC: | ||
463 | if (entry->def.type != | ||
464 | NETLBL_NLTYPE_UNLABELED) { | ||
465 | ret_val = -EINVAL; | ||
466 | goto add_return; | ||
467 | } | ||
468 | entry_b = kzalloc(sizeof(*entry_b), GFP_ATOMIC); | ||
469 | if (entry_b == NULL) { | ||
470 | ret_val = -ENOMEM; | ||
471 | goto add_return; | ||
472 | } | ||
473 | entry_b->family = AF_INET6; | ||
474 | entry_b->def.type = NETLBL_NLTYPE_UNLABELED; | ||
475 | entry_b->valid = 1; | ||
476 | entry->family = AF_INET; | ||
477 | rcu_assign_pointer(netlbl_domhsh_def_ipv4, | ||
478 | entry); | ||
479 | rcu_assign_pointer(netlbl_domhsh_def_ipv6, | ||
480 | entry_b); | ||
481 | break; | ||
482 | default: | ||
483 | /* Already checked in | ||
484 | * netlbl_domhsh_validate(). */ | ||
485 | ret_val = -EINVAL; | ||
486 | goto add_return; | ||
487 | } | ||
401 | } | 488 | } |
402 | 489 | ||
403 | if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) { | 490 | if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) { |
@@ -513,10 +600,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, | |||
513 | spin_lock(&netlbl_domhsh_lock); | 600 | spin_lock(&netlbl_domhsh_lock); |
514 | if (entry->valid) { | 601 | if (entry->valid) { |
515 | entry->valid = 0; | 602 | entry->valid = 0; |
516 | if (entry != rcu_dereference(netlbl_domhsh_def)) | 603 | if (entry == rcu_dereference(netlbl_domhsh_def_ipv4)) |
517 | list_del_rcu(&entry->list); | 604 | RCU_INIT_POINTER(netlbl_domhsh_def_ipv4, NULL); |
605 | else if (entry == rcu_dereference(netlbl_domhsh_def_ipv6)) | ||
606 | RCU_INIT_POINTER(netlbl_domhsh_def_ipv6, NULL); | ||
518 | else | 607 | else |
519 | RCU_INIT_POINTER(netlbl_domhsh_def, NULL); | 608 | list_del_rcu(&entry->list); |
520 | } else | 609 | } else |
521 | ret_val = -ENOENT; | 610 | ret_val = -ENOENT; |
522 | spin_unlock(&netlbl_domhsh_lock); | 611 | spin_unlock(&netlbl_domhsh_lock); |
@@ -533,6 +622,10 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, | |||
533 | if (ret_val == 0) { | 622 | if (ret_val == 0) { |
534 | struct netlbl_af4list *iter4; | 623 | struct netlbl_af4list *iter4; |
535 | struct netlbl_domaddr4_map *map4; | 624 | struct netlbl_domaddr4_map *map4; |
625 | #if IS_ENABLED(CONFIG_IPV6) | ||
626 | struct netlbl_af6list *iter6; | ||
627 | struct netlbl_domaddr6_map *map6; | ||
628 | #endif /* IPv6 */ | ||
536 | 629 | ||
537 | switch (entry->def.type) { | 630 | switch (entry->def.type) { |
538 | case NETLBL_NLTYPE_ADDRSELECT: | 631 | case NETLBL_NLTYPE_ADDRSELECT: |
@@ -541,12 +634,22 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, | |||
541 | map4 = netlbl_domhsh_addr4_entry(iter4); | 634 | map4 = netlbl_domhsh_addr4_entry(iter4); |
542 | cipso_v4_doi_putdef(map4->def.cipso); | 635 | cipso_v4_doi_putdef(map4->def.cipso); |
543 | } | 636 | } |
544 | /* no need to check the IPv6 list since we currently | 637 | #if IS_ENABLED(CONFIG_IPV6) |
545 | * support only unlabeled protocols for IPv6 */ | 638 | netlbl_af6list_foreach_rcu(iter6, |
639 | &entry->def.addrsel->list6) { | ||
640 | map6 = netlbl_domhsh_addr6_entry(iter6); | ||
641 | calipso_doi_putdef(map6->def.calipso); | ||
642 | } | ||
643 | #endif /* IPv6 */ | ||
546 | break; | 644 | break; |
547 | case NETLBL_NLTYPE_CIPSOV4: | 645 | case NETLBL_NLTYPE_CIPSOV4: |
548 | cipso_v4_doi_putdef(entry->def.cipso); | 646 | cipso_v4_doi_putdef(entry->def.cipso); |
549 | break; | 647 | break; |
648 | #if IS_ENABLED(CONFIG_IPV6) | ||
649 | case NETLBL_NLTYPE_CALIPSO: | ||
650 | calipso_doi_putdef(entry->def.calipso); | ||
651 | break; | ||
652 | #endif /* IPv6 */ | ||
550 | } | 653 | } |
551 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); | 654 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); |
552 | } | 655 | } |
@@ -583,9 +686,9 @@ int netlbl_domhsh_remove_af4(const char *domain, | |||
583 | rcu_read_lock(); | 686 | rcu_read_lock(); |
584 | 687 | ||
585 | if (domain) | 688 | if (domain) |
586 | entry_map = netlbl_domhsh_search(domain); | 689 | entry_map = netlbl_domhsh_search(domain, AF_INET); |
587 | else | 690 | else |
588 | entry_map = netlbl_domhsh_search_def(domain); | 691 | entry_map = netlbl_domhsh_search_def(domain, AF_INET); |
589 | if (entry_map == NULL || | 692 | if (entry_map == NULL || |
590 | entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT) | 693 | entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT) |
591 | goto remove_af4_failure; | 694 | goto remove_af4_failure; |
@@ -622,28 +725,114 @@ remove_af4_failure: | |||
622 | return -ENOENT; | 725 | return -ENOENT; |
623 | } | 726 | } |
624 | 727 | ||
728 | #if IS_ENABLED(CONFIG_IPV6) | ||
729 | /** | ||
730 | * netlbl_domhsh_remove_af6 - Removes an address selector entry | ||
731 | * @domain: the domain | ||
732 | * @addr: IPv6 address | ||
733 | * @mask: IPv6 address mask | ||
734 | * @audit_info: NetLabel audit information | ||
735 | * | ||
736 | * Description: | ||
737 | * Removes an individual address selector from a domain mapping and potentially | ||
738 | * the entire mapping if it is empty. Returns zero on success, negative values | ||
739 | * on failure. | ||
740 | * | ||
741 | */ | ||
742 | int netlbl_domhsh_remove_af6(const char *domain, | ||
743 | const struct in6_addr *addr, | ||
744 | const struct in6_addr *mask, | ||
745 | struct netlbl_audit *audit_info) | ||
746 | { | ||
747 | struct netlbl_dom_map *entry_map; | ||
748 | struct netlbl_af6list *entry_addr; | ||
749 | struct netlbl_af4list *iter4; | ||
750 | struct netlbl_af6list *iter6; | ||
751 | struct netlbl_domaddr6_map *entry; | ||
752 | |||
753 | rcu_read_lock(); | ||
754 | |||
755 | if (domain) | ||
756 | entry_map = netlbl_domhsh_search(domain, AF_INET6); | ||
757 | else | ||
758 | entry_map = netlbl_domhsh_search_def(domain, AF_INET6); | ||
759 | if (entry_map == NULL || | ||
760 | entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT) | ||
761 | goto remove_af6_failure; | ||
762 | |||
763 | spin_lock(&netlbl_domhsh_lock); | ||
764 | entry_addr = netlbl_af6list_remove(addr, mask, | ||
765 | &entry_map->def.addrsel->list6); | ||
766 | spin_unlock(&netlbl_domhsh_lock); | ||
767 | |||
768 | if (entry_addr == NULL) | ||
769 | goto remove_af6_failure; | ||
770 | netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4) | ||
771 | goto remove_af6_single_addr; | ||
772 | netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6) | ||
773 | goto remove_af6_single_addr; | ||
774 | /* the domain mapping is empty so remove it from the mapping table */ | ||
775 | netlbl_domhsh_remove_entry(entry_map, audit_info); | ||
776 | |||
777 | remove_af6_single_addr: | ||
778 | rcu_read_unlock(); | ||
779 | /* yick, we can't use call_rcu here because we don't have a rcu head | ||
780 | * pointer but hopefully this should be a rare case so the pause | ||
781 | * shouldn't be a problem */ | ||
782 | synchronize_rcu(); | ||
783 | entry = netlbl_domhsh_addr6_entry(entry_addr); | ||
784 | calipso_doi_putdef(entry->def.calipso); | ||
785 | kfree(entry); | ||
786 | return 0; | ||
787 | |||
788 | remove_af6_failure: | ||
789 | rcu_read_unlock(); | ||
790 | return -ENOENT; | ||
791 | } | ||
792 | #endif /* IPv6 */ | ||
793 | |||
625 | /** | 794 | /** |
626 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | 795 | * netlbl_domhsh_remove - Removes an entry from the domain hash table |
627 | * @domain: the domain to remove | 796 | * @domain: the domain to remove |
797 | * @family: address family | ||
628 | * @audit_info: NetLabel audit information | 798 | * @audit_info: NetLabel audit information |
629 | * | 799 | * |
630 | * Description: | 800 | * Description: |
631 | * Removes an entry from the domain hash table and handles any updates to the | 801 | * Removes an entry from the domain hash table and handles any updates to the |
632 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | 802 | * lower level protocol handler (i.e. CIPSO). @family may be %AF_UNSPEC which |
633 | * negative on failure. | 803 | * removes all address family entries. Returns zero on success, negative on |
804 | * failure. | ||
634 | * | 805 | * |
635 | */ | 806 | */ |
636 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | 807 | int netlbl_domhsh_remove(const char *domain, u16 family, |
808 | struct netlbl_audit *audit_info) | ||
637 | { | 809 | { |
638 | int ret_val; | 810 | int ret_val = -EINVAL; |
639 | struct netlbl_dom_map *entry; | 811 | struct netlbl_dom_map *entry; |
640 | 812 | ||
641 | rcu_read_lock(); | 813 | rcu_read_lock(); |
642 | if (domain) | 814 | |
643 | entry = netlbl_domhsh_search(domain); | 815 | if (family == AF_INET || family == AF_UNSPEC) { |
644 | else | 816 | if (domain) |
645 | entry = netlbl_domhsh_search_def(domain); | 817 | entry = netlbl_domhsh_search(domain, AF_INET); |
646 | ret_val = netlbl_domhsh_remove_entry(entry, audit_info); | 818 | else |
819 | entry = netlbl_domhsh_search_def(domain, AF_INET); | ||
820 | ret_val = netlbl_domhsh_remove_entry(entry, audit_info); | ||
821 | if (ret_val && ret_val != -ENOENT) | ||
822 | goto done; | ||
823 | } | ||
824 | if (family == AF_INET6 || family == AF_UNSPEC) { | ||
825 | int ret_val2; | ||
826 | |||
827 | if (domain) | ||
828 | entry = netlbl_domhsh_search(domain, AF_INET6); | ||
829 | else | ||
830 | entry = netlbl_domhsh_search_def(domain, AF_INET6); | ||
831 | ret_val2 = netlbl_domhsh_remove_entry(entry, audit_info); | ||
832 | if (ret_val2 != -ENOENT) | ||
833 | ret_val = ret_val2; | ||
834 | } | ||
835 | done: | ||
647 | rcu_read_unlock(); | 836 | rcu_read_unlock(); |
648 | 837 | ||
649 | return ret_val; | 838 | return ret_val; |
@@ -651,32 +840,38 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | |||
651 | 840 | ||
652 | /** | 841 | /** |
653 | * netlbl_domhsh_remove_default - Removes the default entry from the table | 842 | * netlbl_domhsh_remove_default - Removes the default entry from the table |
843 | * @family: address family | ||
654 | * @audit_info: NetLabel audit information | 844 | * @audit_info: NetLabel audit information |
655 | * | 845 | * |
656 | * Description: | 846 | * Description: |
657 | * Removes/resets the default entry for the domain hash table and handles any | 847 | * Removes/resets the default entry corresponding to @family from the domain |
658 | * updates to the lower level protocol handler (i.e. CIPSO). Returns zero on | 848 | * hash table and handles any updates to the lower level protocol handler |
659 | * success, non-zero on failure. | 849 | * (i.e. CIPSO). @family may be %AF_UNSPEC which removes all address family |
850 | * entries. Returns zero on success, negative on failure. | ||
660 | * | 851 | * |
661 | */ | 852 | */ |
662 | int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info) | 853 | int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info) |
663 | { | 854 | { |
664 | return netlbl_domhsh_remove(NULL, audit_info); | 855 | return netlbl_domhsh_remove(NULL, family, audit_info); |
665 | } | 856 | } |
666 | 857 | ||
667 | /** | 858 | /** |
668 | * netlbl_domhsh_getentry - Get an entry from the domain hash table | 859 | * netlbl_domhsh_getentry - Get an entry from the domain hash table |
669 | * @domain: the domain name to search for | 860 | * @domain: the domain name to search for |
861 | * @family: address family | ||
670 | * | 862 | * |
671 | * Description: | 863 | * Description: |
672 | * Look through the domain hash table searching for an entry to match @domain, | 864 | * Look through the domain hash table searching for an entry to match @domain, |
673 | * return a pointer to a copy of the entry or NULL. The caller is responsible | 865 | * with address family @family, return a pointer to a copy of the entry or |
674 | * for ensuring that rcu_read_[un]lock() is called. | 866 | * NULL. The caller is responsible for ensuring that rcu_read_[un]lock() is |
867 | * called. | ||
675 | * | 868 | * |
676 | */ | 869 | */ |
677 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) | 870 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family) |
678 | { | 871 | { |
679 | return netlbl_domhsh_search_def(domain); | 872 | if (family == AF_UNSPEC) |
873 | return NULL; | ||
874 | return netlbl_domhsh_search_def(domain, family); | ||
680 | } | 875 | } |
681 | 876 | ||
682 | /** | 877 | /** |
@@ -696,7 +891,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain, | |||
696 | struct netlbl_dom_map *dom_iter; | 891 | struct netlbl_dom_map *dom_iter; |
697 | struct netlbl_af4list *addr_iter; | 892 | struct netlbl_af4list *addr_iter; |
698 | 893 | ||
699 | dom_iter = netlbl_domhsh_search_def(domain); | 894 | dom_iter = netlbl_domhsh_search_def(domain, AF_INET); |
700 | if (dom_iter == NULL) | 895 | if (dom_iter == NULL) |
701 | return NULL; | 896 | return NULL; |
702 | 897 | ||
@@ -726,7 +921,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, | |||
726 | struct netlbl_dom_map *dom_iter; | 921 | struct netlbl_dom_map *dom_iter; |
727 | struct netlbl_af6list *addr_iter; | 922 | struct netlbl_af6list *addr_iter; |
728 | 923 | ||
729 | dom_iter = netlbl_domhsh_search_def(domain); | 924 | dom_iter = netlbl_domhsh_search_def(domain, AF_INET6); |
730 | if (dom_iter == NULL) | 925 | if (dom_iter == NULL) |
731 | return NULL; | 926 | return NULL; |
732 | 927 | ||
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index 680caf4dff56..1f9247781927 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h | |||
@@ -51,6 +51,7 @@ struct netlbl_dommap_def { | |||
51 | union { | 51 | union { |
52 | struct netlbl_domaddr_map *addrsel; | 52 | struct netlbl_domaddr_map *addrsel; |
53 | struct cipso_v4_doi *cipso; | 53 | struct cipso_v4_doi *cipso; |
54 | struct calipso_doi *calipso; | ||
54 | }; | 55 | }; |
55 | }; | 56 | }; |
56 | #define netlbl_domhsh_addr4_entry(iter) \ | 57 | #define netlbl_domhsh_addr4_entry(iter) \ |
@@ -70,6 +71,7 @@ struct netlbl_domaddr6_map { | |||
70 | 71 | ||
71 | struct netlbl_dom_map { | 72 | struct netlbl_dom_map { |
72 | char *domain; | 73 | char *domain; |
74 | u16 family; | ||
73 | struct netlbl_dommap_def def; | 75 | struct netlbl_dommap_def def; |
74 | 76 | ||
75 | u32 valid; | 77 | u32 valid; |
@@ -91,14 +93,23 @@ int netlbl_domhsh_remove_af4(const char *domain, | |||
91 | const struct in_addr *addr, | 93 | const struct in_addr *addr, |
92 | const struct in_addr *mask, | 94 | const struct in_addr *mask, |
93 | struct netlbl_audit *audit_info); | 95 | struct netlbl_audit *audit_info); |
94 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); | 96 | int netlbl_domhsh_remove_af6(const char *domain, |
95 | int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); | 97 | const struct in6_addr *addr, |
96 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); | 98 | const struct in6_addr *mask, |
99 | struct netlbl_audit *audit_info); | ||
100 | int netlbl_domhsh_remove(const char *domain, u16 family, | ||
101 | struct netlbl_audit *audit_info); | ||
102 | int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info); | ||
103 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family); | ||
97 | struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain, | 104 | struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain, |
98 | __be32 addr); | 105 | __be32 addr); |
99 | #if IS_ENABLED(CONFIG_IPV6) | 106 | #if IS_ENABLED(CONFIG_IPV6) |
100 | struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, | 107 | struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, |
101 | const struct in6_addr *addr); | 108 | const struct in6_addr *addr); |
109 | int netlbl_domhsh_remove_af6(const char *domain, | ||
110 | const struct in6_addr *addr, | ||
111 | const struct in6_addr *mask, | ||
112 | struct netlbl_audit *audit_info); | ||
102 | #endif /* IPv6 */ | 113 | #endif /* IPv6 */ |
103 | 114 | ||
104 | int netlbl_domhsh_walk(u32 *skip_bkt, | 115 | int netlbl_domhsh_walk(u32 *skip_bkt, |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 1325776daa27..28c56b95fb7f 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -37,12 +37,14 @@ | |||
37 | #include <net/ipv6.h> | 37 | #include <net/ipv6.h> |
38 | #include <net/netlabel.h> | 38 | #include <net/netlabel.h> |
39 | #include <net/cipso_ipv4.h> | 39 | #include <net/cipso_ipv4.h> |
40 | #include <net/calipso.h> | ||
40 | #include <asm/bug.h> | 41 | #include <asm/bug.h> |
41 | #include <linux/atomic.h> | 42 | #include <linux/atomic.h> |
42 | 43 | ||
43 | #include "netlabel_domainhash.h" | 44 | #include "netlabel_domainhash.h" |
44 | #include "netlabel_unlabeled.h" | 45 | #include "netlabel_unlabeled.h" |
45 | #include "netlabel_cipso_v4.h" | 46 | #include "netlabel_cipso_v4.h" |
47 | #include "netlabel_calipso.h" | ||
46 | #include "netlabel_user.h" | 48 | #include "netlabel_user.h" |
47 | #include "netlabel_mgmt.h" | 49 | #include "netlabel_mgmt.h" |
48 | #include "netlabel_addrlist.h" | 50 | #include "netlabel_addrlist.h" |
@@ -72,12 +74,17 @@ int netlbl_cfg_map_del(const char *domain, | |||
72 | struct netlbl_audit *audit_info) | 74 | struct netlbl_audit *audit_info) |
73 | { | 75 | { |
74 | if (addr == NULL && mask == NULL) { | 76 | if (addr == NULL && mask == NULL) { |
75 | return netlbl_domhsh_remove(domain, audit_info); | 77 | return netlbl_domhsh_remove(domain, family, audit_info); |
76 | } else if (addr != NULL && mask != NULL) { | 78 | } else if (addr != NULL && mask != NULL) { |
77 | switch (family) { | 79 | switch (family) { |
78 | case AF_INET: | 80 | case AF_INET: |
79 | return netlbl_domhsh_remove_af4(domain, addr, mask, | 81 | return netlbl_domhsh_remove_af4(domain, addr, mask, |
80 | audit_info); | 82 | audit_info); |
83 | #if IS_ENABLED(CONFIG_IPV6) | ||
84 | case AF_INET6: | ||
85 | return netlbl_domhsh_remove_af6(domain, addr, mask, | ||
86 | audit_info); | ||
87 | #endif /* IPv6 */ | ||
81 | default: | 88 | default: |
82 | return -EPFNOSUPPORT; | 89 | return -EPFNOSUPPORT; |
83 | } | 90 | } |
@@ -119,6 +126,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain, | |||
119 | if (entry->domain == NULL) | 126 | if (entry->domain == NULL) |
120 | goto cfg_unlbl_map_add_failure; | 127 | goto cfg_unlbl_map_add_failure; |
121 | } | 128 | } |
129 | entry->family = family; | ||
122 | 130 | ||
123 | if (addr == NULL && mask == NULL) | 131 | if (addr == NULL && mask == NULL) |
124 | entry->def.type = NETLBL_NLTYPE_UNLABELED; | 132 | entry->def.type = NETLBL_NLTYPE_UNLABELED; |
@@ -345,6 +353,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, | |||
345 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 353 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
346 | if (entry == NULL) | 354 | if (entry == NULL) |
347 | goto out_entry; | 355 | goto out_entry; |
356 | entry->family = AF_INET; | ||
348 | if (domain != NULL) { | 357 | if (domain != NULL) { |
349 | entry->domain = kstrdup(domain, GFP_ATOMIC); | 358 | entry->domain = kstrdup(domain, GFP_ATOMIC); |
350 | if (entry->domain == NULL) | 359 | if (entry->domain == NULL) |
@@ -399,6 +408,139 @@ out_entry: | |||
399 | return ret_val; | 408 | return ret_val; |
400 | } | 409 | } |
401 | 410 | ||
411 | /** | ||
412 | * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition | ||
413 | * @doi_def: CALIPSO DOI definition | ||
414 | * @audit_info: NetLabel audit information | ||
415 | * | ||
416 | * Description: | ||
417 | * Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on | ||
418 | * success and negative values on failure. | ||
419 | * | ||
420 | */ | ||
421 | int netlbl_cfg_calipso_add(struct calipso_doi *doi_def, | ||
422 | struct netlbl_audit *audit_info) | ||
423 | { | ||
424 | #if IS_ENABLED(CONFIG_IPV6) | ||
425 | return calipso_doi_add(doi_def, audit_info); | ||
426 | #else /* IPv6 */ | ||
427 | return -ENOSYS; | ||
428 | #endif /* IPv6 */ | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition | ||
433 | * @doi: CALIPSO DOI | ||
434 | * @audit_info: NetLabel audit information | ||
435 | * | ||
436 | * Description: | ||
437 | * Remove an existing CALIPSO DOI definition matching @doi. Returns zero on | ||
438 | * success and negative values on failure. | ||
439 | * | ||
440 | */ | ||
441 | void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info) | ||
442 | { | ||
443 | #if IS_ENABLED(CONFIG_IPV6) | ||
444 | calipso_doi_remove(doi, audit_info); | ||
445 | #endif /* IPv6 */ | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping | ||
450 | * @doi: the CALIPSO DOI | ||
451 | * @domain: the domain mapping to add | ||
452 | * @addr: IP address | ||
453 | * @mask: IP address mask | ||
454 | * @audit_info: NetLabel audit information | ||
455 | * | ||
456 | * Description: | ||
457 | * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the | ||
458 | * NetLabel subsystem. A @domain value of NULL adds a new default domain | ||
459 | * mapping. Returns zero on success, negative values on failure. | ||
460 | * | ||
461 | */ | ||
462 | int netlbl_cfg_calipso_map_add(u32 doi, | ||
463 | const char *domain, | ||
464 | const struct in6_addr *addr, | ||
465 | const struct in6_addr *mask, | ||
466 | struct netlbl_audit *audit_info) | ||
467 | { | ||
468 | #if IS_ENABLED(CONFIG_IPV6) | ||
469 | int ret_val = -ENOMEM; | ||
470 | struct calipso_doi *doi_def; | ||
471 | struct netlbl_dom_map *entry; | ||
472 | struct netlbl_domaddr_map *addrmap = NULL; | ||
473 | struct netlbl_domaddr6_map *addrinfo = NULL; | ||
474 | |||
475 | doi_def = calipso_doi_getdef(doi); | ||
476 | if (doi_def == NULL) | ||
477 | return -ENOENT; | ||
478 | |||
479 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
480 | if (entry == NULL) | ||
481 | goto out_entry; | ||
482 | entry->family = AF_INET6; | ||
483 | if (domain != NULL) { | ||
484 | entry->domain = kstrdup(domain, GFP_ATOMIC); | ||
485 | if (entry->domain == NULL) | ||
486 | goto out_domain; | ||
487 | } | ||
488 | |||
489 | if (addr == NULL && mask == NULL) { | ||
490 | entry->def.calipso = doi_def; | ||
491 | entry->def.type = NETLBL_NLTYPE_CALIPSO; | ||
492 | } else if (addr != NULL && mask != NULL) { | ||
493 | addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); | ||
494 | if (addrmap == NULL) | ||
495 | goto out_addrmap; | ||
496 | INIT_LIST_HEAD(&addrmap->list4); | ||
497 | INIT_LIST_HEAD(&addrmap->list6); | ||
498 | |||
499 | addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC); | ||
500 | if (addrinfo == NULL) | ||
501 | goto out_addrinfo; | ||
502 | addrinfo->def.calipso = doi_def; | ||
503 | addrinfo->def.type = NETLBL_NLTYPE_CALIPSO; | ||
504 | addrinfo->list.addr = *addr; | ||
505 | addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; | ||
506 | addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; | ||
507 | addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; | ||
508 | addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; | ||
509 | addrinfo->list.mask = *mask; | ||
510 | addrinfo->list.valid = 1; | ||
511 | ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6); | ||
512 | if (ret_val != 0) | ||
513 | goto cfg_calipso_map_add_failure; | ||
514 | |||
515 | entry->def.addrsel = addrmap; | ||
516 | entry->def.type = NETLBL_NLTYPE_ADDRSELECT; | ||
517 | } else { | ||
518 | ret_val = -EINVAL; | ||
519 | goto out_addrmap; | ||
520 | } | ||
521 | |||
522 | ret_val = netlbl_domhsh_add(entry, audit_info); | ||
523 | if (ret_val != 0) | ||
524 | goto cfg_calipso_map_add_failure; | ||
525 | |||
526 | return 0; | ||
527 | |||
528 | cfg_calipso_map_add_failure: | ||
529 | kfree(addrinfo); | ||
530 | out_addrinfo: | ||
531 | kfree(addrmap); | ||
532 | out_addrmap: | ||
533 | kfree(entry->domain); | ||
534 | out_domain: | ||
535 | kfree(entry); | ||
536 | out_entry: | ||
537 | calipso_doi_putdef(doi_def); | ||
538 | return ret_val; | ||
539 | #else /* IPv6 */ | ||
540 | return -ENOSYS; | ||
541 | #endif /* IPv6 */ | ||
542 | } | ||
543 | |||
402 | /* | 544 | /* |
403 | * Security Attribute Functions | 545 | * Security Attribute Functions |
404 | */ | 546 | */ |
@@ -519,6 +661,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset) | |||
519 | 661 | ||
520 | return -ENOENT; | 662 | return -ENOENT; |
521 | } | 663 | } |
664 | EXPORT_SYMBOL(netlbl_catmap_walk); | ||
522 | 665 | ||
523 | /** | 666 | /** |
524 | * netlbl_catmap_walkrng - Find the end of a string of set bits | 667 | * netlbl_catmap_walkrng - Find the end of a string of set bits |
@@ -609,20 +752,19 @@ int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, | |||
609 | off = catmap->startbit; | 752 | off = catmap->startbit; |
610 | *offset = off; | 753 | *offset = off; |
611 | } | 754 | } |
612 | iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0); | 755 | iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0); |
613 | if (iter == NULL) { | 756 | if (iter == NULL) { |
614 | *offset = (u32)-1; | 757 | *offset = (u32)-1; |
615 | return 0; | 758 | return 0; |
616 | } | 759 | } |
617 | 760 | ||
618 | if (off < iter->startbit) { | 761 | if (off < iter->startbit) { |
619 | off = iter->startbit; | 762 | *offset = iter->startbit; |
620 | *offset = off; | 763 | off = 0; |
621 | } else | 764 | } else |
622 | off -= iter->startbit; | 765 | off -= iter->startbit; |
623 | |||
624 | idx = off / NETLBL_CATMAP_MAPSIZE; | 766 | idx = off / NETLBL_CATMAP_MAPSIZE; |
625 | *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE); | 767 | *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE); |
626 | 768 | ||
627 | return 0; | 769 | return 0; |
628 | } | 770 | } |
@@ -655,6 +797,7 @@ int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, | |||
655 | 797 | ||
656 | return 0; | 798 | return 0; |
657 | } | 799 | } |
800 | EXPORT_SYMBOL(netlbl_catmap_setbit); | ||
658 | 801 | ||
659 | /** | 802 | /** |
660 | * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap | 803 | * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap |
@@ -727,6 +870,76 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, | |||
727 | return 0; | 870 | return 0; |
728 | } | 871 | } |
729 | 872 | ||
873 | /* Bitmap functions | ||
874 | */ | ||
875 | |||
876 | /** | ||
877 | * netlbl_bitmap_walk - Walk a bitmap looking for a bit | ||
878 | * @bitmap: the bitmap | ||
879 | * @bitmap_len: length in bits | ||
880 | * @offset: starting offset | ||
881 | * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit | ||
882 | * | ||
883 | * Description: | ||
884 | * Starting at @offset, walk the bitmap from left to right until either the | ||
885 | * desired bit is found or we reach the end. Return the bit offset, -1 if | ||
886 | * not found, or -2 if error. | ||
887 | */ | ||
888 | int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len, | ||
889 | u32 offset, u8 state) | ||
890 | { | ||
891 | u32 bit_spot; | ||
892 | u32 byte_offset; | ||
893 | unsigned char bitmask; | ||
894 | unsigned char byte; | ||
895 | |||
896 | byte_offset = offset / 8; | ||
897 | byte = bitmap[byte_offset]; | ||
898 | bit_spot = offset; | ||
899 | bitmask = 0x80 >> (offset % 8); | ||
900 | |||
901 | while (bit_spot < bitmap_len) { | ||
902 | if ((state && (byte & bitmask) == bitmask) || | ||
903 | (state == 0 && (byte & bitmask) == 0)) | ||
904 | return bit_spot; | ||
905 | |||
906 | bit_spot++; | ||
907 | bitmask >>= 1; | ||
908 | if (bitmask == 0) { | ||
909 | byte = bitmap[++byte_offset]; | ||
910 | bitmask = 0x80; | ||
911 | } | ||
912 | } | ||
913 | |||
914 | return -1; | ||
915 | } | ||
916 | EXPORT_SYMBOL(netlbl_bitmap_walk); | ||
917 | |||
918 | /** | ||
919 | * netlbl_bitmap_setbit - Sets a single bit in a bitmap | ||
920 | * @bitmap: the bitmap | ||
921 | * @bit: the bit | ||
922 | * @state: if non-zero, set the bit (1) else clear the bit (0) | ||
923 | * | ||
924 | * Description: | ||
925 | * Set a single bit in the bitmask. Returns zero on success, negative values | ||
926 | * on error. | ||
927 | */ | ||
928 | void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state) | ||
929 | { | ||
930 | u32 byte_spot; | ||
931 | u8 bitmask; | ||
932 | |||
933 | /* gcc always rounds to zero when doing integer division */ | ||
934 | byte_spot = bit / 8; | ||
935 | bitmask = 0x80 >> (bit % 8); | ||
936 | if (state) | ||
937 | bitmap[byte_spot] |= bitmask; | ||
938 | else | ||
939 | bitmap[byte_spot] &= ~bitmask; | ||
940 | } | ||
941 | EXPORT_SYMBOL(netlbl_bitmap_setbit); | ||
942 | |||
730 | /* | 943 | /* |
731 | * LSM Functions | 944 | * LSM Functions |
732 | */ | 945 | */ |
@@ -774,7 +987,7 @@ int netlbl_sock_setattr(struct sock *sk, | |||
774 | struct netlbl_dom_map *dom_entry; | 987 | struct netlbl_dom_map *dom_entry; |
775 | 988 | ||
776 | rcu_read_lock(); | 989 | rcu_read_lock(); |
777 | dom_entry = netlbl_domhsh_getentry(secattr->domain); | 990 | dom_entry = netlbl_domhsh_getentry(secattr->domain, family); |
778 | if (dom_entry == NULL) { | 991 | if (dom_entry == NULL) { |
779 | ret_val = -ENOENT; | 992 | ret_val = -ENOENT; |
780 | goto socket_setattr_return; | 993 | goto socket_setattr_return; |
@@ -799,9 +1012,21 @@ int netlbl_sock_setattr(struct sock *sk, | |||
799 | break; | 1012 | break; |
800 | #if IS_ENABLED(CONFIG_IPV6) | 1013 | #if IS_ENABLED(CONFIG_IPV6) |
801 | case AF_INET6: | 1014 | case AF_INET6: |
802 | /* since we don't support any IPv6 labeling protocols right | 1015 | switch (dom_entry->def.type) { |
803 | * now we can optimize everything away until we do */ | 1016 | case NETLBL_NLTYPE_ADDRSELECT: |
804 | ret_val = 0; | 1017 | ret_val = -EDESTADDRREQ; |
1018 | break; | ||
1019 | case NETLBL_NLTYPE_CALIPSO: | ||
1020 | ret_val = calipso_sock_setattr(sk, | ||
1021 | dom_entry->def.calipso, | ||
1022 | secattr); | ||
1023 | break; | ||
1024 | case NETLBL_NLTYPE_UNLABELED: | ||
1025 | ret_val = 0; | ||
1026 | break; | ||
1027 | default: | ||
1028 | ret_val = -ENOENT; | ||
1029 | } | ||
805 | break; | 1030 | break; |
806 | #endif /* IPv6 */ | 1031 | #endif /* IPv6 */ |
807 | default: | 1032 | default: |
@@ -824,7 +1049,16 @@ socket_setattr_return: | |||
824 | */ | 1049 | */ |
825 | void netlbl_sock_delattr(struct sock *sk) | 1050 | void netlbl_sock_delattr(struct sock *sk) |
826 | { | 1051 | { |
827 | cipso_v4_sock_delattr(sk); | 1052 | switch (sk->sk_family) { |
1053 | case AF_INET: | ||
1054 | cipso_v4_sock_delattr(sk); | ||
1055 | break; | ||
1056 | #if IS_ENABLED(CONFIG_IPV6) | ||
1057 | case AF_INET6: | ||
1058 | calipso_sock_delattr(sk); | ||
1059 | break; | ||
1060 | #endif /* IPv6 */ | ||
1061 | } | ||
828 | } | 1062 | } |
829 | 1063 | ||
830 | /** | 1064 | /** |
@@ -850,7 +1084,7 @@ int netlbl_sock_getattr(struct sock *sk, | |||
850 | break; | 1084 | break; |
851 | #if IS_ENABLED(CONFIG_IPV6) | 1085 | #if IS_ENABLED(CONFIG_IPV6) |
852 | case AF_INET6: | 1086 | case AF_INET6: |
853 | ret_val = -ENOMSG; | 1087 | ret_val = calipso_sock_getattr(sk, secattr); |
854 | break; | 1088 | break; |
855 | #endif /* IPv6 */ | 1089 | #endif /* IPv6 */ |
856 | default: | 1090 | default: |
@@ -878,6 +1112,9 @@ int netlbl_conn_setattr(struct sock *sk, | |||
878 | { | 1112 | { |
879 | int ret_val; | 1113 | int ret_val; |
880 | struct sockaddr_in *addr4; | 1114 | struct sockaddr_in *addr4; |
1115 | #if IS_ENABLED(CONFIG_IPV6) | ||
1116 | struct sockaddr_in6 *addr6; | ||
1117 | #endif | ||
881 | struct netlbl_dommap_def *entry; | 1118 | struct netlbl_dommap_def *entry; |
882 | 1119 | ||
883 | rcu_read_lock(); | 1120 | rcu_read_lock(); |
@@ -898,7 +1135,7 @@ int netlbl_conn_setattr(struct sock *sk, | |||
898 | case NETLBL_NLTYPE_UNLABELED: | 1135 | case NETLBL_NLTYPE_UNLABELED: |
899 | /* just delete the protocols we support for right now | 1136 | /* just delete the protocols we support for right now |
900 | * but we could remove other protocols if needed */ | 1137 | * but we could remove other protocols if needed */ |
901 | cipso_v4_sock_delattr(sk); | 1138 | netlbl_sock_delattr(sk); |
902 | ret_val = 0; | 1139 | ret_val = 0; |
903 | break; | 1140 | break; |
904 | default: | 1141 | default: |
@@ -907,9 +1144,27 @@ int netlbl_conn_setattr(struct sock *sk, | |||
907 | break; | 1144 | break; |
908 | #if IS_ENABLED(CONFIG_IPV6) | 1145 | #if IS_ENABLED(CONFIG_IPV6) |
909 | case AF_INET6: | 1146 | case AF_INET6: |
910 | /* since we don't support any IPv6 labeling protocols right | 1147 | addr6 = (struct sockaddr_in6 *)addr; |
911 | * now we can optimize everything away until we do */ | 1148 | entry = netlbl_domhsh_getentry_af6(secattr->domain, |
912 | ret_val = 0; | 1149 | &addr6->sin6_addr); |
1150 | if (entry == NULL) { | ||
1151 | ret_val = -ENOENT; | ||
1152 | goto conn_setattr_return; | ||
1153 | } | ||
1154 | switch (entry->type) { | ||
1155 | case NETLBL_NLTYPE_CALIPSO: | ||
1156 | ret_val = calipso_sock_setattr(sk, | ||
1157 | entry->calipso, secattr); | ||
1158 | break; | ||
1159 | case NETLBL_NLTYPE_UNLABELED: | ||
1160 | /* just delete the protocols we support for right now | ||
1161 | * but we could remove other protocols if needed */ | ||
1162 | netlbl_sock_delattr(sk); | ||
1163 | ret_val = 0; | ||
1164 | break; | ||
1165 | default: | ||
1166 | ret_val = -ENOENT; | ||
1167 | } | ||
913 | break; | 1168 | break; |
914 | #endif /* IPv6 */ | 1169 | #endif /* IPv6 */ |
915 | default: | 1170 | default: |
@@ -936,12 +1191,13 @@ int netlbl_req_setattr(struct request_sock *req, | |||
936 | { | 1191 | { |
937 | int ret_val; | 1192 | int ret_val; |
938 | struct netlbl_dommap_def *entry; | 1193 | struct netlbl_dommap_def *entry; |
1194 | struct inet_request_sock *ireq = inet_rsk(req); | ||
939 | 1195 | ||
940 | rcu_read_lock(); | 1196 | rcu_read_lock(); |
941 | switch (req->rsk_ops->family) { | 1197 | switch (req->rsk_ops->family) { |
942 | case AF_INET: | 1198 | case AF_INET: |
943 | entry = netlbl_domhsh_getentry_af4(secattr->domain, | 1199 | entry = netlbl_domhsh_getentry_af4(secattr->domain, |
944 | inet_rsk(req)->ir_rmt_addr); | 1200 | ireq->ir_rmt_addr); |
945 | if (entry == NULL) { | 1201 | if (entry == NULL) { |
946 | ret_val = -ENOENT; | 1202 | ret_val = -ENOENT; |
947 | goto req_setattr_return; | 1203 | goto req_setattr_return; |
@@ -952,9 +1208,7 @@ int netlbl_req_setattr(struct request_sock *req, | |||
952 | entry->cipso, secattr); | 1208 | entry->cipso, secattr); |
953 | break; | 1209 | break; |
954 | case NETLBL_NLTYPE_UNLABELED: | 1210 | case NETLBL_NLTYPE_UNLABELED: |
955 | /* just delete the protocols we support for right now | 1211 | netlbl_req_delattr(req); |
956 | * but we could remove other protocols if needed */ | ||
957 | cipso_v4_req_delattr(req); | ||
958 | ret_val = 0; | 1212 | ret_val = 0; |
959 | break; | 1213 | break; |
960 | default: | 1214 | default: |
@@ -963,9 +1217,24 @@ int netlbl_req_setattr(struct request_sock *req, | |||
963 | break; | 1217 | break; |
964 | #if IS_ENABLED(CONFIG_IPV6) | 1218 | #if IS_ENABLED(CONFIG_IPV6) |
965 | case AF_INET6: | 1219 | case AF_INET6: |
966 | /* since we don't support any IPv6 labeling protocols right | 1220 | entry = netlbl_domhsh_getentry_af6(secattr->domain, |
967 | * now we can optimize everything away until we do */ | 1221 | &ireq->ir_v6_rmt_addr); |
968 | ret_val = 0; | 1222 | if (entry == NULL) { |
1223 | ret_val = -ENOENT; | ||
1224 | goto req_setattr_return; | ||
1225 | } | ||
1226 | switch (entry->type) { | ||
1227 | case NETLBL_NLTYPE_CALIPSO: | ||
1228 | ret_val = calipso_req_setattr(req, | ||
1229 | entry->calipso, secattr); | ||
1230 | break; | ||
1231 | case NETLBL_NLTYPE_UNLABELED: | ||
1232 | netlbl_req_delattr(req); | ||
1233 | ret_val = 0; | ||
1234 | break; | ||
1235 | default: | ||
1236 | ret_val = -ENOENT; | ||
1237 | } | ||
969 | break; | 1238 | break; |
970 | #endif /* IPv6 */ | 1239 | #endif /* IPv6 */ |
971 | default: | 1240 | default: |
@@ -987,7 +1256,16 @@ req_setattr_return: | |||
987 | */ | 1256 | */ |
988 | void netlbl_req_delattr(struct request_sock *req) | 1257 | void netlbl_req_delattr(struct request_sock *req) |
989 | { | 1258 | { |
990 | cipso_v4_req_delattr(req); | 1259 | switch (req->rsk_ops->family) { |
1260 | case AF_INET: | ||
1261 | cipso_v4_req_delattr(req); | ||
1262 | break; | ||
1263 | #if IS_ENABLED(CONFIG_IPV6) | ||
1264 | case AF_INET6: | ||
1265 | calipso_req_delattr(req); | ||
1266 | break; | ||
1267 | #endif /* IPv6 */ | ||
1268 | } | ||
991 | } | 1269 | } |
992 | 1270 | ||
993 | /** | 1271 | /** |
@@ -1007,13 +1285,17 @@ int netlbl_skbuff_setattr(struct sk_buff *skb, | |||
1007 | { | 1285 | { |
1008 | int ret_val; | 1286 | int ret_val; |
1009 | struct iphdr *hdr4; | 1287 | struct iphdr *hdr4; |
1288 | #if IS_ENABLED(CONFIG_IPV6) | ||
1289 | struct ipv6hdr *hdr6; | ||
1290 | #endif | ||
1010 | struct netlbl_dommap_def *entry; | 1291 | struct netlbl_dommap_def *entry; |
1011 | 1292 | ||
1012 | rcu_read_lock(); | 1293 | rcu_read_lock(); |
1013 | switch (family) { | 1294 | switch (family) { |
1014 | case AF_INET: | 1295 | case AF_INET: |
1015 | hdr4 = ip_hdr(skb); | 1296 | hdr4 = ip_hdr(skb); |
1016 | entry = netlbl_domhsh_getentry_af4(secattr->domain,hdr4->daddr); | 1297 | entry = netlbl_domhsh_getentry_af4(secattr->domain, |
1298 | hdr4->daddr); | ||
1017 | if (entry == NULL) { | 1299 | if (entry == NULL) { |
1018 | ret_val = -ENOENT; | 1300 | ret_val = -ENOENT; |
1019 | goto skbuff_setattr_return; | 1301 | goto skbuff_setattr_return; |
@@ -1034,9 +1316,26 @@ int netlbl_skbuff_setattr(struct sk_buff *skb, | |||
1034 | break; | 1316 | break; |
1035 | #if IS_ENABLED(CONFIG_IPV6) | 1317 | #if IS_ENABLED(CONFIG_IPV6) |
1036 | case AF_INET6: | 1318 | case AF_INET6: |
1037 | /* since we don't support any IPv6 labeling protocols right | 1319 | hdr6 = ipv6_hdr(skb); |
1038 | * now we can optimize everything away until we do */ | 1320 | entry = netlbl_domhsh_getentry_af6(secattr->domain, |
1039 | ret_val = 0; | 1321 | &hdr6->daddr); |
1322 | if (entry == NULL) { | ||
1323 | ret_val = -ENOENT; | ||
1324 | goto skbuff_setattr_return; | ||
1325 | } | ||
1326 | switch (entry->type) { | ||
1327 | case NETLBL_NLTYPE_CALIPSO: | ||
1328 | ret_val = calipso_skbuff_setattr(skb, entry->calipso, | ||
1329 | secattr); | ||
1330 | break; | ||
1331 | case NETLBL_NLTYPE_UNLABELED: | ||
1332 | /* just delete the protocols we support for right now | ||
1333 | * but we could remove other protocols if needed */ | ||
1334 | ret_val = calipso_skbuff_delattr(skb); | ||
1335 | break; | ||
1336 | default: | ||
1337 | ret_val = -ENOENT; | ||
1338 | } | ||
1040 | break; | 1339 | break; |
1041 | #endif /* IPv6 */ | 1340 | #endif /* IPv6 */ |
1042 | default: | 1341 | default: |
@@ -1075,6 +1374,9 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, | |||
1075 | break; | 1374 | break; |
1076 | #if IS_ENABLED(CONFIG_IPV6) | 1375 | #if IS_ENABLED(CONFIG_IPV6) |
1077 | case AF_INET6: | 1376 | case AF_INET6: |
1377 | ptr = calipso_optptr(skb); | ||
1378 | if (ptr && calipso_getattr(ptr, secattr) == 0) | ||
1379 | return 0; | ||
1078 | break; | 1380 | break; |
1079 | #endif /* IPv6 */ | 1381 | #endif /* IPv6 */ |
1080 | } | 1382 | } |
@@ -1085,6 +1387,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, | |||
1085 | /** | 1387 | /** |
1086 | * netlbl_skbuff_err - Handle a LSM error on a sk_buff | 1388 | * netlbl_skbuff_err - Handle a LSM error on a sk_buff |
1087 | * @skb: the packet | 1389 | * @skb: the packet |
1390 | * @family: the family | ||
1088 | * @error: the error code | 1391 | * @error: the error code |
1089 | * @gateway: true if host is acting as a gateway, false otherwise | 1392 | * @gateway: true if host is acting as a gateway, false otherwise |
1090 | * | 1393 | * |
@@ -1094,10 +1397,14 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, | |||
1094 | * according to the packet's labeling protocol. | 1397 | * according to the packet's labeling protocol. |
1095 | * | 1398 | * |
1096 | */ | 1399 | */ |
1097 | void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) | 1400 | void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway) |
1098 | { | 1401 | { |
1099 | if (cipso_v4_optptr(skb)) | 1402 | switch (family) { |
1100 | cipso_v4_error(skb, error, gateway); | 1403 | case AF_INET: |
1404 | if (cipso_v4_optptr(skb)) | ||
1405 | cipso_v4_error(skb, error, gateway); | ||
1406 | break; | ||
1407 | } | ||
1101 | } | 1408 | } |
1102 | 1409 | ||
1103 | /** | 1410 | /** |
@@ -1112,11 +1419,15 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) | |||
1112 | void netlbl_cache_invalidate(void) | 1419 | void netlbl_cache_invalidate(void) |
1113 | { | 1420 | { |
1114 | cipso_v4_cache_invalidate(); | 1421 | cipso_v4_cache_invalidate(); |
1422 | #if IS_ENABLED(CONFIG_IPV6) | ||
1423 | calipso_cache_invalidate(); | ||
1424 | #endif /* IPv6 */ | ||
1115 | } | 1425 | } |
1116 | 1426 | ||
1117 | /** | 1427 | /** |
1118 | * netlbl_cache_add - Add an entry to a NetLabel protocol cache | 1428 | * netlbl_cache_add - Add an entry to a NetLabel protocol cache |
1119 | * @skb: the packet | 1429 | * @skb: the packet |
1430 | * @family: the family | ||
1120 | * @secattr: the packet's security attributes | 1431 | * @secattr: the packet's security attributes |
1121 | * | 1432 | * |
1122 | * Description: | 1433 | * Description: |
@@ -1125,7 +1436,7 @@ void netlbl_cache_invalidate(void) | |||
1125 | * values on error. | 1436 | * values on error. |
1126 | * | 1437 | * |
1127 | */ | 1438 | */ |
1128 | int netlbl_cache_add(const struct sk_buff *skb, | 1439 | int netlbl_cache_add(const struct sk_buff *skb, u16 family, |
1129 | const struct netlbl_lsm_secattr *secattr) | 1440 | const struct netlbl_lsm_secattr *secattr) |
1130 | { | 1441 | { |
1131 | unsigned char *ptr; | 1442 | unsigned char *ptr; |
@@ -1133,10 +1444,20 @@ int netlbl_cache_add(const struct sk_buff *skb, | |||
1133 | if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) | 1444 | if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) |
1134 | return -ENOMSG; | 1445 | return -ENOMSG; |
1135 | 1446 | ||
1136 | ptr = cipso_v4_optptr(skb); | 1447 | switch (family) { |
1137 | if (ptr) | 1448 | case AF_INET: |
1138 | return cipso_v4_cache_add(ptr, secattr); | 1449 | ptr = cipso_v4_optptr(skb); |
1139 | 1450 | if (ptr) | |
1451 | return cipso_v4_cache_add(ptr, secattr); | ||
1452 | break; | ||
1453 | #if IS_ENABLED(CONFIG_IPV6) | ||
1454 | case AF_INET6: | ||
1455 | ptr = calipso_optptr(skb); | ||
1456 | if (ptr) | ||
1457 | return calipso_cache_add(ptr, secattr); | ||
1458 | break; | ||
1459 | #endif /* IPv6 */ | ||
1460 | } | ||
1140 | return -ENOMSG; | 1461 | return -ENOMSG; |
1141 | } | 1462 | } |
1142 | 1463 | ||
@@ -1161,6 +1482,7 @@ struct audit_buffer *netlbl_audit_start(int type, | |||
1161 | { | 1482 | { |
1162 | return netlbl_audit_start_common(type, audit_info); | 1483 | return netlbl_audit_start_common(type, audit_info); |
1163 | } | 1484 | } |
1485 | EXPORT_SYMBOL(netlbl_audit_start); | ||
1164 | 1486 | ||
1165 | /* | 1487 | /* |
1166 | * Setup Functions | 1488 | * Setup Functions |
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 13f777f20995..f85d0e07af2d 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c | |||
@@ -41,8 +41,10 @@ | |||
41 | #include <net/ipv6.h> | 41 | #include <net/ipv6.h> |
42 | #include <net/netlabel.h> | 42 | #include <net/netlabel.h> |
43 | #include <net/cipso_ipv4.h> | 43 | #include <net/cipso_ipv4.h> |
44 | #include <net/calipso.h> | ||
44 | #include <linux/atomic.h> | 45 | #include <linux/atomic.h> |
45 | 46 | ||
47 | #include "netlabel_calipso.h" | ||
46 | #include "netlabel_domainhash.h" | 48 | #include "netlabel_domainhash.h" |
47 | #include "netlabel_user.h" | 49 | #include "netlabel_user.h" |
48 | #include "netlabel_mgmt.h" | 50 | #include "netlabel_mgmt.h" |
@@ -72,6 +74,8 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { | |||
72 | [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, | 74 | [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, |
73 | [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, | 75 | [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, |
74 | [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, | 76 | [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, |
77 | [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 }, | ||
78 | [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 }, | ||
75 | }; | 79 | }; |
76 | 80 | ||
77 | /* | 81 | /* |
@@ -95,6 +99,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info, | |||
95 | int ret_val = -EINVAL; | 99 | int ret_val = -EINVAL; |
96 | struct netlbl_domaddr_map *addrmap = NULL; | 100 | struct netlbl_domaddr_map *addrmap = NULL; |
97 | struct cipso_v4_doi *cipsov4 = NULL; | 101 | struct cipso_v4_doi *cipsov4 = NULL; |
102 | #if IS_ENABLED(CONFIG_IPV6) | ||
103 | struct calipso_doi *calipso = NULL; | ||
104 | #endif | ||
98 | u32 tmp_val; | 105 | u32 tmp_val; |
99 | struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 106 | struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
100 | 107 | ||
@@ -119,6 +126,11 @@ static int netlbl_mgmt_add_common(struct genl_info *info, | |||
119 | 126 | ||
120 | switch (entry->def.type) { | 127 | switch (entry->def.type) { |
121 | case NETLBL_NLTYPE_UNLABELED: | 128 | case NETLBL_NLTYPE_UNLABELED: |
129 | if (info->attrs[NLBL_MGMT_A_FAMILY]) | ||
130 | entry->family = | ||
131 | nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]); | ||
132 | else | ||
133 | entry->family = AF_UNSPEC; | ||
122 | break; | 134 | break; |
123 | case NETLBL_NLTYPE_CIPSOV4: | 135 | case NETLBL_NLTYPE_CIPSOV4: |
124 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) | 136 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) |
@@ -128,12 +140,30 @@ static int netlbl_mgmt_add_common(struct genl_info *info, | |||
128 | cipsov4 = cipso_v4_doi_getdef(tmp_val); | 140 | cipsov4 = cipso_v4_doi_getdef(tmp_val); |
129 | if (cipsov4 == NULL) | 141 | if (cipsov4 == NULL) |
130 | goto add_free_domain; | 142 | goto add_free_domain; |
143 | entry->family = AF_INET; | ||
131 | entry->def.cipso = cipsov4; | 144 | entry->def.cipso = cipsov4; |
132 | break; | 145 | break; |
146 | #if IS_ENABLED(CONFIG_IPV6) | ||
147 | case NETLBL_NLTYPE_CALIPSO: | ||
148 | if (!info->attrs[NLBL_MGMT_A_CLPDOI]) | ||
149 | goto add_free_domain; | ||
150 | |||
151 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]); | ||
152 | calipso = calipso_doi_getdef(tmp_val); | ||
153 | if (calipso == NULL) | ||
154 | goto add_free_domain; | ||
155 | entry->family = AF_INET6; | ||
156 | entry->def.calipso = calipso; | ||
157 | break; | ||
158 | #endif /* IPv6 */ | ||
133 | default: | 159 | default: |
134 | goto add_free_domain; | 160 | goto add_free_domain; |
135 | } | 161 | } |
136 | 162 | ||
163 | if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) || | ||
164 | (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR])) | ||
165 | goto add_doi_put_def; | ||
166 | |||
137 | if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { | 167 | if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { |
138 | struct in_addr *addr; | 168 | struct in_addr *addr; |
139 | struct in_addr *mask; | 169 | struct in_addr *mask; |
@@ -178,6 +208,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, | |||
178 | goto add_free_addrmap; | 208 | goto add_free_addrmap; |
179 | } | 209 | } |
180 | 210 | ||
211 | entry->family = AF_INET; | ||
181 | entry->def.type = NETLBL_NLTYPE_ADDRSELECT; | 212 | entry->def.type = NETLBL_NLTYPE_ADDRSELECT; |
182 | entry->def.addrsel = addrmap; | 213 | entry->def.addrsel = addrmap; |
183 | #if IS_ENABLED(CONFIG_IPV6) | 214 | #if IS_ENABLED(CONFIG_IPV6) |
@@ -220,6 +251,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info, | |||
220 | map->list.mask = *mask; | 251 | map->list.mask = *mask; |
221 | map->list.valid = 1; | 252 | map->list.valid = 1; |
222 | map->def.type = entry->def.type; | 253 | map->def.type = entry->def.type; |
254 | if (calipso) | ||
255 | map->def.calipso = calipso; | ||
223 | 256 | ||
224 | ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); | 257 | ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); |
225 | if (ret_val != 0) { | 258 | if (ret_val != 0) { |
@@ -227,6 +260,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, | |||
227 | goto add_free_addrmap; | 260 | goto add_free_addrmap; |
228 | } | 261 | } |
229 | 262 | ||
263 | entry->family = AF_INET6; | ||
230 | entry->def.type = NETLBL_NLTYPE_ADDRSELECT; | 264 | entry->def.type = NETLBL_NLTYPE_ADDRSELECT; |
231 | entry->def.addrsel = addrmap; | 265 | entry->def.addrsel = addrmap; |
232 | #endif /* IPv6 */ | 266 | #endif /* IPv6 */ |
@@ -242,6 +276,9 @@ add_free_addrmap: | |||
242 | kfree(addrmap); | 276 | kfree(addrmap); |
243 | add_doi_put_def: | 277 | add_doi_put_def: |
244 | cipso_v4_doi_putdef(cipsov4); | 278 | cipso_v4_doi_putdef(cipsov4); |
279 | #if IS_ENABLED(CONFIG_IPV6) | ||
280 | calipso_doi_putdef(calipso); | ||
281 | #endif | ||
245 | add_free_domain: | 282 | add_free_domain: |
246 | kfree(entry->domain); | 283 | kfree(entry->domain); |
247 | add_free_entry: | 284 | add_free_entry: |
@@ -278,6 +315,10 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, | |||
278 | return ret_val; | 315 | return ret_val; |
279 | } | 316 | } |
280 | 317 | ||
318 | ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family); | ||
319 | if (ret_val != 0) | ||
320 | return ret_val; | ||
321 | |||
281 | switch (entry->def.type) { | 322 | switch (entry->def.type) { |
282 | case NETLBL_NLTYPE_ADDRSELECT: | 323 | case NETLBL_NLTYPE_ADDRSELECT: |
283 | nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); | 324 | nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); |
@@ -340,6 +381,15 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, | |||
340 | if (ret_val != 0) | 381 | if (ret_val != 0) |
341 | return ret_val; | 382 | return ret_val; |
342 | 383 | ||
384 | switch (map6->def.type) { | ||
385 | case NETLBL_NLTYPE_CALIPSO: | ||
386 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI, | ||
387 | map6->def.calipso->doi); | ||
388 | if (ret_val != 0) | ||
389 | return ret_val; | ||
390 | break; | ||
391 | } | ||
392 | |||
343 | nla_nest_end(skb, nla_b); | 393 | nla_nest_end(skb, nla_b); |
344 | } | 394 | } |
345 | #endif /* IPv6 */ | 395 | #endif /* IPv6 */ |
@@ -347,15 +397,25 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, | |||
347 | nla_nest_end(skb, nla_a); | 397 | nla_nest_end(skb, nla_a); |
348 | break; | 398 | break; |
349 | case NETLBL_NLTYPE_UNLABELED: | 399 | case NETLBL_NLTYPE_UNLABELED: |
350 | ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); | 400 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, |
401 | entry->def.type); | ||
351 | break; | 402 | break; |
352 | case NETLBL_NLTYPE_CIPSOV4: | 403 | case NETLBL_NLTYPE_CIPSOV4: |
353 | ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); | 404 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, |
405 | entry->def.type); | ||
354 | if (ret_val != 0) | 406 | if (ret_val != 0) |
355 | return ret_val; | 407 | return ret_val; |
356 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, | 408 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, |
357 | entry->def.cipso->doi); | 409 | entry->def.cipso->doi); |
358 | break; | 410 | break; |
411 | case NETLBL_NLTYPE_CALIPSO: | ||
412 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, | ||
413 | entry->def.type); | ||
414 | if (ret_val != 0) | ||
415 | return ret_val; | ||
416 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI, | ||
417 | entry->def.calipso->doi); | ||
418 | break; | ||
359 | } | 419 | } |
360 | 420 | ||
361 | return ret_val; | 421 | return ret_val; |
@@ -418,7 +478,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) | |||
418 | netlbl_netlink_auditinfo(skb, &audit_info); | 478 | netlbl_netlink_auditinfo(skb, &audit_info); |
419 | 479 | ||
420 | domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); | 480 | domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); |
421 | return netlbl_domhsh_remove(domain, &audit_info); | 481 | return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info); |
422 | } | 482 | } |
423 | 483 | ||
424 | /** | 484 | /** |
@@ -536,7 +596,7 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) | |||
536 | 596 | ||
537 | netlbl_netlink_auditinfo(skb, &audit_info); | 597 | netlbl_netlink_auditinfo(skb, &audit_info); |
538 | 598 | ||
539 | return netlbl_domhsh_remove_default(&audit_info); | 599 | return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info); |
540 | } | 600 | } |
541 | 601 | ||
542 | /** | 602 | /** |
@@ -556,6 +616,12 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) | |||
556 | struct sk_buff *ans_skb = NULL; | 616 | struct sk_buff *ans_skb = NULL; |
557 | void *data; | 617 | void *data; |
558 | struct netlbl_dom_map *entry; | 618 | struct netlbl_dom_map *entry; |
619 | u16 family; | ||
620 | |||
621 | if (info->attrs[NLBL_MGMT_A_FAMILY]) | ||
622 | family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]); | ||
623 | else | ||
624 | family = AF_INET; | ||
559 | 625 | ||
560 | ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 626 | ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
561 | if (ans_skb == NULL) | 627 | if (ans_skb == NULL) |
@@ -566,7 +632,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) | |||
566 | goto listdef_failure; | 632 | goto listdef_failure; |
567 | 633 | ||
568 | rcu_read_lock(); | 634 | rcu_read_lock(); |
569 | entry = netlbl_domhsh_getentry(NULL); | 635 | entry = netlbl_domhsh_getentry(NULL, family); |
570 | if (entry == NULL) { | 636 | if (entry == NULL) { |
571 | ret_val = -ENOENT; | 637 | ret_val = -ENOENT; |
572 | goto listdef_failure_lock; | 638 | goto listdef_failure_lock; |
@@ -651,6 +717,15 @@ static int netlbl_mgmt_protocols(struct sk_buff *skb, | |||
651 | goto protocols_return; | 717 | goto protocols_return; |
652 | protos_sent++; | 718 | protos_sent++; |
653 | } | 719 | } |
720 | #if IS_ENABLED(CONFIG_IPV6) | ||
721 | if (protos_sent == 2) { | ||
722 | if (netlbl_mgmt_protocols_cb(skb, | ||
723 | cb, | ||
724 | NETLBL_NLTYPE_CALIPSO) < 0) | ||
725 | goto protocols_return; | ||
726 | protos_sent++; | ||
727 | } | ||
728 | #endif | ||
654 | 729 | ||
655 | protocols_return: | 730 | protocols_return: |
656 | cb->args[0] = protos_sent; | 731 | cb->args[0] = protos_sent; |
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h index 8b6e1ab62b48..ea01e42bca78 100644 --- a/net/netlabel/netlabel_mgmt.h +++ b/net/netlabel/netlabel_mgmt.h | |||
@@ -58,7 +58,10 @@ | |||
58 | * | 58 | * |
59 | * NLBL_MGMT_A_CV4DOI | 59 | * NLBL_MGMT_A_CV4DOI |
60 | * | 60 | * |
61 | * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. | 61 | * If using NETLBL_NLTYPE_UNLABELED no other attributes are required, |
62 | * however the following attribute may optionally be sent: | ||
63 | * | ||
64 | * NLBL_MGMT_A_FAMILY | ||
62 | * | 65 | * |
63 | * o REMOVE: | 66 | * o REMOVE: |
64 | * Sent by an application to remove a domain mapping from the NetLabel | 67 | * Sent by an application to remove a domain mapping from the NetLabel |
@@ -77,6 +80,7 @@ | |||
77 | * Required attributes: | 80 | * Required attributes: |
78 | * | 81 | * |
79 | * NLBL_MGMT_A_DOMAIN | 82 | * NLBL_MGMT_A_DOMAIN |
83 | * NLBL_MGMT_A_FAMILY | ||
80 | * | 84 | * |
81 | * If the IP address selectors are not used the following attribute is | 85 | * If the IP address selectors are not used the following attribute is |
82 | * required: | 86 | * required: |
@@ -108,7 +112,10 @@ | |||
108 | * | 112 | * |
109 | * NLBL_MGMT_A_CV4DOI | 113 | * NLBL_MGMT_A_CV4DOI |
110 | * | 114 | * |
111 | * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. | 115 | * If using NETLBL_NLTYPE_UNLABELED no other attributes are required, |
116 | * however the following attribute may optionally be sent: | ||
117 | * | ||
118 | * NLBL_MGMT_A_FAMILY | ||
112 | * | 119 | * |
113 | * o REMOVEDEF: | 120 | * o REMOVEDEF: |
114 | * Sent by an application to remove the default domain mapping from the | 121 | * Sent by an application to remove the default domain mapping from the |
@@ -117,13 +124,17 @@ | |||
117 | * o LISTDEF: | 124 | * o LISTDEF: |
118 | * This message can be sent either from an application or by the kernel in | 125 | * This message can be sent either from an application or by the kernel in |
119 | * response to an application generated LISTDEF message. When sent by an | 126 | * response to an application generated LISTDEF message. When sent by an |
120 | * application there is no payload. On success the kernel should send a | 127 | * application there may be an optional payload. |
121 | * response using the following format. | ||
122 | * | 128 | * |
123 | * If the IP address selectors are not used the following attribute is | 129 | * NLBL_MGMT_A_FAMILY |
130 | * | ||
131 | * On success the kernel should send a response using the following format: | ||
132 | * | ||
133 | * If the IP address selectors are not used the following attributes are | ||
124 | * required: | 134 | * required: |
125 | * | 135 | * |
126 | * NLBL_MGMT_A_PROTOCOL | 136 | * NLBL_MGMT_A_PROTOCOL |
137 | * NLBL_MGMT_A_FAMILY | ||
127 | * | 138 | * |
128 | * If the IP address selectors are used then the following attritbute is | 139 | * If the IP address selectors are used then the following attritbute is |
129 | * required: | 140 | * required: |
@@ -209,6 +220,12 @@ enum { | |||
209 | /* (NLA_NESTED) | 220 | /* (NLA_NESTED) |
210 | * the selector list, there must be at least one | 221 | * the selector list, there must be at least one |
211 | * NLBL_MGMT_A_ADDRSELECTOR attribute */ | 222 | * NLBL_MGMT_A_ADDRSELECTOR attribute */ |
223 | NLBL_MGMT_A_FAMILY, | ||
224 | /* (NLA_U16) | ||
225 | * The address family */ | ||
226 | NLBL_MGMT_A_CLPDOI, | ||
227 | /* (NLA_U32) | ||
228 | * the CALIPSO DOI value */ | ||
212 | __NLBL_MGMT_A_MAX, | 229 | __NLBL_MGMT_A_MAX, |
213 | }; | 230 | }; |
214 | #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) | 231 | #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) |
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 9eaa9a1e8629..4528cff9138b 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c | |||
@@ -116,8 +116,8 @@ struct netlbl_unlhsh_walk_arg { | |||
116 | static DEFINE_SPINLOCK(netlbl_unlhsh_lock); | 116 | static DEFINE_SPINLOCK(netlbl_unlhsh_lock); |
117 | #define netlbl_unlhsh_rcu_deref(p) \ | 117 | #define netlbl_unlhsh_rcu_deref(p) \ |
118 | rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock)) | 118 | rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock)) |
119 | static struct netlbl_unlhsh_tbl *netlbl_unlhsh; | 119 | static struct netlbl_unlhsh_tbl __rcu *netlbl_unlhsh; |
120 | static struct netlbl_unlhsh_iface *netlbl_unlhsh_def; | 120 | static struct netlbl_unlhsh_iface __rcu *netlbl_unlhsh_def; |
121 | 121 | ||
122 | /* Accept unlabeled packets flag */ | 122 | /* Accept unlabeled packets flag */ |
123 | static u8 netlabel_unlabel_acceptflg; | 123 | static u8 netlabel_unlabel_acceptflg; |
@@ -1537,6 +1537,7 @@ int __init netlbl_unlabel_defconf(void) | |||
1537 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 1537 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
1538 | if (entry == NULL) | 1538 | if (entry == NULL) |
1539 | return -ENOMEM; | 1539 | return -ENOMEM; |
1540 | entry->family = AF_UNSPEC; | ||
1540 | entry->def.type = NETLBL_NLTYPE_UNLABELED; | 1541 | entry->def.type = NETLBL_NLTYPE_UNLABELED; |
1541 | ret_val = netlbl_domhsh_add_default(entry, &audit_info); | 1542 | ret_val = netlbl_domhsh_add_default(entry, &audit_info); |
1542 | if (ret_val != 0) | 1543 | if (ret_val != 0) |
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index adf8b7900da2..58495f44c62a 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include "netlabel_mgmt.h" | 44 | #include "netlabel_mgmt.h" |
45 | #include "netlabel_unlabeled.h" | 45 | #include "netlabel_unlabeled.h" |
46 | #include "netlabel_cipso_v4.h" | 46 | #include "netlabel_cipso_v4.h" |
47 | #include "netlabel_calipso.h" | ||
47 | #include "netlabel_user.h" | 48 | #include "netlabel_user.h" |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -71,6 +72,10 @@ int __init netlbl_netlink_init(void) | |||
71 | if (ret_val != 0) | 72 | if (ret_val != 0) |
72 | return ret_val; | 73 | return ret_val; |
73 | 74 | ||
75 | ret_val = netlbl_calipso_genl_init(); | ||
76 | if (ret_val != 0) | ||
77 | return ret_val; | ||
78 | |||
74 | return netlbl_unlabel_genl_init(); | 79 | return netlbl_unlabel_genl_init(); |
75 | } | 80 | } |
76 | 81 | ||