aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-10-13 17:50:25 -0400
committerJames Morris <jmorris@namei.org>2010-10-20 19:12:58 -0400
commitcee74f47a6baba0ac457e87687fdcf0abd599f0a (patch)
tree3d9fdb073050664e62d9cdb6c28112090cd138da /security
parent00d85c83ac52e2c1a66397f1abc589f80c543425 (diff)
SELinux: allow userspace to read policy back out of the kernel
There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace. Signed-off-by: Eric Paris <eparis@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/include/classmap.h2
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/selinuxfs.c95
-rw-r--r--security/selinux/ss/avtab.c42
-rw-r--r--security/selinux/ss/avtab.h2
-rw-r--r--security/selinux/ss/conditional.c123
-rw-r--r--security/selinux/ss/conditional.h2
-rw-r--r--security/selinux/ss/ebitmap.c81
-rw-r--r--security/selinux/ss/ebitmap.h1
-rw-r--r--security/selinux/ss/policydb.c841
-rw-r--r--security/selinux/ss/policydb.h20
-rw-r--r--security/selinux/ss/services.c48
12 files changed, 1256 insertions, 3 deletions
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b4c9eb4bd6f9..8858d2b2d4b6 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -17,7 +17,7 @@ struct security_class_mapping secclass_map[] = {
17 { "compute_av", "compute_create", "compute_member", 17 { "compute_av", "compute_create", "compute_member",
18 "check_context", "load_policy", "compute_relabel", 18 "check_context", "load_policy", "compute_relabel",
19 "compute_user", "setenforce", "setbool", "setsecparam", 19 "compute_user", "setenforce", "setbool", "setsecparam",
20 "setcheckreqprot", NULL } }, 20 "setcheckreqprot", "read_policy", NULL } },
21 { "process", 21 { "process",
22 { "fork", "transition", "sigchld", "sigkill", 22 { "fork", "transition", "sigchld", "sigkill",
23 "sigstop", "signull", "signal", "ptrace", "getsched", "setsched", 23 "sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 611a526afae7..671273eb1115 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -83,6 +83,8 @@ extern int selinux_policycap_openperm;
83int security_mls_enabled(void); 83int security_mls_enabled(void);
84 84
85int security_load_policy(void *data, size_t len); 85int security_load_policy(void *data, size_t len);
86int security_read_policy(void **data, ssize_t *len);
87size_t security_policydb_len(void);
86 88
87int security_policycap_supported(unsigned int req_cap); 89int security_policycap_supported(unsigned int req_cap);
88 90
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index a2e7a8563b38..8eb102c72606 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -68,6 +68,8 @@ static int *bool_pending_values;
68static struct dentry *class_dir; 68static struct dentry *class_dir;
69static unsigned long last_class_ino; 69static unsigned long last_class_ino;
70 70
71static char policy_opened;
72
71/* global data for policy capabilities */ 73/* global data for policy capabilities */
72static struct dentry *policycap_dir; 74static struct dentry *policycap_dir;
73 75
@@ -111,6 +113,7 @@ enum sel_inos {
111 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ 113 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
112 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ 114 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
113 SEL_STATUS, /* export current status using mmap() */ 115 SEL_STATUS, /* export current status using mmap() */
116 SEL_POLICY, /* allow userspace to read the in kernel policy */
114 SEL_INO_NEXT, /* The next inode number to use */ 117 SEL_INO_NEXT, /* The next inode number to use */
115}; 118};
116 119
@@ -351,6 +354,97 @@ static const struct file_operations sel_mls_ops = {
351 .llseek = generic_file_llseek, 354 .llseek = generic_file_llseek,
352}; 355};
353 356
357struct policy_load_memory {
358 size_t len;
359 void *data;
360};
361
362static int sel_open_policy(struct inode *inode, struct file *filp)
363{
364 struct policy_load_memory *plm = NULL;
365 int rc;
366
367 BUG_ON(filp->private_data);
368
369 mutex_lock(&sel_mutex);
370
371 rc = task_has_security(current, SECURITY__READ_POLICY);
372 if (rc)
373 goto err;
374
375 rc = -EBUSY;
376 if (policy_opened)
377 goto err;
378
379 rc = -ENOMEM;
380 plm = kzalloc(sizeof(*plm), GFP_KERNEL);
381 if (!plm)
382 goto err;
383
384 if (i_size_read(inode) != security_policydb_len()) {
385 mutex_lock(&inode->i_mutex);
386 i_size_write(inode, security_policydb_len());
387 mutex_unlock(&inode->i_mutex);
388 }
389
390 rc = security_read_policy(&plm->data, &plm->len);
391 if (rc)
392 goto err;
393
394 policy_opened = 1;
395
396 filp->private_data = plm;
397
398 mutex_unlock(&sel_mutex);
399
400 return 0;
401err:
402 mutex_unlock(&sel_mutex);
403
404 if (plm)
405 vfree(plm->data);
406 kfree(plm);
407 return rc;
408}
409
410static int sel_release_policy(struct inode *inode, struct file *filp)
411{
412 struct policy_load_memory *plm = filp->private_data;
413
414 BUG_ON(!plm);
415
416 policy_opened = 0;
417
418 vfree(plm->data);
419 kfree(plm);
420
421 return 0;
422}
423
424static ssize_t sel_read_policy(struct file *filp, char __user *buf,
425 size_t count, loff_t *ppos)
426{
427 struct policy_load_memory *plm = filp->private_data;
428 int ret;
429
430 mutex_lock(&sel_mutex);
431
432 ret = task_has_security(current, SECURITY__READ_POLICY);
433 if (ret)
434 goto out;
435
436 ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
437out:
438 mutex_unlock(&sel_mutex);
439 return ret;
440}
441
442static const struct file_operations sel_policy_ops = {
443 .open = sel_open_policy,
444 .read = sel_read_policy,
445 .release = sel_release_policy,
446};
447
354static ssize_t sel_write_load(struct file *file, const char __user *buf, 448static ssize_t sel_write_load(struct file *file, const char __user *buf,
355 size_t count, loff_t *ppos) 449 size_t count, loff_t *ppos)
356 450
@@ -1668,6 +1762,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
1668 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, 1762 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
1669 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, 1763 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
1670 [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, 1764 [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
1765 [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR},
1671 /* last one */ {""} 1766 /* last one */ {""}
1672 }; 1767 };
1673 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); 1768 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 77a917ccc045..a3dd9faa19c0 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -501,6 +501,48 @@ bad:
501 goto out; 501 goto out;
502} 502}
503 503
504int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
505{
506 __le16 buf16[4];
507 __le32 buf32[1];
508 int rc;
509
510 buf16[0] = cpu_to_le16(cur->key.source_type);
511 buf16[1] = cpu_to_le16(cur->key.target_type);
512 buf16[2] = cpu_to_le16(cur->key.target_class);
513 buf16[3] = cpu_to_le16(cur->key.specified);
514 rc = put_entry(buf16, sizeof(u16), 4, fp);
515 if (rc)
516 return rc;
517 buf32[0] = cpu_to_le32(cur->datum.data);
518 rc = put_entry(buf32, sizeof(u32), 1, fp);
519 if (rc)
520 return rc;
521 return 0;
522}
523
524int avtab_write(struct policydb *p, struct avtab *a, void *fp)
525{
526 unsigned int i;
527 int rc = 0;
528 struct avtab_node *cur;
529 __le32 buf[1];
530
531 buf[0] = cpu_to_le32(a->nel);
532 rc = put_entry(buf, sizeof(u32), 1, fp);
533 if (rc)
534 return rc;
535
536 for (i = 0; i < a->nslot; i++) {
537 for (cur = a->htable[i]; cur; cur = cur->next) {
538 rc = avtab_write_item(p, cur, fp);
539 if (rc)
540 return rc;
541 }
542 }
543
544 return rc;
545}
504void avtab_cache_init(void) 546void avtab_cache_init(void)
505{ 547{
506 avtab_node_cachep = kmem_cache_create("avtab_node", 548 avtab_node_cachep = kmem_cache_create("avtab_node",
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 32bd8b39f820..dff0c75345c1 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -71,6 +71,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
71 void *p); 71 void *p);
72 72
73int avtab_read(struct avtab *a, void *fp, struct policydb *pol); 73int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
74int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp);
75int avtab_write(struct policydb *p, struct avtab *a, void *fp);
74 76
75struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, 77struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
76 struct avtab_datum *datum); 78 struct avtab_datum *datum);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index c91e150c3087..655fe1c6cc69 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -490,6 +490,129 @@ err:
490 return rc; 490 return rc;
491} 491}
492 492
493int cond_write_bool(void *vkey, void *datum, void *ptr)
494{
495 char *key = vkey;
496 struct cond_bool_datum *booldatum = datum;
497 struct policy_data *pd = ptr;
498 void *fp = pd->fp;
499 __le32 buf[3];
500 u32 len;
501 int rc;
502
503 len = strlen(key);
504 buf[0] = cpu_to_le32(booldatum->value);
505 buf[1] = cpu_to_le32(booldatum->state);
506 buf[2] = cpu_to_le32(len);
507 rc = put_entry(buf, sizeof(u32), 3, fp);
508 if (rc)
509 return rc;
510 rc = put_entry(key, 1, len, fp);
511 if (rc)
512 return rc;
513 return 0;
514}
515
516/*
517 * cond_write_cond_av_list doesn't write out the av_list nodes.
518 * Instead it writes out the key/value pairs from the avtab. This
519 * is necessary because there is no way to uniquely identifying rules
520 * in the avtab so it is not possible to associate individual rules
521 * in the avtab with a conditional without saving them as part of
522 * the conditional. This means that the avtab with the conditional
523 * rules will not be saved but will be rebuilt on policy load.
524 */
525static int cond_write_av_list(struct policydb *p,
526 struct cond_av_list *list, struct policy_file *fp)
527{
528 __le32 buf[1];
529 struct cond_av_list *cur_list;
530 u32 len;
531 int rc;
532
533 len = 0;
534 for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
535 len++;
536
537 buf[0] = cpu_to_le32(len);
538 rc = put_entry(buf, sizeof(u32), 1, fp);
539 if (rc)
540 return rc;
541
542 if (len == 0)
543 return 0;
544
545 for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
546 rc = avtab_write_item(p, cur_list->node, fp);
547 if (rc)
548 return rc;
549 }
550
551 return 0;
552}
553
554int cond_write_node(struct policydb *p, struct cond_node *node,
555 struct policy_file *fp)
556{
557 struct cond_expr *cur_expr;
558 __le32 buf[2];
559 int rc;
560 u32 len = 0;
561
562 buf[0] = cpu_to_le32(node->cur_state);
563 rc = put_entry(buf, sizeof(u32), 1, fp);
564 if (rc)
565 return rc;
566
567 for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
568 len++;
569
570 buf[0] = cpu_to_le32(len);
571 rc = put_entry(buf, sizeof(u32), 1, fp);
572 if (rc)
573 return rc;
574
575 for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
576 buf[0] = cpu_to_le32(cur_expr->expr_type);
577 buf[1] = cpu_to_le32(cur_expr->bool);
578 rc = put_entry(buf, sizeof(u32), 2, fp);
579 if (rc)
580 return rc;
581 }
582
583 rc = cond_write_av_list(p, node->true_list, fp);
584 if (rc)
585 return rc;
586 rc = cond_write_av_list(p, node->false_list, fp);
587 if (rc)
588 return rc;
589
590 return 0;
591}
592
593int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
594{
595 struct cond_node *cur;
596 u32 len;
597 __le32 buf[1];
598 int rc;
599
600 len = 0;
601 for (cur = list; cur != NULL; cur = cur->next)
602 len++;
603 buf[0] = cpu_to_le32(len);
604 rc = put_entry(buf, sizeof(u32), 1, fp);
605 if (rc)
606 return rc;
607
608 for (cur = list; cur != NULL; cur = cur->next) {
609 rc = cond_write_node(p, cur, fp);
610 if (rc)
611 return rc;
612 }
613
614 return 0;
615}
493/* Determine whether additional permissions are granted by the conditional 616/* Determine whether additional permissions are granted by the conditional
494 * av table, and if so, add them to the result 617 * av table, and if so, add them to the result
495 */ 618 */
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
index 53ddb013ae57..3f209c635295 100644
--- a/security/selinux/ss/conditional.h
+++ b/security/selinux/ss/conditional.h
@@ -69,6 +69,8 @@ int cond_index_bool(void *key, void *datum, void *datap);
69 69
70int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); 70int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
71int cond_read_list(struct policydb *p, void *fp); 71int cond_read_list(struct policydb *p, void *fp);
72int cond_write_bool(void *key, void *datum, void *ptr);
73int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
72 74
73void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); 75void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
74 76
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 04b6145d767f..d42951fcbe87 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -22,6 +22,8 @@
22#include "ebitmap.h" 22#include "ebitmap.h"
23#include "policydb.h" 23#include "policydb.h"
24 24
25#define BITS_PER_U64 (sizeof(u64) * 8)
26
25int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) 27int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
26{ 28{
27 struct ebitmap_node *n1, *n2; 29 struct ebitmap_node *n1, *n2;
@@ -363,10 +365,10 @@ int ebitmap_read(struct ebitmap *e, void *fp)
363 e->highbit = le32_to_cpu(buf[1]); 365 e->highbit = le32_to_cpu(buf[1]);
364 count = le32_to_cpu(buf[2]); 366 count = le32_to_cpu(buf[2]);
365 367
366 if (mapunit != sizeof(u64) * 8) { 368 if (mapunit != BITS_PER_U64) {
367 printk(KERN_ERR "SELinux: ebitmap: map size %u does not " 369 printk(KERN_ERR "SELinux: ebitmap: map size %u does not "
368 "match my size %Zd (high bit was %d)\n", 370 "match my size %Zd (high bit was %d)\n",
369 mapunit, sizeof(u64) * 8, e->highbit); 371 mapunit, BITS_PER_U64, e->highbit);
370 goto bad; 372 goto bad;
371 } 373 }
372 374
@@ -446,3 +448,78 @@ bad:
446 ebitmap_destroy(e); 448 ebitmap_destroy(e);
447 goto out; 449 goto out;
448} 450}
451
452int ebitmap_write(struct ebitmap *e, void *fp)
453{
454 struct ebitmap_node *n;
455 u32 count;
456 __le32 buf[3];
457 u64 map;
458 int bit, last_bit, last_startbit, rc;
459
460 buf[0] = cpu_to_le32(BITS_PER_U64);
461
462 count = 0;
463 last_bit = 0;
464 last_startbit = -1;
465 ebitmap_for_each_positive_bit(e, n, bit) {
466 if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
467 count++;
468 last_startbit = rounddown(bit, BITS_PER_U64);
469 }
470 last_bit = roundup(bit + 1, BITS_PER_U64);
471 }
472 buf[1] = cpu_to_le32(last_bit);
473 buf[2] = cpu_to_le32(count);
474
475 rc = put_entry(buf, sizeof(u32), 3, fp);
476 if (rc)
477 return rc;
478
479 map = 0;
480 last_startbit = INT_MIN;
481 ebitmap_for_each_positive_bit(e, n, bit) {
482 if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
483 __le64 buf64[1];
484
485 /* this is the very first bit */
486 if (!map) {
487 last_startbit = rounddown(bit, BITS_PER_U64);
488 map = (u64)1 << (bit - last_startbit);
489 continue;
490 }
491
492 /* write the last node */
493 buf[0] = cpu_to_le32(last_startbit);
494 rc = put_entry(buf, sizeof(u32), 1, fp);
495 if (rc)
496 return rc;
497
498 buf64[0] = cpu_to_le64(map);
499 rc = put_entry(buf64, sizeof(u64), 1, fp);
500 if (rc)
501 return rc;
502
503 /* set up for the next node */
504 map = 0;
505 last_startbit = rounddown(bit, BITS_PER_U64);
506 }
507 map |= (u64)1 << (bit - last_startbit);
508 }
509 /* write the last node */
510 if (map) {
511 __le64 buf64[1];
512
513 /* write the last node */
514 buf[0] = cpu_to_le32(last_startbit);
515 rc = put_entry(buf, sizeof(u32), 1, fp);
516 if (rc)
517 return rc;
518
519 buf64[0] = cpu_to_le64(map);
520 rc = put_entry(buf64, sizeof(u64), 1, fp);
521 if (rc)
522 return rc;
523 }
524 return 0;
525}
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index f283b4367f54..1f4e93c2ae86 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -123,6 +123,7 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
123int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); 123int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
124void ebitmap_destroy(struct ebitmap *e); 124void ebitmap_destroy(struct ebitmap *e);
125int ebitmap_read(struct ebitmap *e, void *fp); 125int ebitmap_read(struct ebitmap *e, void *fp);
126int ebitmap_write(struct ebitmap *e, void *fp);
126 127
127#ifdef CONFIG_NETLABEL 128#ifdef CONFIG_NETLABEL
128int ebitmap_netlbl_export(struct ebitmap *ebmap, 129int ebitmap_netlbl_export(struct ebitmap *ebmap,
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 97fb0cf0eb69..94f630d93a5c 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -37,6 +37,7 @@
37#include "policydb.h" 37#include "policydb.h"
38#include "conditional.h" 38#include "conditional.h"
39#include "mls.h" 39#include "mls.h"
40#include "services.h"
40 41
41#define _DEBUG_HASHES 42#define _DEBUG_HASHES
42 43
@@ -2316,3 +2317,843 @@ bad:
2316 policydb_destroy(p); 2317 policydb_destroy(p);
2317 goto out; 2318 goto out;
2318} 2319}
2320
2321/*
2322 * Write a MLS level structure to a policydb binary
2323 * representation file.
2324 */
2325static int mls_write_level(struct mls_level *l, void *fp)
2326{
2327 __le32 buf[1];
2328 int rc;
2329
2330 buf[0] = cpu_to_le32(l->sens);
2331 rc = put_entry(buf, sizeof(u32), 1, fp);
2332 if (rc)
2333 return rc;
2334
2335 rc = ebitmap_write(&l->cat, fp);
2336 if (rc)
2337 return rc;
2338
2339 return 0;
2340}
2341
2342/*
2343 * Write a MLS range structure to a policydb binary
2344 * representation file.
2345 */
2346static int mls_write_range_helper(struct mls_range *r, void *fp)
2347{
2348 __le32 buf[3];
2349 size_t items;
2350 int rc, eq;
2351
2352 eq = mls_level_eq(&r->level[1], &r->level[0]);
2353
2354 if (eq)
2355 items = 2;
2356 else
2357 items = 3;
2358 buf[0] = cpu_to_le32(items-1);
2359 buf[1] = cpu_to_le32(r->level[0].sens);
2360 if (!eq)
2361 buf[2] = cpu_to_le32(r->level[1].sens);
2362
2363 BUG_ON(items > (sizeof(buf)/sizeof(buf[0])));
2364
2365 rc = put_entry(buf, sizeof(u32), items, fp);
2366 if (rc)
2367 return rc;
2368
2369 rc = ebitmap_write(&r->level[0].cat, fp);
2370 if (rc)
2371 return rc;
2372 if (!eq) {
2373 rc = ebitmap_write(&r->level[1].cat, fp);
2374 if (rc)
2375 return rc;
2376 }
2377
2378 return 0;
2379}
2380
2381static int sens_write(void *vkey, void *datum, void *ptr)
2382{
2383 char *key = vkey;
2384 struct level_datum *levdatum = datum;
2385 struct policy_data *pd = ptr;
2386 void *fp = pd->fp;
2387 __le32 buf[2];
2388 size_t len;
2389 int rc;
2390
2391 len = strlen(key);
2392 buf[0] = cpu_to_le32(len);
2393 buf[1] = cpu_to_le32(levdatum->isalias);
2394 rc = put_entry(buf, sizeof(u32), 2, fp);
2395 if (rc)
2396 return rc;
2397
2398 rc = put_entry(key, 1, len, fp);
2399 if (rc)
2400 return rc;
2401
2402 rc = mls_write_level(levdatum->level, fp);
2403 if (rc)
2404 return rc;
2405
2406 return 0;
2407}
2408
2409static int cat_write(void *vkey, void *datum, void *ptr)
2410{
2411 char *key = vkey;
2412 struct cat_datum *catdatum = datum;
2413 struct policy_data *pd = ptr;
2414 void *fp = pd->fp;
2415 __le32 buf[3];
2416 size_t len;
2417 int rc;
2418
2419 len = strlen(key);
2420 buf[0] = cpu_to_le32(len);
2421 buf[1] = cpu_to_le32(catdatum->value);
2422 buf[2] = cpu_to_le32(catdatum->isalias);
2423 rc = put_entry(buf, sizeof(u32), 3, fp);
2424 if (rc)
2425 return rc;
2426
2427 rc = put_entry(key, 1, len, fp);
2428 if (rc)
2429 return rc;
2430
2431 return 0;
2432}
2433
2434static int role_trans_write(struct role_trans *r, void *fp)
2435{
2436 struct role_trans *tr;
2437 u32 buf[3];
2438 size_t nel;
2439 int rc;
2440
2441 nel = 0;
2442 for (tr = r; tr; tr = tr->next)
2443 nel++;
2444 buf[0] = cpu_to_le32(nel);
2445 rc = put_entry(buf, sizeof(u32), 1, fp);
2446 if (rc)
2447 return rc;
2448 for (tr = r; tr; tr = tr->next) {
2449 buf[0] = cpu_to_le32(tr->role);
2450 buf[1] = cpu_to_le32(tr->type);
2451 buf[2] = cpu_to_le32(tr->new_role);
2452 rc = put_entry(buf, sizeof(u32), 3, fp);
2453 if (rc)
2454 return rc;
2455 }
2456
2457 return 0;
2458}
2459
2460static int role_allow_write(struct role_allow *r, void *fp)
2461{
2462 struct role_allow *ra;
2463 u32 buf[2];
2464 size_t nel;
2465 int rc;
2466
2467 nel = 0;
2468 for (ra = r; ra; ra = ra->next)
2469 nel++;
2470 buf[0] = cpu_to_le32(nel);
2471 rc = put_entry(buf, sizeof(u32), 1, fp);
2472 if (rc)
2473 return rc;
2474 for (ra = r; ra; ra = ra->next) {
2475 buf[0] = cpu_to_le32(ra->role);
2476 buf[1] = cpu_to_le32(ra->new_role);
2477 rc = put_entry(buf, sizeof(u32), 2, fp);
2478 if (rc)
2479 return rc;
2480 }
2481 return 0;
2482}
2483
2484/*
2485 * Write a security context structure
2486 * to a policydb binary representation file.
2487 */
2488static int context_write(struct policydb *p, struct context *c,
2489 void *fp)
2490{
2491 int rc;
2492 __le32 buf[3];
2493
2494 buf[0] = cpu_to_le32(c->user);
2495 buf[1] = cpu_to_le32(c->role);
2496 buf[2] = cpu_to_le32(c->type);
2497
2498 rc = put_entry(buf, sizeof(u32), 3, fp);
2499 if (rc)
2500 return rc;
2501
2502 rc = mls_write_range_helper(&c->range, fp);
2503 if (rc)
2504 return rc;
2505
2506 return 0;
2507}
2508
2509/*
2510 * The following *_write functions are used to
2511 * write the symbol data to a policy database
2512 * binary representation file.
2513 */
2514
2515static int perm_write(void *vkey, void *datum, void *fp)
2516{
2517 char *key = vkey;
2518 struct perm_datum *perdatum = datum;
2519 __le32 buf[2];
2520 size_t len;
2521 int rc;
2522
2523 len = strlen(key);
2524 buf[0] = cpu_to_le32(len);
2525 buf[1] = cpu_to_le32(perdatum->value);
2526 rc = put_entry(buf, sizeof(u32), 2, fp);
2527 if (rc)
2528 return rc;
2529
2530 rc = put_entry(key, 1, len, fp);
2531 if (rc)
2532 return rc;
2533
2534 return 0;
2535}
2536
2537static int common_write(void *vkey, void *datum, void *ptr)
2538{
2539 char *key = vkey;
2540 struct common_datum *comdatum = datum;
2541 struct policy_data *pd = ptr;
2542 void *fp = pd->fp;
2543 __le32 buf[4];
2544 size_t len;
2545 int rc;
2546
2547 len = strlen(key);
2548 buf[0] = cpu_to_le32(len);
2549 buf[1] = cpu_to_le32(comdatum->value);
2550 buf[2] = cpu_to_le32(comdatum->permissions.nprim);
2551 buf[3] = cpu_to_le32(comdatum->permissions.table->nel);
2552 rc = put_entry(buf, sizeof(u32), 4, fp);
2553 if (rc)
2554 return rc;
2555
2556 rc = put_entry(key, 1, len, fp);
2557 if (rc)
2558 return rc;
2559
2560 rc = hashtab_map(comdatum->permissions.table, perm_write, fp);
2561 if (rc)
2562 return rc;
2563
2564 return 0;
2565}
2566
2567static int write_cons_helper(struct policydb *p, struct constraint_node *node,
2568 void *fp)
2569{
2570 struct constraint_node *c;
2571 struct constraint_expr *e;
2572 __le32 buf[3];
2573 u32 nel;
2574 int rc;
2575
2576 for (c = node; c; c = c->next) {
2577 nel = 0;
2578 for (e = c->expr; e; e = e->next)
2579 nel++;
2580 buf[0] = cpu_to_le32(c->permissions);
2581 buf[1] = cpu_to_le32(nel);
2582 rc = put_entry(buf, sizeof(u32), 2, fp);
2583 if (rc)
2584 return rc;
2585 for (e = c->expr; e; e = e->next) {
2586 buf[0] = cpu_to_le32(e->expr_type);
2587 buf[1] = cpu_to_le32(e->attr);
2588 buf[2] = cpu_to_le32(e->op);
2589 rc = put_entry(buf, sizeof(u32), 3, fp);
2590 if (rc)
2591 return rc;
2592
2593 switch (e->expr_type) {
2594 case CEXPR_NAMES:
2595 rc = ebitmap_write(&e->names, fp);
2596 if (rc)
2597 return rc;
2598 break;
2599 default:
2600 break;
2601 }
2602 }
2603 }
2604
2605 return 0;
2606}
2607
2608static int class_write(void *vkey, void *datum, void *ptr)
2609{
2610 char *key = vkey;
2611 struct class_datum *cladatum = datum;
2612 struct policy_data *pd = ptr;
2613 void *fp = pd->fp;
2614 struct policydb *p = pd->p;
2615 struct constraint_node *c;
2616 __le32 buf[6];
2617 u32 ncons;
2618 size_t len, len2;
2619 int rc;
2620
2621 len = strlen(key);
2622 if (cladatum->comkey)
2623 len2 = strlen(cladatum->comkey);
2624 else
2625 len2 = 0;
2626
2627 ncons = 0;
2628 for (c = cladatum->constraints; c; c = c->next)
2629 ncons++;
2630
2631 buf[0] = cpu_to_le32(len);
2632 buf[1] = cpu_to_le32(len2);
2633 buf[2] = cpu_to_le32(cladatum->value);
2634 buf[3] = cpu_to_le32(cladatum->permissions.nprim);
2635 if (cladatum->permissions.table)
2636 buf[4] = cpu_to_le32(cladatum->permissions.table->nel);
2637 else
2638 buf[4] = 0;
2639 buf[5] = cpu_to_le32(ncons);
2640 rc = put_entry(buf, sizeof(u32), 6, fp);
2641 if (rc)
2642 return rc;
2643
2644 rc = put_entry(key, 1, len, fp);
2645 if (rc)
2646 return rc;
2647
2648 if (cladatum->comkey) {
2649 rc = put_entry(cladatum->comkey, 1, len2, fp);
2650 if (rc)
2651 return rc;
2652 }
2653
2654 rc = hashtab_map(cladatum->permissions.table, perm_write, fp);
2655 if (rc)
2656 return rc;
2657
2658 rc = write_cons_helper(p, cladatum->constraints, fp);
2659 if (rc)
2660 return rc;
2661
2662 /* write out the validatetrans rule */
2663 ncons = 0;
2664 for (c = cladatum->validatetrans; c; c = c->next)
2665 ncons++;
2666
2667 buf[0] = cpu_to_le32(ncons);
2668 rc = put_entry(buf, sizeof(u32), 1, fp);
2669 if (rc)
2670 return rc;
2671
2672 rc = write_cons_helper(p, cladatum->validatetrans, fp);
2673 if (rc)
2674 return rc;
2675
2676 return 0;
2677}
2678
2679static int role_write(void *vkey, void *datum, void *ptr)
2680{
2681 char *key = vkey;
2682 struct role_datum *role = datum;
2683 struct policy_data *pd = ptr;
2684 void *fp = pd->fp;
2685 struct policydb *p = pd->p;
2686 __le32 buf[3];
2687 size_t items, len;
2688 int rc;
2689
2690 len = strlen(key);
2691 items = 0;
2692 buf[items++] = cpu_to_le32(len);
2693 buf[items++] = cpu_to_le32(role->value);
2694 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
2695 buf[items++] = cpu_to_le32(role->bounds);
2696
2697 BUG_ON(items > (sizeof(buf)/sizeof(buf[0])));
2698
2699 rc = put_entry(buf, sizeof(u32), items, fp);
2700 if (rc)
2701 return rc;
2702
2703 rc = put_entry(key, 1, len, fp);
2704 if (rc)
2705 return rc;
2706
2707 rc = ebitmap_write(&role->dominates, fp);
2708 if (rc)
2709 return rc;
2710
2711 rc = ebitmap_write(&role->types, fp);
2712 if (rc)
2713 return rc;
2714
2715 return 0;
2716}
2717
2718static int type_write(void *vkey, void *datum, void *ptr)
2719{
2720 char *key = vkey;
2721 struct type_datum *typdatum = datum;
2722 struct policy_data *pd = ptr;
2723 struct policydb *p = pd->p;
2724 void *fp = pd->fp;
2725 __le32 buf[4];
2726 int rc;
2727 size_t items, len;
2728
2729 len = strlen(key);
2730 items = 0;
2731 buf[items++] = cpu_to_le32(len);
2732 buf[items++] = cpu_to_le32(typdatum->value);
2733 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
2734 u32 properties = 0;
2735
2736 if (typdatum->primary)
2737 properties |= TYPEDATUM_PROPERTY_PRIMARY;
2738
2739 if (typdatum->attribute)
2740 properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
2741
2742 buf[items++] = cpu_to_le32(properties);
2743 buf[items++] = cpu_to_le32(typdatum->bounds);
2744 } else {
2745 buf[items++] = cpu_to_le32(typdatum->primary);
2746 }
2747 BUG_ON(items > (sizeof(buf) / sizeof(buf[0])));
2748 rc = put_entry(buf, sizeof(u32), items, fp);
2749 if (rc)
2750 return rc;
2751
2752 rc = put_entry(key, 1, len, fp);
2753 if (rc)
2754 return rc;
2755
2756 return 0;
2757}
2758
2759static int user_write(void *vkey, void *datum, void *ptr)
2760{
2761 char *key = vkey;
2762 struct user_datum *usrdatum = datum;
2763 struct policy_data *pd = ptr;
2764 struct policydb *p = pd->p;
2765 void *fp = pd->fp;
2766 __le32 buf[3];
2767 size_t items, len;
2768 int rc;
2769
2770 len = strlen(key);
2771 items = 0;
2772 buf[items++] = cpu_to_le32(len);
2773 buf[items++] = cpu_to_le32(usrdatum->value);
2774 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
2775 buf[items++] = cpu_to_le32(usrdatum->bounds);
2776 BUG_ON(items > (sizeof(buf) / sizeof(buf[0])));
2777 rc = put_entry(buf, sizeof(u32), items, fp);
2778 if (rc)
2779 return rc;
2780
2781 rc = put_entry(key, 1, len, fp);
2782 if (rc)
2783 return rc;
2784
2785 rc = ebitmap_write(&usrdatum->roles, fp);
2786 if (rc)
2787 return rc;
2788
2789 rc = mls_write_range_helper(&usrdatum->range, fp);
2790 if (rc)
2791 return rc;
2792
2793 rc = mls_write_level(&usrdatum->dfltlevel, fp);
2794 if (rc)
2795 return rc;
2796
2797 return 0;
2798}
2799
2800static int (*write_f[SYM_NUM]) (void *key, void *datum,
2801 void *datap) =
2802{
2803 common_write,
2804 class_write,
2805 role_write,
2806 type_write,
2807 user_write,
2808 cond_write_bool,
2809 sens_write,
2810 cat_write,
2811};
2812
2813static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
2814 void *fp)
2815{
2816 unsigned int i, j, rc;
2817 size_t nel, len;
2818 __le32 buf[3];
2819 u32 nodebuf[8];
2820 struct ocontext *c;
2821 for (i = 0; i < info->ocon_num; i++) {
2822 nel = 0;
2823 for (c = p->ocontexts[i]; c; c = c->next)
2824 nel++;
2825 buf[0] = cpu_to_le32(nel);
2826 rc = put_entry(buf, sizeof(u32), 1, fp);
2827 if (rc)
2828 return rc;
2829 for (c = p->ocontexts[i]; c; c = c->next) {
2830 switch (i) {
2831 case OCON_ISID:
2832 buf[0] = cpu_to_le32(c->sid[0]);
2833 rc = put_entry(buf, sizeof(u32), 1, fp);
2834 if (rc)
2835 return rc;
2836 rc = context_write(p, &c->context[0], fp);
2837 if (rc)
2838 return rc;
2839 break;
2840 case OCON_FS:
2841 case OCON_NETIF:
2842 len = strlen(c->u.name);
2843 buf[0] = cpu_to_le32(len);
2844 rc = put_entry(buf, sizeof(u32), 1, fp);
2845 if (rc)
2846 return rc;
2847 rc = put_entry(c->u.name, 1, len, fp);
2848 if (rc)
2849 return rc;
2850 rc = context_write(p, &c->context[0], fp);
2851 if (rc)
2852 return rc;
2853 rc = context_write(p, &c->context[1], fp);
2854 if (rc)
2855 return rc;
2856 break;
2857 case OCON_PORT:
2858 buf[0] = cpu_to_le32(c->u.port.protocol);
2859 buf[1] = cpu_to_le32(c->u.port.low_port);
2860 buf[2] = cpu_to_le32(c->u.port.high_port);
2861 rc = put_entry(buf, sizeof(u32), 3, fp);
2862 if (rc)
2863 return rc;
2864 rc = context_write(p, &c->context[0], fp);
2865 if (rc)
2866 return rc;
2867 break;
2868 case OCON_NODE:
2869 nodebuf[0] = c->u.node.addr; /* network order */
2870 nodebuf[1] = c->u.node.mask; /* network order */
2871 rc = put_entry(nodebuf, sizeof(u32), 2, fp);
2872 if (rc)
2873 return rc;
2874 rc = context_write(p, &c->context[0], fp);
2875 if (rc)
2876 return rc;
2877 break;
2878 case OCON_FSUSE:
2879 buf[0] = cpu_to_le32(c->v.behavior);
2880 len = strlen(c->u.name);
2881 buf[1] = cpu_to_le32(len);
2882 rc = put_entry(buf, sizeof(u32), 2, fp);
2883 if (rc)
2884 return rc;
2885 rc = put_entry(c->u.name, 1, len, fp);
2886 if (rc)
2887 return rc;
2888 rc = context_write(p, &c->context[0], fp);
2889 if (rc)
2890 return rc;
2891 break;
2892 case OCON_NODE6:
2893 for (j = 0; j < 4; j++)
2894 nodebuf[j] = c->u.node6.addr[j]; /* network order */
2895 for (j = 0; j < 4; j++)
2896 nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */
2897 rc = put_entry(nodebuf, sizeof(u32), 8, fp);
2898 if (rc)
2899 return rc;
2900 rc = context_write(p, &c->context[0], fp);
2901 if (rc)
2902 return rc;
2903 break;
2904 }
2905 }
2906 }
2907 return 0;
2908}
2909
2910static int genfs_write(struct policydb *p, void *fp)
2911{
2912 struct genfs *genfs;
2913 struct ocontext *c;
2914 size_t len;
2915 __le32 buf[1];
2916 int rc;
2917
2918 len = 0;
2919 for (genfs = p->genfs; genfs; genfs = genfs->next)
2920 len++;
2921 buf[0] = cpu_to_le32(len);
2922 rc = put_entry(buf, sizeof(u32), 1, fp);
2923 if (rc)
2924 return rc;
2925 for (genfs = p->genfs; genfs; genfs = genfs->next) {
2926 len = strlen(genfs->fstype);
2927 buf[0] = cpu_to_le32(len);
2928 rc = put_entry(buf, sizeof(u32), 1, fp);
2929 if (rc)
2930 return rc;
2931 rc = put_entry(genfs->fstype, 1, len, fp);
2932 if (rc)
2933 return rc;
2934 len = 0;
2935 for (c = genfs->head; c; c = c->next)
2936 len++;
2937 buf[0] = cpu_to_le32(len);
2938 rc = put_entry(buf, sizeof(u32), 1, fp);
2939 if (rc)
2940 return rc;
2941 for (c = genfs->head; c; c = c->next) {
2942 len = strlen(c->u.name);
2943 buf[0] = cpu_to_le32(len);
2944 rc = put_entry(buf, sizeof(u32), 1, fp);
2945 if (rc)
2946 return rc;
2947 rc = put_entry(c->u.name, 1, len, fp);
2948 if (rc)
2949 return rc;
2950 buf[0] = cpu_to_le32(c->v.sclass);
2951 rc = put_entry(buf, sizeof(u32), 1, fp);
2952 if (rc)
2953 return rc;
2954 rc = context_write(p, &c->context[0], fp);
2955 if (rc)
2956 return rc;
2957 }
2958 }
2959 return 0;
2960}
2961
2962static int range_count(void *key, void *data, void *ptr)
2963{
2964 int *cnt = ptr;
2965 *cnt = *cnt + 1;
2966
2967 return 0;
2968}
2969
2970static int range_write_helper(void *key, void *data, void *ptr)
2971{
2972 __le32 buf[2];
2973 struct range_trans *rt = key;
2974 struct mls_range *r = data;
2975 struct policy_data *pd = ptr;
2976 void *fp = pd->fp;
2977 struct policydb *p = pd->p;
2978 int rc;
2979
2980 buf[0] = cpu_to_le32(rt->source_type);
2981 buf[1] = cpu_to_le32(rt->target_type);
2982 rc = put_entry(buf, sizeof(u32), 2, fp);
2983 if (rc)
2984 return rc;
2985 if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
2986 buf[0] = cpu_to_le32(rt->target_class);
2987 rc = put_entry(buf, sizeof(u32), 1, fp);
2988 if (rc)
2989 return rc;
2990 }
2991 rc = mls_write_range_helper(r, fp);
2992 if (rc)
2993 return rc;
2994
2995 return 0;
2996}
2997
2998static int range_write(struct policydb *p, void *fp)
2999{
3000 size_t nel;
3001 __le32 buf[1];
3002 int rc;
3003 struct policy_data pd;
3004
3005 pd.p = p;
3006 pd.fp = fp;
3007
3008 /* count the number of entries in the hashtab */
3009 nel = 0;
3010 rc = hashtab_map(p->range_tr, range_count, &nel);
3011 if (rc)
3012 return rc;
3013
3014 buf[0] = cpu_to_le32(nel);
3015 rc = put_entry(buf, sizeof(u32), 1, fp);
3016 if (rc)
3017 return rc;
3018
3019 /* actually write all of the entries */
3020 rc = hashtab_map(p->range_tr, range_write_helper, &pd);
3021 if (rc)
3022 return rc;
3023
3024 return 0;
3025}
3026
3027/*
3028 * Write the configuration data in a policy database
3029 * structure to a policy database binary representation
3030 * file.
3031 */
3032int policydb_write(struct policydb *p, void *fp)
3033{
3034 unsigned int i, num_syms;
3035 int rc;
3036 __le32 buf[4];
3037 u32 config;
3038 size_t len;
3039 struct policydb_compat_info *info;
3040
3041 /*
3042 * refuse to write policy older than compressed avtab
3043 * to simplify the writer. There are other tests dropped
3044 * since we assume this throughout the writer code. Be
3045 * careful if you ever try to remove this restriction
3046 */
3047 if (p->policyvers < POLICYDB_VERSION_AVTAB) {
3048 printk(KERN_ERR "SELinux: refusing to write policy version %d."
3049 " Because it is less than version %d\n", p->policyvers,
3050 POLICYDB_VERSION_AVTAB);
3051 return -EINVAL;
3052 }
3053
3054 config = 0;
3055 if (p->mls_enabled)
3056 config |= POLICYDB_CONFIG_MLS;
3057
3058 if (p->reject_unknown)
3059 config |= REJECT_UNKNOWN;
3060 if (p->allow_unknown)
3061 config |= ALLOW_UNKNOWN;
3062
3063 /* Write the magic number and string identifiers. */
3064 buf[0] = cpu_to_le32(POLICYDB_MAGIC);
3065 len = strlen(POLICYDB_STRING);
3066 buf[1] = cpu_to_le32(len);
3067 rc = put_entry(buf, sizeof(u32), 2, fp);
3068 if (rc)
3069 return rc;
3070 rc = put_entry(POLICYDB_STRING, 1, len, fp);
3071 if (rc)
3072 return rc;
3073
3074 /* Write the version, config, and table sizes. */
3075 info = policydb_lookup_compat(p->policyvers);
3076 if (!info) {
3077 printk(KERN_ERR "SELinux: compatibility lookup failed for policy "
3078 "version %d", p->policyvers);
3079 return rc;
3080 }
3081
3082 buf[0] = cpu_to_le32(p->policyvers);
3083 buf[1] = cpu_to_le32(config);
3084 buf[2] = cpu_to_le32(info->sym_num);
3085 buf[3] = cpu_to_le32(info->ocon_num);
3086
3087 rc = put_entry(buf, sizeof(u32), 4, fp);
3088 if (rc)
3089 return rc;
3090
3091 if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
3092 rc = ebitmap_write(&p->policycaps, fp);
3093 if (rc)
3094 return rc;
3095 }
3096
3097 if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
3098 rc = ebitmap_write(&p->permissive_map, fp);
3099 if (rc)
3100 return rc;
3101 }
3102
3103 num_syms = info->sym_num;
3104 for (i = 0; i < num_syms; i++) {
3105 struct policy_data pd;
3106
3107 pd.fp = fp;
3108 pd.p = p;
3109
3110 buf[0] = cpu_to_le32(p->symtab[i].nprim);
3111 buf[1] = cpu_to_le32(p->symtab[i].table->nel);
3112
3113 rc = put_entry(buf, sizeof(u32), 2, fp);
3114 if (rc)
3115 return rc;
3116 rc = hashtab_map(p->symtab[i].table, write_f[i], &pd);
3117 if (rc)
3118 return rc;
3119 }
3120
3121 rc = avtab_write(p, &p->te_avtab, fp);
3122 if (rc)
3123 return rc;
3124
3125 rc = cond_write_list(p, p->cond_list, fp);
3126 if (rc)
3127 return rc;
3128
3129 rc = role_trans_write(p->role_tr, fp);
3130 if (rc)
3131 return rc;
3132
3133 rc = role_allow_write(p->role_allow, fp);
3134 if (rc)
3135 return rc;
3136
3137 rc = ocontext_write(p, info, fp);
3138 if (rc)
3139 return rc;
3140
3141 rc = genfs_write(p, fp);
3142 if (rc)
3143 return rc;
3144
3145 rc = range_write(p, fp);
3146 if (rc)
3147 return rc;
3148
3149 for (i = 0; i < p->p_types.nprim; i++) {
3150 struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
3151
3152 BUG_ON(!e);
3153 rc = ebitmap_write(e, fp);
3154 if (rc)
3155 return rc;
3156 }
3157
3158 return 0;
3159}
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 310e94442cb8..95d3d7de361e 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -254,6 +254,9 @@ struct policydb {
254 254
255 struct ebitmap permissive_map; 255 struct ebitmap permissive_map;
256 256
257 /* length of this policy when it was loaded */
258 size_t len;
259
257 unsigned int policyvers; 260 unsigned int policyvers;
258 261
259 unsigned int reject_unknown : 1; 262 unsigned int reject_unknown : 1;
@@ -270,6 +273,7 @@ extern int policydb_class_isvalid(struct policydb *p, unsigned int class);
270extern int policydb_type_isvalid(struct policydb *p, unsigned int type); 273extern int policydb_type_isvalid(struct policydb *p, unsigned int type);
271extern int policydb_role_isvalid(struct policydb *p, unsigned int role); 274extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
272extern int policydb_read(struct policydb *p, void *fp); 275extern int policydb_read(struct policydb *p, void *fp);
276extern int policydb_write(struct policydb *p, void *fp);
273 277
274#define PERM_SYMTAB_SIZE 32 278#define PERM_SYMTAB_SIZE 32
275 279
@@ -290,6 +294,11 @@ struct policy_file {
290 size_t len; 294 size_t len;
291}; 295};
292 296
297struct policy_data {
298 struct policydb *p;
299 void *fp;
300};
301
293static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) 302static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
294{ 303{
295 if (bytes > fp->len) 304 if (bytes > fp->len)
@@ -301,6 +310,17 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
301 return 0; 310 return 0;
302} 311}
303 312
313static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp)
314{
315 size_t len = bytes * num;
316
317 memcpy(fp->data, buf, len);
318 fp->data += len;
319 fp->len -= len;
320
321 return 0;
322}
323
304extern u16 string_to_security_class(struct policydb *p, const char *name); 324extern u16 string_to_security_class(struct policydb *p, const char *name);
305extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); 325extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
306 326
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 60964d79e5eb..7565d16aac31 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1776,6 +1776,7 @@ int security_load_policy(void *data, size_t len)
1776 return rc; 1776 return rc;
1777 } 1777 }
1778 1778
1779 policydb.len = len;
1779 rc = selinux_set_mapping(&policydb, secclass_map, 1780 rc = selinux_set_mapping(&policydb, secclass_map,
1780 &current_mapping, 1781 &current_mapping,
1781 &current_mapping_size); 1782 &current_mapping_size);
@@ -1812,6 +1813,7 @@ int security_load_policy(void *data, size_t len)
1812 if (rc) 1813 if (rc)
1813 return rc; 1814 return rc;
1814 1815
1816 newpolicydb.len = len;
1815 /* If switching between different policy types, log MLS status */ 1817 /* If switching between different policy types, log MLS status */
1816 if (policydb.mls_enabled && !newpolicydb.mls_enabled) 1818 if (policydb.mls_enabled && !newpolicydb.mls_enabled)
1817 printk(KERN_INFO "SELinux: Disabling MLS support...\n"); 1819 printk(KERN_INFO "SELinux: Disabling MLS support...\n");
@@ -1892,6 +1894,17 @@ err:
1892 1894
1893} 1895}
1894 1896
1897size_t security_policydb_len(void)
1898{
1899 size_t len;
1900
1901 read_lock(&policy_rwlock);
1902 len = policydb.len;
1903 read_unlock(&policy_rwlock);
1904
1905 return len;
1906}
1907
1895/** 1908/**
1896 * security_port_sid - Obtain the SID for a port. 1909 * security_port_sid - Obtain the SID for a port.
1897 * @protocol: protocol number 1910 * @protocol: protocol number
@@ -3139,3 +3152,38 @@ netlbl_sid_to_secattr_failure:
3139 return rc; 3152 return rc;
3140} 3153}
3141#endif /* CONFIG_NETLABEL */ 3154#endif /* CONFIG_NETLABEL */
3155
3156/**
3157 * security_read_policy - read the policy.
3158 * @data: binary policy data
3159 * @len: length of data in bytes
3160 *
3161 */
3162int security_read_policy(void **data, ssize_t *len)
3163{
3164 int rc;
3165 struct policy_file fp;
3166
3167 if (!ss_initialized)
3168 return -EINVAL;
3169
3170 *len = security_policydb_len();
3171
3172 *data = vmalloc(*len);
3173 if (!*data)
3174 return -ENOMEM;
3175
3176 fp.data = *data;
3177 fp.len = *len;
3178
3179 read_lock(&policy_rwlock);
3180 rc = policydb_write(&policydb, &fp);
3181 read_unlock(&policy_rwlock);
3182
3183 if (rc)
3184 return rc;
3185
3186 *len = (unsigned long)fp.data - (unsigned long)*data;
3187 return 0;
3188
3189}