diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-11-16 14:06:22 -0500 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-11-16 14:06:22 -0500 |
commit | 20b4755e4fbb226eb42951bd40b53fcbce9ef944 (patch) | |
tree | 43da70e0b32ee423d3643ecd422821383411ab72 /security | |
parent | 744f9f104ea262de1dc3e29265870c649f0d9473 (diff) | |
parent | e53beacd23d9cb47590da6a7a7f6d417b941a994 (diff) |
Merge commit 'v2.6.37-rc2' into upstream/xenfs
* commit 'v2.6.37-rc2': (10093 commits)
Linux 2.6.37-rc2
capabilities/syslog: open code cap_syslog logic to fix build failure
i2c: Sanity checks on adapter registration
i2c: Mark i2c_adapter.id as deprecated
i2c: Drivers shouldn't include <linux/i2c-id.h>
i2c: Delete unused adapter IDs
i2c: Remove obsolete cleanup for clientdata
include/linux/kernel.h: Move logging bits to include/linux/printk.h
Fix gcc 4.5.1 miscompiling drivers/char/i8k.c (again)
hwmon: (w83795) Check for BEEP pin availability
hwmon: (w83795) Clear intrusion alarm immediately
hwmon: (w83795) Read the intrusion state properly
hwmon: (w83795) Print the actual temperature channels as sources
hwmon: (w83795) List all usable temperature sources
hwmon: (w83795) Expose fan control method
hwmon: (w83795) Fix fan control mode attributes
hwmon: (lm95241) Check validity of input values
hwmon: Change mail address of Hans J. Koch
PCI: sysfs: fix printk warnings
GFS2: Fix inode deallocation race
...
Diffstat (limited to 'security')
36 files changed, 1878 insertions, 348 deletions
diff --git a/security/Kconfig b/security/Kconfig index bd72ae623494..e80da955e687 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -39,6 +39,18 @@ config KEYS_DEBUG_PROC_KEYS | |||
39 | 39 | ||
40 | If you are unsure as to whether this is required, answer N. | 40 | If you are unsure as to whether this is required, answer N. |
41 | 41 | ||
42 | config SECURITY_DMESG_RESTRICT | ||
43 | bool "Restrict unprivileged access to the kernel syslog" | ||
44 | default n | ||
45 | help | ||
46 | This enforces restrictions on unprivileged users reading the kernel | ||
47 | syslog via dmesg(8). | ||
48 | |||
49 | If this option is not selected, no restrictions will be enforced | ||
50 | unless the dmesg_restrict sysctl is explicitly set to (1). | ||
51 | |||
52 | If you are unsure how to answer this question, answer N. | ||
53 | |||
42 | config SECURITY | 54 | config SECURITY |
43 | bool "Enable different security models" | 55 | bool "Enable different security models" |
44 | depends on SYSFS | 56 | depends on SYSFS |
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore index 0a0a99f3b083..4d995aeaebc0 100644 --- a/security/apparmor/.gitignore +++ b/security/apparmor/.gitignore | |||
@@ -3,3 +3,4 @@ | |||
3 | # | 3 | # |
4 | af_names.h | 4 | af_names.h |
5 | capability_names.h | 5 | capability_names.h |
6 | rlim_names.h | ||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 7320331b44ab..0848292982a2 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c | |||
@@ -29,7 +29,7 @@ | |||
29 | * aa_simple_write_to_buffer - common routine for getting policy from user | 29 | * aa_simple_write_to_buffer - common routine for getting policy from user |
30 | * @op: operation doing the user buffer copy | 30 | * @op: operation doing the user buffer copy |
31 | * @userbuf: user buffer to copy data from (NOT NULL) | 31 | * @userbuf: user buffer to copy data from (NOT NULL) |
32 | * @alloc_size: size of user buffer | 32 | * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size) |
33 | * @copy_size: size of data to copy from user buffer | 33 | * @copy_size: size of data to copy from user buffer |
34 | * @pos: position write is at in the file (NOT NULL) | 34 | * @pos: position write is at in the file (NOT NULL) |
35 | * | 35 | * |
@@ -42,6 +42,8 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, | |||
42 | { | 42 | { |
43 | char *data; | 43 | char *data; |
44 | 44 | ||
45 | BUG_ON(copy_size > alloc_size); | ||
46 | |||
45 | if (*pos != 0) | 47 | if (*pos != 0) |
46 | /* only writes from pos 0, that is complete writes */ | 48 | /* only writes from pos 0, that is complete writes */ |
47 | return ERR_PTR(-ESPIPE); | 49 | return ERR_PTR(-ESPIPE); |
@@ -86,7 +88,8 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, | |||
86 | } | 88 | } |
87 | 89 | ||
88 | static const struct file_operations aa_fs_profile_load = { | 90 | static const struct file_operations aa_fs_profile_load = { |
89 | .write = profile_load | 91 | .write = profile_load, |
92 | .llseek = default_llseek, | ||
90 | }; | 93 | }; |
91 | 94 | ||
92 | /* .replace file hook fn to load and/or replace policy */ | 95 | /* .replace file hook fn to load and/or replace policy */ |
@@ -107,7 +110,8 @@ static ssize_t profile_replace(struct file *f, const char __user *buf, | |||
107 | } | 110 | } |
108 | 111 | ||
109 | static const struct file_operations aa_fs_profile_replace = { | 112 | static const struct file_operations aa_fs_profile_replace = { |
110 | .write = profile_replace | 113 | .write = profile_replace, |
114 | .llseek = default_llseek, | ||
111 | }; | 115 | }; |
112 | 116 | ||
113 | /* .remove file hook fn to remove loaded policy */ | 117 | /* .remove file hook fn to remove loaded policy */ |
@@ -134,7 +138,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, | |||
134 | } | 138 | } |
135 | 139 | ||
136 | static const struct file_operations aa_fs_profile_remove = { | 140 | static const struct file_operations aa_fs_profile_remove = { |
137 | .write = profile_remove | 141 | .write = profile_remove, |
142 | .llseek = default_llseek, | ||
138 | }; | 143 | }; |
139 | 144 | ||
140 | /** Base file system setup **/ | 145 | /** Base file system setup **/ |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index cf1de4462ccd..b7106f192b75 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -922,7 +922,7 @@ static int __init apparmor_init(void) | |||
922 | error = register_security(&apparmor_ops); | 922 | error = register_security(&apparmor_ops); |
923 | if (error) { | 923 | if (error) { |
924 | AA_ERROR("Unable to register AppArmor\n"); | 924 | AA_ERROR("Unable to register AppArmor\n"); |
925 | goto register_security_out; | 925 | goto set_init_cxt_out; |
926 | } | 926 | } |
927 | 927 | ||
928 | /* Report that AppArmor successfully initialized */ | 928 | /* Report that AppArmor successfully initialized */ |
@@ -936,6 +936,9 @@ static int __init apparmor_init(void) | |||
936 | 936 | ||
937 | return error; | 937 | return error; |
938 | 938 | ||
939 | set_init_cxt_out: | ||
940 | aa_free_task_context(current->real_cred->security); | ||
941 | |||
939 | register_security_out: | 942 | register_security_out: |
940 | aa_free_root_ns(); | 943 | aa_free_root_ns(); |
941 | 944 | ||
@@ -944,7 +947,6 @@ alloc_out: | |||
944 | 947 | ||
945 | apparmor_enabled = 0; | 948 | apparmor_enabled = 0; |
946 | return error; | 949 | return error; |
947 | |||
948 | } | 950 | } |
949 | 951 | ||
950 | security_initcall(apparmor_init); | 952 | security_initcall(apparmor_init); |
diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 82396050f186..36cc0cc39e78 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c | |||
@@ -72,10 +72,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, | |||
72 | path_get(&root); | 72 | path_get(&root); |
73 | } | 73 | } |
74 | 74 | ||
75 | spin_lock(&dcache_lock); | ||
76 | tmp = root; | 75 | tmp = root; |
77 | res = __d_path(path, &tmp, buf, buflen); | 76 | res = __d_path(path, &tmp, buf, buflen); |
78 | spin_unlock(&dcache_lock); | ||
79 | 77 | ||
80 | *name = res; | 78 | *name = res; |
81 | /* handle error conditions - and still allow a partial path to | 79 | /* handle error conditions - and still allow a partial path to |
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 52cc865f1464..4f0eadee78b8 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -306,7 +306,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, | |||
306 | return ns; | 306 | return ns; |
307 | 307 | ||
308 | fail_unconfined: | 308 | fail_unconfined: |
309 | kzfree(ns->base.name); | 309 | kzfree(ns->base.hname); |
310 | fail_ns: | 310 | fail_ns: |
311 | kzfree(ns); | 311 | kzfree(ns); |
312 | return NULL; | 312 | return NULL; |
diff --git a/security/capability.c b/security/capability.c index 95a6599a37bb..c773635ca3a0 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -17,6 +17,11 @@ static int cap_sysctl(ctl_table *table, int op) | |||
17 | return 0; | 17 | return 0; |
18 | } | 18 | } |
19 | 19 | ||
20 | static int cap_syslog(int type) | ||
21 | { | ||
22 | return 0; | ||
23 | } | ||
24 | |||
20 | static int cap_quotactl(int cmds, int type, int id, struct super_block *sb) | 25 | static int cap_quotactl(int cmds, int type, int id, struct super_block *sb) |
21 | { | 26 | { |
22 | return 0; | 27 | return 0; |
@@ -677,7 +682,18 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
677 | { | 682 | { |
678 | } | 683 | } |
679 | 684 | ||
685 | static int cap_secmark_relabel_packet(u32 secid) | ||
686 | { | ||
687 | return 0; | ||
688 | } | ||
680 | 689 | ||
690 | static void cap_secmark_refcount_inc(void) | ||
691 | { | ||
692 | } | ||
693 | |||
694 | static void cap_secmark_refcount_dec(void) | ||
695 | { | ||
696 | } | ||
681 | 697 | ||
682 | static void cap_req_classify_flow(const struct request_sock *req, | 698 | static void cap_req_classify_flow(const struct request_sock *req, |
683 | struct flowi *fl) | 699 | struct flowi *fl) |
@@ -777,7 +793,8 @@ static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
777 | 793 | ||
778 | static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) | 794 | static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) |
779 | { | 795 | { |
780 | return -EOPNOTSUPP; | 796 | *secid = 0; |
797 | return 0; | ||
781 | } | 798 | } |
782 | 799 | ||
783 | static void cap_release_secctx(char *secdata, u32 seclen) | 800 | static void cap_release_secctx(char *secdata, u32 seclen) |
@@ -1018,6 +1035,9 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
1018 | set_to_cap_if_null(ops, inet_conn_request); | 1035 | set_to_cap_if_null(ops, inet_conn_request); |
1019 | set_to_cap_if_null(ops, inet_csk_clone); | 1036 | set_to_cap_if_null(ops, inet_csk_clone); |
1020 | set_to_cap_if_null(ops, inet_conn_established); | 1037 | set_to_cap_if_null(ops, inet_conn_established); |
1038 | set_to_cap_if_null(ops, secmark_relabel_packet); | ||
1039 | set_to_cap_if_null(ops, secmark_refcount_inc); | ||
1040 | set_to_cap_if_null(ops, secmark_refcount_dec); | ||
1021 | set_to_cap_if_null(ops, req_classify_flow); | 1041 | set_to_cap_if_null(ops, req_classify_flow); |
1022 | set_to_cap_if_null(ops, tun_dev_create); | 1042 | set_to_cap_if_null(ops, tun_dev_create); |
1023 | set_to_cap_if_null(ops, tun_dev_post_create); | 1043 | set_to_cap_if_null(ops, tun_dev_post_create); |
diff --git a/security/commoncap.c b/security/commoncap.c index 9d172e6e330c..64c2ed9c9015 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/prctl.h> | 28 | #include <linux/prctl.h> |
29 | #include <linux/securebits.h> | 29 | #include <linux/securebits.h> |
30 | #include <linux/syslog.h> | ||
31 | 30 | ||
32 | /* | 31 | /* |
33 | * If a non-root user executes a setuid-root binary in | 32 | * If a non-root user executes a setuid-root binary in |
@@ -719,14 +718,11 @@ static int cap_safe_nice(struct task_struct *p) | |||
719 | /** | 718 | /** |
720 | * cap_task_setscheduler - Detemine if scheduler policy change is permitted | 719 | * cap_task_setscheduler - Detemine if scheduler policy change is permitted |
721 | * @p: The task to affect | 720 | * @p: The task to affect |
722 | * @policy: The policy to effect | ||
723 | * @lp: The parameters to the scheduling policy | ||
724 | * | 721 | * |
725 | * Detemine if the requested scheduler policy change is permitted for the | 722 | * Detemine if the requested scheduler policy change is permitted for the |
726 | * specified task, returning 0 if permission is granted, -ve if denied. | 723 | * specified task, returning 0 if permission is granted, -ve if denied. |
727 | */ | 724 | */ |
728 | int cap_task_setscheduler(struct task_struct *p, int policy, | 725 | int cap_task_setscheduler(struct task_struct *p) |
729 | struct sched_param *lp) | ||
730 | { | 726 | { |
731 | return cap_safe_nice(p); | 727 | return cap_safe_nice(p); |
732 | } | 728 | } |
@@ -887,24 +883,6 @@ error: | |||
887 | } | 883 | } |
888 | 884 | ||
889 | /** | 885 | /** |
890 | * cap_syslog - Determine whether syslog function is permitted | ||
891 | * @type: Function requested | ||
892 | * @from_file: Whether this request came from an open file (i.e. /proc) | ||
893 | * | ||
894 | * Determine whether the current process is permitted to use a particular | ||
895 | * syslog function, returning 0 if permission is granted, -ve if not. | ||
896 | */ | ||
897 | int cap_syslog(int type, bool from_file) | ||
898 | { | ||
899 | if (type != SYSLOG_ACTION_OPEN && from_file) | ||
900 | return 0; | ||
901 | if ((type != SYSLOG_ACTION_READ_ALL && | ||
902 | type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) | ||
903 | return -EPERM; | ||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | /** | ||
908 | * cap_vm_enough_memory - Determine whether a new virtual mapping is permitted | 886 | * cap_vm_enough_memory - Determine whether a new virtual mapping is permitted |
909 | * @mm: The VM space in which the new mapping is to be made | 887 | * @mm: The VM space in which the new mapping is to be made |
910 | * @pages: The size of the mapping | 888 | * @pages: The size of the mapping |
diff --git a/security/inode.c b/security/inode.c index 8c777f022ad1..c4df2fbebe6b 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -53,6 +53,7 @@ static const struct file_operations default_file_ops = { | |||
53 | .read = default_read_file, | 53 | .read = default_read_file, |
54 | .write = default_write_file, | 54 | .write = default_write_file, |
55 | .open = default_open, | 55 | .open = default_open, |
56 | .llseek = noop_llseek, | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) | 59 | static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) |
@@ -60,6 +61,7 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) | |||
60 | struct inode *inode = new_inode(sb); | 61 | struct inode *inode = new_inode(sb); |
61 | 62 | ||
62 | if (inode) { | 63 | if (inode) { |
64 | inode->i_ino = get_next_ino(); | ||
63 | inode->i_mode = mode; | 65 | inode->i_mode = mode; |
64 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 66 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
65 | switch (mode & S_IFMT) { | 67 | switch (mode & S_IFMT) { |
@@ -129,17 +131,17 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
129 | return simple_fill_super(sb, SECURITYFS_MAGIC, files); | 131 | return simple_fill_super(sb, SECURITYFS_MAGIC, files); |
130 | } | 132 | } |
131 | 133 | ||
132 | static int get_sb(struct file_system_type *fs_type, | 134 | static struct dentry *get_sb(struct file_system_type *fs_type, |
133 | int flags, const char *dev_name, | 135 | int flags, const char *dev_name, |
134 | void *data, struct vfsmount *mnt) | 136 | void *data) |
135 | { | 137 | { |
136 | return get_sb_single(fs_type, flags, data, fill_super, mnt); | 138 | return mount_single(fs_type, flags, data, fill_super); |
137 | } | 139 | } |
138 | 140 | ||
139 | static struct file_system_type fs_type = { | 141 | static struct file_system_type fs_type = { |
140 | .owner = THIS_MODULE, | 142 | .owner = THIS_MODULE, |
141 | .name = "securityfs", | 143 | .name = "securityfs", |
142 | .get_sb = get_sb, | 144 | .mount = get_sb, |
143 | .kill_sb = kill_litter_super, | 145 | .kill_sb = kill_litter_super, |
144 | }; | 146 | }; |
145 | 147 | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 3fbcd1dda0ef..ac79032bdf23 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -70,6 +70,7 @@ int ima_init(void); | |||
70 | void ima_cleanup(void); | 70 | void ima_cleanup(void); |
71 | int ima_fs_init(void); | 71 | int ima_fs_init(void); |
72 | void ima_fs_cleanup(void); | 72 | void ima_fs_cleanup(void); |
73 | int ima_inode_alloc(struct inode *inode); | ||
73 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 74 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, |
74 | const char *op, struct inode *inode); | 75 | const char *op, struct inode *inode); |
75 | int ima_calc_hash(struct file *file, char *digest); | 76 | int ima_calc_hash(struct file *file, char *digest); |
@@ -96,19 +97,16 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
96 | } | 97 | } |
97 | 98 | ||
98 | /* iint cache flags */ | 99 | /* iint cache flags */ |
99 | #define IMA_MEASURED 1 | 100 | #define IMA_MEASURED 0x01 |
100 | 101 | ||
101 | /* integrity data associated with an inode */ | 102 | /* integrity data associated with an inode */ |
102 | struct ima_iint_cache { | 103 | struct ima_iint_cache { |
104 | struct rb_node rb_node; /* rooted in ima_iint_tree */ | ||
105 | struct inode *inode; /* back pointer to inode in question */ | ||
103 | u64 version; /* track inode changes */ | 106 | u64 version; /* track inode changes */ |
104 | unsigned long flags; | 107 | unsigned char flags; |
105 | u8 digest[IMA_DIGEST_SIZE]; | 108 | u8 digest[IMA_DIGEST_SIZE]; |
106 | struct mutex mutex; /* protects: version, flags, digest */ | 109 | struct mutex mutex; /* protects: version, flags, digest */ |
107 | long readcount; /* measured files readcount */ | ||
108 | long writecount; /* measured files writecount */ | ||
109 | long opencount; /* opens reference count */ | ||
110 | struct kref refcount; /* ima_iint_cache reference count */ | ||
111 | struct rcu_head rcu; | ||
112 | }; | 110 | }; |
113 | 111 | ||
114 | /* LIM API function definitions */ | 112 | /* LIM API function definitions */ |
@@ -122,13 +120,11 @@ int ima_store_template(struct ima_template_entry *entry, int violation, | |||
122 | void ima_template_show(struct seq_file *m, void *e, | 120 | void ima_template_show(struct seq_file *m, void *e, |
123 | enum ima_show_type show); | 121 | enum ima_show_type show); |
124 | 122 | ||
125 | /* radix tree calls to lookup, insert, delete | 123 | /* rbtree tree calls to lookup, insert, delete |
126 | * integrity data associated with an inode. | 124 | * integrity data associated with an inode. |
127 | */ | 125 | */ |
128 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); | 126 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); |
129 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); | 127 | struct ima_iint_cache *ima_iint_find(struct inode *inode); |
130 | void iint_free(struct kref *kref); | ||
131 | void iint_rcu_free(struct rcu_head *rcu); | ||
132 | 128 | ||
133 | /* IMA policy related functions */ | 129 | /* IMA policy related functions */ |
134 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 52015d098fdf..d3963de6003d 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -116,7 +116,7 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | |||
116 | { | 116 | { |
117 | int must_measure; | 117 | int must_measure; |
118 | 118 | ||
119 | if (iint->flags & IMA_MEASURED) | 119 | if (iint && iint->flags & IMA_MEASURED) |
120 | return 1; | 120 | return 1; |
121 | 121 | ||
122 | must_measure = ima_match_policy(inode, function, mask); | 122 | must_measure = ima_match_policy(inode, function, mask); |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index afba4aef812f..c442e47b6785 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
@@ -12,98 +12,119 @@ | |||
12 | * File: ima_iint.c | 12 | * File: ima_iint.c |
13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free | 13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free |
14 | * - cache integrity information associated with an inode | 14 | * - cache integrity information associated with an inode |
15 | * using a radix tree. | 15 | * using a rbtree tree. |
16 | */ | 16 | */ |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/radix-tree.h> | 20 | #include <linux/rbtree.h> |
21 | #include "ima.h" | 21 | #include "ima.h" |
22 | 22 | ||
23 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); | 23 | static struct rb_root ima_iint_tree = RB_ROOT; |
24 | DEFINE_SPINLOCK(ima_iint_lock); | 24 | static DEFINE_SPINLOCK(ima_iint_lock); |
25 | static struct kmem_cache *iint_cache __read_mostly; | 25 | static struct kmem_cache *iint_cache __read_mostly; |
26 | 26 | ||
27 | int iint_initialized = 0; | 27 | int iint_initialized = 0; |
28 | 28 | ||
29 | /* ima_iint_find_get - return the iint associated with an inode | 29 | /* |
30 | * | 30 | * __ima_iint_find - return the iint associated with an inode |
31 | * ima_iint_find_get gets a reference to the iint. Caller must | ||
32 | * remember to put the iint reference. | ||
33 | */ | 31 | */ |
34 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode) | 32 | static struct ima_iint_cache *__ima_iint_find(struct inode *inode) |
35 | { | 33 | { |
36 | struct ima_iint_cache *iint; | 34 | struct ima_iint_cache *iint; |
35 | struct rb_node *n = ima_iint_tree.rb_node; | ||
36 | |||
37 | assert_spin_locked(&ima_iint_lock); | ||
38 | |||
39 | while (n) { | ||
40 | iint = rb_entry(n, struct ima_iint_cache, rb_node); | ||
41 | |||
42 | if (inode < iint->inode) | ||
43 | n = n->rb_left; | ||
44 | else if (inode > iint->inode) | ||
45 | n = n->rb_right; | ||
46 | else | ||
47 | break; | ||
48 | } | ||
49 | if (!n) | ||
50 | return NULL; | ||
37 | 51 | ||
38 | rcu_read_lock(); | ||
39 | iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode); | ||
40 | if (!iint) | ||
41 | goto out; | ||
42 | kref_get(&iint->refcount); | ||
43 | out: | ||
44 | rcu_read_unlock(); | ||
45 | return iint; | 52 | return iint; |
46 | } | 53 | } |
47 | 54 | ||
48 | /** | 55 | /* |
49 | * ima_inode_alloc - allocate an iint associated with an inode | 56 | * ima_iint_find - return the iint associated with an inode |
50 | * @inode: pointer to the inode | ||
51 | */ | 57 | */ |
52 | int ima_inode_alloc(struct inode *inode) | 58 | struct ima_iint_cache *ima_iint_find(struct inode *inode) |
53 | { | 59 | { |
54 | struct ima_iint_cache *iint = NULL; | 60 | struct ima_iint_cache *iint; |
55 | int rc = 0; | ||
56 | |||
57 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
58 | if (!iint) | ||
59 | return -ENOMEM; | ||
60 | 61 | ||
61 | rc = radix_tree_preload(GFP_NOFS); | 62 | if (!IS_IMA(inode)) |
62 | if (rc < 0) | 63 | return NULL; |
63 | goto out; | ||
64 | 64 | ||
65 | spin_lock(&ima_iint_lock); | 65 | spin_lock(&ima_iint_lock); |
66 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); | 66 | iint = __ima_iint_find(inode); |
67 | spin_unlock(&ima_iint_lock); | 67 | spin_unlock(&ima_iint_lock); |
68 | radix_tree_preload_end(); | ||
69 | out: | ||
70 | if (rc < 0) | ||
71 | kmem_cache_free(iint_cache, iint); | ||
72 | 68 | ||
73 | return rc; | 69 | return iint; |
74 | } | 70 | } |
75 | 71 | ||
76 | /* iint_free - called when the iint refcount goes to zero */ | 72 | static void iint_free(struct ima_iint_cache *iint) |
77 | void iint_free(struct kref *kref) | ||
78 | { | 73 | { |
79 | struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache, | ||
80 | refcount); | ||
81 | iint->version = 0; | 74 | iint->version = 0; |
82 | iint->flags = 0UL; | 75 | iint->flags = 0UL; |
83 | if (iint->readcount != 0) { | ||
84 | printk(KERN_INFO "%s: readcount: %ld\n", __func__, | ||
85 | iint->readcount); | ||
86 | iint->readcount = 0; | ||
87 | } | ||
88 | if (iint->writecount != 0) { | ||
89 | printk(KERN_INFO "%s: writecount: %ld\n", __func__, | ||
90 | iint->writecount); | ||
91 | iint->writecount = 0; | ||
92 | } | ||
93 | if (iint->opencount != 0) { | ||
94 | printk(KERN_INFO "%s: opencount: %ld\n", __func__, | ||
95 | iint->opencount); | ||
96 | iint->opencount = 0; | ||
97 | } | ||
98 | kref_init(&iint->refcount); | ||
99 | kmem_cache_free(iint_cache, iint); | 76 | kmem_cache_free(iint_cache, iint); |
100 | } | 77 | } |
101 | 78 | ||
102 | void iint_rcu_free(struct rcu_head *rcu_head) | 79 | /** |
80 | * ima_inode_alloc - allocate an iint associated with an inode | ||
81 | * @inode: pointer to the inode | ||
82 | */ | ||
83 | int ima_inode_alloc(struct inode *inode) | ||
103 | { | 84 | { |
104 | struct ima_iint_cache *iint = container_of(rcu_head, | 85 | struct rb_node **p; |
105 | struct ima_iint_cache, rcu); | 86 | struct rb_node *new_node, *parent = NULL; |
106 | kref_put(&iint->refcount, iint_free); | 87 | struct ima_iint_cache *new_iint, *test_iint; |
88 | int rc; | ||
89 | |||
90 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
91 | if (!new_iint) | ||
92 | return -ENOMEM; | ||
93 | |||
94 | new_iint->inode = inode; | ||
95 | new_node = &new_iint->rb_node; | ||
96 | |||
97 | mutex_lock(&inode->i_mutex); /* i_flags */ | ||
98 | spin_lock(&ima_iint_lock); | ||
99 | |||
100 | p = &ima_iint_tree.rb_node; | ||
101 | while (*p) { | ||
102 | parent = *p; | ||
103 | test_iint = rb_entry(parent, struct ima_iint_cache, rb_node); | ||
104 | |||
105 | rc = -EEXIST; | ||
106 | if (inode < test_iint->inode) | ||
107 | p = &(*p)->rb_left; | ||
108 | else if (inode > test_iint->inode) | ||
109 | p = &(*p)->rb_right; | ||
110 | else | ||
111 | goto out_err; | ||
112 | } | ||
113 | |||
114 | inode->i_flags |= S_IMA; | ||
115 | rb_link_node(new_node, parent, p); | ||
116 | rb_insert_color(new_node, &ima_iint_tree); | ||
117 | |||
118 | spin_unlock(&ima_iint_lock); | ||
119 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
120 | |||
121 | return 0; | ||
122 | out_err: | ||
123 | spin_unlock(&ima_iint_lock); | ||
124 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
125 | iint_free(new_iint); | ||
126 | |||
127 | return rc; | ||
107 | } | 128 | } |
108 | 129 | ||
109 | /** | 130 | /** |
@@ -116,11 +137,20 @@ void ima_inode_free(struct inode *inode) | |||
116 | { | 137 | { |
117 | struct ima_iint_cache *iint; | 138 | struct ima_iint_cache *iint; |
118 | 139 | ||
140 | if (inode->i_readcount) | ||
141 | printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount); | ||
142 | |||
143 | inode->i_readcount = 0; | ||
144 | |||
145 | if (!IS_IMA(inode)) | ||
146 | return; | ||
147 | |||
119 | spin_lock(&ima_iint_lock); | 148 | spin_lock(&ima_iint_lock); |
120 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | 149 | iint = __ima_iint_find(inode); |
150 | rb_erase(&iint->rb_node, &ima_iint_tree); | ||
121 | spin_unlock(&ima_iint_lock); | 151 | spin_unlock(&ima_iint_lock); |
122 | if (iint) | 152 | |
123 | call_rcu(&iint->rcu, iint_rcu_free); | 153 | iint_free(iint); |
124 | } | 154 | } |
125 | 155 | ||
126 | static void init_once(void *foo) | 156 | static void init_once(void *foo) |
@@ -131,10 +161,6 @@ static void init_once(void *foo) | |||
131 | iint->version = 0; | 161 | iint->version = 0; |
132 | iint->flags = 0UL; | 162 | iint->flags = 0UL; |
133 | mutex_init(&iint->mutex); | 163 | mutex_init(&iint->mutex); |
134 | iint->readcount = 0; | ||
135 | iint->writecount = 0; | ||
136 | iint->opencount = 0; | ||
137 | kref_init(&iint->refcount); | ||
138 | } | 164 | } |
139 | 165 | ||
140 | static int __init ima_iintcache_init(void) | 166 | static int __init ima_iintcache_init(void) |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index e662b89d4079..203de979d305 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -85,50 +85,6 @@ out: | |||
85 | return found; | 85 | return found; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
89 | * | ||
90 | * When opening a file for read, if the file is already open for write, | ||
91 | * the file could change, resulting in a file measurement error. | ||
92 | * | ||
93 | * Opening a file for write, if the file is already open for read, results | ||
94 | * in a time of measure, time of use (ToMToU) error. | ||
95 | * | ||
96 | * In either case invalidate the PCR. | ||
97 | */ | ||
98 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
99 | static void ima_read_write_check(enum iint_pcr_error error, | ||
100 | struct ima_iint_cache *iint, | ||
101 | struct inode *inode, | ||
102 | const unsigned char *filename) | ||
103 | { | ||
104 | switch (error) { | ||
105 | case TOMTOU: | ||
106 | if (iint->readcount > 0) | ||
107 | ima_add_violation(inode, filename, "invalid_pcr", | ||
108 | "ToMToU"); | ||
109 | break; | ||
110 | case OPEN_WRITERS: | ||
111 | if (iint->writecount > 0) | ||
112 | ima_add_violation(inode, filename, "invalid_pcr", | ||
113 | "open_writers"); | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Update the counts given an fmode_t | ||
120 | */ | ||
121 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | ||
122 | { | ||
123 | BUG_ON(!mutex_is_locked(&iint->mutex)); | ||
124 | |||
125 | iint->opencount++; | ||
126 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
127 | iint->readcount++; | ||
128 | if (mode & FMODE_WRITE) | ||
129 | iint->writecount++; | ||
130 | } | ||
131 | |||
132 | /* | 88 | /* |
133 | * ima_counts_get - increment file counts | 89 | * ima_counts_get - increment file counts |
134 | * | 90 | * |
@@ -145,62 +101,101 @@ void ima_counts_get(struct file *file) | |||
145 | struct dentry *dentry = file->f_path.dentry; | 101 | struct dentry *dentry = file->f_path.dentry; |
146 | struct inode *inode = dentry->d_inode; | 102 | struct inode *inode = dentry->d_inode; |
147 | fmode_t mode = file->f_mode; | 103 | fmode_t mode = file->f_mode; |
148 | struct ima_iint_cache *iint; | ||
149 | int rc; | 104 | int rc; |
105 | bool send_tomtou = false, send_writers = false; | ||
150 | 106 | ||
151 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 107 | if (!S_ISREG(inode->i_mode)) |
152 | return; | 108 | return; |
153 | iint = ima_iint_find_get(inode); | 109 | |
154 | if (!iint) | 110 | spin_lock(&inode->i_lock); |
155 | return; | 111 | |
156 | mutex_lock(&iint->mutex); | ||
157 | if (!ima_initialized) | 112 | if (!ima_initialized) |
158 | goto out; | 113 | goto out; |
159 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | ||
160 | if (rc < 0) | ||
161 | goto out; | ||
162 | 114 | ||
163 | if (mode & FMODE_WRITE) { | 115 | if (mode & FMODE_WRITE) { |
164 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); | 116 | if (inode->i_readcount && IS_IMA(inode)) |
117 | send_tomtou = true; | ||
165 | goto out; | 118 | goto out; |
166 | } | 119 | } |
167 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | 120 | |
121 | rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK); | ||
122 | if (rc < 0) | ||
123 | goto out; | ||
124 | |||
125 | if (atomic_read(&inode->i_writecount) > 0) | ||
126 | send_writers = true; | ||
168 | out: | 127 | out: |
169 | ima_inc_counts(iint, file->f_mode); | 128 | /* remember the vfs deals with i_writecount */ |
170 | mutex_unlock(&iint->mutex); | 129 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) |
130 | inode->i_readcount++; | ||
171 | 131 | ||
172 | kref_put(&iint->refcount, iint_free); | 132 | spin_unlock(&inode->i_lock); |
133 | |||
134 | if (send_tomtou) | ||
135 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
136 | "ToMToU"); | ||
137 | if (send_writers) | ||
138 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
139 | "open_writers"); | ||
173 | } | 140 | } |
174 | 141 | ||
175 | /* | 142 | /* |
176 | * Decrement ima counts | 143 | * Decrement ima counts |
177 | */ | 144 | */ |
178 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | 145 | static void ima_dec_counts(struct inode *inode, struct file *file) |
179 | struct file *file) | ||
180 | { | 146 | { |
181 | mode_t mode = file->f_mode; | 147 | mode_t mode = file->f_mode; |
182 | BUG_ON(!mutex_is_locked(&iint->mutex)); | ||
183 | 148 | ||
184 | iint->opencount--; | 149 | assert_spin_locked(&inode->i_lock); |
185 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 150 | |
186 | iint->readcount--; | 151 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { |
187 | if (mode & FMODE_WRITE) { | 152 | if (unlikely(inode->i_readcount == 0)) { |
188 | iint->writecount--; | 153 | if (!ima_limit_imbalance(file)) { |
189 | if (iint->writecount == 0) { | 154 | printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", |
190 | if (iint->version != inode->i_version) | 155 | __func__, inode->i_readcount); |
191 | iint->flags &= ~IMA_MEASURED; | 156 | dump_stack(); |
157 | } | ||
158 | return; | ||
192 | } | 159 | } |
160 | inode->i_readcount--; | ||
193 | } | 161 | } |
162 | } | ||
194 | 163 | ||
195 | if (((iint->opencount < 0) || | 164 | static void ima_check_last_writer(struct ima_iint_cache *iint, |
196 | (iint->readcount < 0) || | 165 | struct inode *inode, |
197 | (iint->writecount < 0)) && | 166 | struct file *file) |
198 | !ima_limit_imbalance(file)) { | 167 | { |
199 | printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", | 168 | mode_t mode = file->f_mode; |
200 | __func__, iint->readcount, iint->writecount, | 169 | |
201 | iint->opencount); | 170 | BUG_ON(!mutex_is_locked(&iint->mutex)); |
202 | dump_stack(); | 171 | assert_spin_locked(&inode->i_lock); |
203 | } | 172 | |
173 | if (mode & FMODE_WRITE && | ||
174 | atomic_read(&inode->i_writecount) == 1 && | ||
175 | iint->version != inode->i_version) | ||
176 | iint->flags &= ~IMA_MEASURED; | ||
177 | } | ||
178 | |||
179 | static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode, | ||
180 | struct file *file) | ||
181 | { | ||
182 | mutex_lock(&iint->mutex); | ||
183 | spin_lock(&inode->i_lock); | ||
184 | |||
185 | ima_dec_counts(inode, file); | ||
186 | ima_check_last_writer(iint, inode, file); | ||
187 | |||
188 | spin_unlock(&inode->i_lock); | ||
189 | mutex_unlock(&iint->mutex); | ||
190 | } | ||
191 | |||
192 | static void ima_file_free_noiint(struct inode *inode, struct file *file) | ||
193 | { | ||
194 | spin_lock(&inode->i_lock); | ||
195 | |||
196 | ima_dec_counts(inode, file); | ||
197 | |||
198 | spin_unlock(&inode->i_lock); | ||
204 | } | 199 | } |
205 | 200 | ||
206 | /** | 201 | /** |
@@ -208,7 +203,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
208 | * @file: pointer to file structure being freed | 203 | * @file: pointer to file structure being freed |
209 | * | 204 | * |
210 | * Flag files that changed, based on i_version; | 205 | * Flag files that changed, based on i_version; |
211 | * and decrement the iint readcount/writecount. | 206 | * and decrement the i_readcount. |
212 | */ | 207 | */ |
213 | void ima_file_free(struct file *file) | 208 | void ima_file_free(struct file *file) |
214 | { | 209 | { |
@@ -217,14 +212,14 @@ void ima_file_free(struct file *file) | |||
217 | 212 | ||
218 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 213 | if (!iint_initialized || !S_ISREG(inode->i_mode)) |
219 | return; | 214 | return; |
220 | iint = ima_iint_find_get(inode); | ||
221 | if (!iint) | ||
222 | return; | ||
223 | 215 | ||
224 | mutex_lock(&iint->mutex); | 216 | iint = ima_iint_find(inode); |
225 | ima_dec_counts(iint, inode, file); | 217 | |
226 | mutex_unlock(&iint->mutex); | 218 | if (iint) |
227 | kref_put(&iint->refcount, iint_free); | 219 | ima_file_free_iint(iint, inode, file); |
220 | else | ||
221 | ima_file_free_noiint(inode, file); | ||
222 | |||
228 | } | 223 | } |
229 | 224 | ||
230 | static int process_measurement(struct file *file, const unsigned char *filename, | 225 | static int process_measurement(struct file *file, const unsigned char *filename, |
@@ -236,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
236 | 231 | ||
237 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 232 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
238 | return 0; | 233 | return 0; |
239 | iint = ima_iint_find_get(inode); | 234 | |
240 | if (!iint) | 235 | rc = ima_must_measure(NULL, inode, mask, function); |
241 | return -ENOMEM; | 236 | if (rc != 0) |
237 | return rc; | ||
238 | retry: | ||
239 | iint = ima_iint_find(inode); | ||
240 | if (!iint) { | ||
241 | rc = ima_inode_alloc(inode); | ||
242 | if (!rc || rc == -EEXIST) | ||
243 | goto retry; | ||
244 | return rc; | ||
245 | } | ||
242 | 246 | ||
243 | mutex_lock(&iint->mutex); | 247 | mutex_lock(&iint->mutex); |
248 | |||
244 | rc = ima_must_measure(iint, inode, mask, function); | 249 | rc = ima_must_measure(iint, inode, mask, function); |
245 | if (rc != 0) | 250 | if (rc != 0) |
246 | goto out; | 251 | goto out; |
@@ -250,7 +255,6 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
250 | ima_store_measurement(iint, file, filename); | 255 | ima_store_measurement(iint, file, filename); |
251 | out: | 256 | out: |
252 | mutex_unlock(&iint->mutex); | 257 | mutex_unlock(&iint->mutex); |
253 | kref_put(&iint->refcount, iint_free); | ||
254 | return rc; | 258 | return rc; |
255 | } | 259 | } |
256 | 260 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index f8e7251ae2c8..504bdd2452bd 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -207,7 +207,7 @@ static int install_process_keyring(void) | |||
207 | ret = install_process_keyring_to_cred(new); | 207 | ret = install_process_keyring_to_cred(new); |
208 | if (ret < 0) { | 208 | if (ret < 0) { |
209 | abort_creds(new); | 209 | abort_creds(new); |
210 | return ret != -EEXIST ?: 0; | 210 | return ret != -EEXIST ? ret : 0; |
211 | } | 211 | } |
212 | 212 | ||
213 | return commit_creds(new); | 213 | return commit_creds(new); |
diff --git a/security/security.c b/security/security.c index c53949f17d9e..1b798d3df710 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -89,20 +89,12 @@ __setup("security=", choose_lsm); | |||
89 | * Return true if: | 89 | * Return true if: |
90 | * -The passed LSM is the one chosen by user at boot time, | 90 | * -The passed LSM is the one chosen by user at boot time, |
91 | * -or the passed LSM is configured as the default and the user did not | 91 | * -or the passed LSM is configured as the default and the user did not |
92 | * choose an alternate LSM at boot time, | 92 | * choose an alternate LSM at boot time. |
93 | * -or there is no default LSM set and the user didn't specify a | ||
94 | * specific LSM and we're the first to ask for registration permission, | ||
95 | * -or the passed LSM is currently loaded. | ||
96 | * Otherwise, return false. | 93 | * Otherwise, return false. |
97 | */ | 94 | */ |
98 | int __init security_module_enable(struct security_operations *ops) | 95 | int __init security_module_enable(struct security_operations *ops) |
99 | { | 96 | { |
100 | if (!*chosen_lsm) | 97 | return !strcmp(ops->name, chosen_lsm); |
101 | strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX); | ||
102 | else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX)) | ||
103 | return 0; | ||
104 | |||
105 | return 1; | ||
106 | } | 98 | } |
107 | 99 | ||
108 | /** | 100 | /** |
@@ -205,9 +197,9 @@ int security_quota_on(struct dentry *dentry) | |||
205 | return security_ops->quota_on(dentry); | 197 | return security_ops->quota_on(dentry); |
206 | } | 198 | } |
207 | 199 | ||
208 | int security_syslog(int type, bool from_file) | 200 | int security_syslog(int type) |
209 | { | 201 | { |
210 | return security_ops->syslog(type, from_file); | 202 | return security_ops->syslog(type); |
211 | } | 203 | } |
212 | 204 | ||
213 | int security_settime(struct timespec *ts, struct timezone *tz) | 205 | int security_settime(struct timespec *ts, struct timezone *tz) |
@@ -333,16 +325,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str); | |||
333 | 325 | ||
334 | int security_inode_alloc(struct inode *inode) | 326 | int security_inode_alloc(struct inode *inode) |
335 | { | 327 | { |
336 | int ret; | ||
337 | |||
338 | inode->i_security = NULL; | 328 | inode->i_security = NULL; |
339 | ret = security_ops->inode_alloc_security(inode); | 329 | return security_ops->inode_alloc_security(inode); |
340 | if (ret) | ||
341 | return ret; | ||
342 | ret = ima_inode_alloc(inode); | ||
343 | if (ret) | ||
344 | security_inode_free(inode); | ||
345 | return ret; | ||
346 | } | 330 | } |
347 | 331 | ||
348 | void security_inode_free(struct inode *inode) | 332 | void security_inode_free(struct inode *inode) |
@@ -786,10 +770,9 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource, | |||
786 | return security_ops->task_setrlimit(p, resource, new_rlim); | 770 | return security_ops->task_setrlimit(p, resource, new_rlim); |
787 | } | 771 | } |
788 | 772 | ||
789 | int security_task_setscheduler(struct task_struct *p, | 773 | int security_task_setscheduler(struct task_struct *p) |
790 | int policy, struct sched_param *lp) | ||
791 | { | 774 | { |
792 | return security_ops->task_setscheduler(p, policy, lp); | 775 | return security_ops->task_setscheduler(p); |
793 | } | 776 | } |
794 | 777 | ||
795 | int security_task_getscheduler(struct task_struct *p) | 778 | int security_task_getscheduler(struct task_struct *p) |
@@ -1145,6 +1128,24 @@ void security_inet_conn_established(struct sock *sk, | |||
1145 | security_ops->inet_conn_established(sk, skb); | 1128 | security_ops->inet_conn_established(sk, skb); |
1146 | } | 1129 | } |
1147 | 1130 | ||
1131 | int security_secmark_relabel_packet(u32 secid) | ||
1132 | { | ||
1133 | return security_ops->secmark_relabel_packet(secid); | ||
1134 | } | ||
1135 | EXPORT_SYMBOL(security_secmark_relabel_packet); | ||
1136 | |||
1137 | void security_secmark_refcount_inc(void) | ||
1138 | { | ||
1139 | security_ops->secmark_refcount_inc(); | ||
1140 | } | ||
1141 | EXPORT_SYMBOL(security_secmark_refcount_inc); | ||
1142 | |||
1143 | void security_secmark_refcount_dec(void) | ||
1144 | { | ||
1145 | security_ops->secmark_refcount_dec(); | ||
1146 | } | ||
1147 | EXPORT_SYMBOL(security_secmark_refcount_dec); | ||
1148 | |||
1148 | int security_tun_dev_create(void) | 1149 | int security_tun_dev_create(void) |
1149 | { | 1150 | { |
1150 | return security_ops->tun_dev_create(); | 1151 | return security_ops->tun_dev_create(); |
diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 58d80f3bd6f6..ad5cd76ec231 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile | |||
@@ -2,25 +2,20 @@ | |||
2 | # Makefile for building the SELinux module as part of the kernel tree. | 2 | # Makefile for building the SELinux module as part of the kernel tree. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/ | 5 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o |
6 | 6 | ||
7 | selinux-y := avc.o \ | 7 | selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ |
8 | hooks.o \ | 8 | netnode.o netport.o exports.o \ |
9 | selinuxfs.o \ | 9 | ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ |
10 | netlink.o \ | 10 | ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o |
11 | nlmsgtab.o \ | ||
12 | netif.o \ | ||
13 | netnode.o \ | ||
14 | netport.o \ | ||
15 | exports.o | ||
16 | 11 | ||
17 | selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o | 12 | selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o |
18 | 13 | ||
19 | selinux-$(CONFIG_NETLABEL) += netlabel.o | 14 | selinux-$(CONFIG_NETLABEL) += netlabel.o |
20 | 15 | ||
21 | EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include | 16 | ccflags-y := -Isecurity/selinux -Isecurity/selinux/include |
22 | 17 | ||
23 | $(obj)/avc.o: $(obj)/flask.h | 18 | $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h |
24 | 19 | ||
25 | quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h | 20 | quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h |
26 | cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h | 21 | cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h |
diff --git a/security/selinux/exports.c b/security/selinux/exports.c index c0a454aee1e0..90664385dead 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c | |||
@@ -11,58 +11,9 @@ | |||
11 | * it under the terms of the GNU General Public License version 2, | 11 | * it under the terms of the GNU General Public License version 2, |
12 | * as published by the Free Software Foundation. | 12 | * as published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | 14 | #include <linux/module.h> |
17 | #include <linux/selinux.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/ipc.h> | ||
20 | #include <asm/atomic.h> | ||
21 | 15 | ||
22 | #include "security.h" | 16 | #include "security.h" |
23 | #include "objsec.h" | ||
24 | |||
25 | /* SECMARK reference count */ | ||
26 | extern atomic_t selinux_secmark_refcount; | ||
27 | |||
28 | int selinux_string_to_sid(char *str, u32 *sid) | ||
29 | { | ||
30 | if (selinux_enabled) | ||
31 | return security_context_to_sid(str, strlen(str), sid); | ||
32 | else { | ||
33 | *sid = 0; | ||
34 | return 0; | ||
35 | } | ||
36 | } | ||
37 | EXPORT_SYMBOL_GPL(selinux_string_to_sid); | ||
38 | |||
39 | int selinux_secmark_relabel_packet_permission(u32 sid) | ||
40 | { | ||
41 | if (selinux_enabled) { | ||
42 | const struct task_security_struct *__tsec; | ||
43 | u32 tsid; | ||
44 | |||
45 | __tsec = current_security(); | ||
46 | tsid = __tsec->sid; | ||
47 | |||
48 | return avc_has_perm(tsid, sid, SECCLASS_PACKET, | ||
49 | PACKET__RELABELTO, NULL); | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission); | ||
54 | |||
55 | void selinux_secmark_refcount_inc(void) | ||
56 | { | ||
57 | atomic_inc(&selinux_secmark_refcount); | ||
58 | } | ||
59 | EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc); | ||
60 | |||
61 | void selinux_secmark_refcount_dec(void) | ||
62 | { | ||
63 | atomic_dec(&selinux_secmark_refcount); | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); | ||
66 | 17 | ||
67 | bool selinux_is_enabled(void) | 18 | bool selinux_is_enabled(void) |
68 | { | 19 | { |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4796ddd4e721..65fa8bf596f5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1973,14 +1973,10 @@ static int selinux_quota_on(struct dentry *dentry) | |||
1973 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); | 1973 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); |
1974 | } | 1974 | } |
1975 | 1975 | ||
1976 | static int selinux_syslog(int type, bool from_file) | 1976 | static int selinux_syslog(int type) |
1977 | { | 1977 | { |
1978 | int rc; | 1978 | int rc; |
1979 | 1979 | ||
1980 | rc = cap_syslog(type, from_file); | ||
1981 | if (rc) | ||
1982 | return rc; | ||
1983 | |||
1984 | switch (type) { | 1980 | switch (type) { |
1985 | case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ | 1981 | case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ |
1986 | case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ | 1982 | case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ |
@@ -3354,11 +3350,11 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, | |||
3354 | return 0; | 3350 | return 0; |
3355 | } | 3351 | } |
3356 | 3352 | ||
3357 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) | 3353 | static int selinux_task_setscheduler(struct task_struct *p) |
3358 | { | 3354 | { |
3359 | int rc; | 3355 | int rc; |
3360 | 3356 | ||
3361 | rc = cap_task_setscheduler(p, policy, lp); | 3357 | rc = cap_task_setscheduler(p); |
3362 | if (rc) | 3358 | if (rc) |
3363 | return rc; | 3359 | return rc; |
3364 | 3360 | ||
@@ -4279,6 +4275,27 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
4279 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4275 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
4280 | } | 4276 | } |
4281 | 4277 | ||
4278 | static int selinux_secmark_relabel_packet(u32 sid) | ||
4279 | { | ||
4280 | const struct task_security_struct *__tsec; | ||
4281 | u32 tsid; | ||
4282 | |||
4283 | __tsec = current_security(); | ||
4284 | tsid = __tsec->sid; | ||
4285 | |||
4286 | return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); | ||
4287 | } | ||
4288 | |||
4289 | static void selinux_secmark_refcount_inc(void) | ||
4290 | { | ||
4291 | atomic_inc(&selinux_secmark_refcount); | ||
4292 | } | ||
4293 | |||
4294 | static void selinux_secmark_refcount_dec(void) | ||
4295 | { | ||
4296 | atomic_dec(&selinux_secmark_refcount); | ||
4297 | } | ||
4298 | |||
4282 | static void selinux_req_classify_flow(const struct request_sock *req, | 4299 | static void selinux_req_classify_flow(const struct request_sock *req, |
4283 | struct flowi *fl) | 4300 | struct flowi *fl) |
4284 | { | 4301 | { |
@@ -5533,6 +5550,9 @@ static struct security_operations selinux_ops = { | |||
5533 | .inet_conn_request = selinux_inet_conn_request, | 5550 | .inet_conn_request = selinux_inet_conn_request, |
5534 | .inet_csk_clone = selinux_inet_csk_clone, | 5551 | .inet_csk_clone = selinux_inet_csk_clone, |
5535 | .inet_conn_established = selinux_inet_conn_established, | 5552 | .inet_conn_established = selinux_inet_conn_established, |
5553 | .secmark_relabel_packet = selinux_secmark_relabel_packet, | ||
5554 | .secmark_refcount_inc = selinux_secmark_refcount_inc, | ||
5555 | .secmark_refcount_dec = selinux_secmark_refcount_dec, | ||
5536 | .req_classify_flow = selinux_req_classify_flow, | 5556 | .req_classify_flow = selinux_req_classify_flow, |
5537 | .tun_dev_create = selinux_tun_dev_create, | 5557 | .tun_dev_create = selinux_tun_dev_create, |
5538 | .tun_dev_post_create = selinux_tun_dev_post_create, | 5558 | .tun_dev_post_create = selinux_tun_dev_post_create, |
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 1f7c2491d3dc..671273eb1115 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #define _SELINUX_SECURITY_H_ | 9 | #define _SELINUX_SECURITY_H_ |
10 | 10 | ||
11 | #include <linux/magic.h> | 11 | #include <linux/magic.h> |
12 | #include <linux/types.h> | ||
12 | #include "flask.h" | 13 | #include "flask.h" |
13 | 14 | ||
14 | #define SECSID_NULL 0x00000000 /* unspecified SID */ | 15 | #define SECSID_NULL 0x00000000 /* unspecified SID */ |
@@ -82,6 +83,8 @@ extern int selinux_policycap_openperm; | |||
82 | int security_mls_enabled(void); | 83 | int security_mls_enabled(void); |
83 | 84 | ||
84 | int security_load_policy(void *data, size_t len); | 85 | int security_load_policy(void *data, size_t len); |
86 | int security_read_policy(void **data, ssize_t *len); | ||
87 | size_t security_policydb_len(void); | ||
85 | 88 | ||
86 | int security_policycap_supported(unsigned int req_cap); | 89 | int security_policycap_supported(unsigned int req_cap); |
87 | 90 | ||
@@ -191,5 +194,25 @@ static inline int security_netlbl_sid_to_secattr(u32 sid, | |||
191 | 194 | ||
192 | const char *security_get_initial_sid_context(u32 sid); | 195 | const char *security_get_initial_sid_context(u32 sid); |
193 | 196 | ||
197 | /* | ||
198 | * status notifier using mmap interface | ||
199 | */ | ||
200 | extern struct page *selinux_kernel_status_page(void); | ||
201 | |||
202 | #define SELINUX_KERNEL_STATUS_VERSION 1 | ||
203 | struct selinux_kernel_status { | ||
204 | u32 version; /* version number of thie structure */ | ||
205 | u32 sequence; /* sequence number of seqlock logic */ | ||
206 | u32 enforcing; /* current setting of enforcing mode */ | ||
207 | u32 policyload; /* times of policy reloaded */ | ||
208 | u32 deny_unknown; /* current setting of deny_unknown */ | ||
209 | /* | ||
210 | * The version > 0 supports above members. | ||
211 | */ | ||
212 | } __attribute__((packed)); | ||
213 | |||
214 | extern void selinux_status_update_setenforce(int enforcing); | ||
215 | extern void selinux_status_update_policyload(int seqno); | ||
216 | |||
194 | #endif /* _SELINUX_SECURITY_H_ */ | 217 | #endif /* _SELINUX_SECURITY_H_ */ |
195 | 218 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 79a1bb635662..073fd5b0a53a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -68,6 +68,8 @@ static int *bool_pending_values; | |||
68 | static struct dentry *class_dir; | 68 | static struct dentry *class_dir; |
69 | static unsigned long last_class_ino; | 69 | static unsigned long last_class_ino; |
70 | 70 | ||
71 | static char policy_opened; | ||
72 | |||
71 | /* global data for policy capabilities */ | 73 | /* global data for policy capabilities */ |
72 | static struct dentry *policycap_dir; | 74 | static struct dentry *policycap_dir; |
73 | 75 | ||
@@ -110,6 +112,8 @@ enum sel_inos { | |||
110 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ | 112 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ |
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 */ |
115 | SEL_STATUS, /* export current status using mmap() */ | ||
116 | SEL_POLICY, /* allow userspace to read the in kernel policy */ | ||
113 | SEL_INO_NEXT, /* The next inode number to use */ | 117 | SEL_INO_NEXT, /* The next inode number to use */ |
114 | }; | 118 | }; |
115 | 119 | ||
@@ -171,6 +175,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
171 | if (selinux_enforcing) | 175 | if (selinux_enforcing) |
172 | avc_ss_reset(0); | 176 | avc_ss_reset(0); |
173 | selnl_notify_setenforce(selinux_enforcing); | 177 | selnl_notify_setenforce(selinux_enforcing); |
178 | selinux_status_update_setenforce(selinux_enforcing); | ||
174 | } | 179 | } |
175 | length = count; | 180 | length = count; |
176 | out: | 181 | out: |
@@ -205,6 +210,59 @@ static const struct file_operations sel_handle_unknown_ops = { | |||
205 | .llseek = generic_file_llseek, | 210 | .llseek = generic_file_llseek, |
206 | }; | 211 | }; |
207 | 212 | ||
213 | static int sel_open_handle_status(struct inode *inode, struct file *filp) | ||
214 | { | ||
215 | struct page *status = selinux_kernel_status_page(); | ||
216 | |||
217 | if (!status) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | filp->private_data = status; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static ssize_t sel_read_handle_status(struct file *filp, char __user *buf, | ||
226 | size_t count, loff_t *ppos) | ||
227 | { | ||
228 | struct page *status = filp->private_data; | ||
229 | |||
230 | BUG_ON(!status); | ||
231 | |||
232 | return simple_read_from_buffer(buf, count, ppos, | ||
233 | page_address(status), | ||
234 | sizeof(struct selinux_kernel_status)); | ||
235 | } | ||
236 | |||
237 | static int sel_mmap_handle_status(struct file *filp, | ||
238 | struct vm_area_struct *vma) | ||
239 | { | ||
240 | struct page *status = filp->private_data; | ||
241 | unsigned long size = vma->vm_end - vma->vm_start; | ||
242 | |||
243 | BUG_ON(!status); | ||
244 | |||
245 | /* only allows one page from the head */ | ||
246 | if (vma->vm_pgoff > 0 || size != PAGE_SIZE) | ||
247 | return -EIO; | ||
248 | /* disallow writable mapping */ | ||
249 | if (vma->vm_flags & VM_WRITE) | ||
250 | return -EPERM; | ||
251 | /* disallow mprotect() turns it into writable */ | ||
252 | vma->vm_flags &= ~VM_MAYWRITE; | ||
253 | |||
254 | return remap_pfn_range(vma, vma->vm_start, | ||
255 | page_to_pfn(status), | ||
256 | size, vma->vm_page_prot); | ||
257 | } | ||
258 | |||
259 | static const struct file_operations sel_handle_status_ops = { | ||
260 | .open = sel_open_handle_status, | ||
261 | .read = sel_read_handle_status, | ||
262 | .mmap = sel_mmap_handle_status, | ||
263 | .llseek = generic_file_llseek, | ||
264 | }; | ||
265 | |||
208 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 266 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
209 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, | 267 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, |
210 | size_t count, loff_t *ppos) | 268 | size_t count, loff_t *ppos) |
@@ -296,6 +354,141 @@ static const struct file_operations sel_mls_ops = { | |||
296 | .llseek = generic_file_llseek, | 354 | .llseek = generic_file_llseek, |
297 | }; | 355 | }; |
298 | 356 | ||
357 | struct policy_load_memory { | ||
358 | size_t len; | ||
359 | void *data; | ||
360 | }; | ||
361 | |||
362 | static 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; | ||
401 | err: | ||
402 | mutex_unlock(&sel_mutex); | ||
403 | |||
404 | if (plm) | ||
405 | vfree(plm->data); | ||
406 | kfree(plm); | ||
407 | return rc; | ||
408 | } | ||
409 | |||
410 | static 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 | |||
424 | static 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); | ||
437 | out: | ||
438 | mutex_unlock(&sel_mutex); | ||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | static int sel_mmap_policy_fault(struct vm_area_struct *vma, | ||
443 | struct vm_fault *vmf) | ||
444 | { | ||
445 | struct policy_load_memory *plm = vma->vm_file->private_data; | ||
446 | unsigned long offset; | ||
447 | struct page *page; | ||
448 | |||
449 | if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE)) | ||
450 | return VM_FAULT_SIGBUS; | ||
451 | |||
452 | offset = vmf->pgoff << PAGE_SHIFT; | ||
453 | if (offset >= roundup(plm->len, PAGE_SIZE)) | ||
454 | return VM_FAULT_SIGBUS; | ||
455 | |||
456 | page = vmalloc_to_page(plm->data + offset); | ||
457 | get_page(page); | ||
458 | |||
459 | vmf->page = page; | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct vm_operations_struct sel_mmap_policy_ops = { | ||
465 | .fault = sel_mmap_policy_fault, | ||
466 | .page_mkwrite = sel_mmap_policy_fault, | ||
467 | }; | ||
468 | |||
469 | int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma) | ||
470 | { | ||
471 | if (vma->vm_flags & VM_SHARED) { | ||
472 | /* do not allow mprotect to make mapping writable */ | ||
473 | vma->vm_flags &= ~VM_MAYWRITE; | ||
474 | |||
475 | if (vma->vm_flags & VM_WRITE) | ||
476 | return -EACCES; | ||
477 | } | ||
478 | |||
479 | vma->vm_flags |= VM_RESERVED; | ||
480 | vma->vm_ops = &sel_mmap_policy_ops; | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static const struct file_operations sel_policy_ops = { | ||
486 | .open = sel_open_policy, | ||
487 | .read = sel_read_policy, | ||
488 | .mmap = sel_mmap_policy, | ||
489 | .release = sel_release_policy, | ||
490 | }; | ||
491 | |||
299 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 492 | static ssize_t sel_write_load(struct file *file, const char __user *buf, |
300 | size_t count, loff_t *ppos) | 493 | size_t count, loff_t *ppos) |
301 | 494 | ||
@@ -785,6 +978,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode) | |||
785 | struct inode *ret = new_inode(sb); | 978 | struct inode *ret = new_inode(sb); |
786 | 979 | ||
787 | if (ret) { | 980 | if (ret) { |
981 | ret->i_ino = get_next_ino(); | ||
788 | ret->i_mode = mode; | 982 | ret->i_mode = mode; |
789 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; | 983 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; |
790 | } | 984 | } |
@@ -1612,6 +1806,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1612 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, | 1806 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, |
1613 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1807 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1614 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1808 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1809 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | ||
1810 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | ||
1615 | /* last one */ {""} | 1811 | /* last one */ {""} |
1616 | }; | 1812 | }; |
1617 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1813 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
@@ -1713,16 +1909,15 @@ err: | |||
1713 | goto out; | 1909 | goto out; |
1714 | } | 1910 | } |
1715 | 1911 | ||
1716 | static int sel_get_sb(struct file_system_type *fs_type, | 1912 | static struct dentry *sel_mount(struct file_system_type *fs_type, |
1717 | int flags, const char *dev_name, void *data, | 1913 | int flags, const char *dev_name, void *data) |
1718 | struct vfsmount *mnt) | ||
1719 | { | 1914 | { |
1720 | return get_sb_single(fs_type, flags, data, sel_fill_super, mnt); | 1915 | return mount_single(fs_type, flags, data, sel_fill_super); |
1721 | } | 1916 | } |
1722 | 1917 | ||
1723 | static struct file_system_type sel_fs_type = { | 1918 | static struct file_system_type sel_fs_type = { |
1724 | .name = "selinuxfs", | 1919 | .name = "selinuxfs", |
1725 | .get_sb = sel_get_sb, | 1920 | .mount = sel_mount, |
1726 | .kill_sb = kill_litter_super, | 1921 | .kill_sb = kill_litter_super, |
1727 | }; | 1922 | }; |
1728 | 1923 | ||
diff --git a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile deleted file mode 100644 index 15d4e62917de..000000000000 --- a/security/selinux/ss/Makefile +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for building the SELinux security server as part of the kernel tree. | ||
3 | # | ||
4 | |||
5 | EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include | ||
6 | obj-y := ss.o | ||
7 | |||
8 | ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o | ||
9 | |||
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 929480c6c430..a3dd9faa19c0 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -266,8 +266,8 @@ int avtab_alloc(struct avtab *h, u32 nrules) | |||
266 | if (shift > 2) | 266 | if (shift > 2) |
267 | shift = shift - 2; | 267 | shift = shift - 2; |
268 | nslot = 1 << shift; | 268 | nslot = 1 << shift; |
269 | if (nslot > MAX_AVTAB_SIZE) | 269 | if (nslot > MAX_AVTAB_HASH_BUCKETS) |
270 | nslot = MAX_AVTAB_SIZE; | 270 | nslot = MAX_AVTAB_HASH_BUCKETS; |
271 | mask = nslot - 1; | 271 | mask = nslot - 1; |
272 | 272 | ||
273 | h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL); | 273 | h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL); |
@@ -501,6 +501,48 @@ bad: | |||
501 | goto out; | 501 | goto out; |
502 | } | 502 | } |
503 | 503 | ||
504 | int 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 | |||
524 | int 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 | } | ||
504 | void avtab_cache_init(void) | 546 | void 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 cd4f734e2749..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 | ||
73 | int avtab_read(struct avtab *a, void *fp, struct policydb *pol); | 73 | int avtab_read(struct avtab *a, void *fp, struct policydb *pol); |
74 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp); | ||
75 | int avtab_write(struct policydb *p, struct avtab *a, void *fp); | ||
74 | 76 | ||
75 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, | 77 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, |
76 | struct avtab_datum *datum); | 78 | struct avtab_datum *datum); |
@@ -85,7 +87,6 @@ void avtab_cache_destroy(void); | |||
85 | #define MAX_AVTAB_HASH_BITS 11 | 87 | #define MAX_AVTAB_HASH_BITS 11 |
86 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) | 88 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) |
87 | #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) | 89 | #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) |
88 | #define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS | ||
89 | 90 | ||
90 | #endif /* _SS_AVTAB_H_ */ | 91 | #endif /* _SS_AVTAB_H_ */ |
91 | 92 | ||
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 | ||
493 | int 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 | */ | ||
525 | static 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 | |||
554 | int 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 | |||
593 | int 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 | ||
70 | int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); | 70 | int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp); |
71 | int cond_read_list(struct policydb *p, void *fp); | 71 | int cond_read_list(struct policydb *p, void *fp); |
72 | int cond_write_bool(void *key, void *datum, void *ptr); | ||
73 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); | ||
72 | 74 | ||
73 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); | 75 | void 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 | |||
25 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) | 27 | int 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 | |||
452 | int 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); | |||
123 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); | 123 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); |
124 | void ebitmap_destroy(struct ebitmap *e); | 124 | void ebitmap_destroy(struct ebitmap *e); |
125 | int ebitmap_read(struct ebitmap *e, void *fp); | 125 | int ebitmap_read(struct ebitmap *e, void *fp); |
126 | int ebitmap_write(struct ebitmap *e, void *fp); | ||
126 | 127 | ||
127 | #ifdef CONFIG_NETLABEL | 128 | #ifdef CONFIG_NETLABEL |
128 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 129 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 3a29704be8ce..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 | ||
@@ -185,9 +186,19 @@ static u32 rangetr_hash(struct hashtab *h, const void *k) | |||
185 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) | 186 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) |
186 | { | 187 | { |
187 | const struct range_trans *key1 = k1, *key2 = k2; | 188 | const struct range_trans *key1 = k1, *key2 = k2; |
188 | return (key1->source_type != key2->source_type || | 189 | int v; |
189 | key1->target_type != key2->target_type || | 190 | |
190 | key1->target_class != key2->target_class); | 191 | v = key1->source_type - key2->source_type; |
192 | if (v) | ||
193 | return v; | ||
194 | |||
195 | v = key1->target_type - key2->target_type; | ||
196 | if (v) | ||
197 | return v; | ||
198 | |||
199 | v = key1->target_class - key2->target_class; | ||
200 | |||
201 | return v; | ||
191 | } | 202 | } |
192 | 203 | ||
193 | /* | 204 | /* |
@@ -1624,11 +1635,11 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap) | |||
1624 | 1635 | ||
1625 | static int type_bounds_sanity_check(void *key, void *datum, void *datap) | 1636 | static int type_bounds_sanity_check(void *key, void *datum, void *datap) |
1626 | { | 1637 | { |
1627 | struct type_datum *upper, *type; | 1638 | struct type_datum *upper; |
1628 | struct policydb *p = datap; | 1639 | struct policydb *p = datap; |
1629 | int depth = 0; | 1640 | int depth = 0; |
1630 | 1641 | ||
1631 | upper = type = datum; | 1642 | upper = datum; |
1632 | while (upper->bounds) { | 1643 | while (upper->bounds) { |
1633 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { | 1644 | if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { |
1634 | printk(KERN_ERR "SELinux: type %s: " | 1645 | printk(KERN_ERR "SELinux: type %s: " |
@@ -2306,3 +2317,843 @@ bad: | |||
2306 | policydb_destroy(p); | 2317 | policydb_destroy(p); |
2307 | goto out; | 2318 | goto out; |
2308 | } | 2319 | } |
2320 | |||
2321 | /* | ||
2322 | * Write a MLS level structure to a policydb binary | ||
2323 | * representation file. | ||
2324 | */ | ||
2325 | static 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 | */ | ||
2346 | static 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 | |||
2381 | static 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 | |||
2409 | static 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 | |||
2434 | static 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 | |||
2460 | static 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 | */ | ||
2488 | static 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 | |||
2515 | static 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 | |||
2537 | static 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 | |||
2567 | static 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 | |||
2608 | static 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 | |||
2679 | static 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 | |||
2718 | static 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 | |||
2759 | static 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 | |||
2800 | static 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 | |||
2813 | static 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 | |||
2910 | static 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 | |||
2962 | static int range_count(void *key, void *data, void *ptr) | ||
2963 | { | ||
2964 | int *cnt = ptr; | ||
2965 | *cnt = *cnt + 1; | ||
2966 | |||
2967 | return 0; | ||
2968 | } | ||
2969 | |||
2970 | static 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 | |||
2998 | static 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 | */ | ||
3032 | int 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); | |||
270 | extern int policydb_type_isvalid(struct policydb *p, unsigned int type); | 273 | extern int policydb_type_isvalid(struct policydb *p, unsigned int type); |
271 | extern int policydb_role_isvalid(struct policydb *p, unsigned int role); | 274 | extern int policydb_role_isvalid(struct policydb *p, unsigned int role); |
272 | extern int policydb_read(struct policydb *p, void *fp); | 275 | extern int policydb_read(struct policydb *p, void *fp); |
276 | extern 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 | ||
297 | struct policy_data { | ||
298 | struct policydb *p; | ||
299 | void *fp; | ||
300 | }; | ||
301 | |||
293 | static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) | 302 | static 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 | ||
313 | static 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 | |||
304 | extern u16 string_to_security_class(struct policydb *p, const char *name); | 324 | extern u16 string_to_security_class(struct policydb *p, const char *name); |
305 | extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); | 325 | extern 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 9ea2feca3cd4..223c1ff6ef23 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/mutex.h> | 51 | #include <linux/mutex.h> |
52 | #include <linux/selinux.h> | 52 | #include <linux/selinux.h> |
53 | #include <linux/flex_array.h> | 53 | #include <linux/flex_array.h> |
54 | #include <linux/vmalloc.h> | ||
54 | #include <net/netlabel.h> | 55 | #include <net/netlabel.h> |
55 | 56 | ||
56 | #include "flask.h" | 57 | #include "flask.h" |
@@ -991,7 +992,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
991 | { | 992 | { |
992 | char *scontextp; | 993 | char *scontextp; |
993 | 994 | ||
994 | *scontext = NULL; | 995 | if (scontext) |
996 | *scontext = NULL; | ||
995 | *scontext_len = 0; | 997 | *scontext_len = 0; |
996 | 998 | ||
997 | if (context->len) { | 999 | if (context->len) { |
@@ -1008,6 +1010,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
1008 | *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; | 1010 | *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; |
1009 | *scontext_len += mls_compute_context_len(context); | 1011 | *scontext_len += mls_compute_context_len(context); |
1010 | 1012 | ||
1013 | if (!scontext) | ||
1014 | return 0; | ||
1015 | |||
1011 | /* Allocate space for the context; caller must free this space. */ | 1016 | /* Allocate space for the context; caller must free this space. */ |
1012 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); | 1017 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); |
1013 | if (!scontextp) | 1018 | if (!scontextp) |
@@ -1047,7 +1052,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext, | |||
1047 | struct context *context; | 1052 | struct context *context; |
1048 | int rc = 0; | 1053 | int rc = 0; |
1049 | 1054 | ||
1050 | *scontext = NULL; | 1055 | if (scontext) |
1056 | *scontext = NULL; | ||
1051 | *scontext_len = 0; | 1057 | *scontext_len = 0; |
1052 | 1058 | ||
1053 | if (!ss_initialized) { | 1059 | if (!ss_initialized) { |
@@ -1055,6 +1061,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext, | |||
1055 | char *scontextp; | 1061 | char *scontextp; |
1056 | 1062 | ||
1057 | *scontext_len = strlen(initial_sid_to_string[sid]) + 1; | 1063 | *scontext_len = strlen(initial_sid_to_string[sid]) + 1; |
1064 | if (!scontext) | ||
1065 | goto out; | ||
1058 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); | 1066 | scontextp = kmalloc(*scontext_len, GFP_ATOMIC); |
1059 | if (!scontextp) { | 1067 | if (!scontextp) { |
1060 | rc = -ENOMEM; | 1068 | rc = -ENOMEM; |
@@ -1769,6 +1777,7 @@ int security_load_policy(void *data, size_t len) | |||
1769 | return rc; | 1777 | return rc; |
1770 | } | 1778 | } |
1771 | 1779 | ||
1780 | policydb.len = len; | ||
1772 | rc = selinux_set_mapping(&policydb, secclass_map, | 1781 | rc = selinux_set_mapping(&policydb, secclass_map, |
1773 | ¤t_mapping, | 1782 | ¤t_mapping, |
1774 | ¤t_mapping_size); | 1783 | ¤t_mapping_size); |
@@ -1791,6 +1800,7 @@ int security_load_policy(void *data, size_t len) | |||
1791 | selinux_complete_init(); | 1800 | selinux_complete_init(); |
1792 | avc_ss_reset(seqno); | 1801 | avc_ss_reset(seqno); |
1793 | selnl_notify_policyload(seqno); | 1802 | selnl_notify_policyload(seqno); |
1803 | selinux_status_update_policyload(seqno); | ||
1794 | selinux_netlbl_cache_invalidate(); | 1804 | selinux_netlbl_cache_invalidate(); |
1795 | selinux_xfrm_notify_policyload(); | 1805 | selinux_xfrm_notify_policyload(); |
1796 | return 0; | 1806 | return 0; |
@@ -1804,6 +1814,7 @@ int security_load_policy(void *data, size_t len) | |||
1804 | if (rc) | 1814 | if (rc) |
1805 | return rc; | 1815 | return rc; |
1806 | 1816 | ||
1817 | newpolicydb.len = len; | ||
1807 | /* If switching between different policy types, log MLS status */ | 1818 | /* If switching between different policy types, log MLS status */ |
1808 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1819 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) |
1809 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | 1820 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); |
@@ -1870,6 +1881,7 @@ int security_load_policy(void *data, size_t len) | |||
1870 | 1881 | ||
1871 | avc_ss_reset(seqno); | 1882 | avc_ss_reset(seqno); |
1872 | selnl_notify_policyload(seqno); | 1883 | selnl_notify_policyload(seqno); |
1884 | selinux_status_update_policyload(seqno); | ||
1873 | selinux_netlbl_cache_invalidate(); | 1885 | selinux_netlbl_cache_invalidate(); |
1874 | selinux_xfrm_notify_policyload(); | 1886 | selinux_xfrm_notify_policyload(); |
1875 | 1887 | ||
@@ -1883,6 +1895,17 @@ err: | |||
1883 | 1895 | ||
1884 | } | 1896 | } |
1885 | 1897 | ||
1898 | size_t security_policydb_len(void) | ||
1899 | { | ||
1900 | size_t len; | ||
1901 | |||
1902 | read_lock(&policy_rwlock); | ||
1903 | len = policydb.len; | ||
1904 | read_unlock(&policy_rwlock); | ||
1905 | |||
1906 | return len; | ||
1907 | } | ||
1908 | |||
1886 | /** | 1909 | /** |
1887 | * security_port_sid - Obtain the SID for a port. | 1910 | * security_port_sid - Obtain the SID for a port. |
1888 | * @protocol: protocol number | 1911 | * @protocol: protocol number |
@@ -2374,6 +2397,7 @@ out: | |||
2374 | if (!rc) { | 2397 | if (!rc) { |
2375 | avc_ss_reset(seqno); | 2398 | avc_ss_reset(seqno); |
2376 | selnl_notify_policyload(seqno); | 2399 | selnl_notify_policyload(seqno); |
2400 | selinux_status_update_policyload(seqno); | ||
2377 | selinux_xfrm_notify_policyload(); | 2401 | selinux_xfrm_notify_policyload(); |
2378 | } | 2402 | } |
2379 | return rc; | 2403 | return rc; |
@@ -3129,3 +3153,38 @@ netlbl_sid_to_secattr_failure: | |||
3129 | return rc; | 3153 | return rc; |
3130 | } | 3154 | } |
3131 | #endif /* CONFIG_NETLABEL */ | 3155 | #endif /* CONFIG_NETLABEL */ |
3156 | |||
3157 | /** | ||
3158 | * security_read_policy - read the policy. | ||
3159 | * @data: binary policy data | ||
3160 | * @len: length of data in bytes | ||
3161 | * | ||
3162 | */ | ||
3163 | int security_read_policy(void **data, ssize_t *len) | ||
3164 | { | ||
3165 | int rc; | ||
3166 | struct policy_file fp; | ||
3167 | |||
3168 | if (!ss_initialized) | ||
3169 | return -EINVAL; | ||
3170 | |||
3171 | *len = security_policydb_len(); | ||
3172 | |||
3173 | *data = vmalloc_user(*len); | ||
3174 | if (!*data) | ||
3175 | return -ENOMEM; | ||
3176 | |||
3177 | fp.data = *data; | ||
3178 | fp.len = *len; | ||
3179 | |||
3180 | read_lock(&policy_rwlock); | ||
3181 | rc = policydb_write(&policydb, &fp); | ||
3182 | read_unlock(&policy_rwlock); | ||
3183 | |||
3184 | if (rc) | ||
3185 | return rc; | ||
3186 | |||
3187 | *len = (unsigned long)fp.data - (unsigned long)*data; | ||
3188 | return 0; | ||
3189 | |||
3190 | } | ||
diff --git a/security/selinux/ss/status.c b/security/selinux/ss/status.c new file mode 100644 index 000000000000..d982365f9d1a --- /dev/null +++ b/security/selinux/ss/status.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * mmap based event notifications for SELinux | ||
3 | * | ||
4 | * Author: KaiGai Kohei <kaigai@ak.jp.nec.com> | ||
5 | * | ||
6 | * Copyright (C) 2010 NEC corporation | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2, | ||
10 | * as published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/gfp.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/mutex.h> | ||
16 | #include "avc.h" | ||
17 | #include "services.h" | ||
18 | |||
19 | /* | ||
20 | * The selinux_status_page shall be exposed to userspace applications | ||
21 | * using mmap interface on /selinux/status. | ||
22 | * It enables to notify applications a few events that will cause reset | ||
23 | * of userspace access vector without context switching. | ||
24 | * | ||
25 | * The selinux_kernel_status structure on the head of status page is | ||
26 | * protected from concurrent accesses using seqlock logic, so userspace | ||
27 | * application should reference the status page according to the seqlock | ||
28 | * logic. | ||
29 | * | ||
30 | * Typically, application checks status->sequence at the head of access | ||
31 | * control routine. If it is odd-number, kernel is updating the status, | ||
32 | * so please wait for a moment. If it is changed from the last sequence | ||
33 | * number, it means something happen, so application will reset userspace | ||
34 | * avc, if needed. | ||
35 | * In most cases, application shall confirm the kernel status is not | ||
36 | * changed without any system call invocations. | ||
37 | */ | ||
38 | static struct page *selinux_status_page; | ||
39 | static DEFINE_MUTEX(selinux_status_lock); | ||
40 | |||
41 | /* | ||
42 | * selinux_kernel_status_page | ||
43 | * | ||
44 | * It returns a reference to selinux_status_page. If the status page is | ||
45 | * not allocated yet, it also tries to allocate it at the first time. | ||
46 | */ | ||
47 | struct page *selinux_kernel_status_page(void) | ||
48 | { | ||
49 | struct selinux_kernel_status *status; | ||
50 | struct page *result = NULL; | ||
51 | |||
52 | mutex_lock(&selinux_status_lock); | ||
53 | if (!selinux_status_page) { | ||
54 | selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); | ||
55 | |||
56 | if (selinux_status_page) { | ||
57 | status = page_address(selinux_status_page); | ||
58 | |||
59 | status->version = SELINUX_KERNEL_STATUS_VERSION; | ||
60 | status->sequence = 0; | ||
61 | status->enforcing = selinux_enforcing; | ||
62 | /* | ||
63 | * NOTE: the next policyload event shall set | ||
64 | * a positive value on the status->policyload, | ||
65 | * although it may not be 1, but never zero. | ||
66 | * So, application can know it was updated. | ||
67 | */ | ||
68 | status->policyload = 0; | ||
69 | status->deny_unknown = !security_get_allow_unknown(); | ||
70 | } | ||
71 | } | ||
72 | result = selinux_status_page; | ||
73 | mutex_unlock(&selinux_status_lock); | ||
74 | |||
75 | return result; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * selinux_status_update_setenforce | ||
80 | * | ||
81 | * It updates status of the current enforcing/permissive mode. | ||
82 | */ | ||
83 | void selinux_status_update_setenforce(int enforcing) | ||
84 | { | ||
85 | struct selinux_kernel_status *status; | ||
86 | |||
87 | mutex_lock(&selinux_status_lock); | ||
88 | if (selinux_status_page) { | ||
89 | status = page_address(selinux_status_page); | ||
90 | |||
91 | status->sequence++; | ||
92 | smp_wmb(); | ||
93 | |||
94 | status->enforcing = enforcing; | ||
95 | |||
96 | smp_wmb(); | ||
97 | status->sequence++; | ||
98 | } | ||
99 | mutex_unlock(&selinux_status_lock); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * selinux_status_update_policyload | ||
104 | * | ||
105 | * It updates status of the times of policy reloaded, and current | ||
106 | * setting of deny_unknown. | ||
107 | */ | ||
108 | void selinux_status_update_policyload(int seqno) | ||
109 | { | ||
110 | struct selinux_kernel_status *status; | ||
111 | |||
112 | mutex_lock(&selinux_status_lock); | ||
113 | if (selinux_status_page) { | ||
114 | status = page_address(selinux_status_page); | ||
115 | |||
116 | status->sequence++; | ||
117 | smp_wmb(); | ||
118 | |||
119 | status->policyload = seqno; | ||
120 | status->deny_unknown = !security_get_allow_unknown(); | ||
121 | |||
122 | smp_wmb(); | ||
123 | status->sequence++; | ||
124 | } | ||
125 | mutex_unlock(&selinux_status_lock); | ||
126 | } | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c448d57ae2b7..489a85afa477 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -157,15 +157,11 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
157 | * | 157 | * |
158 | * Returns 0 on success, error code otherwise. | 158 | * Returns 0 on success, error code otherwise. |
159 | */ | 159 | */ |
160 | static int smack_syslog(int type, bool from_file) | 160 | static int smack_syslog(int typefrom_file) |
161 | { | 161 | { |
162 | int rc; | 162 | int rc = 0; |
163 | char *sp = current_security(); | 163 | char *sp = current_security(); |
164 | 164 | ||
165 | rc = cap_syslog(type, from_file); | ||
166 | if (rc != 0) | ||
167 | return rc; | ||
168 | |||
169 | if (capable(CAP_MAC_OVERRIDE)) | 165 | if (capable(CAP_MAC_OVERRIDE)) |
170 | return 0; | 166 | return 0; |
171 | 167 | ||
@@ -1281,12 +1277,11 @@ static int smack_task_getioprio(struct task_struct *p) | |||
1281 | * | 1277 | * |
1282 | * Return 0 if read access is permitted | 1278 | * Return 0 if read access is permitted |
1283 | */ | 1279 | */ |
1284 | static int smack_task_setscheduler(struct task_struct *p, int policy, | 1280 | static int smack_task_setscheduler(struct task_struct *p) |
1285 | struct sched_param *lp) | ||
1286 | { | 1281 | { |
1287 | int rc; | 1282 | int rc; |
1288 | 1283 | ||
1289 | rc = cap_task_setscheduler(p, policy, lp); | 1284 | rc = cap_task_setscheduler(p); |
1290 | if (rc == 0) | 1285 | if (rc == 0) |
1291 | rc = smk_curacc_on_task(p, MAY_WRITE); | 1286 | rc = smk_curacc_on_task(p, MAY_WRITE); |
1292 | return rc; | 1287 | return rc; |
@@ -3005,7 +3000,8 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
3005 | { | 3000 | { |
3006 | char *sp = smack_from_secid(secid); | 3001 | char *sp = smack_from_secid(secid); |
3007 | 3002 | ||
3008 | *secdata = sp; | 3003 | if (secdata) |
3004 | *secdata = sp; | ||
3009 | *seclen = strlen(sp); | 3005 | *seclen = strlen(sp); |
3010 | return 0; | 3006 | return 0; |
3011 | } | 3007 | } |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index a2b72d77f926..dc1fd6239f24 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -968,6 +968,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, | |||
968 | static const struct file_operations smk_doi_ops = { | 968 | static const struct file_operations smk_doi_ops = { |
969 | .read = smk_read_doi, | 969 | .read = smk_read_doi, |
970 | .write = smk_write_doi, | 970 | .write = smk_write_doi, |
971 | .llseek = default_llseek, | ||
971 | }; | 972 | }; |
972 | 973 | ||
973 | /** | 974 | /** |
@@ -1031,6 +1032,7 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, | |||
1031 | static const struct file_operations smk_direct_ops = { | 1032 | static const struct file_operations smk_direct_ops = { |
1032 | .read = smk_read_direct, | 1033 | .read = smk_read_direct, |
1033 | .write = smk_write_direct, | 1034 | .write = smk_write_direct, |
1035 | .llseek = default_llseek, | ||
1034 | }; | 1036 | }; |
1035 | 1037 | ||
1036 | /** | 1038 | /** |
@@ -1112,6 +1114,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | |||
1112 | static const struct file_operations smk_ambient_ops = { | 1114 | static const struct file_operations smk_ambient_ops = { |
1113 | .read = smk_read_ambient, | 1115 | .read = smk_read_ambient, |
1114 | .write = smk_write_ambient, | 1116 | .write = smk_write_ambient, |
1117 | .llseek = default_llseek, | ||
1115 | }; | 1118 | }; |
1116 | 1119 | ||
1117 | /** | 1120 | /** |
@@ -1191,6 +1194,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1191 | static const struct file_operations smk_onlycap_ops = { | 1194 | static const struct file_operations smk_onlycap_ops = { |
1192 | .read = smk_read_onlycap, | 1195 | .read = smk_read_onlycap, |
1193 | .write = smk_write_onlycap, | 1196 | .write = smk_write_onlycap, |
1197 | .llseek = default_llseek, | ||
1194 | }; | 1198 | }; |
1195 | 1199 | ||
1196 | /** | 1200 | /** |
@@ -1255,6 +1259,7 @@ static ssize_t smk_write_logging(struct file *file, const char __user *buf, | |||
1255 | static const struct file_operations smk_logging_ops = { | 1259 | static const struct file_operations smk_logging_ops = { |
1256 | .read = smk_read_logging, | 1260 | .read = smk_read_logging, |
1257 | .write = smk_write_logging, | 1261 | .write = smk_write_logging, |
1262 | .llseek = default_llseek, | ||
1258 | }; | 1263 | }; |
1259 | /** | 1264 | /** |
1260 | * smk_fill_super - fill the /smackfs superblock | 1265 | * smk_fill_super - fill the /smackfs superblock |
@@ -1305,27 +1310,25 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1305 | } | 1310 | } |
1306 | 1311 | ||
1307 | /** | 1312 | /** |
1308 | * smk_get_sb - get the smackfs superblock | 1313 | * smk_mount - get the smackfs superblock |
1309 | * @fs_type: passed along without comment | 1314 | * @fs_type: passed along without comment |
1310 | * @flags: passed along without comment | 1315 | * @flags: passed along without comment |
1311 | * @dev_name: passed along without comment | 1316 | * @dev_name: passed along without comment |
1312 | * @data: passed along without comment | 1317 | * @data: passed along without comment |
1313 | * @mnt: passed along without comment | ||
1314 | * | 1318 | * |
1315 | * Just passes everything along. | 1319 | * Just passes everything along. |
1316 | * | 1320 | * |
1317 | * Returns what the lower level code does. | 1321 | * Returns what the lower level code does. |
1318 | */ | 1322 | */ |
1319 | static int smk_get_sb(struct file_system_type *fs_type, | 1323 | static struct dentry *smk_mount(struct file_system_type *fs_type, |
1320 | int flags, const char *dev_name, void *data, | 1324 | int flags, const char *dev_name, void *data) |
1321 | struct vfsmount *mnt) | ||
1322 | { | 1325 | { |
1323 | return get_sb_single(fs_type, flags, data, smk_fill_super, mnt); | 1326 | return mount_single(fs_type, flags, data, smk_fill_super); |
1324 | } | 1327 | } |
1325 | 1328 | ||
1326 | static struct file_system_type smk_fs_type = { | 1329 | static struct file_system_type smk_fs_type = { |
1327 | .name = "smackfs", | 1330 | .name = "smackfs", |
1328 | .get_sb = smk_get_sb, | 1331 | .mount = smk_mount, |
1329 | .kill_sb = kill_litter_super, | 1332 | .kill_sb = kill_litter_super, |
1330 | }; | 1333 | }; |
1331 | 1334 | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index c668b447c725..7556315c1978 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -768,8 +768,10 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | |||
768 | return true; /* Do nothing if open(O_WRONLY). */ | 768 | return true; /* Do nothing if open(O_WRONLY). */ |
769 | memset(&head->r, 0, sizeof(head->r)); | 769 | memset(&head->r, 0, sizeof(head->r)); |
770 | head->r.print_this_domain_only = true; | 770 | head->r.print_this_domain_only = true; |
771 | head->r.eof = !domain; | 771 | if (domain) |
772 | head->r.domain = &domain->list; | 772 | head->r.domain = &domain->list; |
773 | else | ||
774 | head->r.eof = 1; | ||
773 | tomoyo_io_printf(head, "# select %s\n", data); | 775 | tomoyo_io_printf(head, "# select %s\n", data); |
774 | if (domain && domain->is_deleted) | 776 | if (domain && domain->is_deleted) |
775 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); | 777 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); |
@@ -2051,13 +2053,22 @@ void tomoyo_check_profile(void) | |||
2051 | const u8 profile = domain->profile; | 2053 | const u8 profile = domain->profile; |
2052 | if (tomoyo_profile_ptr[profile]) | 2054 | if (tomoyo_profile_ptr[profile]) |
2053 | continue; | 2055 | continue; |
2056 | printk(KERN_ERR "You need to define profile %u before using it.\n", | ||
2057 | profile); | ||
2058 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2059 | "for more information.\n"); | ||
2054 | panic("Profile %u (used by '%s') not defined.\n", | 2060 | panic("Profile %u (used by '%s') not defined.\n", |
2055 | profile, domain->domainname->name); | 2061 | profile, domain->domainname->name); |
2056 | } | 2062 | } |
2057 | tomoyo_read_unlock(idx); | 2063 | tomoyo_read_unlock(idx); |
2058 | if (tomoyo_profile_version != 20090903) | 2064 | if (tomoyo_profile_version != 20090903) { |
2065 | printk(KERN_ERR "You need to install userland programs for " | ||
2066 | "TOMOYO 2.3 and initialize policy configuration.\n"); | ||
2067 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2068 | "for more information.\n"); | ||
2059 | panic("Profile version %u is not supported.\n", | 2069 | panic("Profile version %u is not supported.\n", |
2060 | tomoyo_profile_version); | 2070 | tomoyo_profile_version); |
2071 | } | ||
2061 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); | 2072 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); |
2062 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2073 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2063 | } | 2074 | } |
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index ed8ccd680102..1d0bf8fa1922 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -127,10 +127,8 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
127 | /* If we don't have a vfsmount, we can't calculate. */ | 127 | /* If we don't have a vfsmount, we can't calculate. */ |
128 | if (!path->mnt) | 128 | if (!path->mnt) |
129 | break; | 129 | break; |
130 | spin_lock(&dcache_lock); | ||
131 | /* go to whatever namespace root we are under */ | 130 | /* go to whatever namespace root we are under */ |
132 | pos = __d_path(path, &ns_root, buf, buf_len); | 131 | pos = __d_path(path, &ns_root, buf, buf_len); |
133 | spin_unlock(&dcache_lock); | ||
134 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | 132 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ |
135 | if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) && | 133 | if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) && |
136 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { | 134 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { |