aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
committerPaul Moore <paul.moore@hp.com>2008-10-10 10:16:32 -0400
commit63c41688743760631188cf0f4ae986a6793ccb0a (patch)
treeb270091d7b763e8b6c5073d4ca618f0d36065188
parent61e1068219950c672ce979719ad2be3aadb00d7d (diff)
netlabel: Add network address selectors to the NetLabel/LSM domain mapping
This patch extends the NetLabel traffic labeling capabilities to individual packets based not only on the LSM domain but the by the destination address as well. The changes here only affect the core NetLabel infrastructre, changes to the NetLabel KAPI and individial protocol engines are also required but are split out into a different patch to ease review. Signed-off-by: Paul Moore <paul.moore@hp.com> Reviewed-by: James Morris <jmorris@namei.org>
-rw-r--r--include/net/netlabel.h7
-rw-r--r--net/netlabel/netlabel_addrlist.c130
-rw-r--r--net/netlabel/netlabel_addrlist.h15
-rw-r--r--net/netlabel/netlabel_domainhash.c290
-rw-r--r--net/netlabel/netlabel_domainhash.h38
-rw-r--r--net/netlabel/netlabel_kapi.c7
-rw-r--r--net/netlabel/netlabel_mgmt.c398
-rw-r--r--net/netlabel/netlabel_mgmt.h59
-rw-r--r--net/netlabel/netlabel_unlabeled.c96
9 files changed, 816 insertions, 224 deletions
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index e16db0961265..0729f8ce5042 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -9,7 +9,7 @@
9 */ 9 */
10 10
11/* 11/*
12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
13 * 13 *
14 * This program is free software; you can redistribute it and/or modify 14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
@@ -72,8 +72,9 @@ struct cipso_v4_doi;
72/* NetLabel NETLINK protocol version 72/* NetLabel NETLINK protocol version
73 * 1: initial version 73 * 1: initial version
74 * 2: added static labels for unlabeled connections 74 * 2: added static labels for unlabeled connections
75 * 3: network selectors added to the NetLabel/LSM domain mapping
75 */ 76 */
76#define NETLBL_PROTO_VERSION 2 77#define NETLBL_PROTO_VERSION 3
77 78
78/* NetLabel NETLINK types/families */ 79/* NetLabel NETLINK types/families */
79#define NETLBL_NLTYPE_NONE 0 80#define NETLBL_NLTYPE_NONE 0
@@ -87,6 +88,8 @@ struct cipso_v4_doi;
87#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" 88#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6"
88#define NETLBL_NLTYPE_UNLABELED 5 89#define NETLBL_NLTYPE_UNLABELED 5
89#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" 90#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
91#define NETLBL_NLTYPE_ADDRSELECT 6
92#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
90 93
91/* 94/*
92 * NetLabel - Kernel API for accessing the network packet label mappings. 95 * NetLabel - Kernel API for accessing the network packet label mappings.
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
index dd928aa52db1..b0925a303353 100644
--- a/net/netlabel/netlabel_addrlist.c
+++ b/net/netlabel/netlabel_addrlist.c
@@ -39,6 +39,7 @@
39#include <linux/ipv6.h> 39#include <linux/ipv6.h>
40#include <net/ip.h> 40#include <net/ip.h>
41#include <net/ipv6.h> 41#include <net/ipv6.h>
42#include <linux/audit.h>
42 43
43#include "netlabel_addrlist.h" 44#include "netlabel_addrlist.h"
44 45
@@ -69,6 +70,32 @@ struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
69 return NULL; 70 return NULL;
70} 71}
71 72
73/**
74 * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
75 * @addr: IPv4 address
76 * @mask: IPv4 address mask
77 * @head: the list head
78 *
79 * Description:
80 * Searches the IPv4 address list given by @head. If an exact match if found
81 * it is returned, otherwise NULL is returned. The caller is responsible for
82 * calling the rcu_read_[un]lock() functions.
83 *
84 */
85struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
86 __be32 mask,
87 struct list_head *head)
88{
89 struct netlbl_af4list *iter;
90
91 list_for_each_entry_rcu(iter, head, list)
92 if (iter->valid && iter->addr == addr && iter->mask == mask)
93 return iter;
94
95 return NULL;
96}
97
98
72#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 99#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
73/** 100/**
74 * netlbl_af6list_search - Search for a matching IPv6 address entry 101 * netlbl_af6list_search - Search for a matching IPv6 address entry
@@ -93,6 +120,33 @@ struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
93 120
94 return NULL; 121 return NULL;
95} 122}
123
124/**
125 * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
126 * @addr: IPv6 address
127 * @mask: IPv6 address mask
128 * @head: the list head
129 *
130 * Description:
131 * Searches the IPv6 address list given by @head. If an exact match if found
132 * it is returned, otherwise NULL is returned. The caller is responsible for
133 * calling the rcu_read_[un]lock() functions.
134 *
135 */
136struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
137 const struct in6_addr *mask,
138 struct list_head *head)
139{
140 struct netlbl_af6list *iter;
141
142 list_for_each_entry_rcu(iter, head, list)
143 if (iter->valid &&
144 ipv6_addr_equal(&iter->addr, addr) &&
145 ipv6_addr_equal(&iter->mask, mask))
146 return iter;
147
148 return NULL;
149}
96#endif /* IPv6 */ 150#endif /* IPv6 */
97 151
98/** 152/**
@@ -256,3 +310,79 @@ struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
256 return NULL; 310 return NULL;
257} 311}
258#endif /* IPv6 */ 312#endif /* IPv6 */
313
314/*
315 * Audit Helper Functions
316 */
317
318/**
319 * netlbl_af4list_audit_addr - Audit an IPv4 address
320 * @audit_buf: audit buffer
321 * @src: true if source address, false if destination
322 * @dev: network interface
323 * @addr: IP address
324 * @mask: IP address mask
325 *
326 * Description:
327 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
328 *
329 */
330void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
331 int src, const char *dev,
332 __be32 addr, __be32 mask)
333{
334 u32 mask_val = ntohl(mask);
335 char *dir = (src ? "src" : "dst");
336
337 if (dev != NULL)
338 audit_log_format(audit_buf, " netif=%s", dev);
339 audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
340 if (mask_val != 0xffffffff) {
341 u32 mask_len = 0;
342 while (mask_val > 0) {
343 mask_val <<= 1;
344 mask_len++;
345 }
346 audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
347 }
348}
349
350#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
351/**
352 * netlbl_af6list_audit_addr - Audit an IPv6 address
353 * @audit_buf: audit buffer
354 * @src: true if source address, false if destination
355 * @dev: network interface
356 * @addr: IP address
357 * @mask: IP address mask
358 *
359 * Description:
360 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
361 *
362 */
363void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
364 int src,
365 const char *dev,
366 const struct in6_addr *addr,
367 const struct in6_addr *mask)
368{
369 char *dir = (src ? "src" : "dst");
370
371 if (dev != NULL)
372 audit_log_format(audit_buf, " netif=%s", dev);
373 audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
374 if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
375 u32 mask_len = 0;
376 u32 mask_val;
377 int iter = -1;
378 while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
379 mask_len += 32;
380 mask_val = ntohl(mask->s6_addr32[iter]);
381 while (mask_val > 0) {
382 mask_val <<= 1;
383 mask_len++;
384 }
385 audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
386 }
387}
388#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
index 0c41df057fa8..0242bead405f 100644
--- a/net/netlabel/netlabel_addrlist.h
+++ b/net/netlabel/netlabel_addrlist.h
@@ -36,6 +36,7 @@
36#include <linux/rcupdate.h> 36#include <linux/rcupdate.h>
37#include <linux/list.h> 37#include <linux/list.h>
38#include <linux/in6.h> 38#include <linux/in6.h>
39#include <linux/audit.h>
39 40
40/** 41/**
41 * struct netlbl_af4list - NetLabel IPv4 address list 42 * struct netlbl_af4list - NetLabel IPv4 address list
@@ -116,6 +117,12 @@ struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
116void netlbl_af4list_remove_entry(struct netlbl_af4list *entry); 117void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
117struct netlbl_af4list *netlbl_af4list_search(__be32 addr, 118struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
118 struct list_head *head); 119 struct list_head *head);
120struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
121 __be32 mask,
122 struct list_head *head);
123void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
124 int src, const char *dev,
125 __be32 addr, __be32 mask);
119 126
120#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 127#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
121 128
@@ -169,6 +176,14 @@ struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
169void netlbl_af6list_remove_entry(struct netlbl_af6list *entry); 176void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
170struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr, 177struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
171 struct list_head *head); 178 struct list_head *head);
179struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
180 const struct in6_addr *mask,
181 struct list_head *head);
182void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
183 int src,
184 const char *dev,
185 const struct in6_addr *addr,
186 const struct in6_addr *mask);
172#endif /* IPV6 */ 187#endif /* IPV6 */
173 188
174#endif 189#endif
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 0243f0c57b41..5fadf10e5ddf 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -11,7 +11,7 @@
11 */ 11 */
12 12
13/* 13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
15 * 15 *
16 * This program is free software; you can redistribute it and/or modify 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 17 * it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
40#include <asm/bug.h> 40#include <asm/bug.h>
41 41
42#include "netlabel_mgmt.h" 42#include "netlabel_mgmt.h"
43#include "netlabel_addrlist.h"
43#include "netlabel_domainhash.h" 44#include "netlabel_domainhash.h"
44#include "netlabel_user.h" 45#include "netlabel_user.h"
45 46
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
72static void netlbl_domhsh_free_entry(struct rcu_head *entry) 73static void netlbl_domhsh_free_entry(struct rcu_head *entry)
73{ 74{
74 struct netlbl_dom_map *ptr; 75 struct netlbl_dom_map *ptr;
76 struct netlbl_af4list *iter4;
77 struct netlbl_af4list *tmp4;
78#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
79 struct netlbl_af6list *iter6;
80 struct netlbl_af6list *tmp6;
81#endif /* IPv6 */
75 82
76 ptr = container_of(entry, struct netlbl_dom_map, rcu); 83 ptr = container_of(entry, struct netlbl_dom_map, rcu);
84 if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
85 netlbl_af4list_foreach_safe(iter4, tmp4,
86 &ptr->type_def.addrsel->list4) {
87 netlbl_af4list_remove_entry(iter4);
88 kfree(netlbl_domhsh_addr4_entry(iter4));
89 }
90#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
91 netlbl_af6list_foreach_safe(iter6, tmp6,
92 &ptr->type_def.addrsel->list6) {
93 netlbl_af6list_remove_entry(iter6);
94 kfree(netlbl_domhsh_addr6_entry(iter6));
95 }
96#endif /* IPv6 */
97 }
77 kfree(ptr->domain); 98 kfree(ptr->domain);
78 kfree(ptr); 99 kfree(ptr);
79} 100}
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
156 return entry; 177 return entry;
157} 178}
158 179
180/**
181 * netlbl_domhsh_audit_add - Generate an audit entry for an add event
182 * @entry: the entry being added
183 * @addr4: the IPv4 address information
184 * @addr6: the IPv6 address information
185 * @result: the result code
186 * @audit_info: NetLabel audit information
187 *
188 * Description:
189 * Generate an audit record for adding a new NetLabel/LSM mapping entry with
190 * the given information. Caller is responsibile for holding the necessary
191 * locks.
192 *
193 */
194static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
195 struct netlbl_af4list *addr4,
196 struct netlbl_af6list *addr6,
197 int result,
198 struct netlbl_audit *audit_info)
199{
200 struct audit_buffer *audit_buf;
201 struct cipso_v4_doi *cipsov4 = NULL;
202 u32 type;
203
204 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
205 if (audit_buf != NULL) {
206 audit_log_format(audit_buf, " nlbl_domain=%s",
207 entry->domain ? entry->domain : "(default)");
208 if (addr4 != NULL) {
209 struct netlbl_domaddr4_map *map4;
210 map4 = netlbl_domhsh_addr4_entry(addr4);
211 type = map4->type;
212 cipsov4 = map4->type_def.cipsov4;
213 netlbl_af4list_audit_addr(audit_buf, 0, NULL,
214 addr4->addr, addr4->mask);
215#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
216 } else if (addr6 != NULL) {
217 struct netlbl_domaddr6_map *map6;
218 map6 = netlbl_domhsh_addr6_entry(addr6);
219 type = map6->type;
220 netlbl_af6list_audit_addr(audit_buf, 0, NULL,
221 &addr6->addr, &addr6->mask);
222#endif /* IPv6 */
223 } else {
224 type = entry->type;
225 cipsov4 = entry->type_def.cipsov4;
226 }
227 switch (type) {
228 case NETLBL_NLTYPE_UNLABELED:
229 audit_log_format(audit_buf, " nlbl_protocol=unlbl");
230 break;
231 case NETLBL_NLTYPE_CIPSOV4:
232 BUG_ON(cipsov4 == NULL);
233 audit_log_format(audit_buf,
234 " nlbl_protocol=cipsov4 cipso_doi=%u",
235 cipsov4->doi);
236 break;
237 }
238 audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
239 audit_log_end(audit_buf);
240 }
241}
242
159/* 243/*
160 * Domain Hash Table Functions 244 * Domain Hash Table Functions
161 */ 245 */
@@ -213,50 +297,106 @@ int __init netlbl_domhsh_init(u32 size)
213int netlbl_domhsh_add(struct netlbl_dom_map *entry, 297int netlbl_domhsh_add(struct netlbl_dom_map *entry,
214 struct netlbl_audit *audit_info) 298 struct netlbl_audit *audit_info)
215{ 299{
216 int ret_val; 300 int ret_val = 0;
217 u32 bkt; 301 struct netlbl_dom_map *entry_old;
218 struct audit_buffer *audit_buf; 302 struct netlbl_af4list *iter4;
219 303 struct netlbl_af4list *tmp4;
220 entry->valid = 1; 304#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
221 INIT_RCU_HEAD(&entry->rcu); 305 struct netlbl_af6list *iter6;
306 struct netlbl_af6list *tmp6;
307#endif /* IPv6 */
222 308
223 rcu_read_lock(); 309 rcu_read_lock();
310
224 spin_lock(&netlbl_domhsh_lock); 311 spin_lock(&netlbl_domhsh_lock);
225 if (entry->domain != NULL) { 312 if (entry->domain != NULL)
226 bkt = netlbl_domhsh_hash(entry->domain); 313 entry_old = netlbl_domhsh_search(entry->domain);
227 if (netlbl_domhsh_search(entry->domain) == NULL) 314 else
315 entry_old = netlbl_domhsh_search_def(entry->domain);
316 if (entry_old == NULL) {
317 entry->valid = 1;
318 INIT_RCU_HEAD(&entry->rcu);
319
320 if (entry->domain != NULL) {
321 u32 bkt = netlbl_domhsh_hash(entry->domain);
228 list_add_tail_rcu(&entry->list, 322 list_add_tail_rcu(&entry->list,
229 &rcu_dereference(netlbl_domhsh)->tbl[bkt]); 323 &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
230 else 324 } else {
231 ret_val = -EEXIST; 325 INIT_LIST_HEAD(&entry->list);
232 } else {
233 INIT_LIST_HEAD(&entry->list);
234 if (rcu_dereference(netlbl_domhsh_def) == NULL)
235 rcu_assign_pointer(netlbl_domhsh_def, entry); 326 rcu_assign_pointer(netlbl_domhsh_def, entry);
236 else
237 ret_val = -EEXIST;
238 }
239 spin_unlock(&netlbl_domhsh_lock);
240 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
241 if (audit_buf != NULL) {
242 audit_log_format(audit_buf,
243 " nlbl_domain=%s",
244 entry->domain ? entry->domain : "(default)");
245 switch (entry->type) {
246 case NETLBL_NLTYPE_UNLABELED:
247 audit_log_format(audit_buf, " nlbl_protocol=unlbl");
248 break;
249 case NETLBL_NLTYPE_CIPSOV4:
250 audit_log_format(audit_buf,
251 " nlbl_protocol=cipsov4 cipso_doi=%u",
252 entry->type_def.cipsov4->doi);
253 break;
254 } 327 }
255 audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
256 audit_log_end(audit_buf);
257 }
258 rcu_read_unlock();
259 328
329 if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
330 netlbl_af4list_foreach_rcu(iter4,
331 &entry->type_def.addrsel->list4)
332 netlbl_domhsh_audit_add(entry, iter4, NULL,
333 ret_val, audit_info);
334#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
335 netlbl_af6list_foreach_rcu(iter6,
336 &entry->type_def.addrsel->list6)
337 netlbl_domhsh_audit_add(entry, NULL, iter6,
338 ret_val, audit_info);
339#endif /* IPv6 */
340 } else
341 netlbl_domhsh_audit_add(entry, NULL, NULL,
342 ret_val, audit_info);
343 } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
344 entry->type == NETLBL_NLTYPE_ADDRSELECT) {
345 struct list_head *old_list4;
346 struct list_head *old_list6;
347
348 old_list4 = &entry_old->type_def.addrsel->list4;
349 old_list6 = &entry_old->type_def.addrsel->list6;
350
351 /* we only allow the addition of address selectors if all of
352 * the selectors do not exist in the existing domain map */
353 netlbl_af4list_foreach_rcu(iter4,
354 &entry->type_def.addrsel->list4)
355 if (netlbl_af4list_search_exact(iter4->addr,
356 iter4->mask,
357 old_list4)) {
358 ret_val = -EEXIST;
359 goto add_return;
360 }
361#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
362 netlbl_af6list_foreach_rcu(iter6,
363 &entry->type_def.addrsel->list6)
364 if (netlbl_af6list_search_exact(&iter6->addr,
365 &iter6->mask,
366 old_list6)) {
367 ret_val = -EEXIST;
368 goto add_return;
369 }
370#endif /* IPv6 */
371
372 netlbl_af4list_foreach_safe(iter4, tmp4,
373 &entry->type_def.addrsel->list4) {
374 netlbl_af4list_remove_entry(iter4);
375 iter4->valid = 1;
376 ret_val = netlbl_af4list_add(iter4, old_list4);
377 netlbl_domhsh_audit_add(entry_old, iter4, NULL,
378 ret_val, audit_info);
379 if (ret_val != 0)
380 goto add_return;
381 }
382#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
383 netlbl_af6list_foreach_safe(iter6, tmp6,
384 &entry->type_def.addrsel->list6) {
385 netlbl_af6list_remove_entry(iter6);
386 iter6->valid = 1;
387 ret_val = netlbl_af6list_add(iter6, old_list6);
388 netlbl_domhsh_audit_add(entry_old, NULL, iter6,
389 ret_val, audit_info);
390 if (ret_val != 0)
391 goto add_return;
392 }
393#endif /* IPv6 */
394 } else
395 ret_val = -EINVAL;
396
397add_return:
398 spin_unlock(&netlbl_domhsh_lock);
399 rcu_read_unlock();
260 return ret_val; 400 return ret_val;
261} 401}
262 402
@@ -319,7 +459,19 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
319 } 459 }
320 460
321 if (ret_val == 0) { 461 if (ret_val == 0) {
462 struct netlbl_af4list *iter4;
463 struct netlbl_domaddr4_map *map4;
464
322 switch (entry->type) { 465 switch (entry->type) {
466 case NETLBL_NLTYPE_ADDRSELECT:
467 netlbl_af4list_foreach_rcu(iter4,
468 &entry->type_def.addrsel->list4) {
469 map4 = netlbl_domhsh_addr4_entry(iter4);
470 cipso_v4_doi_putdef(map4->type_def.cipsov4);
471 }
472 /* no need to check the IPv6 list since we currently
473 * support only unlabeled protocols for IPv6 */
474 break;
323 case NETLBL_NLTYPE_CIPSOV4: 475 case NETLBL_NLTYPE_CIPSOV4:
324 cipso_v4_doi_putdef(entry->type_def.cipsov4); 476 cipso_v4_doi_putdef(entry->type_def.cipsov4);
325 break; 477 break;
@@ -388,6 +540,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
388} 540}
389 541
390/** 542/**
543 * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
544 * @domain: the domain name to search for
545 * @addr: the IP address to search for
546 *
547 * Description:
548 * Look through the domain hash table searching for an entry to match @domain
549 * and @addr, return a pointer to a copy of the entry or NULL. The caller is
550 * responsible for ensuring that rcu_read_[un]lock() is called.
551 *
552 */
553struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
554 __be32 addr)
555{
556 struct netlbl_dom_map *dom_iter;
557 struct netlbl_af4list *addr_iter;
558
559 dom_iter = netlbl_domhsh_search_def(domain);
560 if (dom_iter == NULL)
561 return NULL;
562 if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
563 return NULL;
564
565 addr_iter = netlbl_af4list_search(addr,
566 &dom_iter->type_def.addrsel->list4);
567 if (addr_iter == NULL)
568 return NULL;
569
570 return netlbl_domhsh_addr4_entry(addr_iter);
571}
572
573#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
574/**
575 * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
576 * @domain: the domain name to search for
577 * @addr: the IP address to search for
578 *
579 * Description:
580 * Look through the domain hash table searching for an entry to match @domain
581 * and @addr, return a pointer to a copy of the entry or NULL. The caller is
582 * responsible for ensuring that rcu_read_[un]lock() is called.
583 *
584 */
585struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
586 const struct in6_addr *addr)
587{
588 struct netlbl_dom_map *dom_iter;
589 struct netlbl_af6list *addr_iter;
590
591 dom_iter = netlbl_domhsh_search_def(domain);
592 if (dom_iter == NULL)
593 return NULL;
594 if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
595 return NULL;
596
597 addr_iter = netlbl_af6list_search(addr,
598 &dom_iter->type_def.addrsel->list6);
599 if (addr_iter == NULL)
600 return NULL;
601
602 return netlbl_domhsh_addr6_entry(addr_iter);
603}
604#endif /* IPv6 */
605
606/**
391 * netlbl_domhsh_walk - Iterate through the domain mapping hash table 607 * netlbl_domhsh_walk - Iterate through the domain mapping hash table
392 * @skip_bkt: the number of buckets to skip at the start 608 * @skip_bkt: the number of buckets to skip at the start
393 * @skip_chain: the number of entries to skip in the first iterated bucket 609 * @skip_chain: the number of entries to skip in the first iterated bucket
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index afcc41a7432d..bfcb6763a1a1 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -11,7 +11,7 @@
11 */ 11 */
12 12
13/* 13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
15 * 15 *
16 * This program is free software; you can redistribute it and/or modify 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 17 * it under the terms of the GNU General Public License as published by
@@ -36,16 +36,43 @@
36#include <linux/rcupdate.h> 36#include <linux/rcupdate.h>
37#include <linux/list.h> 37#include <linux/list.h>
38 38
39#include "netlabel_addrlist.h"
40
39/* Domain hash table size */ 41/* Domain hash table size */
40/* XXX - currently this number is an uneducated guess */ 42/* XXX - currently this number is an uneducated guess */
41#define NETLBL_DOMHSH_BITSIZE 7 43#define NETLBL_DOMHSH_BITSIZE 7
42 44
43/* Domain mapping definition struct */ 45/* Domain mapping definition structures */
46#define netlbl_domhsh_addr4_entry(iter) \
47 container_of(iter, struct netlbl_domaddr4_map, list)
48struct netlbl_domaddr4_map {
49 u32 type;
50 union {
51 struct cipso_v4_doi *cipsov4;
52 } type_def;
53
54 struct netlbl_af4list list;
55};
56#define netlbl_domhsh_addr6_entry(iter) \
57 container_of(iter, struct netlbl_domaddr6_map, list)
58struct netlbl_domaddr6_map {
59 u32 type;
60
61 /* NOTE: no 'type_def' union needed at present since we don't currently
62 * support any IPv6 labeling protocols */
63
64 struct netlbl_af6list list;
65};
66struct netlbl_domaddr_map {
67 struct list_head list4;
68 struct list_head list6;
69};
44struct netlbl_dom_map { 70struct netlbl_dom_map {
45 char *domain; 71 char *domain;
46 u32 type; 72 u32 type;
47 union { 73 union {
48 struct cipso_v4_doi *cipsov4; 74 struct cipso_v4_doi *cipsov4;
75 struct netlbl_domaddr_map *addrsel;
49 } type_def; 76 } type_def;
50 77
51 u32 valid; 78 u32 valid;
@@ -66,9 +93,16 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
66int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); 93int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
67int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); 94int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
68struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); 95struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
96struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
97 __be32 addr);
69int netlbl_domhsh_walk(u32 *skip_bkt, 98int netlbl_domhsh_walk(u32 *skip_bkt,
70 u32 *skip_chain, 99 u32 *skip_chain,
71 int (*callback) (struct netlbl_dom_map *entry, void *arg), 100 int (*callback) (struct netlbl_dom_map *entry, void *arg),
72 void *cb_arg); 101 void *cb_arg);
73 102
103#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
104struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
105 const struct in6_addr *addr);
106#endif /* IPv6 */
107
74#endif 108#endif
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 7d8ecea93914..8b820dc98060 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -419,7 +419,9 @@ int netlbl_enabled(void)
419 * Attach the correct label to the given socket using the security attributes 419 * Attach the correct label to the given socket using the security attributes
420 * specified in @secattr. This function requires exclusive access to @sk, 420 * specified in @secattr. This function requires exclusive access to @sk,
421 * which means it either needs to be in the process of being created or locked. 421 * which means it either needs to be in the process of being created or locked.
422 * Returns zero on success, negative values on failure. 422 * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
423 * network address selectors (can't blindly label the socket), and negative
424 * values on all other failures.
423 * 425 *
424 */ 426 */
425int netlbl_sock_setattr(struct sock *sk, 427int netlbl_sock_setattr(struct sock *sk,
@@ -433,6 +435,9 @@ int netlbl_sock_setattr(struct sock *sk,
433 if (dom_entry == NULL) 435 if (dom_entry == NULL)
434 goto socket_setattr_return; 436 goto socket_setattr_return;
435 switch (dom_entry->type) { 437 switch (dom_entry->type) {
438 case NETLBL_NLTYPE_ADDRSELECT:
439 ret_val = -EDESTADDRREQ;
440 break;
436 case NETLBL_NLTYPE_CIPSOV4: 441 case NETLBL_NLTYPE_CIPSOV4:
437 ret_val = cipso_v4_sock_setattr(sk, 442 ret_val = cipso_v4_sock_setattr(sk,
438 dom_entry->type_def.cipsov4, 443 dom_entry->type_def.cipsov4,
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index c4e18c7bc0c1..ee769ecaa13c 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
@@ -32,9 +32,13 @@
32#include <linux/socket.h> 32#include <linux/socket.h>
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/skbuff.h> 34#include <linux/skbuff.h>
35#include <linux/in.h>
36#include <linux/in6.h>
35#include <net/sock.h> 37#include <net/sock.h>
36#include <net/netlink.h> 38#include <net/netlink.h>
37#include <net/genetlink.h> 39#include <net/genetlink.h>
40#include <net/ip.h>
41#include <net/ipv6.h>
38#include <net/netlabel.h> 42#include <net/netlabel.h>
39#include <net/cipso_ipv4.h> 43#include <net/cipso_ipv4.h>
40#include <asm/atomic.h> 44#include <asm/atomic.h>
@@ -71,80 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
71}; 75};
72 76
73/* 77/*
74 * NetLabel Command Handlers 78 * Helper Functions
75 */ 79 */
76 80
77/** 81/**
78 * netlbl_mgmt_add - Handle an ADD message 82 * netlbl_mgmt_add - Handle an ADD message
79 * @skb: the NETLINK buffer
80 * @info: the Generic NETLINK info block 83 * @info: the Generic NETLINK info block
84 * @audit_info: NetLabel audit information
81 * 85 *
82 * Description: 86 * Description:
83 * Process a user generated ADD message and add the domains from the message 87 * Helper function for the ADD and ADDDEF messages to add the domain mappings
84 * to the hash table. See netlabel.h for a description of the message format. 88 * from the message to the hash table. See netlabel.h for a description of the
85 * Returns zero on success, negative values on failure. 89 * message format. Returns zero on success, negative values on failure.
86 * 90 *
87 */ 91 */
88static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 92static int netlbl_mgmt_add_common(struct genl_info *info,
93 struct netlbl_audit *audit_info)
89{ 94{
90 int ret_val = -EINVAL; 95 int ret_val = -EINVAL;
91 struct netlbl_dom_map *entry = NULL; 96 struct netlbl_dom_map *entry = NULL;
92 size_t tmp_size; 97 struct netlbl_domaddr_map *addrmap = NULL;
98 struct cipso_v4_doi *cipsov4 = NULL;
93 u32 tmp_val; 99 u32 tmp_val;
94 struct netlbl_audit audit_info;
95
96 if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
97 !info->attrs[NLBL_MGMT_A_PROTOCOL])
98 goto add_failure;
99
100 netlbl_netlink_auditinfo(skb, &audit_info);
101 100
102 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 101 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
103 if (entry == NULL) { 102 if (entry == NULL) {
104 ret_val = -ENOMEM; 103 ret_val = -ENOMEM;
105 goto add_failure; 104 goto add_failure;
106 } 105 }
107 tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
108 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
109 if (entry->domain == NULL) {
110 ret_val = -ENOMEM;
111 goto add_failure;
112 }
113 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 106 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
114 nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 107 if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
108 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
109 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
110 if (entry->domain == NULL) {
111 ret_val = -ENOMEM;
112 goto add_failure;
113 }
114 nla_strlcpy(entry->domain,
115 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
116 }
117
118 /* NOTE: internally we allow/use a entry->type value of
119 * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
120 * to pass that as a protocol value because we need to know the
121 * "real" protocol */
115 122
116 switch (entry->type) { 123 switch (entry->type) {
117 case NETLBL_NLTYPE_UNLABELED: 124 case NETLBL_NLTYPE_UNLABELED:
118 ret_val = netlbl_domhsh_add(entry, &audit_info);
119 break; 125 break;
120 case NETLBL_NLTYPE_CIPSOV4: 126 case NETLBL_NLTYPE_CIPSOV4:
121 if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 127 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
122 goto add_failure; 128 goto add_failure;
123 129
124 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 130 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
125 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 131 cipsov4 = cipso_v4_doi_getdef(tmp_val);
126 if (entry->type_def.cipsov4 == NULL) 132 if (cipsov4 == NULL)
127 goto add_failure; 133 goto add_failure;
128 ret_val = netlbl_domhsh_add(entry, &audit_info); 134 entry->type_def.cipsov4 = cipsov4;
129 if (ret_val != 0)
130 cipso_v4_doi_putdef(entry->type_def.cipsov4);
131 break; 135 break;
132 default: 136 default:
133 goto add_failure; 137 goto add_failure;
134 } 138 }
139
140 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
141 struct in_addr *addr;
142 struct in_addr *mask;
143 struct netlbl_domaddr4_map *map;
144
145 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
146 if (addrmap == NULL) {
147 ret_val = -ENOMEM;
148 goto add_failure;
149 }
150 INIT_LIST_HEAD(&addrmap->list4);
151 INIT_LIST_HEAD(&addrmap->list6);
152
153 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
154 sizeof(struct in_addr)) {
155 ret_val = -EINVAL;
156 goto add_failure;
157 }
158 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
159 sizeof(struct in_addr)) {
160 ret_val = -EINVAL;
161 goto add_failure;
162 }
163 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
164 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
165
166 map = kzalloc(sizeof(*map), GFP_KERNEL);
167 if (map == NULL) {
168 ret_val = -ENOMEM;
169 goto add_failure;
170 }
171 map->list.addr = addr->s_addr & mask->s_addr;
172 map->list.mask = mask->s_addr;
173 map->list.valid = 1;
174 map->type = entry->type;
175 if (cipsov4)
176 map->type_def.cipsov4 = cipsov4;
177
178 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
179 if (ret_val != 0) {
180 kfree(map);
181 goto add_failure;
182 }
183
184 entry->type = NETLBL_NLTYPE_ADDRSELECT;
185 entry->type_def.addrsel = addrmap;
186#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
187 } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
188 struct in6_addr *addr;
189 struct in6_addr *mask;
190 struct netlbl_domaddr6_map *map;
191
192 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
193 if (addrmap == NULL) {
194 ret_val = -ENOMEM;
195 goto add_failure;
196 }
197 INIT_LIST_HEAD(&addrmap->list4);
198 INIT_LIST_HEAD(&addrmap->list6);
199
200 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
201 sizeof(struct in6_addr)) {
202 ret_val = -EINVAL;
203 goto add_failure;
204 }
205 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
206 sizeof(struct in6_addr)) {
207 ret_val = -EINVAL;
208 goto add_failure;
209 }
210 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
211 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
212
213 map = kzalloc(sizeof(*map), GFP_KERNEL);
214 if (map == NULL) {
215 ret_val = -ENOMEM;
216 goto add_failure;
217 }
218 ipv6_addr_copy(&map->list.addr, addr);
219 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
220 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
221 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
222 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
223 ipv6_addr_copy(&map->list.mask, mask);
224 map->list.valid = 1;
225 map->type = entry->type;
226
227 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
228 if (ret_val != 0) {
229 kfree(map);
230 goto add_failure;
231 }
232
233 entry->type = NETLBL_NLTYPE_ADDRSELECT;
234 entry->type_def.addrsel = addrmap;
235#endif /* IPv6 */
236 }
237
238 ret_val = netlbl_domhsh_add(entry, audit_info);
135 if (ret_val != 0) 239 if (ret_val != 0)
136 goto add_failure; 240 goto add_failure;
137 241
138 return 0; 242 return 0;
139 243
140add_failure: 244add_failure:
245 if (cipsov4)
246 cipso_v4_doi_putdef(cipsov4);
141 if (entry) 247 if (entry)
142 kfree(entry->domain); 248 kfree(entry->domain);
249 kfree(addrmap);
143 kfree(entry); 250 kfree(entry);
144 return ret_val; 251 return ret_val;
145} 252}
146 253
147/** 254/**
255 * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
256 * @skb: the NETLINK buffer
257 * @entry: the map entry
258 *
259 * Description:
260 * This function is a helper function used by the LISTALL and LISTDEF command
261 * handlers. The caller is responsibile for ensuring that the RCU read lock
262 * is held. Returns zero on success, negative values on failure.
263 *
264 */
265static int netlbl_mgmt_listentry(struct sk_buff *skb,
266 struct netlbl_dom_map *entry)
267{
268 int ret_val;
269 struct nlattr *nla_a;
270 struct nlattr *nla_b;
271 struct netlbl_af4list *iter4;
272#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
273 struct netlbl_af6list *iter6;
274#endif
275
276 if (entry->domain != NULL) {
277 ret_val = nla_put_string(skb,
278 NLBL_MGMT_A_DOMAIN, entry->domain);
279 if (ret_val != 0)
280 return ret_val;
281 }
282
283 switch (entry->type) {
284 case NETLBL_NLTYPE_ADDRSELECT:
285 nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
286 if (nla_a == NULL)
287 return -ENOMEM;
288
289 netlbl_af4list_foreach_rcu(iter4,
290 &entry->type_def.addrsel->list4) {
291 struct netlbl_domaddr4_map *map4;
292 struct in_addr addr_struct;
293
294 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
295 if (nla_b == NULL)
296 return -ENOMEM;
297
298 addr_struct.s_addr = iter4->addr;
299 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
300 sizeof(struct in_addr),
301 &addr_struct);
302 if (ret_val != 0)
303 return ret_val;
304 addr_struct.s_addr = iter4->mask;
305 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
306 sizeof(struct in_addr),
307 &addr_struct);
308 if (ret_val != 0)
309 return ret_val;
310 map4 = netlbl_domhsh_addr4_entry(iter4);
311 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
312 map4->type);
313 if (ret_val != 0)
314 return ret_val;
315 switch (map4->type) {
316 case NETLBL_NLTYPE_CIPSOV4:
317 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
318 map4->type_def.cipsov4->doi);
319 if (ret_val != 0)
320 return ret_val;
321 break;
322 }
323
324 nla_nest_end(skb, nla_b);
325 }
326#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
327 netlbl_af6list_foreach_rcu(iter6,
328 &entry->type_def.addrsel->list6) {
329 struct netlbl_domaddr6_map *map6;
330
331 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
332 if (nla_b == NULL)
333 return -ENOMEM;
334
335 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
336 sizeof(struct in6_addr),
337 &iter6->addr);
338 if (ret_val != 0)
339 return ret_val;
340 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
341 sizeof(struct in6_addr),
342 &iter6->mask);
343 if (ret_val != 0)
344 return ret_val;
345 map6 = netlbl_domhsh_addr6_entry(iter6);
346 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
347 map6->type);
348 if (ret_val != 0)
349 return ret_val;
350
351 nla_nest_end(skb, nla_b);
352 }
353#endif /* IPv6 */
354
355 nla_nest_end(skb, nla_a);
356 break;
357 case NETLBL_NLTYPE_UNLABELED:
358 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
359 break;
360 case NETLBL_NLTYPE_CIPSOV4:
361 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
362 if (ret_val != 0)
363 return ret_val;
364 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
365 entry->type_def.cipsov4->doi);
366 break;
367 }
368
369 return ret_val;
370}
371
372/*
373 * NetLabel Command Handlers
374 */
375
376/**
377 * netlbl_mgmt_add - Handle an ADD message
378 * @skb: the NETLINK buffer
379 * @info: the Generic NETLINK info block
380 *
381 * Description:
382 * Process a user generated ADD message and add the domains from the message
383 * to the hash table. See netlabel.h for a description of the message format.
384 * Returns zero on success, negative values on failure.
385 *
386 */
387static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
388{
389 struct netlbl_audit audit_info;
390
391 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
392 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
393 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
394 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
395 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
396 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
397 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
398 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
399 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
400 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
401 return -EINVAL;
402
403 netlbl_netlink_auditinfo(skb, &audit_info);
404
405 return netlbl_mgmt_add_common(info, &audit_info);
406}
407
408/**
148 * netlbl_mgmt_remove - Handle a REMOVE message 409 * netlbl_mgmt_remove - Handle a REMOVE message
149 * @skb: the NETLINK buffer 410 * @skb: the NETLINK buffer
150 * @info: the Generic NETLINK info block 411 * @info: the Generic NETLINK info block
@@ -192,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
192 if (data == NULL) 453 if (data == NULL)
193 goto listall_cb_failure; 454 goto listall_cb_failure;
194 455
195 ret_val = nla_put_string(cb_arg->skb, 456 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
196 NLBL_MGMT_A_DOMAIN,
197 entry->domain);
198 if (ret_val != 0) 457 if (ret_val != 0)
199 goto listall_cb_failure; 458 goto listall_cb_failure;
200 ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
201 if (ret_val != 0)
202 goto listall_cb_failure;
203 switch (entry->type) {
204 case NETLBL_NLTYPE_CIPSOV4:
205 ret_val = nla_put_u32(cb_arg->skb,
206 NLBL_MGMT_A_CV4DOI,
207 entry->type_def.cipsov4->doi);
208 if (ret_val != 0)
209 goto listall_cb_failure;
210 break;
211 }
212 459
213 cb_arg->seq++; 460 cb_arg->seq++;
214 return genlmsg_end(cb_arg->skb, data); 461 return genlmsg_end(cb_arg->skb, data);
@@ -262,50 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
262 */ 509 */
263static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 510static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
264{ 511{
265 int ret_val = -EINVAL;
266 struct netlbl_dom_map *entry = NULL;
267 u32 tmp_val;
268 struct netlbl_audit audit_info; 512 struct netlbl_audit audit_info;
269 513
270 if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) 514 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
271 goto adddef_failure; 515 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
516 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
517 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
518 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
519 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
520 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
521 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
522 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
523 return -EINVAL;
272 524
273 netlbl_netlink_auditinfo(skb, &audit_info); 525 netlbl_netlink_auditinfo(skb, &audit_info);
274 526
275 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 527 return netlbl_mgmt_add_common(info, &audit_info);
276 if (entry == NULL) {
277 ret_val = -ENOMEM;
278 goto adddef_failure;
279 }
280 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
281
282 switch (entry->type) {
283 case NETLBL_NLTYPE_UNLABELED:
284 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
285 break;
286 case NETLBL_NLTYPE_CIPSOV4:
287 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
288 goto adddef_failure;
289
290 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
291 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
292 if (entry->type_def.cipsov4 == NULL)
293 goto adddef_failure;
294 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
295 if (ret_val != 0)
296 cipso_v4_doi_putdef(entry->type_def.cipsov4);
297 break;
298 default:
299 goto adddef_failure;
300 }
301 if (ret_val != 0)
302 goto adddef_failure;
303
304 return 0;
305
306adddef_failure:
307 kfree(entry);
308 return ret_val;
309} 528}
310 529
311/** 530/**
@@ -359,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
359 ret_val = -ENOENT; 578 ret_val = -ENOENT;
360 goto listdef_failure_lock; 579 goto listdef_failure_lock;
361 } 580 }
362 ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); 581 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
363 if (ret_val != 0)
364 goto listdef_failure_lock;
365 switch (entry->type) {
366 case NETLBL_NLTYPE_CIPSOV4:
367 ret_val = nla_put_u32(ans_skb,
368 NLBL_MGMT_A_CV4DOI,
369 entry->type_def.cipsov4->doi);
370 if (ret_val != 0)
371 goto listdef_failure_lock;
372 break;
373 }
374 rcu_read_unlock(); 582 rcu_read_unlock();
583 if (ret_val != 0)
584 goto listdef_failure;
375 585
376 genlmsg_end(ans_skb, data); 586 genlmsg_end(ans_skb, data);
377 return genlmsg_reply(ans_skb, info); 587 return genlmsg_reply(ans_skb, info);
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index a43bff169d6b..05d96431f819 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -45,6 +45,16 @@
45 * NLBL_MGMT_A_DOMAIN 45 * NLBL_MGMT_A_DOMAIN
46 * NLBL_MGMT_A_PROTOCOL 46 * NLBL_MGMT_A_PROTOCOL
47 * 47 *
48 * If IPv4 is specified the following attributes are required:
49 *
50 * NLBL_MGMT_A_IPV4ADDR
51 * NLBL_MGMT_A_IPV4MASK
52 *
53 * If IPv6 is specified the following attributes are required:
54 *
55 * NLBL_MGMT_A_IPV6ADDR
56 * NLBL_MGMT_A_IPV6MASK
57 *
48 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 58 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
49 * 59 *
50 * NLBL_MGMT_A_CV4DOI 60 * NLBL_MGMT_A_CV4DOI
@@ -68,13 +78,24 @@
68 * Required attributes: 78 * Required attributes:
69 * 79 *
70 * NLBL_MGMT_A_DOMAIN 80 * NLBL_MGMT_A_DOMAIN
81 *
82 * If the IP address selectors are not used the following attribute is
83 * required:
84 *
71 * NLBL_MGMT_A_PROTOCOL 85 * NLBL_MGMT_A_PROTOCOL
72 * 86 *
73 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 87 * If the IP address selectors are used then the following attritbute is
88 * required:
89 *
90 * NLBL_MGMT_A_SELECTORLIST
91 *
92 * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
93 * attributes are required:
74 * 94 *
75 * NLBL_MGMT_A_CV4DOI 95 * NLBL_MGMT_A_CV4DOI
76 * 96 *
77 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 97 * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
98 * attributes are required.
78 * 99 *
79 * o ADDDEF: 100 * o ADDDEF:
80 * Sent by an application to set the default domain mapping for the NetLabel 101 * Sent by an application to set the default domain mapping for the NetLabel
@@ -100,15 +121,23 @@
100 * application there is no payload. On success the kernel should send a 121 * application there is no payload. On success the kernel should send a
101 * response using the following format. 122 * response using the following format.
102 * 123 *
103 * Required attributes: 124 * If the IP address selectors are not used the following attribute is
125 * required:
104 * 126 *
105 * NLBL_MGMT_A_PROTOCOL 127 * NLBL_MGMT_A_PROTOCOL
106 * 128 *
107 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 129 * If the IP address selectors are used then the following attritbute is
130 * required:
131 *
132 * NLBL_MGMT_A_SELECTORLIST
133 *
134 * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
135 * attributes are required:
108 * 136 *
109 * NLBL_MGMT_A_CV4DOI 137 * NLBL_MGMT_A_CV4DOI
110 * 138 *
111 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 139 * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
140 * attributes are required.
112 * 141 *
113 * o PROTOCOLS: 142 * o PROTOCOLS:
114 * Sent by an application to request a list of configured NetLabel protocols 143 * Sent by an application to request a list of configured NetLabel protocols
@@ -162,6 +191,26 @@ enum {
162 NLBL_MGMT_A_CV4DOI, 191 NLBL_MGMT_A_CV4DOI,
163 /* (NLA_U32) 192 /* (NLA_U32)
164 * the CIPSOv4 DOI value */ 193 * the CIPSOv4 DOI value */
194 NLBL_MGMT_A_IPV6ADDR,
195 /* (NLA_BINARY, struct in6_addr)
196 * an IPv6 address */
197 NLBL_MGMT_A_IPV6MASK,
198 /* (NLA_BINARY, struct in6_addr)
199 * an IPv6 address mask */
200 NLBL_MGMT_A_IPV4ADDR,
201 /* (NLA_BINARY, struct in_addr)
202 * an IPv4 address */
203 NLBL_MGMT_A_IPV4MASK,
204 /* (NLA_BINARY, struct in_addr)
205 * and IPv4 address mask */
206 NLBL_MGMT_A_ADDRSELECTOR,
207 /* (NLA_NESTED)
208 * an IP address selector, must contain an address, mask, and protocol
209 * attribute plus any protocol specific attributes */
210 NLBL_MGMT_A_SELECTORLIST,
211 /* (NLA_NESTED)
212 * the selector list, there must be at least one
213 * NLBL_MGMT_A_ADDRSELECTOR attribute */
165 __NLBL_MGMT_A_MAX, 214 __NLBL_MGMT_A_MAX,
166}; 215};
167#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) 216#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 ab8131a8e489..e8a5c32b0f10 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -146,76 +146,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
146}; 146};
147 147
148/* 148/*
149 * Audit Helper Functions
150 */
151
152/**
153 * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
154 * @audit_buf: audit buffer
155 * @dev: network interface
156 * @addr: IP address
157 * @mask: IP address mask
158 *
159 * Description:
160 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
161 *
162 */
163static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
164 const char *dev,
165 __be32 addr, __be32 mask)
166{
167 u32 mask_val = ntohl(mask);
168
169 if (dev != NULL)
170 audit_log_format(audit_buf, " netif=%s", dev);
171 audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
172 if (mask_val != 0xffffffff) {
173 u32 mask_len = 0;
174 while (mask_val > 0) {
175 mask_val <<= 1;
176 mask_len++;
177 }
178 audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
179 }
180}
181
182#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
183/**
184 * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
185 * @audit_buf: audit buffer
186 * @dev: network interface
187 * @addr: IP address
188 * @mask: IP address mask
189 *
190 * Description:
191 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
192 *
193 */
194static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
195 const char *dev,
196 const struct in6_addr *addr,
197 const struct in6_addr *mask)
198{
199 if (dev != NULL)
200 audit_log_format(audit_buf, " netif=%s", dev);
201 audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
202 if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
203 u32 mask_len = 0;
204 u32 mask_val;
205 int iter = -1;
206 while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
207 mask_len += 32;
208 mask_val = ntohl(mask->s6_addr32[iter]);
209 while (mask_val > 0) {
210 mask_val <<= 1;
211 mask_len++;
212 }
213 audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
214 }
215}
216#endif /* IPv6 */
217
218/*
219 * Unlabeled Connection Hash Table Functions 149 * Unlabeled Connection Hash Table Functions
220 */ 150 */
221 151
@@ -571,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net,
571 mask4 = (struct in_addr *)mask; 501 mask4 = (struct in_addr *)mask;
572 ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); 502 ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
573 if (audit_buf != NULL) 503 if (audit_buf != NULL)
574 netlbl_unlabel_audit_addr4(audit_buf, 504 netlbl_af4list_audit_addr(audit_buf, 1,
575 dev_name, 505 dev_name,
576 addr4->s_addr, 506 addr4->s_addr,
577 mask4->s_addr); 507 mask4->s_addr);
578 break; 508 break;
579 } 509 }
580#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 510#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -585,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net,
585 mask6 = (struct in6_addr *)mask; 515 mask6 = (struct in6_addr *)mask;
586 ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); 516 ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
587 if (audit_buf != NULL) 517 if (audit_buf != NULL)
588 netlbl_unlabel_audit_addr6(audit_buf, 518 netlbl_af6list_audit_addr(audit_buf, 1,
589 dev_name, 519 dev_name,
590 addr6, mask6); 520 addr6, mask6);
591 break; 521 break;
592 } 522 }
593#endif /* IPv6 */ 523#endif /* IPv6 */
@@ -652,9 +582,9 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
652 audit_info); 582 audit_info);
653 if (audit_buf != NULL) { 583 if (audit_buf != NULL) {
654 dev = dev_get_by_index(net, iface->ifindex); 584 dev = dev_get_by_index(net, iface->ifindex);
655 netlbl_unlabel_audit_addr4(audit_buf, 585 netlbl_af4list_audit_addr(audit_buf, 1,
656 (dev != NULL ? dev->name : NULL), 586 (dev != NULL ? dev->name : NULL),
657 addr->s_addr, mask->s_addr); 587 addr->s_addr, mask->s_addr);
658 if (dev != NULL) 588 if (dev != NULL)
659 dev_put(dev); 589 dev_put(dev);
660 if (entry && security_secid_to_secctx(entry->secid, 590 if (entry && security_secid_to_secctx(entry->secid,
@@ -712,9 +642,9 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
712 audit_info); 642 audit_info);
713 if (audit_buf != NULL) { 643 if (audit_buf != NULL) {
714 dev = dev_get_by_index(net, iface->ifindex); 644 dev = dev_get_by_index(net, iface->ifindex);
715 netlbl_unlabel_audit_addr6(audit_buf, 645 netlbl_af6list_audit_addr(audit_buf, 1,
716 (dev != NULL ? dev->name : NULL), 646 (dev != NULL ? dev->name : NULL),
717 addr, mask); 647 addr, mask);
718 if (dev != NULL) 648 if (dev != NULL)
719 dev_put(dev); 649 dev_put(dev);
720 if (entry && security_secid_to_secctx(entry->secid, 650 if (entry && security_secid_to_secctx(entry->secid,