22faba620e4b86de5191d6fbadc44d936a80de4c
[linux-2.6.git] / net / netlabel / netlabel_kapi.c
1 /*
2  * NetLabel Kernel API
3  *
4  * This file defines the kernel API for the NetLabel system.  The NetLabel
5  * system manages static and dynamic label mappings for network protocols such
6  * as CIPSO and RIPSO.
7  *
8  * Author: Paul Moore <paul.moore@hp.com>
9  *
10  */
11
12 /*
13  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14  *
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
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
23  * the GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program;  if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28  *
29  */
30
31 #include <linux/init.h>
32 #include <linux/types.h>
33 #include <linux/audit.h>
34 #include <net/ip.h>
35 #include <net/netlabel.h>
36 #include <net/cipso_ipv4.h>
37 #include <asm/bug.h>
38 #include <asm/atomic.h>
39
40 #include "netlabel_domainhash.h"
41 #include "netlabel_unlabeled.h"
42 #include "netlabel_cipso_v4.h"
43 #include "netlabel_user.h"
44 #include "netlabel_mgmt.h"
45
46 /*
47  * Configuration Functions
48  */
49
50 /**
51  * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
52  * @domain: the domain mapping to remove
53  * @audit_info: NetLabel audit information
54  *
55  * Description:
56  * Removes a NetLabel/LSM domain mapping.  A @domain value of NULL causes the
57  * default domain mapping to be removed.  Returns zero on success, negative
58  * values on failure.
59  *
60  */
61 int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
62 {
63         return netlbl_domhsh_remove(domain, audit_info);
64 }
65
66 /**
67  * netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping
68  * @domain: the domain mapping to add
69  * @audit_info: NetLabel audit information
70  *
71  * Description:
72  * Adds a new unlabeled NetLabel/LSM domain mapping.  A @domain value of NULL
73  * causes a new default domain mapping to be added.  Returns zero on success,
74  * negative values on failure.
75  *
76  */
77 int netlbl_cfg_unlbl_add_map(const char *domain,
78                              struct netlbl_audit *audit_info)
79 {
80         int ret_val = -ENOMEM;
81         struct netlbl_dom_map *entry;
82
83         entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
84         if (entry == NULL)
85                 return -ENOMEM;
86         if (domain != NULL) {
87                 entry->domain = kstrdup(domain, GFP_ATOMIC);
88                 if (entry->domain == NULL)
89                         goto cfg_unlbl_add_map_failure;
90         }
91         entry->type = NETLBL_NLTYPE_UNLABELED;
92
93         ret_val = netlbl_domhsh_add(entry, audit_info);
94         if (ret_val != 0)
95                 goto cfg_unlbl_add_map_failure;
96
97         return 0;
98
99 cfg_unlbl_add_map_failure:
100         if (entry != NULL)
101                 kfree(entry->domain);
102         kfree(entry);
103         return ret_val;
104 }
105
106 /**
107  * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
108  * @doi_def: the DOI definition
109  * @domain: the domain mapping to add
110  * @audit_info: NetLabel audit information
111  *
112  * Description:
113  * Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this
114  * new DOI definition to the NetLabel subsystem.  A @domain value of NULL adds
115  * a new default domain mapping.  Returns zero on success, negative values on
116  * failure.
117  *
118  */
119 int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
120                                const char *domain,
121                                struct netlbl_audit *audit_info)
122 {
123         int ret_val = -ENOMEM;
124         struct netlbl_dom_map *entry;
125         const char *type_str;
126         struct audit_buffer *audit_buf;
127
128         entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
129         if (entry == NULL)
130                 return -ENOMEM;
131         if (domain != NULL) {
132                 entry->domain = kstrdup(domain, GFP_ATOMIC);
133                 if (entry->domain == NULL)
134                         goto cfg_cipsov4_add_map_failure;
135         }
136         entry->type = NETLBL_NLTYPE_CIPSOV4;
137         entry->type_def.cipsov4 = doi_def;
138
139         /* Grab a RCU read lock here so nothing happens to the doi_def variable
140          * between adding it to the CIPSOv4 protocol engine and adding a
141          * domain mapping for it. */
142
143         rcu_read_lock();
144         ret_val = cipso_v4_doi_add(doi_def);
145         if (ret_val != 0)
146                 goto cfg_cipsov4_add_map_failure_unlock;
147         ret_val = netlbl_domhsh_add(entry, audit_info);
148         if (ret_val != 0)
149                 goto cfg_cipsov4_add_map_failure_remove_doi;
150         rcu_read_unlock();
151
152         return 0;
153
154 cfg_cipsov4_add_map_failure_remove_doi:
155         cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
156 cfg_cipsov4_add_map_failure_unlock:
157         rcu_read_unlock();
158         audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
159                                               audit_info);
160         if (audit_buf != NULL) {
161                 switch (doi_def->type) {
162                 case CIPSO_V4_MAP_STD:
163                         type_str = "std";
164                         break;
165                 case CIPSO_V4_MAP_PASS:
166                         type_str = "pass";
167                         break;
168                 default:
169                         type_str = "(unknown)";
170                 }
171                 audit_log_format(audit_buf,
172                                  " cipso_doi=%u cipso_type=%s res=%u",
173                                  doi_def->doi, type_str, ret_val == 0 ? 1 : 0);
174                 audit_log_end(audit_buf);
175         }
176 cfg_cipsov4_add_map_failure:
177         if (entry != NULL)
178                 kfree(entry->domain);
179         kfree(entry);
180         return ret_val;
181 }
182
183 /*
184  * Security Attribute Functions
185  */
186
187 /**
188  * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit
189  * @catmap: the category bitmap
190  * @offset: the offset to start searching at, in bits
191  *
192  * Description:
193  * This function walks a LSM secattr category bitmap starting at @offset and
194  * returns the spot of the first set bit or -ENOENT if no bits are set.
195  *
196  */
197 int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
198                                u32 offset)
199 {
200         struct netlbl_lsm_secattr_catmap *iter = catmap;
201         u32 node_idx;
202         u32 node_bit;
203         NETLBL_CATMAP_MAPTYPE bitmap;
204
205         if (offset > iter->startbit) {
206                 while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
207                         iter = iter->next;
208                         if (iter == NULL)
209                                 return -ENOENT;
210                 }
211                 node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
212                 node_bit = offset - iter->startbit -
213                            (NETLBL_CATMAP_MAPSIZE * node_idx);
214         } else {
215                 node_idx = 0;
216                 node_bit = 0;
217         }
218         bitmap = iter->bitmap[node_idx] >> node_bit;
219
220         for (;;) {
221                 if (bitmap != 0) {
222                         while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
223                                 bitmap >>= 1;
224                                 node_bit++;
225                         }
226                         return iter->startbit +
227                                 (NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit;
228                 }
229                 if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
230                         if (iter->next != NULL) {
231                                 iter = iter->next;
232                                 node_idx = 0;
233                         } else
234                                 return -ENOENT;
235                 }
236                 bitmap = iter->bitmap[node_idx];
237                 node_bit = 0;
238         }
239
240         return -ENOENT;
241 }
242
243 /**
244  * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits
245  * @catmap: the category bitmap
246  * @offset: the offset to start searching at, in bits
247  *
248  * Description:
249  * This function walks a LSM secattr category bitmap starting at @offset and
250  * returns the spot of the first cleared bit or -ENOENT if the offset is past
251  * the end of the bitmap.
252  *
253  */
254 int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
255                                    u32 offset)
256 {
257         struct netlbl_lsm_secattr_catmap *iter = catmap;
258         u32 node_idx;
259         u32 node_bit;
260         NETLBL_CATMAP_MAPTYPE bitmask;
261         NETLBL_CATMAP_MAPTYPE bitmap;
262
263         if (offset > iter->startbit) {
264                 while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
265                         iter = iter->next;
266                         if (iter == NULL)
267                                 return -ENOENT;
268                 }
269                 node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
270                 node_bit = offset - iter->startbit -
271                            (NETLBL_CATMAP_MAPSIZE * node_idx);
272         } else {
273                 node_idx = 0;
274                 node_bit = 0;
275         }
276         bitmask = NETLBL_CATMAP_BIT << node_bit;
277
278         for (;;) {
279                 bitmap = iter->bitmap[node_idx];
280                 while (bitmask != 0 && (bitmap & bitmask) != 0) {
281                         bitmask <<= 1;
282                         node_bit++;
283                 }
284
285                 if (bitmask != 0)
286                         return iter->startbit +
287                                 (NETLBL_CATMAP_MAPSIZE * node_idx) +
288                                 node_bit - 1;
289                 else if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
290                         if (iter->next == NULL)
291                                 return iter->startbit + NETLBL_CATMAP_SIZE - 1;
292                         iter = iter->next;
293                         node_idx = 0;
294                 }
295                 bitmask = NETLBL_CATMAP_BIT;
296                 node_bit = 0;
297         }
298
299         return -ENOENT;
300 }
301
302 /**
303  * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap
304  * @catmap: the category bitmap
305  * @bit: the bit to set
306  * @flags: memory allocation flags
307  *
308  * Description:
309  * Set the bit specified by @bit in @catmap.  Returns zero on success,
310  * negative values on failure.
311  *
312  */
313 int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
314                                  u32 bit,
315                                  gfp_t flags)
316 {
317         struct netlbl_lsm_secattr_catmap *iter = catmap;
318         u32 node_bit;
319         u32 node_idx;
320
321         while (iter->next != NULL &&
322                bit >= (iter->startbit + NETLBL_CATMAP_SIZE))
323                 iter = iter->next;
324         if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
325                 iter->next = netlbl_secattr_catmap_alloc(flags);
326                 if (iter->next == NULL)
327                         return -ENOMEM;
328                 iter = iter->next;
329                 iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1);
330         }
331
332         /* gcc always rounds to zero when doing integer division */
333         node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
334         node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx);
335         iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit;
336
337         return 0;
338 }
339
340 /**
341  * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap
342  * @catmap: the category bitmap
343  * @start: the starting bit
344  * @end: the last bit in the string
345  * @flags: memory allocation flags
346  *
347  * Description:
348  * Set a range of bits, starting at @start and ending with @end.  Returns zero
349  * on success, negative values on failure.
350  *
351  */
352 int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
353                                  u32 start,
354                                  u32 end,
355                                  gfp_t flags)
356 {
357         int ret_val = 0;
358         struct netlbl_lsm_secattr_catmap *iter = catmap;
359         u32 iter_max_spot;
360         u32 spot;
361
362         /* XXX - This could probably be made a bit faster by combining writes
363          * to the catmap instead of setting a single bit each time, but for
364          * right now skipping to the start of the range in the catmap should
365          * be a nice improvement over calling the individual setbit function
366          * repeatedly from a loop. */
367
368         while (iter->next != NULL &&
369                start >= (iter->startbit + NETLBL_CATMAP_SIZE))
370                 iter = iter->next;
371         iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
372
373         for (spot = start; spot <= end && ret_val == 0; spot++) {
374                 if (spot >= iter_max_spot && iter->next != NULL) {
375                         iter = iter->next;
376                         iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
377                 }
378                 ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC);
379         }
380
381         return ret_val;
382 }
383
384 /*
385  * LSM Functions
386  */
387
388 /**
389  * netlbl_enabled - Determine if the NetLabel subsystem is enabled
390  *
391  * Description:
392  * The LSM can use this function to determine if it should use NetLabel
393  * security attributes in it's enforcement mechanism.  Currently, NetLabel is
394  * considered to be enabled when it's configuration contains a valid setup for
395  * at least one labeled protocol (i.e. NetLabel can understand incoming
396  * labeled packets of at least one type); otherwise NetLabel is considered to
397  * be disabled.
398  *
399  */
400 int netlbl_enabled(void)
401 {
402         /* At some point we probably want to expose this mechanism to the user
403          * as well so that admins can toggle NetLabel regardless of the
404          * configuration */
405         return (atomic_read(&netlabel_mgmt_protocount) > 0);
406 }
407
408 /**
409  * netlbl_socket_setattr - Label a socket using the correct protocol
410  * @sk: the socket to label
411  * @secattr: the security attributes
412  *
413  * Description:
414  * Attach the correct label to the given socket using the security attributes
415  * specified in @secattr.  This function requires exclusive access to @sk,
416  * which means it either needs to be in the process of being created or locked.
417  * Returns zero on success, negative values on failure.
418  *
419  */
420 int netlbl_sock_setattr(struct sock *sk,
421                         const struct netlbl_lsm_secattr *secattr)
422 {
423         int ret_val = -ENOENT;
424         struct netlbl_dom_map *dom_entry;
425
426         rcu_read_lock();
427         dom_entry = netlbl_domhsh_getentry(secattr->domain);
428         if (dom_entry == NULL)
429                 goto socket_setattr_return;
430         switch (dom_entry->type) {
431         case NETLBL_NLTYPE_CIPSOV4:
432                 ret_val = cipso_v4_sock_setattr(sk,
433                                                 dom_entry->type_def.cipsov4,
434                                                 secattr);
435                 break;
436         case NETLBL_NLTYPE_UNLABELED:
437                 ret_val = 0;
438                 break;
439         default:
440                 ret_val = -ENOENT;
441         }
442
443 socket_setattr_return:
444         rcu_read_unlock();
445         return ret_val;
446 }
447
448 /**
449  * netlbl_sock_getattr - Determine the security attributes of a sock
450  * @sk: the sock
451  * @secattr: the security attributes
452  *
453  * Description:
454  * Examines the given sock to see if any NetLabel style labeling has been
455  * applied to the sock, if so it parses the socket label and returns the
456  * security attributes in @secattr.  Returns zero on success, negative values
457  * on failure.
458  *
459  */
460 int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
461 {
462         return cipso_v4_sock_getattr(sk, secattr);
463 }
464
465 /**
466  * netlbl_skbuff_getattr - Determine the security attributes of a packet
467  * @skb: the packet
468  * @family: protocol family
469  * @secattr: the security attributes
470  *
471  * Description:
472  * Examines the given packet to see if a recognized form of packet labeling
473  * is present, if so it parses the packet label and returns the security
474  * attributes in @secattr.  Returns zero on success, negative values on
475  * failure.
476  *
477  */
478 int netlbl_skbuff_getattr(const struct sk_buff *skb,
479                           u16 family,
480                           struct netlbl_lsm_secattr *secattr)
481 {
482         if (CIPSO_V4_OPTEXIST(skb) &&
483             cipso_v4_skbuff_getattr(skb, secattr) == 0)
484                 return 0;
485
486         return netlbl_unlabel_getattr(skb, family, secattr);
487 }
488
489 /**
490  * netlbl_skbuff_err - Handle a LSM error on a sk_buff
491  * @skb: the packet
492  * @error: the error code
493  * @gateway: true if host is acting as a gateway, false otherwise
494  *
495  * Description:
496  * Deal with a LSM problem when handling the packet in @skb, typically this is
497  * a permission denied problem (-EACCES).  The correct action is determined
498  * according to the packet's labeling protocol.
499  *
500  */
501 void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
502 {
503         if (CIPSO_V4_OPTEXIST(skb))
504                 cipso_v4_error(skb, error, gateway);
505 }
506
507 /**
508  * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
509  *
510  * Description:
511  * For all of the NetLabel protocols that support some form of label mapping
512  * cache, invalidate the cache.  Returns zero on success, negative values on
513  * error.
514  *
515  */
516 void netlbl_cache_invalidate(void)
517 {
518         cipso_v4_cache_invalidate();
519 }
520
521 /**
522  * netlbl_cache_add - Add an entry to a NetLabel protocol cache
523  * @skb: the packet
524  * @secattr: the packet's security attributes
525  *
526  * Description:
527  * Add the LSM security attributes for the given packet to the underlying
528  * NetLabel protocol's label mapping cache.  Returns zero on success, negative
529  * values on error.
530  *
531  */
532 int netlbl_cache_add(const struct sk_buff *skb,
533                      const struct netlbl_lsm_secattr *secattr)
534 {
535         if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
536                 return -ENOMSG;
537
538         if (CIPSO_V4_OPTEXIST(skb))
539                 return cipso_v4_cache_add(skb, secattr);
540
541         return -ENOMSG;
542 }
543
544 /*
545  * Setup Functions
546  */
547
548 /**
549  * netlbl_init - Initialize NetLabel
550  *
551  * Description:
552  * Perform the required NetLabel initialization before first use.
553  *
554  */
555 static int __init netlbl_init(void)
556 {
557         int ret_val;
558
559         printk(KERN_INFO "NetLabel: Initializing\n");
560         printk(KERN_INFO "NetLabel:  domain hash size = %u\n",
561                (1 << NETLBL_DOMHSH_BITSIZE));
562         printk(KERN_INFO "NetLabel:  protocols ="
563                " UNLABELED"
564                " CIPSOv4"
565                "\n");
566
567         ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
568         if (ret_val != 0)
569                 goto init_failure;
570
571         ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
572         if (ret_val != 0)
573                 goto init_failure;
574
575         ret_val = netlbl_netlink_init();
576         if (ret_val != 0)
577                 goto init_failure;
578
579         ret_val = netlbl_unlabel_defconf();
580         if (ret_val != 0)
581                 goto init_failure;
582         printk(KERN_INFO "NetLabel:  unlabeled traffic allowed by default\n");
583
584         return 0;
585
586 init_failure:
587         panic("NetLabel: failed to initialize properly (%d)\n", ret_val);
588 }
589
590 subsys_initcall(netlbl_init);