diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/Kconfig | 5 | ||||
-rw-r--r-- | security/Makefile | 4 | ||||
-rw-r--r-- | security/inode.c | 7 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 55 | ||||
-rw-r--r-- | security/integrity/ima/Makefile | 9 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 166 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 190 | ||||
-rw-r--r-- | security/integrity/ima/ima_audit.c | 78 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 140 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 376 | ||||
-rw-r--r-- | security/integrity/ima/ima_iint.c | 202 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 96 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 327 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 413 | ||||
-rw-r--r-- | security/integrity/ima/ima_queue.c | 140 | ||||
-rw-r--r-- | security/selinux/hooks.c | 241 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 2 | ||||
-rw-r--r-- | security/selinux/include/security.h | 8 |
18 files changed, 2277 insertions, 182 deletions
diff --git a/security/Kconfig b/security/Kconfig index 9438535d7fd0..bf129f87de7e 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -55,7 +55,8 @@ config SECURITYFS | |||
55 | bool "Enable the securityfs filesystem" | 55 | bool "Enable the securityfs filesystem" |
56 | help | 56 | help |
57 | This will build the securityfs filesystem. It is currently used by | 57 | This will build the securityfs filesystem. It is currently used by |
58 | the TPM bios character driver. It is not used by SELinux or SMACK. | 58 | the TPM bios character driver and IMA, an integrity provider. It is |
59 | not used by SELinux or SMACK. | ||
59 | 60 | ||
60 | If you are unsure how to answer this question, answer N. | 61 | If you are unsure how to answer this question, answer N. |
61 | 62 | ||
@@ -135,5 +136,7 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR | |||
135 | source security/selinux/Kconfig | 136 | source security/selinux/Kconfig |
136 | source security/smack/Kconfig | 137 | source security/smack/Kconfig |
137 | 138 | ||
139 | source security/integrity/ima/Kconfig | ||
140 | |||
138 | endmenu | 141 | endmenu |
139 | 142 | ||
diff --git a/security/Makefile b/security/Makefile index c05c127fff9a..595536cbffb2 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -17,3 +17,7 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | |||
17 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o | 17 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o |
18 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o | 18 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o |
19 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 19 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
20 | |||
21 | # Object integrity file lists | ||
22 | subdir-$(CONFIG_IMA) += integrity/ima | ||
23 | obj-$(CONFIG_IMA) += integrity/ima/built-in.o | ||
diff --git a/security/inode.c b/security/inode.c index 007ef252dde7..f3b91bfbe4cb 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -202,12 +202,11 @@ static int create_by_name(const char *name, mode_t mode, | |||
202 | * This function returns a pointer to a dentry if it succeeds. This | 202 | * This function returns a pointer to a dentry if it succeeds. This |
203 | * pointer must be passed to the securityfs_remove() function when the file is | 203 | * pointer must be passed to the securityfs_remove() function when the file is |
204 | * to be removed (no automatic cleanup happens if your module is unloaded, | 204 | * to be removed (no automatic cleanup happens if your module is unloaded, |
205 | * you are responsible here). If an error occurs, %NULL is returned. | 205 | * you are responsible here). If an error occurs, the function will return |
206 | * the erorr value (via ERR_PTR). | ||
206 | * | 207 | * |
207 | * If securityfs is not enabled in the kernel, the value %-ENODEV is | 208 | * If securityfs is not enabled in the kernel, the value %-ENODEV is |
208 | * returned. It is not wise to check for this value, but rather, check for | 209 | * returned. |
209 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | ||
210 | * code. | ||
211 | */ | 210 | */ |
212 | struct dentry *securityfs_create_file(const char *name, mode_t mode, | 211 | struct dentry *securityfs_create_file(const char *name, mode_t mode, |
213 | struct dentry *parent, void *data, | 212 | struct dentry *parent, void *data, |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig new file mode 100644 index 000000000000..3d2b6ee778a0 --- /dev/null +++ b/security/integrity/ima/Kconfig | |||
@@ -0,0 +1,55 @@ | |||
1 | # IBM Integrity Measurement Architecture | ||
2 | # | ||
3 | config IMA | ||
4 | bool "Integrity Measurement Architecture(IMA)" | ||
5 | depends on ACPI | ||
6 | select SECURITYFS | ||
7 | select CRYPTO | ||
8 | select CRYPTO_HMAC | ||
9 | select CRYPTO_MD5 | ||
10 | select CRYPTO_SHA1 | ||
11 | select TCG_TPM | ||
12 | select TCG_TIS | ||
13 | help | ||
14 | The Trusted Computing Group(TCG) runtime Integrity | ||
15 | Measurement Architecture(IMA) maintains a list of hash | ||
16 | values of executables and other sensitive system files, | ||
17 | as they are read or executed. If an attacker manages | ||
18 | to change the contents of an important system file | ||
19 | being measured, we can tell. | ||
20 | |||
21 | If your system has a TPM chip, then IMA also maintains | ||
22 | an aggregate integrity value over this list inside the | ||
23 | TPM hardware, so that the TPM can prove to a third party | ||
24 | whether or not critical system files have been modified. | ||
25 | Read <http://www.usenix.org/events/sec04/tech/sailer.html> | ||
26 | to learn more about IMA. | ||
27 | If unsure, say N. | ||
28 | |||
29 | config IMA_MEASURE_PCR_IDX | ||
30 | int | ||
31 | depends on IMA | ||
32 | range 8 14 | ||
33 | default 10 | ||
34 | help | ||
35 | IMA_MEASURE_PCR_IDX determines the TPM PCR register index | ||
36 | that IMA uses to maintain the integrity aggregate of the | ||
37 | measurement list. If unsure, use the default 10. | ||
38 | |||
39 | config IMA_AUDIT | ||
40 | bool | ||
41 | depends on IMA | ||
42 | default y | ||
43 | help | ||
44 | This option adds a kernel parameter 'ima_audit', which | ||
45 | allows informational auditing messages to be enabled | ||
46 | at boot. If this option is selected, informational integrity | ||
47 | auditing messages can be enabled with 'ima_audit=1' on | ||
48 | the kernel command line. | ||
49 | |||
50 | config IMA_LSM_RULES | ||
51 | bool | ||
52 | depends on IMA && (SECURITY_SELINUX || SECURITY_SMACK) | ||
53 | default y | ||
54 | help | ||
55 | Disabling this option will disregard LSM based policy rules | ||
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile new file mode 100644 index 000000000000..787c4cb916cd --- /dev/null +++ b/security/integrity/ima/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for building Trusted Computing Group's(TCG) runtime Integrity | ||
3 | # Measurement Architecture(IMA). | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_IMA) += ima.o | ||
7 | |||
8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | ||
9 | ima_policy.o ima_iint.o ima_audit.o | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h new file mode 100644 index 000000000000..e3c16a21a38e --- /dev/null +++ b/security/integrity/ima/ima.h | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Reiner Sailer <sailer@watson.ibm.com> | ||
6 | * Mimi Zohar <zohar@us.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation, version 2 of the | ||
11 | * License. | ||
12 | * | ||
13 | * File: ima.h | ||
14 | * internal Integrity Measurement Architecture (IMA) definitions | ||
15 | */ | ||
16 | |||
17 | #ifndef __LINUX_IMA_H | ||
18 | #define __LINUX_IMA_H | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/crypto.h> | ||
22 | #include <linux/security.h> | ||
23 | #include <linux/hash.h> | ||
24 | #include <linux/tpm.h> | ||
25 | #include <linux/audit.h> | ||
26 | |||
27 | enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII }; | ||
28 | enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | ||
29 | |||
30 | /* digest size for IMA, fits SHA1 or MD5 */ | ||
31 | #define IMA_DIGEST_SIZE 20 | ||
32 | #define IMA_EVENT_NAME_LEN_MAX 255 | ||
33 | |||
34 | #define IMA_HASH_BITS 9 | ||
35 | #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS) | ||
36 | |||
37 | /* set during initialization */ | ||
38 | extern int ima_initialized; | ||
39 | extern int ima_used_chip; | ||
40 | extern char *ima_hash; | ||
41 | |||
42 | /* IMA inode template definition */ | ||
43 | struct ima_template_data { | ||
44 | u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */ | ||
45 | char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */ | ||
46 | }; | ||
47 | |||
48 | struct ima_template_entry { | ||
49 | u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ | ||
50 | char *template_name; | ||
51 | int template_len; | ||
52 | struct ima_template_data template; | ||
53 | }; | ||
54 | |||
55 | struct ima_queue_entry { | ||
56 | struct hlist_node hnext; /* place in hash collision list */ | ||
57 | struct list_head later; /* place in ima_measurements list */ | ||
58 | struct ima_template_entry *entry; | ||
59 | }; | ||
60 | extern struct list_head ima_measurements; /* list of all measurements */ | ||
61 | |||
62 | /* declarations */ | ||
63 | void integrity_audit_msg(int audit_msgno, struct inode *inode, | ||
64 | const unsigned char *fname, const char *op, | ||
65 | const char *cause, int result, int info); | ||
66 | |||
67 | /* Internal IMA function definitions */ | ||
68 | void ima_iintcache_init(void); | ||
69 | int ima_init(void); | ||
70 | void ima_cleanup(void); | ||
71 | int ima_fs_init(void); | ||
72 | void ima_fs_cleanup(void); | ||
73 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | ||
74 | const char *op, struct inode *inode); | ||
75 | int ima_calc_hash(struct file *file, char *digest); | ||
76 | int ima_calc_template_hash(int template_len, void *template, char *digest); | ||
77 | int ima_calc_boot_aggregate(char *digest); | ||
78 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | ||
79 | const char *op, const char *cause); | ||
80 | |||
81 | /* | ||
82 | * used to protect h_table and sha_table | ||
83 | */ | ||
84 | extern spinlock_t ima_queue_lock; | ||
85 | |||
86 | struct ima_h_table { | ||
87 | atomic_long_t len; /* number of stored measurements in the list */ | ||
88 | atomic_long_t violations; | ||
89 | struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; | ||
90 | }; | ||
91 | extern struct ima_h_table ima_htable; | ||
92 | |||
93 | static inline unsigned long ima_hash_key(u8 *digest) | ||
94 | { | ||
95 | return hash_long(*digest, IMA_HASH_BITS); | ||
96 | } | ||
97 | |||
98 | /* iint cache flags */ | ||
99 | #define IMA_MEASURED 1 | ||
100 | #define IMA_IINT_DUMP_STACK 512 | ||
101 | |||
102 | /* integrity data associated with an inode */ | ||
103 | struct ima_iint_cache { | ||
104 | u64 version; /* track inode changes */ | ||
105 | unsigned long flags; | ||
106 | u8 digest[IMA_DIGEST_SIZE]; | ||
107 | struct mutex mutex; /* protects: version, flags, digest */ | ||
108 | long readcount; /* measured files readcount */ | ||
109 | long writecount; /* measured files writecount */ | ||
110 | long opencount; /* opens reference count */ | ||
111 | struct kref refcount; /* ima_iint_cache reference count */ | ||
112 | struct rcu_head rcu; | ||
113 | }; | ||
114 | |||
115 | /* LIM API function definitions */ | ||
116 | int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | ||
117 | int mask, int function); | ||
118 | int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file); | ||
119 | void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, | ||
120 | const unsigned char *filename); | ||
121 | int ima_store_template(struct ima_template_entry *entry, int violation, | ||
122 | struct inode *inode); | ||
123 | void ima_template_show(struct seq_file *m, void *e, | ||
124 | enum ima_show_type show); | ||
125 | |||
126 | /* radix tree calls to lookup, insert, delete | ||
127 | * integrity data associated with an inode. | ||
128 | */ | ||
129 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); | ||
130 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); | ||
131 | struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode); | ||
132 | void ima_iint_delete(struct inode *inode); | ||
133 | void iint_free(struct kref *kref); | ||
134 | void iint_rcu_free(struct rcu_head *rcu); | ||
135 | |||
136 | /* IMA policy related functions */ | ||
137 | enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | ||
138 | |||
139 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | ||
140 | void ima_init_policy(void); | ||
141 | void ima_update_policy(void); | ||
142 | int ima_parse_add_rule(char *); | ||
143 | void ima_delete_rules(void); | ||
144 | |||
145 | /* LSM based policy rules require audit */ | ||
146 | #ifdef CONFIG_IMA_LSM_RULES | ||
147 | |||
148 | #define security_filter_rule_init security_audit_rule_init | ||
149 | #define security_filter_rule_match security_audit_rule_match | ||
150 | |||
151 | #else | ||
152 | |||
153 | static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr, | ||
154 | void **lsmrule) | ||
155 | { | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | |||
159 | static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, | ||
160 | void *lsmrule, | ||
161 | struct audit_context *actx) | ||
162 | { | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | #endif /* CONFIG_IMA_LSM_RULES */ | ||
166 | #endif | ||
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c new file mode 100644 index 000000000000..a148a25804f6 --- /dev/null +++ b/security/integrity/ima/ima_api.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * | ||
4 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2 of the | ||
9 | * License. | ||
10 | * | ||
11 | * File: ima_api.c | ||
12 | * Implements must_measure, collect_measurement, store_measurement, | ||
13 | * and store_template. | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | #include "ima.h" | ||
18 | static char *IMA_TEMPLATE_NAME = "ima"; | ||
19 | |||
20 | /* | ||
21 | * ima_store_template - store ima template measurements | ||
22 | * | ||
23 | * Calculate the hash of a template entry, add the template entry | ||
24 | * to an ordered list of measurement entries maintained inside the kernel, | ||
25 | * and also update the aggregate integrity value (maintained inside the | ||
26 | * configured TPM PCR) over the hashes of the current list of measurement | ||
27 | * entries. | ||
28 | * | ||
29 | * Applications retrieve the current kernel-held measurement list through | ||
30 | * the securityfs entries in /sys/kernel/security/ima. The signed aggregate | ||
31 | * TPM PCR (called quote) can be retrieved using a TPM user space library | ||
32 | * and is used to validate the measurement list. | ||
33 | * | ||
34 | * Returns 0 on success, error code otherwise | ||
35 | */ | ||
36 | int ima_store_template(struct ima_template_entry *entry, | ||
37 | int violation, struct inode *inode) | ||
38 | { | ||
39 | const char *op = "add_template_measure"; | ||
40 | const char *audit_cause = "hashing_error"; | ||
41 | int result; | ||
42 | |||
43 | memset(entry->digest, 0, sizeof(entry->digest)); | ||
44 | entry->template_name = IMA_TEMPLATE_NAME; | ||
45 | entry->template_len = sizeof(entry->template); | ||
46 | |||
47 | if (!violation) { | ||
48 | result = ima_calc_template_hash(entry->template_len, | ||
49 | &entry->template, | ||
50 | entry->digest); | ||
51 | if (result < 0) { | ||
52 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | ||
53 | entry->template_name, op, | ||
54 | audit_cause, result, 0); | ||
55 | return result; | ||
56 | } | ||
57 | } | ||
58 | result = ima_add_template_entry(entry, violation, op, inode); | ||
59 | return result; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * ima_add_violation - add violation to measurement list. | ||
64 | * | ||
65 | * Violations are flagged in the measurement list with zero hash values. | ||
66 | * By extending the PCR with 0xFF's instead of with zeroes, the PCR | ||
67 | * value is invalidated. | ||
68 | */ | ||
69 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | ||
70 | const char *op, const char *cause) | ||
71 | { | ||
72 | struct ima_template_entry *entry; | ||
73 | int violation = 1; | ||
74 | int result; | ||
75 | |||
76 | /* can overflow, only indicator */ | ||
77 | atomic_long_inc(&ima_htable.violations); | ||
78 | |||
79 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
80 | if (!entry) { | ||
81 | result = -ENOMEM; | ||
82 | goto err_out; | ||
83 | } | ||
84 | memset(&entry->template, 0, sizeof(entry->template)); | ||
85 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
86 | result = ima_store_template(entry, violation, inode); | ||
87 | if (result < 0) | ||
88 | kfree(entry); | ||
89 | err_out: | ||
90 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | ||
91 | op, cause, result, 0); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * ima_must_measure - measure decision based on policy. | ||
96 | * @inode: pointer to inode to measure | ||
97 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | ||
98 | * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP) | ||
99 | * | ||
100 | * The policy is defined in terms of keypairs: | ||
101 | * subj=, obj=, type=, func=, mask=, fsmagic= | ||
102 | * subj,obj, and type: are LSM specific. | ||
103 | * func: PATH_CHECK | BPRM_CHECK | FILE_MMAP | ||
104 | * mask: contains the permission mask | ||
105 | * fsmagic: hex value | ||
106 | * | ||
107 | * Must be called with iint->mutex held. | ||
108 | * | ||
109 | * Return 0 to measure. Return 1 if already measured. | ||
110 | * For matching a DONT_MEASURE policy, no policy, or other | ||
111 | * error, return an error code. | ||
112 | */ | ||
113 | int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | ||
114 | int mask, int function) | ||
115 | { | ||
116 | int must_measure; | ||
117 | |||
118 | if (iint->flags & IMA_MEASURED) | ||
119 | return 1; | ||
120 | |||
121 | must_measure = ima_match_policy(inode, function, mask); | ||
122 | return must_measure ? 0 : -EACCES; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * ima_collect_measurement - collect file measurement | ||
127 | * | ||
128 | * Calculate the file hash, if it doesn't already exist, | ||
129 | * storing the measurement and i_version in the iint. | ||
130 | * | ||
131 | * Must be called with iint->mutex held. | ||
132 | * | ||
133 | * Return 0 on success, error code otherwise | ||
134 | */ | ||
135 | int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file) | ||
136 | { | ||
137 | int result = -EEXIST; | ||
138 | |||
139 | if (!(iint->flags & IMA_MEASURED)) { | ||
140 | u64 i_version = file->f_dentry->d_inode->i_version; | ||
141 | |||
142 | memset(iint->digest, 0, IMA_DIGEST_SIZE); | ||
143 | result = ima_calc_hash(file, iint->digest); | ||
144 | if (!result) | ||
145 | iint->version = i_version; | ||
146 | } | ||
147 | return result; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * ima_store_measurement - store file measurement | ||
152 | * | ||
153 | * Create an "ima" template and then store the template by calling | ||
154 | * ima_store_template. | ||
155 | * | ||
156 | * We only get here if the inode has not already been measured, | ||
157 | * but the measurement could already exist: | ||
158 | * - multiple copies of the same file on either the same or | ||
159 | * different filesystems. | ||
160 | * - the inode was previously flushed as well as the iint info, | ||
161 | * containing the hashing info. | ||
162 | * | ||
163 | * Must be called with iint->mutex held. | ||
164 | */ | ||
165 | void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, | ||
166 | const unsigned char *filename) | ||
167 | { | ||
168 | const char *op = "add_template_measure"; | ||
169 | const char *audit_cause = "ENOMEM"; | ||
170 | int result = -ENOMEM; | ||
171 | struct inode *inode = file->f_dentry->d_inode; | ||
172 | struct ima_template_entry *entry; | ||
173 | int violation = 0; | ||
174 | |||
175 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
176 | if (!entry) { | ||
177 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | ||
178 | op, audit_cause, result, 0); | ||
179 | return; | ||
180 | } | ||
181 | memset(&entry->template, 0, sizeof(entry->template)); | ||
182 | memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE); | ||
183 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
184 | |||
185 | result = ima_store_template(entry, violation, inode); | ||
186 | if (!result) | ||
187 | iint->flags |= IMA_MEASURED; | ||
188 | else | ||
189 | kfree(entry); | ||
190 | } | ||
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c new file mode 100644 index 000000000000..8a0f1e23ccf1 --- /dev/null +++ b/security/integrity/ima/ima_audit.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, version 2 of the License. | ||
8 | * | ||
9 | * File: integrity_audit.c | ||
10 | * Audit calls for the integrity subsystem | ||
11 | */ | ||
12 | |||
13 | #include <linux/fs.h> | ||
14 | #include <linux/audit.h> | ||
15 | #include "ima.h" | ||
16 | |||
17 | static int ima_audit; | ||
18 | |||
19 | #ifdef CONFIG_IMA_AUDIT | ||
20 | |||
21 | /* ima_audit_setup - enable informational auditing messages */ | ||
22 | static int __init ima_audit_setup(char *str) | ||
23 | { | ||
24 | unsigned long audit; | ||
25 | int rc; | ||
26 | char *op; | ||
27 | |||
28 | rc = strict_strtoul(str, 0, &audit); | ||
29 | if (rc || audit > 1) | ||
30 | printk(KERN_INFO "ima: invalid ima_audit value\n"); | ||
31 | else | ||
32 | ima_audit = audit; | ||
33 | op = ima_audit ? "ima_audit_enabled" : "ima_audit_not_enabled"; | ||
34 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0, 0); | ||
35 | return 1; | ||
36 | } | ||
37 | __setup("ima_audit=", ima_audit_setup); | ||
38 | #endif | ||
39 | |||
40 | void integrity_audit_msg(int audit_msgno, struct inode *inode, | ||
41 | const unsigned char *fname, const char *op, | ||
42 | const char *cause, int result, int audit_info) | ||
43 | { | ||
44 | struct audit_buffer *ab; | ||
45 | |||
46 | if (!ima_audit && audit_info == 1) /* Skip informational messages */ | ||
47 | return; | ||
48 | |||
49 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); | ||
50 | audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u", | ||
51 | current->pid, current->cred->uid, | ||
52 | audit_get_loginuid(current)); | ||
53 | audit_log_task_context(ab); | ||
54 | switch (audit_msgno) { | ||
55 | case AUDIT_INTEGRITY_DATA: | ||
56 | case AUDIT_INTEGRITY_METADATA: | ||
57 | case AUDIT_INTEGRITY_PCR: | ||
58 | audit_log_format(ab, " op=%s cause=%s", op, cause); | ||
59 | break; | ||
60 | case AUDIT_INTEGRITY_HASH: | ||
61 | audit_log_format(ab, " op=%s hash=%s", op, cause); | ||
62 | break; | ||
63 | case AUDIT_INTEGRITY_STATUS: | ||
64 | default: | ||
65 | audit_log_format(ab, " op=%s", op); | ||
66 | } | ||
67 | audit_log_format(ab, " comm="); | ||
68 | audit_log_untrustedstring(ab, current->comm); | ||
69 | if (fname) { | ||
70 | audit_log_format(ab, " name="); | ||
71 | audit_log_untrustedstring(ab, fname); | ||
72 | } | ||
73 | if (inode) | ||
74 | audit_log_format(ab, " dev=%s ino=%lu", | ||
75 | inode->i_sb->s_id, inode->i_ino); | ||
76 | audit_log_format(ab, " res=%d", result); | ||
77 | audit_log_end(ab); | ||
78 | } | ||
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c new file mode 100644 index 000000000000..c2a46e40999d --- /dev/null +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Mimi Zohar <zohar@us.ibm.com> | ||
6 | * Kylene Hall <kjhall@us.ibm.com> | ||
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 as published by | ||
10 | * the Free Software Foundation, version 2 of the License. | ||
11 | * | ||
12 | * File: ima_crypto.c | ||
13 | * Calculates md5/sha1 file hash, template hash, boot-aggreate hash | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/file.h> | ||
18 | #include <linux/crypto.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/err.h> | ||
21 | #include "ima.h" | ||
22 | |||
23 | static int init_desc(struct hash_desc *desc) | ||
24 | { | ||
25 | int rc; | ||
26 | |||
27 | desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC); | ||
28 | if (IS_ERR(desc->tfm)) { | ||
29 | pr_info("failed to load %s transform: %ld\n", | ||
30 | ima_hash, PTR_ERR(desc->tfm)); | ||
31 | rc = PTR_ERR(desc->tfm); | ||
32 | return rc; | ||
33 | } | ||
34 | desc->flags = 0; | ||
35 | rc = crypto_hash_init(desc); | ||
36 | if (rc) | ||
37 | crypto_free_hash(desc->tfm); | ||
38 | return rc; | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * Calculate the MD5/SHA1 file digest | ||
43 | */ | ||
44 | int ima_calc_hash(struct file *file, char *digest) | ||
45 | { | ||
46 | struct hash_desc desc; | ||
47 | struct scatterlist sg[1]; | ||
48 | loff_t i_size; | ||
49 | char *rbuf; | ||
50 | int rc, offset = 0; | ||
51 | |||
52 | rc = init_desc(&desc); | ||
53 | if (rc != 0) | ||
54 | return rc; | ||
55 | |||
56 | rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
57 | if (!rbuf) { | ||
58 | rc = -ENOMEM; | ||
59 | goto out; | ||
60 | } | ||
61 | i_size = i_size_read(file->f_dentry->d_inode); | ||
62 | while (offset < i_size) { | ||
63 | int rbuf_len; | ||
64 | |||
65 | rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE); | ||
66 | if (rbuf_len < 0) { | ||
67 | rc = rbuf_len; | ||
68 | break; | ||
69 | } | ||
70 | offset += rbuf_len; | ||
71 | sg_set_buf(sg, rbuf, rbuf_len); | ||
72 | |||
73 | rc = crypto_hash_update(&desc, sg, rbuf_len); | ||
74 | if (rc) | ||
75 | break; | ||
76 | } | ||
77 | kfree(rbuf); | ||
78 | if (!rc) | ||
79 | rc = crypto_hash_final(&desc, digest); | ||
80 | out: | ||
81 | crypto_free_hash(desc.tfm); | ||
82 | return rc; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Calculate the hash of a given template | ||
87 | */ | ||
88 | int ima_calc_template_hash(int template_len, void *template, char *digest) | ||
89 | { | ||
90 | struct hash_desc desc; | ||
91 | struct scatterlist sg[1]; | ||
92 | int rc; | ||
93 | |||
94 | rc = init_desc(&desc); | ||
95 | if (rc != 0) | ||
96 | return rc; | ||
97 | |||
98 | sg_set_buf(sg, template, template_len); | ||
99 | rc = crypto_hash_update(&desc, sg, template_len); | ||
100 | if (!rc) | ||
101 | rc = crypto_hash_final(&desc, digest); | ||
102 | crypto_free_hash(desc.tfm); | ||
103 | return rc; | ||
104 | } | ||
105 | |||
106 | static void ima_pcrread(int idx, u8 *pcr) | ||
107 | { | ||
108 | if (!ima_used_chip) | ||
109 | return; | ||
110 | |||
111 | if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) | ||
112 | pr_err("Error Communicating to TPM chip\n"); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Calculate the boot aggregate hash | ||
117 | */ | ||
118 | int ima_calc_boot_aggregate(char *digest) | ||
119 | { | ||
120 | struct hash_desc desc; | ||
121 | struct scatterlist sg; | ||
122 | u8 pcr_i[IMA_DIGEST_SIZE]; | ||
123 | int rc, i; | ||
124 | |||
125 | rc = init_desc(&desc); | ||
126 | if (rc != 0) | ||
127 | return rc; | ||
128 | |||
129 | /* cumulative sha1 over tpm registers 0-7 */ | ||
130 | for (i = TPM_PCR0; i < TPM_PCR8; i++) { | ||
131 | ima_pcrread(i, pcr_i); | ||
132 | /* now accumulate with current aggregate */ | ||
133 | sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE); | ||
134 | rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE); | ||
135 | } | ||
136 | if (!rc) | ||
137 | crypto_hash_final(&desc, digest); | ||
138 | crypto_free_hash(desc.tfm); | ||
139 | return rc; | ||
140 | } | ||
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c new file mode 100644 index 000000000000..573780c76f1f --- /dev/null +++ b/security/integrity/ima/ima_fs.c | |||
@@ -0,0 +1,376 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Kylene Hall <kjhall@us.ibm.com> | ||
6 | * Reiner Sailer <sailer@us.ibm.com> | ||
7 | * Mimi Zohar <zohar@us.ibm.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation, version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | * File: ima_fs.c | ||
15 | * implemenents security file system for reporting | ||
16 | * current measurement list and IMA statistics | ||
17 | */ | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/rculist.h> | ||
21 | #include <linux/rcupdate.h> | ||
22 | #include <linux/parser.h> | ||
23 | |||
24 | #include "ima.h" | ||
25 | |||
26 | static int valid_policy = 1; | ||
27 | #define TMPBUFLEN 12 | ||
28 | static ssize_t ima_show_htable_value(char __user *buf, size_t count, | ||
29 | loff_t *ppos, atomic_long_t *val) | ||
30 | { | ||
31 | char tmpbuf[TMPBUFLEN]; | ||
32 | ssize_t len; | ||
33 | |||
34 | len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val)); | ||
35 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); | ||
36 | } | ||
37 | |||
38 | static ssize_t ima_show_htable_violations(struct file *filp, | ||
39 | char __user *buf, | ||
40 | size_t count, loff_t *ppos) | ||
41 | { | ||
42 | return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); | ||
43 | } | ||
44 | |||
45 | static struct file_operations ima_htable_violations_ops = { | ||
46 | .read = ima_show_htable_violations | ||
47 | }; | ||
48 | |||
49 | static ssize_t ima_show_measurements_count(struct file *filp, | ||
50 | char __user *buf, | ||
51 | size_t count, loff_t *ppos) | ||
52 | { | ||
53 | return ima_show_htable_value(buf, count, ppos, &ima_htable.len); | ||
54 | |||
55 | } | ||
56 | |||
57 | static struct file_operations ima_measurements_count_ops = { | ||
58 | .read = ima_show_measurements_count | ||
59 | }; | ||
60 | |||
61 | /* returns pointer to hlist_node */ | ||
62 | static void *ima_measurements_start(struct seq_file *m, loff_t *pos) | ||
63 | { | ||
64 | loff_t l = *pos; | ||
65 | struct ima_queue_entry *qe; | ||
66 | |||
67 | /* we need a lock since pos could point beyond last element */ | ||
68 | rcu_read_lock(); | ||
69 | list_for_each_entry_rcu(qe, &ima_measurements, later) { | ||
70 | if (!l--) { | ||
71 | rcu_read_unlock(); | ||
72 | return qe; | ||
73 | } | ||
74 | } | ||
75 | rcu_read_unlock(); | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) | ||
80 | { | ||
81 | struct ima_queue_entry *qe = v; | ||
82 | |||
83 | /* lock protects when reading beyond last element | ||
84 | * against concurrent list-extension | ||
85 | */ | ||
86 | rcu_read_lock(); | ||
87 | qe = list_entry(rcu_dereference(qe->later.next), | ||
88 | struct ima_queue_entry, later); | ||
89 | rcu_read_unlock(); | ||
90 | (*pos)++; | ||
91 | |||
92 | return (&qe->later == &ima_measurements) ? NULL : qe; | ||
93 | } | ||
94 | |||
95 | static void ima_measurements_stop(struct seq_file *m, void *v) | ||
96 | { | ||
97 | } | ||
98 | |||
99 | static void ima_putc(struct seq_file *m, void *data, int datalen) | ||
100 | { | ||
101 | while (datalen--) | ||
102 | seq_putc(m, *(char *)data++); | ||
103 | } | ||
104 | |||
105 | /* print format: | ||
106 | * 32bit-le=pcr# | ||
107 | * char[20]=template digest | ||
108 | * 32bit-le=template name size | ||
109 | * char[n]=template name | ||
110 | * eventdata[n]=template specific data | ||
111 | */ | ||
112 | static int ima_measurements_show(struct seq_file *m, void *v) | ||
113 | { | ||
114 | /* the list never shrinks, so we don't need a lock here */ | ||
115 | struct ima_queue_entry *qe = v; | ||
116 | struct ima_template_entry *e; | ||
117 | int namelen; | ||
118 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | ||
119 | |||
120 | /* get entry */ | ||
121 | e = qe->entry; | ||
122 | if (e == NULL) | ||
123 | return -1; | ||
124 | |||
125 | /* | ||
126 | * 1st: PCRIndex | ||
127 | * PCR used is always the same (config option) in | ||
128 | * little-endian format | ||
129 | */ | ||
130 | ima_putc(m, &pcr, sizeof pcr); | ||
131 | |||
132 | /* 2nd: template digest */ | ||
133 | ima_putc(m, e->digest, IMA_DIGEST_SIZE); | ||
134 | |||
135 | /* 3rd: template name size */ | ||
136 | namelen = strlen(e->template_name); | ||
137 | ima_putc(m, &namelen, sizeof namelen); | ||
138 | |||
139 | /* 4th: template name */ | ||
140 | ima_putc(m, e->template_name, namelen); | ||
141 | |||
142 | /* 5th: template specific data */ | ||
143 | ima_template_show(m, (struct ima_template_data *)&e->template, | ||
144 | IMA_SHOW_BINARY); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static struct seq_operations ima_measurments_seqops = { | ||
149 | .start = ima_measurements_start, | ||
150 | .next = ima_measurements_next, | ||
151 | .stop = ima_measurements_stop, | ||
152 | .show = ima_measurements_show | ||
153 | }; | ||
154 | |||
155 | static int ima_measurements_open(struct inode *inode, struct file *file) | ||
156 | { | ||
157 | return seq_open(file, &ima_measurments_seqops); | ||
158 | } | ||
159 | |||
160 | static struct file_operations ima_measurements_ops = { | ||
161 | .open = ima_measurements_open, | ||
162 | .read = seq_read, | ||
163 | .llseek = seq_lseek, | ||
164 | .release = seq_release, | ||
165 | }; | ||
166 | |||
167 | static void ima_print_digest(struct seq_file *m, u8 *digest) | ||
168 | { | ||
169 | int i; | ||
170 | |||
171 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | ||
172 | seq_printf(m, "%02x", *(digest + i)); | ||
173 | } | ||
174 | |||
175 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show) | ||
176 | { | ||
177 | struct ima_template_data *entry = e; | ||
178 | int namelen; | ||
179 | |||
180 | switch (show) { | ||
181 | case IMA_SHOW_ASCII: | ||
182 | ima_print_digest(m, entry->digest); | ||
183 | seq_printf(m, " %s\n", entry->file_name); | ||
184 | break; | ||
185 | case IMA_SHOW_BINARY: | ||
186 | ima_putc(m, entry->digest, IMA_DIGEST_SIZE); | ||
187 | |||
188 | namelen = strlen(entry->file_name); | ||
189 | ima_putc(m, &namelen, sizeof namelen); | ||
190 | ima_putc(m, entry->file_name, namelen); | ||
191 | default: | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | /* print in ascii */ | ||
197 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) | ||
198 | { | ||
199 | /* the list never shrinks, so we don't need a lock here */ | ||
200 | struct ima_queue_entry *qe = v; | ||
201 | struct ima_template_entry *e; | ||
202 | |||
203 | /* get entry */ | ||
204 | e = qe->entry; | ||
205 | if (e == NULL) | ||
206 | return -1; | ||
207 | |||
208 | /* 1st: PCR used (config option) */ | ||
209 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); | ||
210 | |||
211 | /* 2nd: SHA1 template hash */ | ||
212 | ima_print_digest(m, e->digest); | ||
213 | |||
214 | /* 3th: template name */ | ||
215 | seq_printf(m, " %s ", e->template_name); | ||
216 | |||
217 | /* 4th: template specific data */ | ||
218 | ima_template_show(m, (struct ima_template_data *)&e->template, | ||
219 | IMA_SHOW_ASCII); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static struct seq_operations ima_ascii_measurements_seqops = { | ||
224 | .start = ima_measurements_start, | ||
225 | .next = ima_measurements_next, | ||
226 | .stop = ima_measurements_stop, | ||
227 | .show = ima_ascii_measurements_show | ||
228 | }; | ||
229 | |||
230 | static int ima_ascii_measurements_open(struct inode *inode, struct file *file) | ||
231 | { | ||
232 | return seq_open(file, &ima_ascii_measurements_seqops); | ||
233 | } | ||
234 | |||
235 | static struct file_operations ima_ascii_measurements_ops = { | ||
236 | .open = ima_ascii_measurements_open, | ||
237 | .read = seq_read, | ||
238 | .llseek = seq_lseek, | ||
239 | .release = seq_release, | ||
240 | }; | ||
241 | |||
242 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, | ||
243 | size_t datalen, loff_t *ppos) | ||
244 | { | ||
245 | char *data; | ||
246 | int rc; | ||
247 | |||
248 | if (datalen >= PAGE_SIZE) | ||
249 | return -ENOMEM; | ||
250 | if (*ppos != 0) { | ||
251 | /* No partial writes. */ | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | data = kmalloc(datalen + 1, GFP_KERNEL); | ||
255 | if (!data) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | if (copy_from_user(data, buf, datalen)) { | ||
259 | kfree(data); | ||
260 | return -EFAULT; | ||
261 | } | ||
262 | *(data + datalen) = '\0'; | ||
263 | rc = ima_parse_add_rule(data); | ||
264 | if (rc < 0) { | ||
265 | datalen = -EINVAL; | ||
266 | valid_policy = 0; | ||
267 | } | ||
268 | |||
269 | kfree(data); | ||
270 | return datalen; | ||
271 | } | ||
272 | |||
273 | static struct dentry *ima_dir; | ||
274 | static struct dentry *binary_runtime_measurements; | ||
275 | static struct dentry *ascii_runtime_measurements; | ||
276 | static struct dentry *runtime_measurements_count; | ||
277 | static struct dentry *violations; | ||
278 | static struct dentry *ima_policy; | ||
279 | |||
280 | static atomic_t policy_opencount = ATOMIC_INIT(1); | ||
281 | /* | ||
282 | * ima_open_policy: sequentialize access to the policy file | ||
283 | */ | ||
284 | int ima_open_policy(struct inode * inode, struct file * filp) | ||
285 | { | ||
286 | if (atomic_dec_and_test(&policy_opencount)) | ||
287 | return 0; | ||
288 | return -EBUSY; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * ima_release_policy - start using the new measure policy rules. | ||
293 | * | ||
294 | * Initially, ima_measure points to the default policy rules, now | ||
295 | * point to the new policy rules, and remove the securityfs policy file, | ||
296 | * assuming a valid policy. | ||
297 | */ | ||
298 | static int ima_release_policy(struct inode *inode, struct file *file) | ||
299 | { | ||
300 | if (!valid_policy) { | ||
301 | ima_delete_rules(); | ||
302 | valid_policy = 1; | ||
303 | atomic_set(&policy_opencount, 1); | ||
304 | return 0; | ||
305 | } | ||
306 | ima_update_policy(); | ||
307 | securityfs_remove(ima_policy); | ||
308 | ima_policy = NULL; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static struct file_operations ima_measure_policy_ops = { | ||
313 | .open = ima_open_policy, | ||
314 | .write = ima_write_policy, | ||
315 | .release = ima_release_policy | ||
316 | }; | ||
317 | |||
318 | int ima_fs_init(void) | ||
319 | { | ||
320 | ima_dir = securityfs_create_dir("ima", NULL); | ||
321 | if (IS_ERR(ima_dir)) | ||
322 | return -1; | ||
323 | |||
324 | binary_runtime_measurements = | ||
325 | securityfs_create_file("binary_runtime_measurements", | ||
326 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
327 | &ima_measurements_ops); | ||
328 | if (IS_ERR(binary_runtime_measurements)) | ||
329 | goto out; | ||
330 | |||
331 | ascii_runtime_measurements = | ||
332 | securityfs_create_file("ascii_runtime_measurements", | ||
333 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
334 | &ima_ascii_measurements_ops); | ||
335 | if (IS_ERR(ascii_runtime_measurements)) | ||
336 | goto out; | ||
337 | |||
338 | runtime_measurements_count = | ||
339 | securityfs_create_file("runtime_measurements_count", | ||
340 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
341 | &ima_measurements_count_ops); | ||
342 | if (IS_ERR(runtime_measurements_count)) | ||
343 | goto out; | ||
344 | |||
345 | violations = | ||
346 | securityfs_create_file("violations", S_IRUSR | S_IRGRP, | ||
347 | ima_dir, NULL, &ima_htable_violations_ops); | ||
348 | if (IS_ERR(violations)) | ||
349 | goto out; | ||
350 | |||
351 | ima_policy = securityfs_create_file("policy", | ||
352 | S_IRUSR | S_IRGRP | S_IWUSR, | ||
353 | ima_dir, NULL, | ||
354 | &ima_measure_policy_ops); | ||
355 | if (IS_ERR(ima_policy)) | ||
356 | goto out; | ||
357 | |||
358 | return 0; | ||
359 | out: | ||
360 | securityfs_remove(runtime_measurements_count); | ||
361 | securityfs_remove(ascii_runtime_measurements); | ||
362 | securityfs_remove(binary_runtime_measurements); | ||
363 | securityfs_remove(ima_dir); | ||
364 | securityfs_remove(ima_policy); | ||
365 | return -1; | ||
366 | } | ||
367 | |||
368 | void __exit ima_fs_cleanup(void) | ||
369 | { | ||
370 | securityfs_remove(violations); | ||
371 | securityfs_remove(runtime_measurements_count); | ||
372 | securityfs_remove(ascii_runtime_measurements); | ||
373 | securityfs_remove(binary_runtime_measurements); | ||
374 | securityfs_remove(ima_dir); | ||
375 | securityfs_remove(ima_policy); | ||
376 | } | ||
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c new file mode 100644 index 000000000000..1f035e8d29c7 --- /dev/null +++ b/security/integrity/ima/ima_iint.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Mimi Zohar <zohar@us.ibm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation, version 2 of the | ||
10 | * License. | ||
11 | * | ||
12 | * File: ima_iint.c | ||
13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free | ||
14 | * - cache integrity information associated with an inode | ||
15 | * using a radix tree. | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/radix-tree.h> | ||
20 | #include "ima.h" | ||
21 | |||
22 | #define ima_iint_delete ima_inode_free | ||
23 | |||
24 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); | ||
25 | DEFINE_SPINLOCK(ima_iint_lock); | ||
26 | |||
27 | static struct kmem_cache *iint_cache __read_mostly; | ||
28 | |||
29 | /* ima_iint_find_get - return the iint associated with an inode | ||
30 | * | ||
31 | * ima_iint_find_get gets a reference to the iint. Caller must | ||
32 | * remember to put the iint reference. | ||
33 | */ | ||
34 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode) | ||
35 | { | ||
36 | struct ima_iint_cache *iint; | ||
37 | |||
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; | ||
46 | } | ||
47 | |||
48 | /* Allocate memory for the iint associated with the inode | ||
49 | * from the iint_cache slab, initialize the iint, and | ||
50 | * insert it into the radix tree. | ||
51 | * | ||
52 | * On success return a pointer to the iint; on failure return NULL. | ||
53 | */ | ||
54 | struct ima_iint_cache *ima_iint_insert(struct inode *inode) | ||
55 | { | ||
56 | struct ima_iint_cache *iint = NULL; | ||
57 | int rc = 0; | ||
58 | |||
59 | if (!ima_initialized) | ||
60 | return iint; | ||
61 | iint = kmem_cache_alloc(iint_cache, GFP_KERNEL); | ||
62 | if (!iint) | ||
63 | return iint; | ||
64 | |||
65 | rc = radix_tree_preload(GFP_KERNEL); | ||
66 | if (rc < 0) | ||
67 | goto out; | ||
68 | |||
69 | spin_lock(&ima_iint_lock); | ||
70 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); | ||
71 | spin_unlock(&ima_iint_lock); | ||
72 | out: | ||
73 | if (rc < 0) { | ||
74 | kmem_cache_free(iint_cache, iint); | ||
75 | if (rc == -EEXIST) { | ||
76 | iint = radix_tree_lookup(&ima_iint_store, | ||
77 | (unsigned long)inode); | ||
78 | } else | ||
79 | iint = NULL; | ||
80 | } | ||
81 | radix_tree_preload_end(); | ||
82 | return iint; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * ima_inode_alloc - allocate an iint associated with an inode | ||
87 | * @inode: pointer to the inode | ||
88 | * | ||
89 | * Return 0 on success, 1 on failure. | ||
90 | */ | ||
91 | int ima_inode_alloc(struct inode *inode) | ||
92 | { | ||
93 | struct ima_iint_cache *iint; | ||
94 | |||
95 | if (!ima_initialized) | ||
96 | return 0; | ||
97 | |||
98 | iint = ima_iint_insert(inode); | ||
99 | if (!iint) | ||
100 | return 1; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* ima_iint_find_insert_get - get the iint associated with an inode | ||
105 | * | ||
106 | * Most insertions are done at inode_alloc, except those allocated | ||
107 | * before late_initcall. When the iint does not exist, allocate it, | ||
108 | * initialize and insert it, and increment the iint refcount. | ||
109 | * | ||
110 | * (Can't initialize at security_initcall before any inodes are | ||
111 | * allocated, got to wait at least until proc_init.) | ||
112 | * | ||
113 | * Return the iint. | ||
114 | */ | ||
115 | struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode) | ||
116 | { | ||
117 | struct ima_iint_cache *iint = NULL; | ||
118 | |||
119 | iint = ima_iint_find_get(inode); | ||
120 | if (iint) | ||
121 | return iint; | ||
122 | |||
123 | iint = ima_iint_insert(inode); | ||
124 | if (iint) | ||
125 | kref_get(&iint->refcount); | ||
126 | |||
127 | return iint; | ||
128 | } | ||
129 | EXPORT_SYMBOL_GPL(ima_iint_find_insert_get); | ||
130 | |||
131 | /* iint_free - called when the iint refcount goes to zero */ | ||
132 | void iint_free(struct kref *kref) | ||
133 | { | ||
134 | struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache, | ||
135 | refcount); | ||
136 | iint->version = 0; | ||
137 | iint->flags = 0UL; | ||
138 | if (iint->readcount != 0) { | ||
139 | printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__, | ||
140 | iint->readcount); | ||
141 | iint->readcount = 0; | ||
142 | } | ||
143 | if (iint->writecount != 0) { | ||
144 | printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__, | ||
145 | iint->writecount); | ||
146 | iint->writecount = 0; | ||
147 | } | ||
148 | if (iint->opencount != 0) { | ||
149 | printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__, | ||
150 | iint->opencount); | ||
151 | iint->opencount = 0; | ||
152 | } | ||
153 | kref_set(&iint->refcount, 1); | ||
154 | kmem_cache_free(iint_cache, iint); | ||
155 | } | ||
156 | |||
157 | void iint_rcu_free(struct rcu_head *rcu_head) | ||
158 | { | ||
159 | struct ima_iint_cache *iint = container_of(rcu_head, | ||
160 | struct ima_iint_cache, rcu); | ||
161 | kref_put(&iint->refcount, iint_free); | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * ima_iint_delete - called on integrity_inode_free | ||
166 | * @inode: pointer to the inode | ||
167 | * | ||
168 | * Free the integrity information(iint) associated with an inode. | ||
169 | */ | ||
170 | void ima_iint_delete(struct inode *inode) | ||
171 | { | ||
172 | struct ima_iint_cache *iint; | ||
173 | |||
174 | if (!ima_initialized) | ||
175 | return; | ||
176 | spin_lock(&ima_iint_lock); | ||
177 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | ||
178 | spin_unlock(&ima_iint_lock); | ||
179 | if (iint) | ||
180 | call_rcu(&iint->rcu, iint_rcu_free); | ||
181 | } | ||
182 | |||
183 | static void init_once(void *foo) | ||
184 | { | ||
185 | struct ima_iint_cache *iint = foo; | ||
186 | |||
187 | memset(iint, 0, sizeof *iint); | ||
188 | iint->version = 0; | ||
189 | iint->flags = 0UL; | ||
190 | mutex_init(&iint->mutex); | ||
191 | iint->readcount = 0; | ||
192 | iint->writecount = 0; | ||
193 | iint->opencount = 0; | ||
194 | kref_set(&iint->refcount, 1); | ||
195 | } | ||
196 | |||
197 | void ima_iintcache_init(void) | ||
198 | { | ||
199 | iint_cache = | ||
200 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | ||
201 | SLAB_PANIC, init_once); | ||
202 | } | ||
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c new file mode 100644 index 000000000000..cf227dbfac2c --- /dev/null +++ b/security/integrity/ima/ima_init.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Reiner Sailer <sailer@watson.ibm.com> | ||
6 | * Leendert van Doorn <leendert@watson.ibm.com> | ||
7 | * Mimi Zohar <zohar@us.ibm.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation, version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | * File: ima_init.c | ||
15 | * initialization and cleanup functions | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/scatterlist.h> | ||
19 | #include <linux/err.h> | ||
20 | #include "ima.h" | ||
21 | |||
22 | /* name for boot aggregate entry */ | ||
23 | static char *boot_aggregate_name = "boot_aggregate"; | ||
24 | int ima_used_chip; | ||
25 | |||
26 | /* Add the boot aggregate to the IMA measurement list and extend | ||
27 | * the PCR register. | ||
28 | * | ||
29 | * Calculate the boot aggregate, a SHA1 over tpm registers 0-7, | ||
30 | * assuming a TPM chip exists, and zeroes if the TPM chip does not | ||
31 | * exist. Add the boot aggregate measurement to the measurement | ||
32 | * list and extend the PCR register. | ||
33 | * | ||
34 | * If a tpm chip does not exist, indicate the core root of trust is | ||
35 | * not hardware based by invalidating the aggregate PCR value. | ||
36 | * (The aggregate PCR value is invalidated by adding one value to | ||
37 | * the measurement list and extending the aggregate PCR value with | ||
38 | * a different value.) Violations add a zero entry to the measurement | ||
39 | * list and extend the aggregate PCR value with ff...ff's. | ||
40 | */ | ||
41 | static void ima_add_boot_aggregate(void) | ||
42 | { | ||
43 | struct ima_template_entry *entry; | ||
44 | const char *op = "add_boot_aggregate"; | ||
45 | const char *audit_cause = "ENOMEM"; | ||
46 | int result = -ENOMEM; | ||
47 | int violation = 1; | ||
48 | |||
49 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
50 | if (!entry) | ||
51 | goto err_out; | ||
52 | |||
53 | memset(&entry->template, 0, sizeof(entry->template)); | ||
54 | strncpy(entry->template.file_name, boot_aggregate_name, | ||
55 | IMA_EVENT_NAME_LEN_MAX); | ||
56 | if (ima_used_chip) { | ||
57 | violation = 0; | ||
58 | result = ima_calc_boot_aggregate(entry->template.digest); | ||
59 | if (result < 0) { | ||
60 | audit_cause = "hashing_error"; | ||
61 | kfree(entry); | ||
62 | goto err_out; | ||
63 | } | ||
64 | } | ||
65 | result = ima_store_template(entry, violation, NULL); | ||
66 | if (result < 0) | ||
67 | kfree(entry); | ||
68 | return; | ||
69 | err_out: | ||
70 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, | ||
71 | audit_cause, result, 0); | ||
72 | } | ||
73 | |||
74 | int ima_init(void) | ||
75 | { | ||
76 | u8 pcr_i[IMA_DIGEST_SIZE]; | ||
77 | int rc; | ||
78 | |||
79 | ima_used_chip = 0; | ||
80 | rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i); | ||
81 | if (rc == 0) | ||
82 | ima_used_chip = 1; | ||
83 | |||
84 | if (!ima_used_chip) | ||
85 | pr_info("No TPM chip found, activating TPM-bypass!\n"); | ||
86 | |||
87 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ | ||
88 | ima_init_policy(); | ||
89 | |||
90 | return ima_fs_init(); | ||
91 | } | ||
92 | |||
93 | void __exit ima_cleanup(void) | ||
94 | { | ||
95 | ima_fs_cleanup(); | ||
96 | } | ||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c new file mode 100644 index 000000000000..f4e7266f5aee --- /dev/null +++ b/security/integrity/ima/ima_main.c | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Reiner Sailer <sailer@watson.ibm.com> | ||
6 | * Serge Hallyn <serue@us.ibm.com> | ||
7 | * Kylene Hall <kylene@us.ibm.com> | ||
8 | * Mimi Zohar <zohar@us.ibm.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation, version 2 of the | ||
13 | * License. | ||
14 | * | ||
15 | * File: ima_main.c | ||
16 | * implements the IMA hooks: ima_bprm_check, ima_file_mmap, | ||
17 | * and ima_path_check. | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/file.h> | ||
21 | #include <linux/binfmts.h> | ||
22 | #include <linux/mount.h> | ||
23 | #include <linux/mman.h> | ||
24 | |||
25 | #include "ima.h" | ||
26 | |||
27 | int ima_initialized; | ||
28 | |||
29 | char *ima_hash = "sha1"; | ||
30 | static int __init hash_setup(char *str) | ||
31 | { | ||
32 | const char *op = "hash_setup"; | ||
33 | const char *hash = "sha1"; | ||
34 | int result = 0; | ||
35 | int audit_info = 0; | ||
36 | |||
37 | if (strncmp(str, "md5", 3) == 0) { | ||
38 | hash = "md5"; | ||
39 | ima_hash = str; | ||
40 | } else if (strncmp(str, "sha1", 4) != 0) { | ||
41 | hash = "invalid_hash_type"; | ||
42 | result = 1; | ||
43 | } | ||
44 | integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, | ||
45 | result, audit_info); | ||
46 | return 1; | ||
47 | } | ||
48 | __setup("ima_hash=", hash_setup); | ||
49 | |||
50 | /** | ||
51 | * ima_file_free - called on __fput() | ||
52 | * @file: pointer to file structure being freed | ||
53 | * | ||
54 | * Flag files that changed, based on i_version; | ||
55 | * and decrement the iint readcount/writecount. | ||
56 | */ | ||
57 | void ima_file_free(struct file *file) | ||
58 | { | ||
59 | struct inode *inode = file->f_dentry->d_inode; | ||
60 | struct ima_iint_cache *iint; | ||
61 | |||
62 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
63 | return; | ||
64 | iint = ima_iint_find_get(inode); | ||
65 | if (!iint) | ||
66 | return; | ||
67 | |||
68 | mutex_lock(&iint->mutex); | ||
69 | if (iint->opencount <= 0) { | ||
70 | printk(KERN_INFO | ||
71 | "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n", | ||
72 | __FUNCTION__, file->f_dentry->d_name.name, | ||
73 | iint->readcount, iint->writecount, | ||
74 | iint->opencount, atomic_long_read(&file->f_count)); | ||
75 | if (!(iint->flags & IMA_IINT_DUMP_STACK)) { | ||
76 | dump_stack(); | ||
77 | iint->flags |= IMA_IINT_DUMP_STACK; | ||
78 | } | ||
79 | } | ||
80 | iint->opencount--; | ||
81 | |||
82 | if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
83 | iint->readcount--; | ||
84 | |||
85 | if (file->f_mode & FMODE_WRITE) { | ||
86 | iint->writecount--; | ||
87 | if (iint->writecount == 0) { | ||
88 | if (iint->version != inode->i_version) | ||
89 | iint->flags &= ~IMA_MEASURED; | ||
90 | } | ||
91 | } | ||
92 | mutex_unlock(&iint->mutex); | ||
93 | kref_put(&iint->refcount, iint_free); | ||
94 | } | ||
95 | |||
96 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
97 | * | ||
98 | * When opening a file for read, if the file is already open for write, | ||
99 | * the file could change, resulting in a file measurement error. | ||
100 | * | ||
101 | * Opening a file for write, if the file is already open for read, results | ||
102 | * in a time of measure, time of use (ToMToU) error. | ||
103 | * | ||
104 | * In either case invalidate the PCR. | ||
105 | */ | ||
106 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
107 | static void ima_read_write_check(enum iint_pcr_error error, | ||
108 | struct ima_iint_cache *iint, | ||
109 | struct inode *inode, | ||
110 | const unsigned char *filename) | ||
111 | { | ||
112 | switch (error) { | ||
113 | case TOMTOU: | ||
114 | if (iint->readcount > 0) | ||
115 | ima_add_violation(inode, filename, "invalid_pcr", | ||
116 | "ToMToU"); | ||
117 | break; | ||
118 | case OPEN_WRITERS: | ||
119 | if (iint->writecount > 0) | ||
120 | ima_add_violation(inode, filename, "invalid_pcr", | ||
121 | "open_writers"); | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | ||
127 | const unsigned char *filename) | ||
128 | { | ||
129 | int rc = 0; | ||
130 | |||
131 | if (IS_ERR(file)) { | ||
132 | pr_info("%s dentry_open failed\n", filename); | ||
133 | return rc; | ||
134 | } | ||
135 | iint->opencount++; | ||
136 | iint->readcount++; | ||
137 | |||
138 | rc = ima_collect_measurement(iint, file); | ||
139 | if (!rc) | ||
140 | ima_store_measurement(iint, file, filename); | ||
141 | return rc; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * ima_path_check - based on policy, collect/store measurement. | ||
146 | * @path: contains a pointer to the path to be measured | ||
147 | * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE | ||
148 | * | ||
149 | * Measure the file being open for readonly, based on the | ||
150 | * ima_must_measure() policy decision. | ||
151 | * | ||
152 | * Keep read/write counters for all files, but only | ||
153 | * invalidate the PCR for measured files: | ||
154 | * - Opening a file for write when already open for read, | ||
155 | * results in a time of measure, time of use (ToMToU) error. | ||
156 | * - Opening a file for read when already open for write, | ||
157 | * could result in a file measurement error. | ||
158 | * | ||
159 | * Return 0 on success, an error code on failure. | ||
160 | * (Based on the results of appraise_measurement().) | ||
161 | */ | ||
162 | int ima_path_check(struct path *path, int mask) | ||
163 | { | ||
164 | struct inode *inode = path->dentry->d_inode; | ||
165 | struct ima_iint_cache *iint; | ||
166 | struct file *file = NULL; | ||
167 | int rc; | ||
168 | |||
169 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
170 | return 0; | ||
171 | iint = ima_iint_find_insert_get(inode); | ||
172 | if (!iint) | ||
173 | return 0; | ||
174 | |||
175 | mutex_lock(&iint->mutex); | ||
176 | iint->opencount++; | ||
177 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
178 | iint->writecount++; | ||
179 | else if (mask & (MAY_READ | MAY_EXEC)) | ||
180 | iint->readcount++; | ||
181 | |||
182 | rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); | ||
183 | if (rc < 0) | ||
184 | goto out; | ||
185 | |||
186 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
187 | ima_read_write_check(TOMTOU, iint, inode, | ||
188 | path->dentry->d_name.name); | ||
189 | |||
190 | if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ) | ||
191 | goto out; | ||
192 | |||
193 | ima_read_write_check(OPEN_WRITERS, iint, inode, | ||
194 | path->dentry->d_name.name); | ||
195 | if (!(iint->flags & IMA_MEASURED)) { | ||
196 | struct dentry *dentry = dget(path->dentry); | ||
197 | struct vfsmount *mnt = mntget(path->mnt); | ||
198 | |||
199 | file = dentry_open(dentry, mnt, O_RDONLY, current->cred); | ||
200 | rc = get_path_measurement(iint, file, dentry->d_name.name); | ||
201 | } | ||
202 | out: | ||
203 | mutex_unlock(&iint->mutex); | ||
204 | if (file) | ||
205 | fput(file); | ||
206 | kref_put(&iint->refcount, iint_free); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int process_measurement(struct file *file, const unsigned char *filename, | ||
211 | int mask, int function) | ||
212 | { | ||
213 | struct inode *inode = file->f_dentry->d_inode; | ||
214 | struct ima_iint_cache *iint; | ||
215 | int rc; | ||
216 | |||
217 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
218 | return 0; | ||
219 | iint = ima_iint_find_insert_get(inode); | ||
220 | if (!iint) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | mutex_lock(&iint->mutex); | ||
224 | rc = ima_must_measure(iint, inode, mask, function); | ||
225 | if (rc != 0) | ||
226 | goto out; | ||
227 | |||
228 | rc = ima_collect_measurement(iint, file); | ||
229 | if (!rc) | ||
230 | ima_store_measurement(iint, file, filename); | ||
231 | out: | ||
232 | mutex_unlock(&iint->mutex); | ||
233 | kref_put(&iint->refcount, iint_free); | ||
234 | return rc; | ||
235 | } | ||
236 | |||
237 | static void opencount_get(struct file *file) | ||
238 | { | ||
239 | struct inode *inode = file->f_dentry->d_inode; | ||
240 | struct ima_iint_cache *iint; | ||
241 | |||
242 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
243 | return; | ||
244 | iint = ima_iint_find_insert_get(inode); | ||
245 | if (!iint) | ||
246 | return; | ||
247 | mutex_lock(&iint->mutex); | ||
248 | iint->opencount++; | ||
249 | mutex_unlock(&iint->mutex); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * ima_file_mmap - based on policy, collect/store measurement. | ||
254 | * @file: pointer to the file to be measured (May be NULL) | ||
255 | * @prot: contains the protection that will be applied by the kernel. | ||
256 | * | ||
257 | * Measure files being mmapped executable based on the ima_must_measure() | ||
258 | * policy decision. | ||
259 | * | ||
260 | * Return 0 on success, an error code on failure. | ||
261 | * (Based on the results of appraise_measurement().) | ||
262 | */ | ||
263 | int ima_file_mmap(struct file *file, unsigned long prot) | ||
264 | { | ||
265 | int rc; | ||
266 | |||
267 | if (!file) | ||
268 | return 0; | ||
269 | if (prot & PROT_EXEC) | ||
270 | rc = process_measurement(file, file->f_dentry->d_name.name, | ||
271 | MAY_EXEC, FILE_MMAP); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * ima_shm_check - IPC shm and shmat create/fput a file | ||
277 | * | ||
278 | * Maintain the opencount for these files to prevent unnecessary | ||
279 | * imbalance messages. | ||
280 | */ | ||
281 | void ima_shm_check(struct file *file) | ||
282 | { | ||
283 | opencount_get(file); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * ima_bprm_check - based on policy, collect/store measurement. | ||
289 | * @bprm: contains the linux_binprm structure | ||
290 | * | ||
291 | * The OS protects against an executable file, already open for write, | ||
292 | * from being executed in deny_write_access() and an executable file, | ||
293 | * already open for execute, from being modified in get_write_access(). | ||
294 | * So we can be certain that what we verify and measure here is actually | ||
295 | * what is being executed. | ||
296 | * | ||
297 | * Return 0 on success, an error code on failure. | ||
298 | * (Based on the results of appraise_measurement().) | ||
299 | */ | ||
300 | int ima_bprm_check(struct linux_binprm *bprm) | ||
301 | { | ||
302 | int rc; | ||
303 | |||
304 | rc = process_measurement(bprm->file, bprm->filename, | ||
305 | MAY_EXEC, BPRM_CHECK); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int __init init_ima(void) | ||
310 | { | ||
311 | int error; | ||
312 | |||
313 | ima_iintcache_init(); | ||
314 | error = ima_init(); | ||
315 | ima_initialized = 1; | ||
316 | return error; | ||
317 | } | ||
318 | |||
319 | static void __exit cleanup_ima(void) | ||
320 | { | ||
321 | ima_cleanup(); | ||
322 | } | ||
323 | |||
324 | late_initcall(init_ima); /* Start IMA after the TPM is available */ | ||
325 | |||
326 | MODULE_DESCRIPTION("Integrity Measurement Architecture"); | ||
327 | MODULE_LICENSE("GPL"); | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c new file mode 100644 index 000000000000..23810e0bfc68 --- /dev/null +++ b/security/integrity/ima/ima_policy.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, version 2 of the License. | ||
8 | * | ||
9 | * ima_policy.c | ||
10 | * - initialize default measure policy rules | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <linux/audit.h> | ||
16 | #include <linux/security.h> | ||
17 | #include <linux/magic.h> | ||
18 | #include <linux/parser.h> | ||
19 | |||
20 | #include "ima.h" | ||
21 | |||
22 | /* flags definitions */ | ||
23 | #define IMA_FUNC 0x0001 | ||
24 | #define IMA_MASK 0x0002 | ||
25 | #define IMA_FSMAGIC 0x0004 | ||
26 | #define IMA_UID 0x0008 | ||
27 | |||
28 | enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; | ||
29 | |||
30 | #define MAX_LSM_RULES 6 | ||
31 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | ||
32 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | ||
33 | }; | ||
34 | |||
35 | struct ima_measure_rule_entry { | ||
36 | struct list_head list; | ||
37 | enum ima_action action; | ||
38 | unsigned int flags; | ||
39 | enum ima_hooks func; | ||
40 | int mask; | ||
41 | unsigned long fsmagic; | ||
42 | uid_t uid; | ||
43 | struct { | ||
44 | void *rule; /* LSM file metadata specific */ | ||
45 | int type; /* audit type */ | ||
46 | } lsm[MAX_LSM_RULES]; | ||
47 | }; | ||
48 | |||
49 | /* Without LSM specific knowledge, the default policy can only be | ||
50 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | ||
51 | */ | ||
52 | static struct ima_measure_rule_entry default_rules[] = { | ||
53 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, | ||
54 | .flags = IMA_FSMAGIC}, | ||
55 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
56 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
57 | {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
58 | {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC, | ||
59 | .flags = IMA_FSMAGIC}, | ||
60 | {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC}, | ||
61 | {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, | ||
62 | .flags = IMA_FUNC | IMA_MASK}, | ||
63 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, | ||
64 | .flags = IMA_FUNC | IMA_MASK}, | ||
65 | {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, | ||
66 | .flags = IMA_FUNC | IMA_MASK | IMA_UID} | ||
67 | }; | ||
68 | |||
69 | static LIST_HEAD(measure_default_rules); | ||
70 | static LIST_HEAD(measure_policy_rules); | ||
71 | static struct list_head *ima_measure; | ||
72 | |||
73 | static DEFINE_MUTEX(ima_measure_mutex); | ||
74 | |||
75 | /** | ||
76 | * ima_match_rules - determine whether an inode matches the measure rule. | ||
77 | * @rule: a pointer to a rule | ||
78 | * @inode: a pointer to an inode | ||
79 | * @func: LIM hook identifier | ||
80 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | ||
81 | * | ||
82 | * Returns true on rule match, false on failure. | ||
83 | */ | ||
84 | static bool ima_match_rules(struct ima_measure_rule_entry *rule, | ||
85 | struct inode *inode, enum ima_hooks func, int mask) | ||
86 | { | ||
87 | struct task_struct *tsk = current; | ||
88 | int i; | ||
89 | |||
90 | if ((rule->flags & IMA_FUNC) && rule->func != func) | ||
91 | return false; | ||
92 | if ((rule->flags & IMA_MASK) && rule->mask != mask) | ||
93 | return false; | ||
94 | if ((rule->flags & IMA_FSMAGIC) | ||
95 | && rule->fsmagic != inode->i_sb->s_magic) | ||
96 | return false; | ||
97 | if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) | ||
98 | return false; | ||
99 | for (i = 0; i < MAX_LSM_RULES; i++) { | ||
100 | int rc; | ||
101 | u32 osid, sid; | ||
102 | |||
103 | if (!rule->lsm[i].rule) | ||
104 | continue; | ||
105 | |||
106 | switch (i) { | ||
107 | case LSM_OBJ_USER: | ||
108 | case LSM_OBJ_ROLE: | ||
109 | case LSM_OBJ_TYPE: | ||
110 | security_inode_getsecid(inode, &osid); | ||
111 | rc = security_filter_rule_match(osid, | ||
112 | rule->lsm[i].type, | ||
113 | AUDIT_EQUAL, | ||
114 | rule->lsm[i].rule, | ||
115 | NULL); | ||
116 | break; | ||
117 | case LSM_SUBJ_USER: | ||
118 | case LSM_SUBJ_ROLE: | ||
119 | case LSM_SUBJ_TYPE: | ||
120 | security_task_getsecid(tsk, &sid); | ||
121 | rc = security_filter_rule_match(sid, | ||
122 | rule->lsm[i].type, | ||
123 | AUDIT_EQUAL, | ||
124 | rule->lsm[i].rule, | ||
125 | NULL); | ||
126 | default: | ||
127 | break; | ||
128 | } | ||
129 | if (!rc) | ||
130 | return false; | ||
131 | } | ||
132 | return true; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * ima_match_policy - decision based on LSM and other conditions | ||
137 | * @inode: pointer to an inode for which the policy decision is being made | ||
138 | * @func: IMA hook identifier | ||
139 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | ||
140 | * | ||
141 | * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) | ||
142 | * conditions. | ||
143 | * | ||
144 | * (There is no need for locking when walking the policy list, | ||
145 | * as elements in the list are never deleted, nor does the list | ||
146 | * change.) | ||
147 | */ | ||
148 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | ||
149 | { | ||
150 | struct ima_measure_rule_entry *entry; | ||
151 | |||
152 | list_for_each_entry(entry, ima_measure, list) { | ||
153 | bool rc; | ||
154 | |||
155 | rc = ima_match_rules(entry, inode, func, mask); | ||
156 | if (rc) | ||
157 | return entry->action; | ||
158 | } | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * ima_init_policy - initialize the default measure rules. | ||
164 | * | ||
165 | * ima_measure points to either the measure_default_rules or the | ||
166 | * the new measure_policy_rules. | ||
167 | */ | ||
168 | void ima_init_policy(void) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | for (i = 0; i < ARRAY_SIZE(default_rules); i++) | ||
173 | list_add_tail(&default_rules[i].list, &measure_default_rules); | ||
174 | ima_measure = &measure_default_rules; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * ima_update_policy - update default_rules with new measure rules | ||
179 | * | ||
180 | * Called on file .release to update the default rules with a complete new | ||
181 | * policy. Once updated, the policy is locked, no additional rules can be | ||
182 | * added to the policy. | ||
183 | */ | ||
184 | void ima_update_policy(void) | ||
185 | { | ||
186 | const char *op = "policy_update"; | ||
187 | const char *cause = "already exists"; | ||
188 | int result = 1; | ||
189 | int audit_info = 0; | ||
190 | |||
191 | if (ima_measure == &measure_default_rules) { | ||
192 | ima_measure = &measure_policy_rules; | ||
193 | cause = "complete"; | ||
194 | result = 0; | ||
195 | } | ||
196 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
197 | NULL, op, cause, result, audit_info); | ||
198 | } | ||
199 | |||
200 | enum { | ||
201 | Opt_err = -1, | ||
202 | Opt_measure = 1, Opt_dont_measure, | ||
203 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | ||
204 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | ||
205 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid | ||
206 | }; | ||
207 | |||
208 | static match_table_t policy_tokens = { | ||
209 | {Opt_measure, "measure"}, | ||
210 | {Opt_dont_measure, "dont_measure"}, | ||
211 | {Opt_obj_user, "obj_user=%s"}, | ||
212 | {Opt_obj_role, "obj_role=%s"}, | ||
213 | {Opt_obj_type, "obj_type=%s"}, | ||
214 | {Opt_subj_user, "subj_user=%s"}, | ||
215 | {Opt_subj_role, "subj_role=%s"}, | ||
216 | {Opt_subj_type, "subj_type=%s"}, | ||
217 | {Opt_func, "func=%s"}, | ||
218 | {Opt_mask, "mask=%s"}, | ||
219 | {Opt_fsmagic, "fsmagic=%s"}, | ||
220 | {Opt_uid, "uid=%s"}, | ||
221 | {Opt_err, NULL} | ||
222 | }; | ||
223 | |||
224 | static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | ||
225 | char *args, int lsm_rule, int audit_type) | ||
226 | { | ||
227 | int result; | ||
228 | |||
229 | entry->lsm[lsm_rule].type = audit_type; | ||
230 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, | ||
231 | AUDIT_EQUAL, args, | ||
232 | &entry->lsm[lsm_rule].rule); | ||
233 | return result; | ||
234 | } | ||
235 | |||
236 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | ||
237 | { | ||
238 | struct audit_buffer *ab; | ||
239 | char *p; | ||
240 | int result = 0; | ||
241 | |||
242 | ab = audit_log_start(current->audit_context, GFP_KERNEL, | ||
243 | AUDIT_INTEGRITY_STATUS); | ||
244 | |||
245 | entry->action = -1; | ||
246 | while ((p = strsep(&rule, " \n")) != NULL) { | ||
247 | substring_t args[MAX_OPT_ARGS]; | ||
248 | int token; | ||
249 | unsigned long lnum; | ||
250 | |||
251 | if (result < 0) | ||
252 | break; | ||
253 | if (!*p) | ||
254 | continue; | ||
255 | token = match_token(p, policy_tokens, args); | ||
256 | switch (token) { | ||
257 | case Opt_measure: | ||
258 | audit_log_format(ab, "%s ", "measure"); | ||
259 | entry->action = MEASURE; | ||
260 | break; | ||
261 | case Opt_dont_measure: | ||
262 | audit_log_format(ab, "%s ", "dont_measure"); | ||
263 | entry->action = DONT_MEASURE; | ||
264 | break; | ||
265 | case Opt_func: | ||
266 | audit_log_format(ab, "func=%s ", args[0].from); | ||
267 | if (strcmp(args[0].from, "PATH_CHECK") == 0) | ||
268 | entry->func = PATH_CHECK; | ||
269 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) | ||
270 | entry->func = FILE_MMAP; | ||
271 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) | ||
272 | entry->func = BPRM_CHECK; | ||
273 | else | ||
274 | result = -EINVAL; | ||
275 | if (!result) | ||
276 | entry->flags |= IMA_FUNC; | ||
277 | break; | ||
278 | case Opt_mask: | ||
279 | audit_log_format(ab, "mask=%s ", args[0].from); | ||
280 | if ((strcmp(args[0].from, "MAY_EXEC")) == 0) | ||
281 | entry->mask = MAY_EXEC; | ||
282 | else if (strcmp(args[0].from, "MAY_WRITE") == 0) | ||
283 | entry->mask = MAY_WRITE; | ||
284 | else if (strcmp(args[0].from, "MAY_READ") == 0) | ||
285 | entry->mask = MAY_READ; | ||
286 | else if (strcmp(args[0].from, "MAY_APPEND") == 0) | ||
287 | entry->mask = MAY_APPEND; | ||
288 | else | ||
289 | result = -EINVAL; | ||
290 | if (!result) | ||
291 | entry->flags |= IMA_MASK; | ||
292 | break; | ||
293 | case Opt_fsmagic: | ||
294 | audit_log_format(ab, "fsmagic=%s ", args[0].from); | ||
295 | result = strict_strtoul(args[0].from, 16, | ||
296 | &entry->fsmagic); | ||
297 | if (!result) | ||
298 | entry->flags |= IMA_FSMAGIC; | ||
299 | break; | ||
300 | case Opt_uid: | ||
301 | audit_log_format(ab, "uid=%s ", args[0].from); | ||
302 | result = strict_strtoul(args[0].from, 10, &lnum); | ||
303 | if (!result) { | ||
304 | entry->uid = (uid_t) lnum; | ||
305 | if (entry->uid != lnum) | ||
306 | result = -EINVAL; | ||
307 | else | ||
308 | entry->flags |= IMA_UID; | ||
309 | } | ||
310 | break; | ||
311 | case Opt_obj_user: | ||
312 | audit_log_format(ab, "obj_user=%s ", args[0].from); | ||
313 | result = ima_lsm_rule_init(entry, args[0].from, | ||
314 | LSM_OBJ_USER, | ||
315 | AUDIT_OBJ_USER); | ||
316 | break; | ||
317 | case Opt_obj_role: | ||
318 | audit_log_format(ab, "obj_role=%s ", args[0].from); | ||
319 | result = ima_lsm_rule_init(entry, args[0].from, | ||
320 | LSM_OBJ_ROLE, | ||
321 | AUDIT_OBJ_ROLE); | ||
322 | break; | ||
323 | case Opt_obj_type: | ||
324 | audit_log_format(ab, "obj_type=%s ", args[0].from); | ||
325 | result = ima_lsm_rule_init(entry, args[0].from, | ||
326 | LSM_OBJ_TYPE, | ||
327 | AUDIT_OBJ_TYPE); | ||
328 | break; | ||
329 | case Opt_subj_user: | ||
330 | audit_log_format(ab, "subj_user=%s ", args[0].from); | ||
331 | result = ima_lsm_rule_init(entry, args[0].from, | ||
332 | LSM_SUBJ_USER, | ||
333 | AUDIT_SUBJ_USER); | ||
334 | break; | ||
335 | case Opt_subj_role: | ||
336 | audit_log_format(ab, "subj_role=%s ", args[0].from); | ||
337 | result = ima_lsm_rule_init(entry, args[0].from, | ||
338 | LSM_SUBJ_ROLE, | ||
339 | AUDIT_SUBJ_ROLE); | ||
340 | break; | ||
341 | case Opt_subj_type: | ||
342 | audit_log_format(ab, "subj_type=%s ", args[0].from); | ||
343 | result = ima_lsm_rule_init(entry, args[0].from, | ||
344 | LSM_SUBJ_TYPE, | ||
345 | AUDIT_SUBJ_TYPE); | ||
346 | break; | ||
347 | case Opt_err: | ||
348 | printk(KERN_INFO "%s: unknown token: %s\n", | ||
349 | __FUNCTION__, p); | ||
350 | break; | ||
351 | } | ||
352 | } | ||
353 | if (entry->action == UNKNOWN) | ||
354 | result = -EINVAL; | ||
355 | |||
356 | audit_log_format(ab, "res=%d", result); | ||
357 | audit_log_end(ab); | ||
358 | return result; | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * ima_parse_add_rule - add a rule to measure_policy_rules | ||
363 | * @rule - ima measurement policy rule | ||
364 | * | ||
365 | * Uses a mutex to protect the policy list from multiple concurrent writers. | ||
366 | * Returns 0 on success, an error code on failure. | ||
367 | */ | ||
368 | int ima_parse_add_rule(char *rule) | ||
369 | { | ||
370 | const char *op = "add_rule"; | ||
371 | struct ima_measure_rule_entry *entry; | ||
372 | int result = 0; | ||
373 | int audit_info = 0; | ||
374 | |||
375 | /* Prevent installed policy from changing */ | ||
376 | if (ima_measure != &measure_default_rules) { | ||
377 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
378 | NULL, op, "already exists", | ||
379 | -EACCES, audit_info); | ||
380 | return -EACCES; | ||
381 | } | ||
382 | |||
383 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
384 | if (!entry) { | ||
385 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
386 | NULL, op, "-ENOMEM", -ENOMEM, audit_info); | ||
387 | return -ENOMEM; | ||
388 | } | ||
389 | |||
390 | INIT_LIST_HEAD(&entry->list); | ||
391 | |||
392 | result = ima_parse_rule(rule, entry); | ||
393 | if (!result) { | ||
394 | mutex_lock(&ima_measure_mutex); | ||
395 | list_add_tail(&entry->list, &measure_policy_rules); | ||
396 | mutex_unlock(&ima_measure_mutex); | ||
397 | } else | ||
398 | kfree(entry); | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | /* ima_delete_rules called to cleanup invalid policy */ | ||
403 | void ima_delete_rules(void) | ||
404 | { | ||
405 | struct ima_measure_rule_entry *entry, *tmp; | ||
406 | |||
407 | mutex_lock(&ima_measure_mutex); | ||
408 | list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { | ||
409 | list_del(&entry->list); | ||
410 | kfree(entry); | ||
411 | } | ||
412 | mutex_unlock(&ima_measure_mutex); | ||
413 | } | ||
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c new file mode 100644 index 000000000000..7ec94314ac0c --- /dev/null +++ b/security/integrity/ima/ima_queue.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Serge Hallyn <serue@us.ibm.com> | ||
6 | * Reiner Sailer <sailer@watson.ibm.com> | ||
7 | * Mimi Zohar <zohar@us.ibm.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation, version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | * File: ima_queue.c | ||
15 | * Implements queues that store template measurements and | ||
16 | * maintains aggregate over the stored measurements | ||
17 | * in the pre-configured TPM PCR (if available). | ||
18 | * The measurement list is append-only. No entry is | ||
19 | * ever removed or changed during the boot-cycle. | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/rculist.h> | ||
23 | #include "ima.h" | ||
24 | |||
25 | LIST_HEAD(ima_measurements); /* list of all measurements */ | ||
26 | |||
27 | /* key: inode (before secure-hashing a file) */ | ||
28 | struct ima_h_table ima_htable = { | ||
29 | .len = ATOMIC_LONG_INIT(0), | ||
30 | .violations = ATOMIC_LONG_INIT(0), | ||
31 | .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT | ||
32 | }; | ||
33 | |||
34 | /* mutex protects atomicity of extending measurement list | ||
35 | * and extending the TPM PCR aggregate. Since tpm_extend can take | ||
36 | * long (and the tpm driver uses a mutex), we can't use the spinlock. | ||
37 | */ | ||
38 | static DEFINE_MUTEX(ima_extend_list_mutex); | ||
39 | |||
40 | /* lookup up the digest value in the hash table, and return the entry */ | ||
41 | static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value) | ||
42 | { | ||
43 | struct ima_queue_entry *qe, *ret = NULL; | ||
44 | unsigned int key; | ||
45 | struct hlist_node *pos; | ||
46 | int rc; | ||
47 | |||
48 | key = ima_hash_key(digest_value); | ||
49 | rcu_read_lock(); | ||
50 | hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) { | ||
51 | rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE); | ||
52 | if (rc == 0) { | ||
53 | ret = qe; | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | rcu_read_unlock(); | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | /* ima_add_template_entry helper function: | ||
62 | * - Add template entry to measurement list and hash table. | ||
63 | * | ||
64 | * (Called with ima_extend_list_mutex held.) | ||
65 | */ | ||
66 | static int ima_add_digest_entry(struct ima_template_entry *entry) | ||
67 | { | ||
68 | struct ima_queue_entry *qe; | ||
69 | unsigned int key; | ||
70 | |||
71 | qe = kmalloc(sizeof(*qe), GFP_KERNEL); | ||
72 | if (qe == NULL) { | ||
73 | pr_err("OUT OF MEMORY ERROR creating queue entry.\n"); | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | qe->entry = entry; | ||
77 | |||
78 | INIT_LIST_HEAD(&qe->later); | ||
79 | list_add_tail_rcu(&qe->later, &ima_measurements); | ||
80 | |||
81 | atomic_long_inc(&ima_htable.len); | ||
82 | key = ima_hash_key(entry->digest); | ||
83 | hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int ima_pcr_extend(const u8 *hash) | ||
88 | { | ||
89 | int result = 0; | ||
90 | |||
91 | if (!ima_used_chip) | ||
92 | return result; | ||
93 | |||
94 | result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); | ||
95 | if (result != 0) | ||
96 | pr_err("Error Communicating to TPM chip\n"); | ||
97 | return result; | ||
98 | } | ||
99 | |||
100 | /* Add template entry to the measurement list and hash table, | ||
101 | * and extend the pcr. | ||
102 | */ | ||
103 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | ||
104 | const char *op, struct inode *inode) | ||
105 | { | ||
106 | u8 digest[IMA_DIGEST_SIZE]; | ||
107 | const char *audit_cause = "hash_added"; | ||
108 | int audit_info = 1; | ||
109 | int result = 0; | ||
110 | |||
111 | mutex_lock(&ima_extend_list_mutex); | ||
112 | if (!violation) { | ||
113 | memcpy(digest, entry->digest, sizeof digest); | ||
114 | if (ima_lookup_digest_entry(digest)) { | ||
115 | audit_cause = "hash_exists"; | ||
116 | goto out; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | result = ima_add_digest_entry(entry); | ||
121 | if (result < 0) { | ||
122 | audit_cause = "ENOMEM"; | ||
123 | audit_info = 0; | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | if (violation) /* invalidate pcr */ | ||
128 | memset(digest, 0xff, sizeof digest); | ||
129 | |||
130 | result = ima_pcr_extend(digest); | ||
131 | if (result != 0) { | ||
132 | audit_cause = "TPM error"; | ||
133 | audit_info = 0; | ||
134 | } | ||
135 | out: | ||
136 | mutex_unlock(&ima_extend_list_mutex); | ||
137 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, entry->template_name, | ||
138 | op, audit_cause, result, audit_info); | ||
139 | return result; | ||
140 | } | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 00815973d412..a69d6f8970ca 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -89,7 +89,7 @@ | |||
89 | #define XATTR_SELINUX_SUFFIX "selinux" | 89 | #define XATTR_SELINUX_SUFFIX "selinux" |
90 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX | 90 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX |
91 | 91 | ||
92 | #define NUM_SEL_MNT_OPTS 4 | 92 | #define NUM_SEL_MNT_OPTS 5 |
93 | 93 | ||
94 | extern unsigned int policydb_loaded_version; | 94 | extern unsigned int policydb_loaded_version; |
95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
@@ -353,6 +353,7 @@ enum { | |||
353 | Opt_fscontext = 2, | 353 | Opt_fscontext = 2, |
354 | Opt_defcontext = 3, | 354 | Opt_defcontext = 3, |
355 | Opt_rootcontext = 4, | 355 | Opt_rootcontext = 4, |
356 | Opt_labelsupport = 5, | ||
356 | }; | 357 | }; |
357 | 358 | ||
358 | static const match_table_t tokens = { | 359 | static const match_table_t tokens = { |
@@ -360,6 +361,7 @@ static const match_table_t tokens = { | |||
360 | {Opt_fscontext, FSCONTEXT_STR "%s"}, | 361 | {Opt_fscontext, FSCONTEXT_STR "%s"}, |
361 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, | 362 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, |
362 | {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, | 363 | {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, |
364 | {Opt_labelsupport, LABELSUPP_STR}, | ||
363 | {Opt_error, NULL}, | 365 | {Opt_error, NULL}, |
364 | }; | 366 | }; |
365 | 367 | ||
@@ -431,7 +433,7 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
431 | } | 433 | } |
432 | } | 434 | } |
433 | 435 | ||
434 | sbsec->initialized = 1; | 436 | sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP); |
435 | 437 | ||
436 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | 438 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) |
437 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", | 439 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", |
@@ -441,6 +443,12 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
441 | sb->s_id, sb->s_type->name, | 443 | sb->s_id, sb->s_type->name, |
442 | labeling_behaviors[sbsec->behavior-1]); | 444 | labeling_behaviors[sbsec->behavior-1]); |
443 | 445 | ||
446 | if (sbsec->behavior == SECURITY_FS_USE_GENFS || | ||
447 | sbsec->behavior == SECURITY_FS_USE_MNTPOINT || | ||
448 | sbsec->behavior == SECURITY_FS_USE_NONE || | ||
449 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | ||
450 | sbsec->flags &= ~SE_SBLABELSUPP; | ||
451 | |||
444 | /* Initialize the root inode. */ | 452 | /* Initialize the root inode. */ |
445 | rc = inode_doinit_with_dentry(root_inode, root); | 453 | rc = inode_doinit_with_dentry(root_inode, root); |
446 | 454 | ||
@@ -487,23 +495,22 @@ static int selinux_get_mnt_opts(const struct super_block *sb, | |||
487 | 495 | ||
488 | security_init_mnt_opts(opts); | 496 | security_init_mnt_opts(opts); |
489 | 497 | ||
490 | if (!sbsec->initialized) | 498 | if (!(sbsec->flags & SE_SBINITIALIZED)) |
491 | return -EINVAL; | 499 | return -EINVAL; |
492 | 500 | ||
493 | if (!ss_initialized) | 501 | if (!ss_initialized) |
494 | return -EINVAL; | 502 | return -EINVAL; |
495 | 503 | ||
496 | /* | 504 | tmp = sbsec->flags & SE_MNTMASK; |
497 | * if we ever use sbsec flags for anything other than tracking mount | ||
498 | * settings this is going to need a mask | ||
499 | */ | ||
500 | tmp = sbsec->flags; | ||
501 | /* count the number of mount options for this sb */ | 505 | /* count the number of mount options for this sb */ |
502 | for (i = 0; i < 8; i++) { | 506 | for (i = 0; i < 8; i++) { |
503 | if (tmp & 0x01) | 507 | if (tmp & 0x01) |
504 | opts->num_mnt_opts++; | 508 | opts->num_mnt_opts++; |
505 | tmp >>= 1; | 509 | tmp >>= 1; |
506 | } | 510 | } |
511 | /* Check if the Label support flag is set */ | ||
512 | if (sbsec->flags & SE_SBLABELSUPP) | ||
513 | opts->num_mnt_opts++; | ||
507 | 514 | ||
508 | opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); | 515 | opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); |
509 | if (!opts->mnt_opts) { | 516 | if (!opts->mnt_opts) { |
@@ -549,6 +556,10 @@ static int selinux_get_mnt_opts(const struct super_block *sb, | |||
549 | opts->mnt_opts[i] = context; | 556 | opts->mnt_opts[i] = context; |
550 | opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; | 557 | opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; |
551 | } | 558 | } |
559 | if (sbsec->flags & SE_SBLABELSUPP) { | ||
560 | opts->mnt_opts[i] = NULL; | ||
561 | opts->mnt_opts_flags[i++] = SE_SBLABELSUPP; | ||
562 | } | ||
552 | 563 | ||
553 | BUG_ON(i != opts->num_mnt_opts); | 564 | BUG_ON(i != opts->num_mnt_opts); |
554 | 565 | ||
@@ -562,8 +573,10 @@ out_free: | |||
562 | static int bad_option(struct superblock_security_struct *sbsec, char flag, | 573 | static int bad_option(struct superblock_security_struct *sbsec, char flag, |
563 | u32 old_sid, u32 new_sid) | 574 | u32 old_sid, u32 new_sid) |
564 | { | 575 | { |
576 | char mnt_flags = sbsec->flags & SE_MNTMASK; | ||
577 | |||
565 | /* check if the old mount command had the same options */ | 578 | /* check if the old mount command had the same options */ |
566 | if (sbsec->initialized) | 579 | if (sbsec->flags & SE_SBINITIALIZED) |
567 | if (!(sbsec->flags & flag) || | 580 | if (!(sbsec->flags & flag) || |
568 | (old_sid != new_sid)) | 581 | (old_sid != new_sid)) |
569 | return 1; | 582 | return 1; |
@@ -571,8 +584,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, | |||
571 | /* check if we were passed the same options twice, | 584 | /* check if we were passed the same options twice, |
572 | * aka someone passed context=a,context=b | 585 | * aka someone passed context=a,context=b |
573 | */ | 586 | */ |
574 | if (!sbsec->initialized) | 587 | if (!(sbsec->flags & SE_SBINITIALIZED)) |
575 | if (sbsec->flags & flag) | 588 | if (mnt_flags & flag) |
576 | return 1; | 589 | return 1; |
577 | return 0; | 590 | return 0; |
578 | } | 591 | } |
@@ -626,7 +639,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
626 | * this sb does not set any security options. (The first options | 639 | * this sb does not set any security options. (The first options |
627 | * will be used for both mounts) | 640 | * will be used for both mounts) |
628 | */ | 641 | */ |
629 | if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) | 642 | if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) |
630 | && (num_opts == 0)) | 643 | && (num_opts == 0)) |
631 | goto out; | 644 | goto out; |
632 | 645 | ||
@@ -637,6 +650,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
637 | */ | 650 | */ |
638 | for (i = 0; i < num_opts; i++) { | 651 | for (i = 0; i < num_opts; i++) { |
639 | u32 sid; | 652 | u32 sid; |
653 | |||
654 | if (flags[i] == SE_SBLABELSUPP) | ||
655 | continue; | ||
640 | rc = security_context_to_sid(mount_options[i], | 656 | rc = security_context_to_sid(mount_options[i], |
641 | strlen(mount_options[i]), &sid); | 657 | strlen(mount_options[i]), &sid); |
642 | if (rc) { | 658 | if (rc) { |
@@ -690,19 +706,19 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
690 | } | 706 | } |
691 | } | 707 | } |
692 | 708 | ||
693 | if (sbsec->initialized) { | 709 | if (sbsec->flags & SE_SBINITIALIZED) { |
694 | /* previously mounted with options, but not on this attempt? */ | 710 | /* previously mounted with options, but not on this attempt? */ |
695 | if (sbsec->flags && !num_opts) | 711 | if ((sbsec->flags & SE_MNTMASK) && !num_opts) |
696 | goto out_double_mount; | 712 | goto out_double_mount; |
697 | rc = 0; | 713 | rc = 0; |
698 | goto out; | 714 | goto out; |
699 | } | 715 | } |
700 | 716 | ||
701 | if (strcmp(sb->s_type->name, "proc") == 0) | 717 | if (strcmp(sb->s_type->name, "proc") == 0) |
702 | sbsec->proc = 1; | 718 | sbsec->flags |= SE_SBPROC; |
703 | 719 | ||
704 | /* Determine the labeling behavior to use for this filesystem type. */ | 720 | /* Determine the labeling behavior to use for this filesystem type. */ |
705 | rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); | 721 | rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); |
706 | if (rc) { | 722 | if (rc) { |
707 | printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", | 723 | printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", |
708 | __func__, sb->s_type->name, rc); | 724 | __func__, sb->s_type->name, rc); |
@@ -806,10 +822,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
806 | } | 822 | } |
807 | 823 | ||
808 | /* how can we clone if the old one wasn't set up?? */ | 824 | /* how can we clone if the old one wasn't set up?? */ |
809 | BUG_ON(!oldsbsec->initialized); | 825 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); |
810 | 826 | ||
811 | /* if fs is reusing a sb, just let its options stand... */ | 827 | /* if fs is reusing a sb, just let its options stand... */ |
812 | if (newsbsec->initialized) | 828 | if (newsbsec->flags & SE_SBINITIALIZED) |
813 | return; | 829 | return; |
814 | 830 | ||
815 | mutex_lock(&newsbsec->lock); | 831 | mutex_lock(&newsbsec->lock); |
@@ -917,7 +933,8 @@ static int selinux_parse_opts_str(char *options, | |||
917 | goto out_err; | 933 | goto out_err; |
918 | } | 934 | } |
919 | break; | 935 | break; |
920 | 936 | case Opt_labelsupport: | |
937 | break; | ||
921 | default: | 938 | default: |
922 | rc = -EINVAL; | 939 | rc = -EINVAL; |
923 | printk(KERN_WARNING "SELinux: unknown mount option\n"); | 940 | printk(KERN_WARNING "SELinux: unknown mount option\n"); |
@@ -999,7 +1016,12 @@ static void selinux_write_opts(struct seq_file *m, | |||
999 | char *prefix; | 1016 | char *prefix; |
1000 | 1017 | ||
1001 | for (i = 0; i < opts->num_mnt_opts; i++) { | 1018 | for (i = 0; i < opts->num_mnt_opts; i++) { |
1002 | char *has_comma = strchr(opts->mnt_opts[i], ','); | 1019 | char *has_comma; |
1020 | |||
1021 | if (opts->mnt_opts[i]) | ||
1022 | has_comma = strchr(opts->mnt_opts[i], ','); | ||
1023 | else | ||
1024 | has_comma = NULL; | ||
1003 | 1025 | ||
1004 | switch (opts->mnt_opts_flags[i]) { | 1026 | switch (opts->mnt_opts_flags[i]) { |
1005 | case CONTEXT_MNT: | 1027 | case CONTEXT_MNT: |
@@ -1014,6 +1036,10 @@ static void selinux_write_opts(struct seq_file *m, | |||
1014 | case DEFCONTEXT_MNT: | 1036 | case DEFCONTEXT_MNT: |
1015 | prefix = DEFCONTEXT_STR; | 1037 | prefix = DEFCONTEXT_STR; |
1016 | break; | 1038 | break; |
1039 | case SE_SBLABELSUPP: | ||
1040 | seq_putc(m, ','); | ||
1041 | seq_puts(m, LABELSUPP_STR); | ||
1042 | continue; | ||
1017 | default: | 1043 | default: |
1018 | BUG(); | 1044 | BUG(); |
1019 | }; | 1045 | }; |
@@ -1209,7 +1235,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1209 | goto out_unlock; | 1235 | goto out_unlock; |
1210 | 1236 | ||
1211 | sbsec = inode->i_sb->s_security; | 1237 | sbsec = inode->i_sb->s_security; |
1212 | if (!sbsec->initialized) { | 1238 | if (!(sbsec->flags & SE_SBINITIALIZED)) { |
1213 | /* Defer initialization until selinux_complete_init, | 1239 | /* Defer initialization until selinux_complete_init, |
1214 | after the initial policy is loaded and the security | 1240 | after the initial policy is loaded and the security |
1215 | server is ready to handle calls. */ | 1241 | server is ready to handle calls. */ |
@@ -1326,7 +1352,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1326 | /* Default to the fs superblock SID. */ | 1352 | /* Default to the fs superblock SID. */ |
1327 | isec->sid = sbsec->sid; | 1353 | isec->sid = sbsec->sid; |
1328 | 1354 | ||
1329 | if (sbsec->proc && !S_ISLNK(inode->i_mode)) { | 1355 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { |
1330 | struct proc_inode *proci = PROC_I(inode); | 1356 | struct proc_inode *proci = PROC_I(inode); |
1331 | if (proci->pde) { | 1357 | if (proci->pde) { |
1332 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1358 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
@@ -1587,7 +1613,7 @@ static int may_create(struct inode *dir, | |||
1587 | if (rc) | 1613 | if (rc) |
1588 | return rc; | 1614 | return rc; |
1589 | 1615 | ||
1590 | if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { | 1616 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
1591 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); | 1617 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); |
1592 | if (rc) | 1618 | if (rc) |
1593 | return rc; | 1619 | return rc; |
@@ -1866,6 +1892,16 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
1866 | return cred_has_perm(old, new, PROCESS__SETCAP); | 1892 | return cred_has_perm(old, new, PROCESS__SETCAP); |
1867 | } | 1893 | } |
1868 | 1894 | ||
1895 | /* | ||
1896 | * (This comment used to live with the selinux_task_setuid hook, | ||
1897 | * which was removed). | ||
1898 | * | ||
1899 | * Since setuid only affects the current process, and since the SELinux | ||
1900 | * controls are not based on the Linux identity attributes, SELinux does not | ||
1901 | * need to control this operation. However, SELinux does control the use of | ||
1902 | * the CAP_SETUID and CAP_SETGID capabilities using the capable hook. | ||
1903 | */ | ||
1904 | |||
1869 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, | 1905 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, |
1870 | int cap, int audit) | 1906 | int cap, int audit) |
1871 | { | 1907 | { |
@@ -2156,11 +2192,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2156 | return 0; | 2192 | return 0; |
2157 | } | 2193 | } |
2158 | 2194 | ||
2159 | static int selinux_bprm_check_security(struct linux_binprm *bprm) | ||
2160 | { | ||
2161 | return secondary_ops->bprm_check_security(bprm); | ||
2162 | } | ||
2163 | |||
2164 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) | 2195 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) |
2165 | { | 2196 | { |
2166 | const struct cred *cred = current_cred(); | 2197 | const struct cred *cred = current_cred(); |
@@ -2290,8 +2321,6 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) | |||
2290 | struct rlimit *rlim, *initrlim; | 2321 | struct rlimit *rlim, *initrlim; |
2291 | int rc, i; | 2322 | int rc, i; |
2292 | 2323 | ||
2293 | secondary_ops->bprm_committing_creds(bprm); | ||
2294 | |||
2295 | new_tsec = bprm->cred->security; | 2324 | new_tsec = bprm->cred->security; |
2296 | if (new_tsec->sid == new_tsec->osid) | 2325 | if (new_tsec->sid == new_tsec->osid) |
2297 | return; | 2326 | return; |
@@ -2337,8 +2366,6 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) | |||
2337 | int rc, i; | 2366 | int rc, i; |
2338 | unsigned long flags; | 2367 | unsigned long flags; |
2339 | 2368 | ||
2340 | secondary_ops->bprm_committed_creds(bprm); | ||
2341 | |||
2342 | osid = tsec->osid; | 2369 | osid = tsec->osid; |
2343 | sid = tsec->sid; | 2370 | sid = tsec->sid; |
2344 | 2371 | ||
@@ -2400,7 +2427,8 @@ static inline int selinux_option(char *option, int len) | |||
2400 | return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || | 2427 | return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || |
2401 | match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || | 2428 | match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || |
2402 | match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || | 2429 | match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || |
2403 | match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len)); | 2430 | match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) || |
2431 | match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len)); | ||
2404 | } | 2432 | } |
2405 | 2433 | ||
2406 | static inline void take_option(char **to, char *from, int *first, int len) | 2434 | static inline void take_option(char **to, char *from, int *first, int len) |
@@ -2513,11 +2541,6 @@ static int selinux_mount(char *dev_name, | |||
2513 | void *data) | 2541 | void *data) |
2514 | { | 2542 | { |
2515 | const struct cred *cred = current_cred(); | 2543 | const struct cred *cred = current_cred(); |
2516 | int rc; | ||
2517 | |||
2518 | rc = secondary_ops->sb_mount(dev_name, path, type, flags, data); | ||
2519 | if (rc) | ||
2520 | return rc; | ||
2521 | 2544 | ||
2522 | if (flags & MS_REMOUNT) | 2545 | if (flags & MS_REMOUNT) |
2523 | return superblock_has_perm(cred, path->mnt->mnt_sb, | 2546 | return superblock_has_perm(cred, path->mnt->mnt_sb, |
@@ -2530,11 +2553,6 @@ static int selinux_mount(char *dev_name, | |||
2530 | static int selinux_umount(struct vfsmount *mnt, int flags) | 2553 | static int selinux_umount(struct vfsmount *mnt, int flags) |
2531 | { | 2554 | { |
2532 | const struct cred *cred = current_cred(); | 2555 | const struct cred *cred = current_cred(); |
2533 | int rc; | ||
2534 | |||
2535 | rc = secondary_ops->sb_umount(mnt, flags); | ||
2536 | if (rc) | ||
2537 | return rc; | ||
2538 | 2556 | ||
2539 | return superblock_has_perm(cred, mnt->mnt_sb, | 2557 | return superblock_has_perm(cred, mnt->mnt_sb, |
2540 | FILESYSTEM__UNMOUNT, NULL); | 2558 | FILESYSTEM__UNMOUNT, NULL); |
@@ -2570,7 +2588,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2570 | sid = tsec->sid; | 2588 | sid = tsec->sid; |
2571 | newsid = tsec->create_sid; | 2589 | newsid = tsec->create_sid; |
2572 | 2590 | ||
2573 | if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { | 2591 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
2574 | rc = security_transition_sid(sid, dsec->sid, | 2592 | rc = security_transition_sid(sid, dsec->sid, |
2575 | inode_mode_to_security_class(inode->i_mode), | 2593 | inode_mode_to_security_class(inode->i_mode), |
2576 | &newsid); | 2594 | &newsid); |
@@ -2585,14 +2603,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2585 | } | 2603 | } |
2586 | 2604 | ||
2587 | /* Possibly defer initialization to selinux_complete_init. */ | 2605 | /* Possibly defer initialization to selinux_complete_init. */ |
2588 | if (sbsec->initialized) { | 2606 | if (sbsec->flags & SE_SBINITIALIZED) { |
2589 | struct inode_security_struct *isec = inode->i_security; | 2607 | struct inode_security_struct *isec = inode->i_security; |
2590 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 2608 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
2591 | isec->sid = newsid; | 2609 | isec->sid = newsid; |
2592 | isec->initialized = 1; | 2610 | isec->initialized = 1; |
2593 | } | 2611 | } |
2594 | 2612 | ||
2595 | if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 2613 | if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP)) |
2596 | return -EOPNOTSUPP; | 2614 | return -EOPNOTSUPP; |
2597 | 2615 | ||
2598 | if (name) { | 2616 | if (name) { |
@@ -2622,21 +2640,11 @@ static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int ma | |||
2622 | 2640 | ||
2623 | static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2641 | static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
2624 | { | 2642 | { |
2625 | int rc; | ||
2626 | |||
2627 | rc = secondary_ops->inode_link(old_dentry, dir, new_dentry); | ||
2628 | if (rc) | ||
2629 | return rc; | ||
2630 | return may_link(dir, old_dentry, MAY_LINK); | 2643 | return may_link(dir, old_dentry, MAY_LINK); |
2631 | } | 2644 | } |
2632 | 2645 | ||
2633 | static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) | 2646 | static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) |
2634 | { | 2647 | { |
2635 | int rc; | ||
2636 | |||
2637 | rc = secondary_ops->inode_unlink(dir, dentry); | ||
2638 | if (rc) | ||
2639 | return rc; | ||
2640 | return may_link(dir, dentry, MAY_UNLINK); | 2648 | return may_link(dir, dentry, MAY_UNLINK); |
2641 | } | 2649 | } |
2642 | 2650 | ||
@@ -2657,12 +2665,6 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) | |||
2657 | 2665 | ||
2658 | static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | 2666 | static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) |
2659 | { | 2667 | { |
2660 | int rc; | ||
2661 | |||
2662 | rc = secondary_ops->inode_mknod(dir, dentry, mode, dev); | ||
2663 | if (rc) | ||
2664 | return rc; | ||
2665 | |||
2666 | return may_create(dir, dentry, inode_mode_to_security_class(mode)); | 2668 | return may_create(dir, dentry, inode_mode_to_security_class(mode)); |
2667 | } | 2669 | } |
2668 | 2670 | ||
@@ -2682,22 +2684,13 @@ static int selinux_inode_readlink(struct dentry *dentry) | |||
2682 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) | 2684 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) |
2683 | { | 2685 | { |
2684 | const struct cred *cred = current_cred(); | 2686 | const struct cred *cred = current_cred(); |
2685 | int rc; | ||
2686 | 2687 | ||
2687 | rc = secondary_ops->inode_follow_link(dentry, nameidata); | ||
2688 | if (rc) | ||
2689 | return rc; | ||
2690 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2688 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); |
2691 | } | 2689 | } |
2692 | 2690 | ||
2693 | static int selinux_inode_permission(struct inode *inode, int mask) | 2691 | static int selinux_inode_permission(struct inode *inode, int mask) |
2694 | { | 2692 | { |
2695 | const struct cred *cred = current_cred(); | 2693 | const struct cred *cred = current_cred(); |
2696 | int rc; | ||
2697 | |||
2698 | rc = secondary_ops->inode_permission(inode, mask); | ||
2699 | if (rc) | ||
2700 | return rc; | ||
2701 | 2694 | ||
2702 | if (!mask) { | 2695 | if (!mask) { |
2703 | /* No permission to check. Existence test. */ | 2696 | /* No permission to check. Existence test. */ |
@@ -2711,11 +2704,6 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2711 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2704 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
2712 | { | 2705 | { |
2713 | const struct cred *cred = current_cred(); | 2706 | const struct cred *cred = current_cred(); |
2714 | int rc; | ||
2715 | |||
2716 | rc = secondary_ops->inode_setattr(dentry, iattr); | ||
2717 | if (rc) | ||
2718 | return rc; | ||
2719 | 2707 | ||
2720 | if (iattr->ia_valid & ATTR_FORCE) | 2708 | if (iattr->ia_valid & ATTR_FORCE) |
2721 | return 0; | 2709 | return 0; |
@@ -2769,7 +2757,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2769 | return selinux_inode_setotherxattr(dentry, name); | 2757 | return selinux_inode_setotherxattr(dentry, name); |
2770 | 2758 | ||
2771 | sbsec = inode->i_sb->s_security; | 2759 | sbsec = inode->i_sb->s_security; |
2772 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 2760 | if (!(sbsec->flags & SE_SBLABELSUPP)) |
2773 | return -EOPNOTSUPP; | 2761 | return -EOPNOTSUPP; |
2774 | 2762 | ||
2775 | if (!is_owner_or_cap(inode)) | 2763 | if (!is_owner_or_cap(inode)) |
@@ -2931,16 +2919,6 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t | |||
2931 | return len; | 2919 | return len; |
2932 | } | 2920 | } |
2933 | 2921 | ||
2934 | static int selinux_inode_need_killpriv(struct dentry *dentry) | ||
2935 | { | ||
2936 | return secondary_ops->inode_need_killpriv(dentry); | ||
2937 | } | ||
2938 | |||
2939 | static int selinux_inode_killpriv(struct dentry *dentry) | ||
2940 | { | ||
2941 | return secondary_ops->inode_killpriv(dentry); | ||
2942 | } | ||
2943 | |||
2944 | static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) | 2922 | static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) |
2945 | { | 2923 | { |
2946 | struct inode_security_struct *isec = inode->i_security; | 2924 | struct inode_security_struct *isec = inode->i_security; |
@@ -3078,18 +3056,13 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
3078 | unsigned long prot) | 3056 | unsigned long prot) |
3079 | { | 3057 | { |
3080 | const struct cred *cred = current_cred(); | 3058 | const struct cred *cred = current_cred(); |
3081 | int rc; | ||
3082 | |||
3083 | rc = secondary_ops->file_mprotect(vma, reqprot, prot); | ||
3084 | if (rc) | ||
3085 | return rc; | ||
3086 | 3059 | ||
3087 | if (selinux_checkreqprot) | 3060 | if (selinux_checkreqprot) |
3088 | prot = reqprot; | 3061 | prot = reqprot; |
3089 | 3062 | ||
3090 | #ifndef CONFIG_PPC32 | 3063 | #ifndef CONFIG_PPC32 |
3091 | if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { | 3064 | if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { |
3092 | rc = 0; | 3065 | int rc = 0; |
3093 | if (vma->vm_start >= vma->vm_mm->start_brk && | 3066 | if (vma->vm_start >= vma->vm_mm->start_brk && |
3094 | vma->vm_end <= vma->vm_mm->brk) { | 3067 | vma->vm_end <= vma->vm_mm->brk) { |
3095 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); | 3068 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); |
@@ -3239,12 +3212,6 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3239 | 3212 | ||
3240 | static int selinux_task_create(unsigned long clone_flags) | 3213 | static int selinux_task_create(unsigned long clone_flags) |
3241 | { | 3214 | { |
3242 | int rc; | ||
3243 | |||
3244 | rc = secondary_ops->task_create(clone_flags); | ||
3245 | if (rc) | ||
3246 | return rc; | ||
3247 | |||
3248 | return current_has_perm(current, PROCESS__FORK); | 3215 | return current_has_perm(current, PROCESS__FORK); |
3249 | } | 3216 | } |
3250 | 3217 | ||
@@ -3278,14 +3245,6 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, | |||
3278 | } | 3245 | } |
3279 | 3246 | ||
3280 | /* | 3247 | /* |
3281 | * commit new credentials | ||
3282 | */ | ||
3283 | static void selinux_cred_commit(struct cred *new, const struct cred *old) | ||
3284 | { | ||
3285 | secondary_ops->cred_commit(new, old); | ||
3286 | } | ||
3287 | |||
3288 | /* | ||
3289 | * set the security data for a kernel service | 3248 | * set the security data for a kernel service |
3290 | * - all the creation contexts are set to unlabelled | 3249 | * - all the creation contexts are set to unlabelled |
3291 | */ | 3250 | */ |
@@ -3329,29 +3288,6 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
3329 | return 0; | 3288 | return 0; |
3330 | } | 3289 | } |
3331 | 3290 | ||
3332 | static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | ||
3333 | { | ||
3334 | /* Since setuid only affects the current process, and | ||
3335 | since the SELinux controls are not based on the Linux | ||
3336 | identity attributes, SELinux does not need to control | ||
3337 | this operation. However, SELinux does control the use | ||
3338 | of the CAP_SETUID and CAP_SETGID capabilities using the | ||
3339 | capable hook. */ | ||
3340 | return 0; | ||
3341 | } | ||
3342 | |||
3343 | static int selinux_task_fix_setuid(struct cred *new, const struct cred *old, | ||
3344 | int flags) | ||
3345 | { | ||
3346 | return secondary_ops->task_fix_setuid(new, old, flags); | ||
3347 | } | ||
3348 | |||
3349 | static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | ||
3350 | { | ||
3351 | /* See the comment for setuid above. */ | ||
3352 | return 0; | ||
3353 | } | ||
3354 | |||
3355 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) | 3291 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) |
3356 | { | 3292 | { |
3357 | return current_has_perm(p, PROCESS__SETPGID); | 3293 | return current_has_perm(p, PROCESS__SETPGID); |
@@ -3372,12 +3308,6 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid) | |||
3372 | *secid = task_sid(p); | 3308 | *secid = task_sid(p); |
3373 | } | 3309 | } |
3374 | 3310 | ||
3375 | static int selinux_task_setgroups(struct group_info *group_info) | ||
3376 | { | ||
3377 | /* See the comment for setuid above. */ | ||
3378 | return 0; | ||
3379 | } | ||
3380 | |||
3381 | static int selinux_task_setnice(struct task_struct *p, int nice) | 3311 | static int selinux_task_setnice(struct task_struct *p, int nice) |
3382 | { | 3312 | { |
3383 | int rc; | 3313 | int rc; |
@@ -3408,11 +3338,6 @@ static int selinux_task_getioprio(struct task_struct *p) | |||
3408 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) | 3338 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) |
3409 | { | 3339 | { |
3410 | struct rlimit *old_rlim = current->signal->rlim + resource; | 3340 | struct rlimit *old_rlim = current->signal->rlim + resource; |
3411 | int rc; | ||
3412 | |||
3413 | rc = secondary_ops->task_setrlimit(resource, new_rlim); | ||
3414 | if (rc) | ||
3415 | return rc; | ||
3416 | 3341 | ||
3417 | /* Control the ability to change the hard limit (whether | 3342 | /* Control the ability to change the hard limit (whether |
3418 | lowering or raising it), so that the hard limit can | 3343 | lowering or raising it), so that the hard limit can |
@@ -3451,10 +3376,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | |||
3451 | u32 perm; | 3376 | u32 perm; |
3452 | int rc; | 3377 | int rc; |
3453 | 3378 | ||
3454 | rc = secondary_ops->task_kill(p, info, sig, secid); | ||
3455 | if (rc) | ||
3456 | return rc; | ||
3457 | |||
3458 | if (!sig) | 3379 | if (!sig) |
3459 | perm = PROCESS__SIGNULL; /* null signal; existence test */ | 3380 | perm = PROCESS__SIGNULL; /* null signal; existence test */ |
3460 | else | 3381 | else |
@@ -3467,18 +3388,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | |||
3467 | return rc; | 3388 | return rc; |
3468 | } | 3389 | } |
3469 | 3390 | ||
3470 | static int selinux_task_prctl(int option, | ||
3471 | unsigned long arg2, | ||
3472 | unsigned long arg3, | ||
3473 | unsigned long arg4, | ||
3474 | unsigned long arg5) | ||
3475 | { | ||
3476 | /* The current prctl operations do not appear to require | ||
3477 | any SELinux controls since they merely observe or modify | ||
3478 | the state of the current process. */ | ||
3479 | return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5); | ||
3480 | } | ||
3481 | |||
3482 | static int selinux_task_wait(struct task_struct *p) | 3391 | static int selinux_task_wait(struct task_struct *p) |
3483 | { | 3392 | { |
3484 | return task_has_perm(p, current, PROCESS__SIGCHLD); | 3393 | return task_has_perm(p, current, PROCESS__SIGCHLD); |
@@ -4047,10 +3956,6 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
4047 | struct avc_audit_data ad; | 3956 | struct avc_audit_data ad; |
4048 | int err; | 3957 | int err; |
4049 | 3958 | ||
4050 | err = secondary_ops->unix_stream_connect(sock, other, newsk); | ||
4051 | if (err) | ||
4052 | return err; | ||
4053 | |||
4054 | isec = SOCK_INODE(sock)->i_security; | 3959 | isec = SOCK_INODE(sock)->i_security; |
4055 | other_isec = SOCK_INODE(other)->i_security; | 3960 | other_isec = SOCK_INODE(other)->i_security; |
4056 | 3961 | ||
@@ -5167,11 +5072,6 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, | |||
5167 | char __user *shmaddr, int shmflg) | 5072 | char __user *shmaddr, int shmflg) |
5168 | { | 5073 | { |
5169 | u32 perms; | 5074 | u32 perms; |
5170 | int rc; | ||
5171 | |||
5172 | rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg); | ||
5173 | if (rc) | ||
5174 | return rc; | ||
5175 | 5075 | ||
5176 | if (shmflg & SHM_RDONLY) | 5076 | if (shmflg & SHM_RDONLY) |
5177 | perms = SHM__READ; | 5077 | perms = SHM__READ; |
@@ -5581,7 +5481,6 @@ static struct security_operations selinux_ops = { | |||
5581 | .netlink_recv = selinux_netlink_recv, | 5481 | .netlink_recv = selinux_netlink_recv, |
5582 | 5482 | ||
5583 | .bprm_set_creds = selinux_bprm_set_creds, | 5483 | .bprm_set_creds = selinux_bprm_set_creds, |
5584 | .bprm_check_security = selinux_bprm_check_security, | ||
5585 | .bprm_committing_creds = selinux_bprm_committing_creds, | 5484 | .bprm_committing_creds = selinux_bprm_committing_creds, |
5586 | .bprm_committed_creds = selinux_bprm_committed_creds, | 5485 | .bprm_committed_creds = selinux_bprm_committed_creds, |
5587 | .bprm_secureexec = selinux_bprm_secureexec, | 5486 | .bprm_secureexec = selinux_bprm_secureexec, |
@@ -5623,8 +5522,6 @@ static struct security_operations selinux_ops = { | |||
5623 | .inode_getsecurity = selinux_inode_getsecurity, | 5522 | .inode_getsecurity = selinux_inode_getsecurity, |
5624 | .inode_setsecurity = selinux_inode_setsecurity, | 5523 | .inode_setsecurity = selinux_inode_setsecurity, |
5625 | .inode_listsecurity = selinux_inode_listsecurity, | 5524 | .inode_listsecurity = selinux_inode_listsecurity, |
5626 | .inode_need_killpriv = selinux_inode_need_killpriv, | ||
5627 | .inode_killpriv = selinux_inode_killpriv, | ||
5628 | .inode_getsecid = selinux_inode_getsecid, | 5525 | .inode_getsecid = selinux_inode_getsecid, |
5629 | 5526 | ||
5630 | .file_permission = selinux_file_permission, | 5527 | .file_permission = selinux_file_permission, |
@@ -5644,17 +5541,12 @@ static struct security_operations selinux_ops = { | |||
5644 | .task_create = selinux_task_create, | 5541 | .task_create = selinux_task_create, |
5645 | .cred_free = selinux_cred_free, | 5542 | .cred_free = selinux_cred_free, |
5646 | .cred_prepare = selinux_cred_prepare, | 5543 | .cred_prepare = selinux_cred_prepare, |
5647 | .cred_commit = selinux_cred_commit, | ||
5648 | .kernel_act_as = selinux_kernel_act_as, | 5544 | .kernel_act_as = selinux_kernel_act_as, |
5649 | .kernel_create_files_as = selinux_kernel_create_files_as, | 5545 | .kernel_create_files_as = selinux_kernel_create_files_as, |
5650 | .task_setuid = selinux_task_setuid, | ||
5651 | .task_fix_setuid = selinux_task_fix_setuid, | ||
5652 | .task_setgid = selinux_task_setgid, | ||
5653 | .task_setpgid = selinux_task_setpgid, | 5546 | .task_setpgid = selinux_task_setpgid, |
5654 | .task_getpgid = selinux_task_getpgid, | 5547 | .task_getpgid = selinux_task_getpgid, |
5655 | .task_getsid = selinux_task_getsid, | 5548 | .task_getsid = selinux_task_getsid, |
5656 | .task_getsecid = selinux_task_getsecid, | 5549 | .task_getsecid = selinux_task_getsecid, |
5657 | .task_setgroups = selinux_task_setgroups, | ||
5658 | .task_setnice = selinux_task_setnice, | 5550 | .task_setnice = selinux_task_setnice, |
5659 | .task_setioprio = selinux_task_setioprio, | 5551 | .task_setioprio = selinux_task_setioprio, |
5660 | .task_getioprio = selinux_task_getioprio, | 5552 | .task_getioprio = selinux_task_getioprio, |
@@ -5664,7 +5556,6 @@ static struct security_operations selinux_ops = { | |||
5664 | .task_movememory = selinux_task_movememory, | 5556 | .task_movememory = selinux_task_movememory, |
5665 | .task_kill = selinux_task_kill, | 5557 | .task_kill = selinux_task_kill, |
5666 | .task_wait = selinux_task_wait, | 5558 | .task_wait = selinux_task_wait, |
5667 | .task_prctl = selinux_task_prctl, | ||
5668 | .task_to_inode = selinux_task_to_inode, | 5559 | .task_to_inode = selinux_task_to_inode, |
5669 | 5560 | ||
5670 | .ipc_permission = selinux_ipc_permission, | 5561 | .ipc_permission = selinux_ipc_permission, |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 3cc45168f674..c4e062336ef3 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -60,9 +60,7 @@ struct superblock_security_struct { | |||
60 | u32 def_sid; /* default SID for labeling */ | 60 | u32 def_sid; /* default SID for labeling */ |
61 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ | 61 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ |
62 | unsigned int behavior; /* labeling behavior */ | 62 | unsigned int behavior; /* labeling behavior */ |
63 | unsigned char initialized; /* initialization flag */ | ||
64 | unsigned char flags; /* which mount options were specified */ | 63 | unsigned char flags; /* which mount options were specified */ |
65 | unsigned char proc; /* proc fs */ | ||
66 | struct mutex lock; | 64 | struct mutex lock; |
67 | struct list_head isec_head; | 65 | struct list_head isec_head; |
68 | spinlock_t isec_lock; | 66 | spinlock_t isec_lock; |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 72447370bc95..e1d9db779983 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -37,15 +37,23 @@ | |||
37 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY | 37 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | /* Mask for just the mount related flags */ | ||
41 | #define SE_MNTMASK 0x0f | ||
42 | /* Super block security struct flags for mount options */ | ||
40 | #define CONTEXT_MNT 0x01 | 43 | #define CONTEXT_MNT 0x01 |
41 | #define FSCONTEXT_MNT 0x02 | 44 | #define FSCONTEXT_MNT 0x02 |
42 | #define ROOTCONTEXT_MNT 0x04 | 45 | #define ROOTCONTEXT_MNT 0x04 |
43 | #define DEFCONTEXT_MNT 0x08 | 46 | #define DEFCONTEXT_MNT 0x08 |
47 | /* Non-mount related flags */ | ||
48 | #define SE_SBINITIALIZED 0x10 | ||
49 | #define SE_SBPROC 0x20 | ||
50 | #define SE_SBLABELSUPP 0x40 | ||
44 | 51 | ||
45 | #define CONTEXT_STR "context=" | 52 | #define CONTEXT_STR "context=" |
46 | #define FSCONTEXT_STR "fscontext=" | 53 | #define FSCONTEXT_STR "fscontext=" |
47 | #define ROOTCONTEXT_STR "rootcontext=" | 54 | #define ROOTCONTEXT_STR "rootcontext=" |
48 | #define DEFCONTEXT_STR "defcontext=" | 55 | #define DEFCONTEXT_STR "defcontext=" |
56 | #define LABELSUPP_STR "seclabel" | ||
49 | 57 | ||
50 | struct netlbl_lsm_secattr; | 58 | struct netlbl_lsm_secattr; |
51 | 59 | ||