diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-27 22:26:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-27 22:26:38 -0400 |
commit | 95b6886526bb510b8370b625a49bc0ab3b8ff10f (patch) | |
tree | 2862606224820d200be12d2092dcd26df1654b80 /security | |
parent | 22712200e175e0df5c7f9edfe6c6bf5c94c23b83 (diff) | |
parent | 29412f0f6a19e34336368f13eab848091c343952 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (54 commits)
tpm_nsc: Fix bug when loading multiple TPM drivers
tpm: Move tpm_tis_reenable_interrupts out of CONFIG_PNP block
tpm: Fix compilation warning when CONFIG_PNP is not defined
TOMOYO: Update kernel-doc.
tpm: Fix a typo
tpm_tis: Probing function for Intel iTPM bug
tpm_tis: Fix the probing for interrupts
tpm_tis: Delay ACPI S3 suspend while the TPM is busy
tpm_tis: Re-enable interrupts upon (S3) resume
tpm: Fix display of data in pubek sysfs entry
tpm_tis: Add timeouts sysfs entry
tpm: Adjust interface timeouts if they are too small
tpm: Use interface timeouts returned from the TPM
tpm_tis: Introduce durations sysfs entry
tpm: Adjust the durations if they are too small
tpm: Use durations returned from TPM
TOMOYO: Enable conditional ACL.
TOMOYO: Allow using argv[]/envp[] of execve() as conditions.
TOMOYO: Allow using executable's realpath and symlink's target as conditions.
TOMOYO: Allow using owner/group etc. of file objects as conditions.
...
Fix up trivial conflict in security/tomoyo/realpath.c
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/domain.c | 2 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 2 | ||||
-rw-r--r-- | security/keys/Makefile | 2 | ||||
-rw-r--r-- | security/keys/ecryptfs_format.c | 81 | ||||
-rw-r--r-- | security/keys/ecryptfs_format.h | 30 | ||||
-rw-r--r-- | security/keys/encrypted.c | 251 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 2 | ||||
-rw-r--r-- | security/tomoyo/Kconfig | 61 | ||||
-rw-r--r-- | security/tomoyo/Makefile | 49 | ||||
-rw-r--r-- | security/tomoyo/audit.c | 456 | ||||
-rw-r--r-- | security/tomoyo/common.c | 1959 | ||||
-rw-r--r-- | security/tomoyo/common.h | 1197 | ||||
-rw-r--r-- | security/tomoyo/condition.c | 1035 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 630 | ||||
-rw-r--r-- | security/tomoyo/file.c | 954 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 551 | ||||
-rw-r--r-- | security/tomoyo/group.c | 61 | ||||
-rw-r--r-- | security/tomoyo/load_policy.c | 80 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 173 | ||||
-rw-r--r-- | security/tomoyo/mount.c | 176 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 226 | ||||
-rw-r--r-- | security/tomoyo/securityfs_if.c | 22 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 238 | ||||
-rw-r--r-- | security/tomoyo/util.c | 363 |
24 files changed, 5954 insertions, 2647 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 7312bf9f7afc..c1e18ba5bdc0 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -73,7 +73,6 @@ static int may_change_ptraced_domain(struct task_struct *task, | |||
73 | cred = get_task_cred(tracer); | 73 | cred = get_task_cred(tracer); |
74 | tracerp = aa_cred_profile(cred); | 74 | tracerp = aa_cred_profile(cred); |
75 | } | 75 | } |
76 | rcu_read_unlock(); | ||
77 | 76 | ||
78 | /* not ptraced */ | 77 | /* not ptraced */ |
79 | if (!tracer || unconfined(tracerp)) | 78 | if (!tracer || unconfined(tracerp)) |
@@ -82,6 +81,7 @@ static int may_change_ptraced_domain(struct task_struct *task, | |||
82 | error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH); | 81 | error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH); |
83 | 82 | ||
84 | out: | 83 | out: |
84 | rcu_read_unlock(); | ||
85 | if (cred) | 85 | if (cred) |
86 | put_cred(cred); | 86 | put_cred(cred); |
87 | 87 | ||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 3d2fd141dff7..37832026e58a 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -127,7 +127,7 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, | |||
127 | *inheritable = cred->cap_inheritable; | 127 | *inheritable = cred->cap_inheritable; |
128 | *permitted = cred->cap_permitted; | 128 | *permitted = cred->cap_permitted; |
129 | 129 | ||
130 | if (!unconfined(profile)) { | 130 | if (!unconfined(profile) && !COMPLAIN_MODE(profile)) { |
131 | *effective = cap_intersect(*effective, profile->caps.allow); | 131 | *effective = cap_intersect(*effective, profile->caps.allow); |
132 | *permitted = cap_intersect(*permitted, profile->caps.allow); | 132 | *permitted = cap_intersect(*permitted, profile->caps.allow); |
133 | } | 133 | } |
diff --git a/security/keys/Makefile b/security/keys/Makefile index 1bf090a885fe..b34cc6ee6900 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -14,7 +14,7 @@ obj-y := \ | |||
14 | user_defined.o | 14 | user_defined.o |
15 | 15 | ||
16 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | 16 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o |
17 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o | 17 | obj-$(CONFIG_ENCRYPTED_KEYS) += ecryptfs_format.o encrypted.o |
18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
19 | obj-$(CONFIG_PROC_FS) += proc.o | 19 | obj-$(CONFIG_PROC_FS) += proc.o |
20 | obj-$(CONFIG_SYSCTL) += sysctl.o | 20 | obj-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/security/keys/ecryptfs_format.c b/security/keys/ecryptfs_format.c new file mode 100644 index 000000000000..6daa3b6ff9ed --- /dev/null +++ b/security/keys/ecryptfs_format.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * ecryptfs_format.c: helper functions for the encrypted key type | ||
3 | * | ||
4 | * Copyright (C) 2006 International Business Machines Corp. | ||
5 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
6 | * TORSEC group -- http://security.polito.it | ||
7 | * | ||
8 | * Authors: | ||
9 | * Michael A. Halcrow <mahalcro@us.ibm.com> | ||
10 | * Tyler Hicks <tyhicks@ou.edu> | ||
11 | * Roberto Sassu <roberto.sassu@polito.it> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation, version 2 of the License. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include "ecryptfs_format.h" | ||
20 | |||
21 | u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok) | ||
22 | { | ||
23 | return auth_tok->token.password.session_key_encryption_key; | ||
24 | } | ||
25 | EXPORT_SYMBOL(ecryptfs_get_auth_tok_key); | ||
26 | |||
27 | /* | ||
28 | * ecryptfs_get_versions() | ||
29 | * | ||
30 | * Source code taken from the software 'ecryptfs-utils' version 83. | ||
31 | * | ||
32 | */ | ||
33 | void ecryptfs_get_versions(int *major, int *minor, int *file_version) | ||
34 | { | ||
35 | *major = ECRYPTFS_VERSION_MAJOR; | ||
36 | *minor = ECRYPTFS_VERSION_MINOR; | ||
37 | if (file_version) | ||
38 | *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION; | ||
39 | } | ||
40 | EXPORT_SYMBOL(ecryptfs_get_versions); | ||
41 | |||
42 | /* | ||
43 | * ecryptfs_fill_auth_tok - fill the ecryptfs_auth_tok structure | ||
44 | * | ||
45 | * Fill the ecryptfs_auth_tok structure with required ecryptfs data. | ||
46 | * The source code is inspired to the original function generate_payload() | ||
47 | * shipped with the software 'ecryptfs-utils' version 83. | ||
48 | * | ||
49 | */ | ||
50 | int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok, | ||
51 | const char *key_desc) | ||
52 | { | ||
53 | int major, minor; | ||
54 | |||
55 | ecryptfs_get_versions(&major, &minor, NULL); | ||
56 | auth_tok->version = (((uint16_t)(major << 8) & 0xFF00) | ||
57 | | ((uint16_t)minor & 0x00FF)); | ||
58 | auth_tok->token_type = ECRYPTFS_PASSWORD; | ||
59 | strncpy((char *)auth_tok->token.password.signature, key_desc, | ||
60 | ECRYPTFS_PASSWORD_SIG_SIZE); | ||
61 | auth_tok->token.password.session_key_encryption_key_bytes = | ||
62 | ECRYPTFS_MAX_KEY_BYTES; | ||
63 | /* | ||
64 | * Removed auth_tok->token.password.salt and | ||
65 | * auth_tok->token.password.session_key_encryption_key | ||
66 | * initialization from the original code | ||
67 | */ | ||
68 | /* TODO: Make the hash parameterizable via policy */ | ||
69 | auth_tok->token.password.flags |= | ||
70 | ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET; | ||
71 | /* The kernel code will encrypt the session key. */ | ||
72 | auth_tok->session_key.encrypted_key[0] = 0; | ||
73 | auth_tok->session_key.encrypted_key_size = 0; | ||
74 | /* Default; subject to change by kernel eCryptfs */ | ||
75 | auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512; | ||
76 | auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD); | ||
77 | return 0; | ||
78 | } | ||
79 | EXPORT_SYMBOL(ecryptfs_fill_auth_tok); | ||
80 | |||
81 | MODULE_LICENSE("GPL"); | ||
diff --git a/security/keys/ecryptfs_format.h b/security/keys/ecryptfs_format.h new file mode 100644 index 000000000000..40294de238bb --- /dev/null +++ b/security/keys/ecryptfs_format.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * ecryptfs_format.h: helper functions for the encrypted key type | ||
3 | * | ||
4 | * Copyright (C) 2006 International Business Machines Corp. | ||
5 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
6 | * TORSEC group -- http://security.polito.it | ||
7 | * | ||
8 | * Authors: | ||
9 | * Michael A. Halcrow <mahalcro@us.ibm.com> | ||
10 | * Tyler Hicks <tyhicks@ou.edu> | ||
11 | * Roberto Sassu <roberto.sassu@polito.it> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation, version 2 of the License. | ||
16 | */ | ||
17 | |||
18 | #ifndef __KEYS_ECRYPTFS_H | ||
19 | #define __KEYS_ECRYPTFS_H | ||
20 | |||
21 | #include <linux/ecryptfs.h> | ||
22 | |||
23 | #define PGP_DIGEST_ALGO_SHA512 10 | ||
24 | |||
25 | u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok); | ||
26 | void ecryptfs_get_versions(int *major, int *minor, int *file_version); | ||
27 | int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok, | ||
28 | const char *key_desc); | ||
29 | |||
30 | #endif /* __KEYS_ECRYPTFS_H */ | ||
diff --git a/security/keys/encrypted.c b/security/keys/encrypted.c index b1cba5bf0a5e..e7eca9ec4c65 100644 --- a/security/keys/encrypted.c +++ b/security/keys/encrypted.c | |||
@@ -1,8 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 IBM Corporation | 2 | * Copyright (C) 2010 IBM Corporation |
3 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
4 | * TORSEC group -- http://security.polito.it | ||
3 | * | 5 | * |
4 | * Author: | 6 | * Authors: |
5 | * Mimi Zohar <zohar@us.ibm.com> | 7 | * Mimi Zohar <zohar@us.ibm.com> |
8 | * Roberto Sassu <roberto.sassu@polito.it> | ||
6 | * | 9 | * |
7 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -26,22 +29,27 @@ | |||
26 | #include <linux/rcupdate.h> | 29 | #include <linux/rcupdate.h> |
27 | #include <linux/scatterlist.h> | 30 | #include <linux/scatterlist.h> |
28 | #include <linux/crypto.h> | 31 | #include <linux/crypto.h> |
32 | #include <linux/ctype.h> | ||
29 | #include <crypto/hash.h> | 33 | #include <crypto/hash.h> |
30 | #include <crypto/sha.h> | 34 | #include <crypto/sha.h> |
31 | #include <crypto/aes.h> | 35 | #include <crypto/aes.h> |
32 | 36 | ||
33 | #include "encrypted.h" | 37 | #include "encrypted.h" |
38 | #include "ecryptfs_format.h" | ||
34 | 39 | ||
35 | static const char KEY_TRUSTED_PREFIX[] = "trusted:"; | 40 | static const char KEY_TRUSTED_PREFIX[] = "trusted:"; |
36 | static const char KEY_USER_PREFIX[] = "user:"; | 41 | static const char KEY_USER_PREFIX[] = "user:"; |
37 | static const char hash_alg[] = "sha256"; | 42 | static const char hash_alg[] = "sha256"; |
38 | static const char hmac_alg[] = "hmac(sha256)"; | 43 | static const char hmac_alg[] = "hmac(sha256)"; |
39 | static const char blkcipher_alg[] = "cbc(aes)"; | 44 | static const char blkcipher_alg[] = "cbc(aes)"; |
45 | static const char key_format_default[] = "default"; | ||
46 | static const char key_format_ecryptfs[] = "ecryptfs"; | ||
40 | static unsigned int ivsize; | 47 | static unsigned int ivsize; |
41 | static int blksize; | 48 | static int blksize; |
42 | 49 | ||
43 | #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1) | 50 | #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1) |
44 | #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1) | 51 | #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1) |
52 | #define KEY_ECRYPTFS_DESC_LEN 16 | ||
45 | #define HASH_SIZE SHA256_DIGEST_SIZE | 53 | #define HASH_SIZE SHA256_DIGEST_SIZE |
46 | #define MAX_DATA_SIZE 4096 | 54 | #define MAX_DATA_SIZE 4096 |
47 | #define MIN_DATA_SIZE 20 | 55 | #define MIN_DATA_SIZE 20 |
@@ -58,6 +66,16 @@ enum { | |||
58 | Opt_err = -1, Opt_new, Opt_load, Opt_update | 66 | Opt_err = -1, Opt_new, Opt_load, Opt_update |
59 | }; | 67 | }; |
60 | 68 | ||
69 | enum { | ||
70 | Opt_error = -1, Opt_default, Opt_ecryptfs | ||
71 | }; | ||
72 | |||
73 | static const match_table_t key_format_tokens = { | ||
74 | {Opt_default, "default"}, | ||
75 | {Opt_ecryptfs, "ecryptfs"}, | ||
76 | {Opt_error, NULL} | ||
77 | }; | ||
78 | |||
61 | static const match_table_t key_tokens = { | 79 | static const match_table_t key_tokens = { |
62 | {Opt_new, "new"}, | 80 | {Opt_new, "new"}, |
63 | {Opt_load, "load"}, | 81 | {Opt_load, "load"}, |
@@ -82,9 +100,37 @@ static int aes_get_sizes(void) | |||
82 | } | 100 | } |
83 | 101 | ||
84 | /* | 102 | /* |
103 | * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key | ||
104 | * | ||
105 | * The description of a encrypted key with format 'ecryptfs' must contain | ||
106 | * exactly 16 hexadecimal characters. | ||
107 | * | ||
108 | */ | ||
109 | static int valid_ecryptfs_desc(const char *ecryptfs_desc) | ||
110 | { | ||
111 | int i; | ||
112 | |||
113 | if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) { | ||
114 | pr_err("encrypted_key: key description must be %d hexadecimal " | ||
115 | "characters long\n", KEY_ECRYPTFS_DESC_LEN); | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | |||
119 | for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) { | ||
120 | if (!isxdigit(ecryptfs_desc[i])) { | ||
121 | pr_err("encrypted_key: key description must contain " | ||
122 | "only hexadecimal characters\n"); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* | ||
85 | * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key | 131 | * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key |
86 | * | 132 | * |
87 | * key-type:= "trusted:" | "encrypted:" | 133 | * key-type:= "trusted:" | "user:" |
88 | * desc:= master-key description | 134 | * desc:= master-key description |
89 | * | 135 | * |
90 | * Verify that 'key-type' is valid and that 'desc' exists. On key update, | 136 | * Verify that 'key-type' is valid and that 'desc' exists. On key update, |
@@ -118,8 +164,9 @@ out: | |||
118 | * datablob_parse - parse the keyctl data | 164 | * datablob_parse - parse the keyctl data |
119 | * | 165 | * |
120 | * datablob format: | 166 | * datablob format: |
121 | * new <master-key name> <decrypted data length> | 167 | * new [<format>] <master-key name> <decrypted data length> |
122 | * load <master-key name> <decrypted data length> <encrypted iv + data> | 168 | * load [<format>] <master-key name> <decrypted data length> |
169 | * <encrypted iv + data> | ||
123 | * update <new-master-key name> | 170 | * update <new-master-key name> |
124 | * | 171 | * |
125 | * Tokenizes a copy of the keyctl data, returning a pointer to each token, | 172 | * Tokenizes a copy of the keyctl data, returning a pointer to each token, |
@@ -127,52 +174,95 @@ out: | |||
127 | * | 174 | * |
128 | * On success returns 0, otherwise -EINVAL. | 175 | * On success returns 0, otherwise -EINVAL. |
129 | */ | 176 | */ |
130 | static int datablob_parse(char *datablob, char **master_desc, | 177 | static int datablob_parse(char *datablob, const char **format, |
131 | char **decrypted_datalen, char **hex_encoded_iv) | 178 | char **master_desc, char **decrypted_datalen, |
179 | char **hex_encoded_iv) | ||
132 | { | 180 | { |
133 | substring_t args[MAX_OPT_ARGS]; | 181 | substring_t args[MAX_OPT_ARGS]; |
134 | int ret = -EINVAL; | 182 | int ret = -EINVAL; |
135 | int key_cmd; | 183 | int key_cmd; |
136 | char *p; | 184 | int key_format; |
185 | char *p, *keyword; | ||
186 | |||
187 | keyword = strsep(&datablob, " \t"); | ||
188 | if (!keyword) { | ||
189 | pr_info("encrypted_key: insufficient parameters specified\n"); | ||
190 | return ret; | ||
191 | } | ||
192 | key_cmd = match_token(keyword, key_tokens, args); | ||
137 | 193 | ||
194 | /* Get optional format: default | ecryptfs */ | ||
138 | p = strsep(&datablob, " \t"); | 195 | p = strsep(&datablob, " \t"); |
139 | if (!p) | 196 | if (!p) { |
197 | pr_err("encrypted_key: insufficient parameters specified\n"); | ||
140 | return ret; | 198 | return ret; |
141 | key_cmd = match_token(p, key_tokens, args); | 199 | } |
142 | 200 | ||
143 | *master_desc = strsep(&datablob, " \t"); | 201 | key_format = match_token(p, key_format_tokens, args); |
144 | if (!*master_desc) | 202 | switch (key_format) { |
203 | case Opt_ecryptfs: | ||
204 | case Opt_default: | ||
205 | *format = p; | ||
206 | *master_desc = strsep(&datablob, " \t"); | ||
207 | break; | ||
208 | case Opt_error: | ||
209 | *master_desc = p; | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | if (!*master_desc) { | ||
214 | pr_info("encrypted_key: master key parameter is missing\n"); | ||
145 | goto out; | 215 | goto out; |
216 | } | ||
146 | 217 | ||
147 | if (valid_master_desc(*master_desc, NULL) < 0) | 218 | if (valid_master_desc(*master_desc, NULL) < 0) { |
219 | pr_info("encrypted_key: master key parameter \'%s\' " | ||
220 | "is invalid\n", *master_desc); | ||
148 | goto out; | 221 | goto out; |
222 | } | ||
149 | 223 | ||
150 | if (decrypted_datalen) { | 224 | if (decrypted_datalen) { |
151 | *decrypted_datalen = strsep(&datablob, " \t"); | 225 | *decrypted_datalen = strsep(&datablob, " \t"); |
152 | if (!*decrypted_datalen) | 226 | if (!*decrypted_datalen) { |
227 | pr_info("encrypted_key: keylen parameter is missing\n"); | ||
153 | goto out; | 228 | goto out; |
229 | } | ||
154 | } | 230 | } |
155 | 231 | ||
156 | switch (key_cmd) { | 232 | switch (key_cmd) { |
157 | case Opt_new: | 233 | case Opt_new: |
158 | if (!decrypted_datalen) | 234 | if (!decrypted_datalen) { |
235 | pr_info("encrypted_key: keyword \'%s\' not allowed " | ||
236 | "when called from .update method\n", keyword); | ||
159 | break; | 237 | break; |
238 | } | ||
160 | ret = 0; | 239 | ret = 0; |
161 | break; | 240 | break; |
162 | case Opt_load: | 241 | case Opt_load: |
163 | if (!decrypted_datalen) | 242 | if (!decrypted_datalen) { |
243 | pr_info("encrypted_key: keyword \'%s\' not allowed " | ||
244 | "when called from .update method\n", keyword); | ||
164 | break; | 245 | break; |
246 | } | ||
165 | *hex_encoded_iv = strsep(&datablob, " \t"); | 247 | *hex_encoded_iv = strsep(&datablob, " \t"); |
166 | if (!*hex_encoded_iv) | 248 | if (!*hex_encoded_iv) { |
249 | pr_info("encrypted_key: hex blob is missing\n"); | ||
167 | break; | 250 | break; |
251 | } | ||
168 | ret = 0; | 252 | ret = 0; |
169 | break; | 253 | break; |
170 | case Opt_update: | 254 | case Opt_update: |
171 | if (decrypted_datalen) | 255 | if (decrypted_datalen) { |
256 | pr_info("encrypted_key: keyword \'%s\' not allowed " | ||
257 | "when called from .instantiate method\n", | ||
258 | keyword); | ||
172 | break; | 259 | break; |
260 | } | ||
173 | ret = 0; | 261 | ret = 0; |
174 | break; | 262 | break; |
175 | case Opt_err: | 263 | case Opt_err: |
264 | pr_info("encrypted_key: keyword \'%s\' not recognized\n", | ||
265 | keyword); | ||
176 | break; | 266 | break; |
177 | } | 267 | } |
178 | out: | 268 | out: |
@@ -197,8 +287,8 @@ static char *datablob_format(struct encrypted_key_payload *epayload, | |||
197 | ascii_buf[asciiblob_len] = '\0'; | 287 | ascii_buf[asciiblob_len] = '\0'; |
198 | 288 | ||
199 | /* copy datablob master_desc and datalen strings */ | 289 | /* copy datablob master_desc and datalen strings */ |
200 | len = sprintf(ascii_buf, "%s %s ", epayload->master_desc, | 290 | len = sprintf(ascii_buf, "%s %s %s ", epayload->format, |
201 | epayload->datalen); | 291 | epayload->master_desc, epayload->datalen); |
202 | 292 | ||
203 | /* convert the hex encoded iv, encrypted-data and HMAC to ascii */ | 293 | /* convert the hex encoded iv, encrypted-data and HMAC to ascii */ |
204 | bufp = &ascii_buf[len]; | 294 | bufp = &ascii_buf[len]; |
@@ -378,11 +468,13 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload, | |||
378 | } else | 468 | } else |
379 | goto out; | 469 | goto out; |
380 | 470 | ||
381 | if (IS_ERR(mkey)) | 471 | if (IS_ERR(mkey)) { |
382 | pr_info("encrypted_key: key %s not found", | 472 | pr_info("encrypted_key: key %s not found", |
383 | epayload->master_desc); | 473 | epayload->master_desc); |
384 | if (mkey) | 474 | goto out; |
385 | dump_master_key(*master_key, *master_keylen); | 475 | } |
476 | |||
477 | dump_master_key(*master_key, *master_keylen); | ||
386 | out: | 478 | out: |
387 | return mkey; | 479 | return mkey; |
388 | } | 480 | } |
@@ -439,9 +531,9 @@ static int datablob_hmac_append(struct encrypted_key_payload *epayload, | |||
439 | if (ret < 0) | 531 | if (ret < 0) |
440 | goto out; | 532 | goto out; |
441 | 533 | ||
442 | digest = epayload->master_desc + epayload->datablob_len; | 534 | digest = epayload->format + epayload->datablob_len; |
443 | ret = calc_hmac(digest, derived_key, sizeof derived_key, | 535 | ret = calc_hmac(digest, derived_key, sizeof derived_key, |
444 | epayload->master_desc, epayload->datablob_len); | 536 | epayload->format, epayload->datablob_len); |
445 | if (!ret) | 537 | if (!ret) |
446 | dump_hmac(NULL, digest, HASH_SIZE); | 538 | dump_hmac(NULL, digest, HASH_SIZE); |
447 | out: | 539 | out: |
@@ -450,26 +542,35 @@ out: | |||
450 | 542 | ||
451 | /* verify HMAC before decrypting encrypted key */ | 543 | /* verify HMAC before decrypting encrypted key */ |
452 | static int datablob_hmac_verify(struct encrypted_key_payload *epayload, | 544 | static int datablob_hmac_verify(struct encrypted_key_payload *epayload, |
453 | const u8 *master_key, size_t master_keylen) | 545 | const u8 *format, const u8 *master_key, |
546 | size_t master_keylen) | ||
454 | { | 547 | { |
455 | u8 derived_key[HASH_SIZE]; | 548 | u8 derived_key[HASH_SIZE]; |
456 | u8 digest[HASH_SIZE]; | 549 | u8 digest[HASH_SIZE]; |
457 | int ret; | 550 | int ret; |
551 | char *p; | ||
552 | unsigned short len; | ||
458 | 553 | ||
459 | ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); | 554 | ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); |
460 | if (ret < 0) | 555 | if (ret < 0) |
461 | goto out; | 556 | goto out; |
462 | 557 | ||
463 | ret = calc_hmac(digest, derived_key, sizeof derived_key, | 558 | len = epayload->datablob_len; |
464 | epayload->master_desc, epayload->datablob_len); | 559 | if (!format) { |
560 | p = epayload->master_desc; | ||
561 | len -= strlen(epayload->format) + 1; | ||
562 | } else | ||
563 | p = epayload->format; | ||
564 | |||
565 | ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len); | ||
465 | if (ret < 0) | 566 | if (ret < 0) |
466 | goto out; | 567 | goto out; |
467 | ret = memcmp(digest, epayload->master_desc + epayload->datablob_len, | 568 | ret = memcmp(digest, epayload->format + epayload->datablob_len, |
468 | sizeof digest); | 569 | sizeof digest); |
469 | if (ret) { | 570 | if (ret) { |
470 | ret = -EINVAL; | 571 | ret = -EINVAL; |
471 | dump_hmac("datablob", | 572 | dump_hmac("datablob", |
472 | epayload->master_desc + epayload->datablob_len, | 573 | epayload->format + epayload->datablob_len, |
473 | HASH_SIZE); | 574 | HASH_SIZE); |
474 | dump_hmac("calc", digest, HASH_SIZE); | 575 | dump_hmac("calc", digest, HASH_SIZE); |
475 | } | 576 | } |
@@ -514,13 +615,16 @@ out: | |||
514 | 615 | ||
515 | /* Allocate memory for decrypted key and datablob. */ | 616 | /* Allocate memory for decrypted key and datablob. */ |
516 | static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | 617 | static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, |
618 | const char *format, | ||
517 | const char *master_desc, | 619 | const char *master_desc, |
518 | const char *datalen) | 620 | const char *datalen) |
519 | { | 621 | { |
520 | struct encrypted_key_payload *epayload = NULL; | 622 | struct encrypted_key_payload *epayload = NULL; |
521 | unsigned short datablob_len; | 623 | unsigned short datablob_len; |
522 | unsigned short decrypted_datalen; | 624 | unsigned short decrypted_datalen; |
625 | unsigned short payload_datalen; | ||
523 | unsigned int encrypted_datalen; | 626 | unsigned int encrypted_datalen; |
627 | unsigned int format_len; | ||
524 | long dlen; | 628 | long dlen; |
525 | int ret; | 629 | int ret; |
526 | 630 | ||
@@ -528,29 +632,43 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | |||
528 | if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) | 632 | if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) |
529 | return ERR_PTR(-EINVAL); | 633 | return ERR_PTR(-EINVAL); |
530 | 634 | ||
635 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | ||
531 | decrypted_datalen = dlen; | 636 | decrypted_datalen = dlen; |
637 | payload_datalen = decrypted_datalen; | ||
638 | if (format && !strcmp(format, key_format_ecryptfs)) { | ||
639 | if (dlen != ECRYPTFS_MAX_KEY_BYTES) { | ||
640 | pr_err("encrypted_key: keylen for the ecryptfs format " | ||
641 | "must be equal to %d bytes\n", | ||
642 | ECRYPTFS_MAX_KEY_BYTES); | ||
643 | return ERR_PTR(-EINVAL); | ||
644 | } | ||
645 | decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES; | ||
646 | payload_datalen = sizeof(struct ecryptfs_auth_tok); | ||
647 | } | ||
648 | |||
532 | encrypted_datalen = roundup(decrypted_datalen, blksize); | 649 | encrypted_datalen = roundup(decrypted_datalen, blksize); |
533 | 650 | ||
534 | datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1 | 651 | datablob_len = format_len + 1 + strlen(master_desc) + 1 |
535 | + ivsize + 1 + encrypted_datalen; | 652 | + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen; |
536 | 653 | ||
537 | ret = key_payload_reserve(key, decrypted_datalen + datablob_len | 654 | ret = key_payload_reserve(key, payload_datalen + datablob_len |
538 | + HASH_SIZE + 1); | 655 | + HASH_SIZE + 1); |
539 | if (ret < 0) | 656 | if (ret < 0) |
540 | return ERR_PTR(ret); | 657 | return ERR_PTR(ret); |
541 | 658 | ||
542 | epayload = kzalloc(sizeof(*epayload) + decrypted_datalen + | 659 | epayload = kzalloc(sizeof(*epayload) + payload_datalen + |
543 | datablob_len + HASH_SIZE + 1, GFP_KERNEL); | 660 | datablob_len + HASH_SIZE + 1, GFP_KERNEL); |
544 | if (!epayload) | 661 | if (!epayload) |
545 | return ERR_PTR(-ENOMEM); | 662 | return ERR_PTR(-ENOMEM); |
546 | 663 | ||
664 | epayload->payload_datalen = payload_datalen; | ||
547 | epayload->decrypted_datalen = decrypted_datalen; | 665 | epayload->decrypted_datalen = decrypted_datalen; |
548 | epayload->datablob_len = datablob_len; | 666 | epayload->datablob_len = datablob_len; |
549 | return epayload; | 667 | return epayload; |
550 | } | 668 | } |
551 | 669 | ||
552 | static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, | 670 | static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, |
553 | const char *hex_encoded_iv) | 671 | const char *format, const char *hex_encoded_iv) |
554 | { | 672 | { |
555 | struct key *mkey; | 673 | struct key *mkey; |
556 | u8 derived_key[HASH_SIZE]; | 674 | u8 derived_key[HASH_SIZE]; |
@@ -571,14 +689,14 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, | |||
571 | hex2bin(epayload->iv, hex_encoded_iv, ivsize); | 689 | hex2bin(epayload->iv, hex_encoded_iv, ivsize); |
572 | hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen); | 690 | hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen); |
573 | 691 | ||
574 | hmac = epayload->master_desc + epayload->datablob_len; | 692 | hmac = epayload->format + epayload->datablob_len; |
575 | hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE); | 693 | hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE); |
576 | 694 | ||
577 | mkey = request_master_key(epayload, &master_key, &master_keylen); | 695 | mkey = request_master_key(epayload, &master_key, &master_keylen); |
578 | if (IS_ERR(mkey)) | 696 | if (IS_ERR(mkey)) |
579 | return PTR_ERR(mkey); | 697 | return PTR_ERR(mkey); |
580 | 698 | ||
581 | ret = datablob_hmac_verify(epayload, master_key, master_keylen); | 699 | ret = datablob_hmac_verify(epayload, format, master_key, master_keylen); |
582 | if (ret < 0) { | 700 | if (ret < 0) { |
583 | pr_err("encrypted_key: bad hmac (%d)\n", ret); | 701 | pr_err("encrypted_key: bad hmac (%d)\n", ret); |
584 | goto out; | 702 | goto out; |
@@ -598,13 +716,28 @@ out: | |||
598 | } | 716 | } |
599 | 717 | ||
600 | static void __ekey_init(struct encrypted_key_payload *epayload, | 718 | static void __ekey_init(struct encrypted_key_payload *epayload, |
601 | const char *master_desc, const char *datalen) | 719 | const char *format, const char *master_desc, |
720 | const char *datalen) | ||
602 | { | 721 | { |
603 | epayload->master_desc = epayload->decrypted_data | 722 | unsigned int format_len; |
604 | + epayload->decrypted_datalen; | 723 | |
724 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | ||
725 | epayload->format = epayload->payload_data + epayload->payload_datalen; | ||
726 | epayload->master_desc = epayload->format + format_len + 1; | ||
605 | epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; | 727 | epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; |
606 | epayload->iv = epayload->datalen + strlen(datalen) + 1; | 728 | epayload->iv = epayload->datalen + strlen(datalen) + 1; |
607 | epayload->encrypted_data = epayload->iv + ivsize + 1; | 729 | epayload->encrypted_data = epayload->iv + ivsize + 1; |
730 | epayload->decrypted_data = epayload->payload_data; | ||
731 | |||
732 | if (!format) | ||
733 | memcpy(epayload->format, key_format_default, format_len); | ||
734 | else { | ||
735 | if (!strcmp(format, key_format_ecryptfs)) | ||
736 | epayload->decrypted_data = | ||
737 | ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data); | ||
738 | |||
739 | memcpy(epayload->format, format, format_len); | ||
740 | } | ||
608 | 741 | ||
609 | memcpy(epayload->master_desc, master_desc, strlen(master_desc)); | 742 | memcpy(epayload->master_desc, master_desc, strlen(master_desc)); |
610 | memcpy(epayload->datalen, datalen, strlen(datalen)); | 743 | memcpy(epayload->datalen, datalen, strlen(datalen)); |
@@ -617,19 +750,29 @@ static void __ekey_init(struct encrypted_key_payload *epayload, | |||
617 | * itself. For an old key, decrypt the hex encoded data. | 750 | * itself. For an old key, decrypt the hex encoded data. |
618 | */ | 751 | */ |
619 | static int encrypted_init(struct encrypted_key_payload *epayload, | 752 | static int encrypted_init(struct encrypted_key_payload *epayload, |
753 | const char *key_desc, const char *format, | ||
620 | const char *master_desc, const char *datalen, | 754 | const char *master_desc, const char *datalen, |
621 | const char *hex_encoded_iv) | 755 | const char *hex_encoded_iv) |
622 | { | 756 | { |
623 | int ret = 0; | 757 | int ret = 0; |
624 | 758 | ||
625 | __ekey_init(epayload, master_desc, datalen); | 759 | if (format && !strcmp(format, key_format_ecryptfs)) { |
760 | ret = valid_ecryptfs_desc(key_desc); | ||
761 | if (ret < 0) | ||
762 | return ret; | ||
763 | |||
764 | ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data, | ||
765 | key_desc); | ||
766 | } | ||
767 | |||
768 | __ekey_init(epayload, format, master_desc, datalen); | ||
626 | if (!hex_encoded_iv) { | 769 | if (!hex_encoded_iv) { |
627 | get_random_bytes(epayload->iv, ivsize); | 770 | get_random_bytes(epayload->iv, ivsize); |
628 | 771 | ||
629 | get_random_bytes(epayload->decrypted_data, | 772 | get_random_bytes(epayload->decrypted_data, |
630 | epayload->decrypted_datalen); | 773 | epayload->decrypted_datalen); |
631 | } else | 774 | } else |
632 | ret = encrypted_key_decrypt(epayload, hex_encoded_iv); | 775 | ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv); |
633 | return ret; | 776 | return ret; |
634 | } | 777 | } |
635 | 778 | ||
@@ -646,6 +789,7 @@ static int encrypted_instantiate(struct key *key, const void *data, | |||
646 | { | 789 | { |
647 | struct encrypted_key_payload *epayload = NULL; | 790 | struct encrypted_key_payload *epayload = NULL; |
648 | char *datablob = NULL; | 791 | char *datablob = NULL; |
792 | const char *format = NULL; | ||
649 | char *master_desc = NULL; | 793 | char *master_desc = NULL; |
650 | char *decrypted_datalen = NULL; | 794 | char *decrypted_datalen = NULL; |
651 | char *hex_encoded_iv = NULL; | 795 | char *hex_encoded_iv = NULL; |
@@ -659,18 +803,19 @@ static int encrypted_instantiate(struct key *key, const void *data, | |||
659 | return -ENOMEM; | 803 | return -ENOMEM; |
660 | datablob[datalen] = 0; | 804 | datablob[datalen] = 0; |
661 | memcpy(datablob, data, datalen); | 805 | memcpy(datablob, data, datalen); |
662 | ret = datablob_parse(datablob, &master_desc, &decrypted_datalen, | 806 | ret = datablob_parse(datablob, &format, &master_desc, |
663 | &hex_encoded_iv); | 807 | &decrypted_datalen, &hex_encoded_iv); |
664 | if (ret < 0) | 808 | if (ret < 0) |
665 | goto out; | 809 | goto out; |
666 | 810 | ||
667 | epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen); | 811 | epayload = encrypted_key_alloc(key, format, master_desc, |
812 | decrypted_datalen); | ||
668 | if (IS_ERR(epayload)) { | 813 | if (IS_ERR(epayload)) { |
669 | ret = PTR_ERR(epayload); | 814 | ret = PTR_ERR(epayload); |
670 | goto out; | 815 | goto out; |
671 | } | 816 | } |
672 | ret = encrypted_init(epayload, master_desc, decrypted_datalen, | 817 | ret = encrypted_init(epayload, key->description, format, master_desc, |
673 | hex_encoded_iv); | 818 | decrypted_datalen, hex_encoded_iv); |
674 | if (ret < 0) { | 819 | if (ret < 0) { |
675 | kfree(epayload); | 820 | kfree(epayload); |
676 | goto out; | 821 | goto out; |
@@ -706,6 +851,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) | |||
706 | struct encrypted_key_payload *new_epayload; | 851 | struct encrypted_key_payload *new_epayload; |
707 | char *buf; | 852 | char *buf; |
708 | char *new_master_desc = NULL; | 853 | char *new_master_desc = NULL; |
854 | const char *format = NULL; | ||
709 | int ret = 0; | 855 | int ret = 0; |
710 | 856 | ||
711 | if (datalen <= 0 || datalen > 32767 || !data) | 857 | if (datalen <= 0 || datalen > 32767 || !data) |
@@ -717,7 +863,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) | |||
717 | 863 | ||
718 | buf[datalen] = 0; | 864 | buf[datalen] = 0; |
719 | memcpy(buf, data, datalen); | 865 | memcpy(buf, data, datalen); |
720 | ret = datablob_parse(buf, &new_master_desc, NULL, NULL); | 866 | ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); |
721 | if (ret < 0) | 867 | if (ret < 0) |
722 | goto out; | 868 | goto out; |
723 | 869 | ||
@@ -725,18 +871,19 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) | |||
725 | if (ret < 0) | 871 | if (ret < 0) |
726 | goto out; | 872 | goto out; |
727 | 873 | ||
728 | new_epayload = encrypted_key_alloc(key, new_master_desc, | 874 | new_epayload = encrypted_key_alloc(key, epayload->format, |
729 | epayload->datalen); | 875 | new_master_desc, epayload->datalen); |
730 | if (IS_ERR(new_epayload)) { | 876 | if (IS_ERR(new_epayload)) { |
731 | ret = PTR_ERR(new_epayload); | 877 | ret = PTR_ERR(new_epayload); |
732 | goto out; | 878 | goto out; |
733 | } | 879 | } |
734 | 880 | ||
735 | __ekey_init(new_epayload, new_master_desc, epayload->datalen); | 881 | __ekey_init(new_epayload, epayload->format, new_master_desc, |
882 | epayload->datalen); | ||
736 | 883 | ||
737 | memcpy(new_epayload->iv, epayload->iv, ivsize); | 884 | memcpy(new_epayload->iv, epayload->iv, ivsize); |
738 | memcpy(new_epayload->decrypted_data, epayload->decrypted_data, | 885 | memcpy(new_epayload->payload_data, epayload->payload_data, |
739 | epayload->decrypted_datalen); | 886 | epayload->payload_datalen); |
740 | 887 | ||
741 | rcu_assign_pointer(key->payload.data, new_epayload); | 888 | rcu_assign_pointer(key->payload.data, new_epayload); |
742 | call_rcu(&epayload->rcu, encrypted_rcu_free); | 889 | call_rcu(&epayload->rcu, encrypted_rcu_free); |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 6cff37529b80..60d4e3f5e4bb 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -251,6 +251,8 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) | |||
251 | 251 | ||
252 | if (IS_ERR(authkey_ref)) { | 252 | if (IS_ERR(authkey_ref)) { |
253 | authkey = ERR_CAST(authkey_ref); | 253 | authkey = ERR_CAST(authkey_ref); |
254 | if (authkey == ERR_PTR(-EAGAIN)) | ||
255 | authkey = ERR_PTR(-ENOKEY); | ||
254 | goto error; | 256 | goto error; |
255 | } | 257 | } |
256 | 258 | ||
diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index c8f385793235..7c7f8c16c10f 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig | |||
@@ -9,3 +9,64 @@ config SECURITY_TOMOYO | |||
9 | Required userspace tools and further information may be | 9 | Required userspace tools and further information may be |
10 | found at <http://tomoyo.sourceforge.jp/>. | 10 | found at <http://tomoyo.sourceforge.jp/>. |
11 | If you are unsure how to answer this question, answer N. | 11 | If you are unsure how to answer this question, answer N. |
12 | |||
13 | config SECURITY_TOMOYO_MAX_ACCEPT_ENTRY | ||
14 | int "Default maximal count for learning mode" | ||
15 | default 2048 | ||
16 | range 0 2147483647 | ||
17 | depends on SECURITY_TOMOYO | ||
18 | help | ||
19 | This is the default value for maximal ACL entries | ||
20 | that are automatically appended into policy at "learning mode". | ||
21 | Some programs access thousands of objects, so running | ||
22 | such programs in "learning mode" dulls the system response | ||
23 | and consumes much memory. | ||
24 | This is the safeguard for such programs. | ||
25 | |||
26 | config SECURITY_TOMOYO_MAX_AUDIT_LOG | ||
27 | int "Default maximal count for audit log" | ||
28 | default 1024 | ||
29 | range 0 2147483647 | ||
30 | depends on SECURITY_TOMOYO | ||
31 | help | ||
32 | This is the default value for maximal entries for | ||
33 | audit logs that the kernel can hold on memory. | ||
34 | You can read the log via /sys/kernel/security/tomoyo/audit. | ||
35 | If you don't need audit logs, you may set this value to 0. | ||
36 | |||
37 | config SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
38 | bool "Activate without calling userspace policy loader." | ||
39 | default n | ||
40 | depends on SECURITY_TOMOYO | ||
41 | ---help--- | ||
42 | Say Y here if you want to activate access control as soon as built-in | ||
43 | policy was loaded. This option will be useful for systems where | ||
44 | operations which can lead to the hijacking of the boot sequence are | ||
45 | needed before loading the policy. For example, you can activate | ||
46 | immediately after loading the fixed part of policy which will allow | ||
47 | only operations needed for mounting a partition which contains the | ||
48 | variant part of policy and verifying (e.g. running GPG check) and | ||
49 | loading the variant part of policy. Since you can start using | ||
50 | enforcing mode from the beginning, you can reduce the possibility of | ||
51 | hijacking the boot sequence. | ||
52 | |||
53 | config SECURITY_TOMOYO_POLICY_LOADER | ||
54 | string "Location of userspace policy loader" | ||
55 | default "/sbin/tomoyo-init" | ||
56 | depends on SECURITY_TOMOYO | ||
57 | depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
58 | ---help--- | ||
59 | This is the default pathname of policy loader which is called before | ||
60 | activation. You can override this setting via TOMOYO_loader= kernel | ||
61 | command line option. | ||
62 | |||
63 | config SECURITY_TOMOYO_ACTIVATION_TRIGGER | ||
64 | string "Trigger for calling userspace policy loader" | ||
65 | default "/sbin/init" | ||
66 | depends on SECURITY_TOMOYO | ||
67 | depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
68 | ---help--- | ||
69 | This is the default pathname of activation trigger. | ||
70 | You can override this setting via TOMOYO_trigger= kernel command line | ||
71 | option. For example, if you pass init=/bin/systemd option, you may | ||
72 | want to also pass TOMOYO_trigger=/bin/systemd option. | ||
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 91640e96bd06..95278b71fc21 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1 +1,48 @@ | |||
1 | obj-y = common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o | 1 | obj-y = audit.o common.o condition.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o |
2 | |||
3 | $(obj)/policy/profile.conf: | ||
4 | @mkdir -p $(obj)/policy/ | ||
5 | @echo Creating an empty policy/profile.conf | ||
6 | @touch $@ | ||
7 | |||
8 | $(obj)/policy/exception_policy.conf: | ||
9 | @mkdir -p $(obj)/policy/ | ||
10 | @echo Creating a default policy/exception_policy.conf | ||
11 | @echo initialize_domain /sbin/modprobe from any >> $@ | ||
12 | @echo initialize_domain /sbin/hotplug from any >> $@ | ||
13 | |||
14 | $(obj)/policy/domain_policy.conf: | ||
15 | @mkdir -p $(obj)/policy/ | ||
16 | @echo Creating an empty policy/domain_policy.conf | ||
17 | @touch $@ | ||
18 | |||
19 | $(obj)/policy/manager.conf: | ||
20 | @mkdir -p $(obj)/policy/ | ||
21 | @echo Creating an empty policy/manager.conf | ||
22 | @touch $@ | ||
23 | |||
24 | $(obj)/policy/stat.conf: | ||
25 | @mkdir -p $(obj)/policy/ | ||
26 | @echo Creating an empty policy/stat.conf | ||
27 | @touch $@ | ||
28 | |||
29 | $(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf | ||
30 | @echo Generating built-in policy for TOMOYO 2.4.x. | ||
31 | @echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp | ||
32 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp | ||
33 | @echo "\"\";" >> $@.tmp | ||
34 | @echo "static char tomoyo_builtin_exception_policy[] __initdata =" >> $@.tmp | ||
35 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/exception_policy.conf >> $@.tmp | ||
36 | @echo "\"\";" >> $@.tmp | ||
37 | @echo "static char tomoyo_builtin_domain_policy[] __initdata =" >> $@.tmp | ||
38 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/domain_policy.conf >> $@.tmp | ||
39 | @echo "\"\";" >> $@.tmp | ||
40 | @echo "static char tomoyo_builtin_manager[] __initdata =" >> $@.tmp | ||
41 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/manager.conf >> $@.tmp | ||
42 | @echo "\"\";" >> $@.tmp | ||
43 | @echo "static char tomoyo_builtin_stat[] __initdata =" >> $@.tmp | ||
44 | @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/stat.conf >> $@.tmp | ||
45 | @echo "\"\";" >> $@.tmp | ||
46 | @mv $@.tmp $@ | ||
47 | |||
48 | $(obj)/common.o: $(obj)/builtin-policy.h | ||
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c new file mode 100644 index 000000000000..5dbb1f7617c0 --- /dev/null +++ b/security/tomoyo/audit.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | * security/tomoyo/audit.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION | ||
5 | */ | ||
6 | |||
7 | #include "common.h" | ||
8 | #include <linux/slab.h> | ||
9 | |||
10 | /** | ||
11 | * tomoyo_print_bprm - Print "struct linux_binprm" for auditing. | ||
12 | * | ||
13 | * @bprm: Pointer to "struct linux_binprm". | ||
14 | * @dump: Pointer to "struct tomoyo_page_dump". | ||
15 | * | ||
16 | * Returns the contents of @bprm on success, NULL otherwise. | ||
17 | * | ||
18 | * This function uses kzalloc(), so caller must kfree() if this function | ||
19 | * didn't return NULL. | ||
20 | */ | ||
21 | static char *tomoyo_print_bprm(struct linux_binprm *bprm, | ||
22 | struct tomoyo_page_dump *dump) | ||
23 | { | ||
24 | static const int tomoyo_buffer_len = 4096 * 2; | ||
25 | char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS); | ||
26 | char *cp; | ||
27 | char *last_start; | ||
28 | int len; | ||
29 | unsigned long pos = bprm->p; | ||
30 | int offset = pos % PAGE_SIZE; | ||
31 | int argv_count = bprm->argc; | ||
32 | int envp_count = bprm->envc; | ||
33 | bool truncated = false; | ||
34 | if (!buffer) | ||
35 | return NULL; | ||
36 | len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ "); | ||
37 | cp = buffer + len; | ||
38 | if (!argv_count) { | ||
39 | memmove(cp, "} envp[]={ ", 11); | ||
40 | cp += 11; | ||
41 | } | ||
42 | last_start = cp; | ||
43 | while (argv_count || envp_count) { | ||
44 | if (!tomoyo_dump_page(bprm, pos, dump)) | ||
45 | goto out; | ||
46 | pos += PAGE_SIZE - offset; | ||
47 | /* Read. */ | ||
48 | while (offset < PAGE_SIZE) { | ||
49 | const char *kaddr = dump->data; | ||
50 | const unsigned char c = kaddr[offset++]; | ||
51 | if (cp == last_start) | ||
52 | *cp++ = '"'; | ||
53 | if (cp >= buffer + tomoyo_buffer_len - 32) { | ||
54 | /* Reserve some room for "..." string. */ | ||
55 | truncated = true; | ||
56 | } else if (c == '\\') { | ||
57 | *cp++ = '\\'; | ||
58 | *cp++ = '\\'; | ||
59 | } else if (c > ' ' && c < 127) { | ||
60 | *cp++ = c; | ||
61 | } else if (!c) { | ||
62 | *cp++ = '"'; | ||
63 | *cp++ = ' '; | ||
64 | last_start = cp; | ||
65 | } else { | ||
66 | *cp++ = '\\'; | ||
67 | *cp++ = (c >> 6) + '0'; | ||
68 | *cp++ = ((c >> 3) & 7) + '0'; | ||
69 | *cp++ = (c & 7) + '0'; | ||
70 | } | ||
71 | if (c) | ||
72 | continue; | ||
73 | if (argv_count) { | ||
74 | if (--argv_count == 0) { | ||
75 | if (truncated) { | ||
76 | cp = last_start; | ||
77 | memmove(cp, "... ", 4); | ||
78 | cp += 4; | ||
79 | } | ||
80 | memmove(cp, "} envp[]={ ", 11); | ||
81 | cp += 11; | ||
82 | last_start = cp; | ||
83 | truncated = false; | ||
84 | } | ||
85 | } else if (envp_count) { | ||
86 | if (--envp_count == 0) { | ||
87 | if (truncated) { | ||
88 | cp = last_start; | ||
89 | memmove(cp, "... ", 4); | ||
90 | cp += 4; | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | if (!argv_count && !envp_count) | ||
95 | break; | ||
96 | } | ||
97 | offset = 0; | ||
98 | } | ||
99 | *cp++ = '}'; | ||
100 | *cp = '\0'; | ||
101 | return buffer; | ||
102 | out: | ||
103 | snprintf(buffer, tomoyo_buffer_len - 1, | ||
104 | "argv[]={ ... } envp[]= { ... }"); | ||
105 | return buffer; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * tomoyo_filetype - Get string representation of file type. | ||
110 | * | ||
111 | * @mode: Mode value for stat(). | ||
112 | * | ||
113 | * Returns file type string. | ||
114 | */ | ||
115 | static inline const char *tomoyo_filetype(const mode_t mode) | ||
116 | { | ||
117 | switch (mode & S_IFMT) { | ||
118 | case S_IFREG: | ||
119 | case 0: | ||
120 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE]; | ||
121 | case S_IFDIR: | ||
122 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY]; | ||
123 | case S_IFLNK: | ||
124 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK]; | ||
125 | case S_IFIFO: | ||
126 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO]; | ||
127 | case S_IFSOCK: | ||
128 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET]; | ||
129 | case S_IFBLK: | ||
130 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV]; | ||
131 | case S_IFCHR: | ||
132 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV]; | ||
133 | } | ||
134 | return "unknown"; /* This should not happen. */ | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * tomoyo_print_header - Get header line of audit log. | ||
139 | * | ||
140 | * @r: Pointer to "struct tomoyo_request_info". | ||
141 | * | ||
142 | * Returns string representation. | ||
143 | * | ||
144 | * This function uses kmalloc(), so caller must kfree() if this function | ||
145 | * didn't return NULL. | ||
146 | */ | ||
147 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | ||
148 | { | ||
149 | struct tomoyo_time stamp; | ||
150 | const pid_t gpid = task_pid_nr(current); | ||
151 | struct tomoyo_obj_info *obj = r->obj; | ||
152 | static const int tomoyo_buffer_len = 4096; | ||
153 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | ||
154 | int pos; | ||
155 | u8 i; | ||
156 | if (!buffer) | ||
157 | return NULL; | ||
158 | { | ||
159 | struct timeval tv; | ||
160 | do_gettimeofday(&tv); | ||
161 | tomoyo_convert_time(tv.tv_sec, &stamp); | ||
162 | } | ||
163 | pos = snprintf(buffer, tomoyo_buffer_len - 1, | ||
164 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " | ||
165 | "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " | ||
166 | "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " | ||
167 | "fsuid=%u fsgid=%u }", stamp.year, stamp.month, | ||
168 | stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, | ||
169 | tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, | ||
170 | tomoyo_sys_getpid(), tomoyo_sys_getppid(), | ||
171 | current_uid(), current_gid(), current_euid(), | ||
172 | current_egid(), current_suid(), current_sgid(), | ||
173 | current_fsuid(), current_fsgid()); | ||
174 | if (!obj) | ||
175 | goto no_obj_info; | ||
176 | if (!obj->validate_done) { | ||
177 | tomoyo_get_attributes(obj); | ||
178 | obj->validate_done = true; | ||
179 | } | ||
180 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { | ||
181 | struct tomoyo_mini_stat *stat; | ||
182 | unsigned int dev; | ||
183 | mode_t mode; | ||
184 | if (!obj->stat_valid[i]) | ||
185 | continue; | ||
186 | stat = &obj->stat[i]; | ||
187 | dev = stat->dev; | ||
188 | mode = stat->mode; | ||
189 | if (i & 1) { | ||
190 | pos += snprintf(buffer + pos, | ||
191 | tomoyo_buffer_len - 1 - pos, | ||
192 | " path%u.parent={ uid=%u gid=%u " | ||
193 | "ino=%lu perm=0%o }", (i >> 1) + 1, | ||
194 | stat->uid, stat->gid, (unsigned long) | ||
195 | stat->ino, stat->mode & S_IALLUGO); | ||
196 | continue; | ||
197 | } | ||
198 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | ||
199 | " path%u={ uid=%u gid=%u ino=%lu major=%u" | ||
200 | " minor=%u perm=0%o type=%s", (i >> 1) + 1, | ||
201 | stat->uid, stat->gid, (unsigned long) | ||
202 | stat->ino, MAJOR(dev), MINOR(dev), | ||
203 | mode & S_IALLUGO, tomoyo_filetype(mode)); | ||
204 | if (S_ISCHR(mode) || S_ISBLK(mode)) { | ||
205 | dev = stat->rdev; | ||
206 | pos += snprintf(buffer + pos, | ||
207 | tomoyo_buffer_len - 1 - pos, | ||
208 | " dev_major=%u dev_minor=%u", | ||
209 | MAJOR(dev), MINOR(dev)); | ||
210 | } | ||
211 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | ||
212 | " }"); | ||
213 | } | ||
214 | no_obj_info: | ||
215 | if (pos < tomoyo_buffer_len - 1) | ||
216 | return buffer; | ||
217 | kfree(buffer); | ||
218 | return NULL; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * tomoyo_init_log - Allocate buffer for audit logs. | ||
223 | * | ||
224 | * @r: Pointer to "struct tomoyo_request_info". | ||
225 | * @len: Buffer size needed for @fmt and @args. | ||
226 | * @fmt: The printf()'s format string. | ||
227 | * @args: va_list structure for @fmt. | ||
228 | * | ||
229 | * Returns pointer to allocated memory. | ||
230 | * | ||
231 | * This function uses kzalloc(), so caller must kfree() if this function | ||
232 | * didn't return NULL. | ||
233 | */ | ||
234 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | ||
235 | va_list args) | ||
236 | { | ||
237 | char *buf = NULL; | ||
238 | char *bprm_info = NULL; | ||
239 | const char *header = NULL; | ||
240 | char *realpath = NULL; | ||
241 | const char *symlink = NULL; | ||
242 | int pos; | ||
243 | const char *domainname = r->domain->domainname->name; | ||
244 | header = tomoyo_print_header(r); | ||
245 | if (!header) | ||
246 | return NULL; | ||
247 | /* +10 is for '\n' etc. and '\0'. */ | ||
248 | len += strlen(domainname) + strlen(header) + 10; | ||
249 | if (r->ee) { | ||
250 | struct file *file = r->ee->bprm->file; | ||
251 | realpath = tomoyo_realpath_from_path(&file->f_path); | ||
252 | bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump); | ||
253 | if (!realpath || !bprm_info) | ||
254 | goto out; | ||
255 | /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */ | ||
256 | len += strlen(realpath) + 80 + strlen(bprm_info); | ||
257 | } else if (r->obj && r->obj->symlink_target) { | ||
258 | symlink = r->obj->symlink_target->name; | ||
259 | /* +18 is for " symlink.target=\"%s\"" */ | ||
260 | len += 18 + strlen(symlink); | ||
261 | } | ||
262 | len = tomoyo_round2(len); | ||
263 | buf = kzalloc(len, GFP_NOFS); | ||
264 | if (!buf) | ||
265 | goto out; | ||
266 | len--; | ||
267 | pos = snprintf(buf, len, "%s", header); | ||
268 | if (realpath) { | ||
269 | struct linux_binprm *bprm = r->ee->bprm; | ||
270 | pos += snprintf(buf + pos, len - pos, | ||
271 | " exec={ realpath=\"%s\" argc=%d envc=%d %s }", | ||
272 | realpath, bprm->argc, bprm->envc, bprm_info); | ||
273 | } else if (symlink) | ||
274 | pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"", | ||
275 | symlink); | ||
276 | pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname); | ||
277 | vsnprintf(buf + pos, len - pos, fmt, args); | ||
278 | out: | ||
279 | kfree(realpath); | ||
280 | kfree(bprm_info); | ||
281 | kfree(header); | ||
282 | return buf; | ||
283 | } | ||
284 | |||
285 | /* Wait queue for /sys/kernel/security/tomoyo/audit. */ | ||
286 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait); | ||
287 | |||
288 | /* Structure for audit log. */ | ||
289 | struct tomoyo_log { | ||
290 | struct list_head list; | ||
291 | char *log; | ||
292 | int size; | ||
293 | }; | ||
294 | |||
295 | /* The list for "struct tomoyo_log". */ | ||
296 | static LIST_HEAD(tomoyo_log); | ||
297 | |||
298 | /* Lock for "struct list_head tomoyo_log". */ | ||
299 | static DEFINE_SPINLOCK(tomoyo_log_lock); | ||
300 | |||
301 | /* Length of "stuct list_head tomoyo_log". */ | ||
302 | static unsigned int tomoyo_log_count; | ||
303 | |||
304 | /** | ||
305 | * tomoyo_get_audit - Get audit mode. | ||
306 | * | ||
307 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
308 | * @profile: Profile number. | ||
309 | * @index: Index number of functionality. | ||
310 | * @is_granted: True if granted log, false otherwise. | ||
311 | * | ||
312 | * Returns true if this request should be audited, false otherwise. | ||
313 | */ | ||
314 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, | ||
315 | const u8 profile, const u8 index, | ||
316 | const bool is_granted) | ||
317 | { | ||
318 | u8 mode; | ||
319 | const u8 category = tomoyo_index2category[index] + | ||
320 | TOMOYO_MAX_MAC_INDEX; | ||
321 | struct tomoyo_profile *p; | ||
322 | if (!tomoyo_policy_loaded) | ||
323 | return false; | ||
324 | p = tomoyo_profile(ns, profile); | ||
325 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) | ||
326 | return false; | ||
327 | mode = p->config[index]; | ||
328 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | ||
329 | mode = p->config[category]; | ||
330 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | ||
331 | mode = p->default_config; | ||
332 | if (is_granted) | ||
333 | return mode & TOMOYO_CONFIG_WANT_GRANT_LOG; | ||
334 | return mode & TOMOYO_CONFIG_WANT_REJECT_LOG; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * tomoyo_write_log2 - Write an audit log. | ||
339 | * | ||
340 | * @r: Pointer to "struct tomoyo_request_info". | ||
341 | * @len: Buffer size needed for @fmt and @args. | ||
342 | * @fmt: The printf()'s format string. | ||
343 | * @args: va_list structure for @fmt. | ||
344 | * | ||
345 | * Returns nothing. | ||
346 | */ | ||
347 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | ||
348 | va_list args) | ||
349 | { | ||
350 | char *buf; | ||
351 | struct tomoyo_log *entry; | ||
352 | bool quota_exceeded = false; | ||
353 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted)) | ||
354 | goto out; | ||
355 | buf = tomoyo_init_log(r, len, fmt, args); | ||
356 | if (!buf) | ||
357 | goto out; | ||
358 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | ||
359 | if (!entry) { | ||
360 | kfree(buf); | ||
361 | goto out; | ||
362 | } | ||
363 | entry->log = buf; | ||
364 | len = tomoyo_round2(strlen(buf) + 1); | ||
365 | /* | ||
366 | * The entry->size is used for memory quota checks. | ||
367 | * Don't go beyond strlen(entry->log). | ||
368 | */ | ||
369 | entry->size = len + tomoyo_round2(sizeof(*entry)); | ||
370 | spin_lock(&tomoyo_log_lock); | ||
371 | if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] && | ||
372 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >= | ||
373 | tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) { | ||
374 | quota_exceeded = true; | ||
375 | } else { | ||
376 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size; | ||
377 | list_add_tail(&entry->list, &tomoyo_log); | ||
378 | tomoyo_log_count++; | ||
379 | } | ||
380 | spin_unlock(&tomoyo_log_lock); | ||
381 | if (quota_exceeded) { | ||
382 | kfree(buf); | ||
383 | kfree(entry); | ||
384 | goto out; | ||
385 | } | ||
386 | wake_up(&tomoyo_log_wait); | ||
387 | out: | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * tomoyo_write_log - Write an audit log. | ||
393 | * | ||
394 | * @r: Pointer to "struct tomoyo_request_info". | ||
395 | * @fmt: The printf()'s format string, followed by parameters. | ||
396 | * | ||
397 | * Returns nothing. | ||
398 | */ | ||
399 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
400 | { | ||
401 | va_list args; | ||
402 | int len; | ||
403 | va_start(args, fmt); | ||
404 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | ||
405 | va_end(args); | ||
406 | va_start(args, fmt); | ||
407 | tomoyo_write_log2(r, len, fmt, args); | ||
408 | va_end(args); | ||
409 | } | ||
410 | |||
411 | /** | ||
412 | * tomoyo_read_log - Read an audit log. | ||
413 | * | ||
414 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
415 | * | ||
416 | * Returns nothing. | ||
417 | */ | ||
418 | void tomoyo_read_log(struct tomoyo_io_buffer *head) | ||
419 | { | ||
420 | struct tomoyo_log *ptr = NULL; | ||
421 | if (head->r.w_pos) | ||
422 | return; | ||
423 | kfree(head->read_buf); | ||
424 | head->read_buf = NULL; | ||
425 | spin_lock(&tomoyo_log_lock); | ||
426 | if (!list_empty(&tomoyo_log)) { | ||
427 | ptr = list_entry(tomoyo_log.next, typeof(*ptr), list); | ||
428 | list_del(&ptr->list); | ||
429 | tomoyo_log_count--; | ||
430 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size; | ||
431 | } | ||
432 | spin_unlock(&tomoyo_log_lock); | ||
433 | if (ptr) { | ||
434 | head->read_buf = ptr->log; | ||
435 | head->r.w[head->r.w_pos++] = head->read_buf; | ||
436 | kfree(ptr); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * tomoyo_poll_log - Wait for an audit log. | ||
442 | * | ||
443 | * @file: Pointer to "struct file". | ||
444 | * @wait: Pointer to "poll_table". | ||
445 | * | ||
446 | * Returns POLLIN | POLLRDNORM when ready to read an audit log. | ||
447 | */ | ||
448 | int tomoyo_poll_log(struct file *file, poll_table *wait) | ||
449 | { | ||
450 | if (tomoyo_log_count) | ||
451 | return POLLIN | POLLRDNORM; | ||
452 | poll_wait(file, &tomoyo_log_wait, wait); | ||
453 | if (tomoyo_log_count) | ||
454 | return POLLIN | POLLRDNORM; | ||
455 | return 0; | ||
456 | } | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index a0d09e56874b..c8439cf2a448 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/common.c | 2 | * security/tomoyo/common.c |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
@@ -11,54 +9,131 @@ | |||
11 | #include <linux/security.h> | 9 | #include <linux/security.h> |
12 | #include "common.h" | 10 | #include "common.h" |
13 | 11 | ||
14 | static struct tomoyo_profile tomoyo_default_profile = { | 12 | /* String table for operation mode. */ |
15 | .learning = &tomoyo_default_profile.preference, | 13 | const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { |
16 | .permissive = &tomoyo_default_profile.preference, | 14 | [TOMOYO_CONFIG_DISABLED] = "disabled", |
17 | .enforcing = &tomoyo_default_profile.preference, | 15 | [TOMOYO_CONFIG_LEARNING] = "learning", |
18 | .preference.enforcing_verbose = true, | 16 | [TOMOYO_CONFIG_PERMISSIVE] = "permissive", |
19 | .preference.learning_max_entry = 2048, | 17 | [TOMOYO_CONFIG_ENFORCING] = "enforcing" |
20 | .preference.learning_verbose = false, | ||
21 | .preference.permissive_verbose = true | ||
22 | }; | 18 | }; |
23 | 19 | ||
24 | /* Profile version. Currently only 20090903 is defined. */ | 20 | /* String table for /sys/kernel/security/tomoyo/profile */ |
25 | static unsigned int tomoyo_profile_version; | 21 | const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX |
22 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | ||
23 | [TOMOYO_MAC_FILE_EXECUTE] = "execute", | ||
24 | [TOMOYO_MAC_FILE_OPEN] = "open", | ||
25 | [TOMOYO_MAC_FILE_CREATE] = "create", | ||
26 | [TOMOYO_MAC_FILE_UNLINK] = "unlink", | ||
27 | [TOMOYO_MAC_FILE_GETATTR] = "getattr", | ||
28 | [TOMOYO_MAC_FILE_MKDIR] = "mkdir", | ||
29 | [TOMOYO_MAC_FILE_RMDIR] = "rmdir", | ||
30 | [TOMOYO_MAC_FILE_MKFIFO] = "mkfifo", | ||
31 | [TOMOYO_MAC_FILE_MKSOCK] = "mksock", | ||
32 | [TOMOYO_MAC_FILE_TRUNCATE] = "truncate", | ||
33 | [TOMOYO_MAC_FILE_SYMLINK] = "symlink", | ||
34 | [TOMOYO_MAC_FILE_MKBLOCK] = "mkblock", | ||
35 | [TOMOYO_MAC_FILE_MKCHAR] = "mkchar", | ||
36 | [TOMOYO_MAC_FILE_LINK] = "link", | ||
37 | [TOMOYO_MAC_FILE_RENAME] = "rename", | ||
38 | [TOMOYO_MAC_FILE_CHMOD] = "chmod", | ||
39 | [TOMOYO_MAC_FILE_CHOWN] = "chown", | ||
40 | [TOMOYO_MAC_FILE_CHGRP] = "chgrp", | ||
41 | [TOMOYO_MAC_FILE_IOCTL] = "ioctl", | ||
42 | [TOMOYO_MAC_FILE_CHROOT] = "chroot", | ||
43 | [TOMOYO_MAC_FILE_MOUNT] = "mount", | ||
44 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", | ||
45 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", | ||
46 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | ||
47 | }; | ||
26 | 48 | ||
27 | /* Profile table. Memory is allocated as needed. */ | 49 | /* String table for conditions. */ |
28 | static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; | 50 | const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = { |
51 | [TOMOYO_TASK_UID] = "task.uid", | ||
52 | [TOMOYO_TASK_EUID] = "task.euid", | ||
53 | [TOMOYO_TASK_SUID] = "task.suid", | ||
54 | [TOMOYO_TASK_FSUID] = "task.fsuid", | ||
55 | [TOMOYO_TASK_GID] = "task.gid", | ||
56 | [TOMOYO_TASK_EGID] = "task.egid", | ||
57 | [TOMOYO_TASK_SGID] = "task.sgid", | ||
58 | [TOMOYO_TASK_FSGID] = "task.fsgid", | ||
59 | [TOMOYO_TASK_PID] = "task.pid", | ||
60 | [TOMOYO_TASK_PPID] = "task.ppid", | ||
61 | [TOMOYO_EXEC_ARGC] = "exec.argc", | ||
62 | [TOMOYO_EXEC_ENVC] = "exec.envc", | ||
63 | [TOMOYO_TYPE_IS_SOCKET] = "socket", | ||
64 | [TOMOYO_TYPE_IS_SYMLINK] = "symlink", | ||
65 | [TOMOYO_TYPE_IS_FILE] = "file", | ||
66 | [TOMOYO_TYPE_IS_BLOCK_DEV] = "block", | ||
67 | [TOMOYO_TYPE_IS_DIRECTORY] = "directory", | ||
68 | [TOMOYO_TYPE_IS_CHAR_DEV] = "char", | ||
69 | [TOMOYO_TYPE_IS_FIFO] = "fifo", | ||
70 | [TOMOYO_MODE_SETUID] = "setuid", | ||
71 | [TOMOYO_MODE_SETGID] = "setgid", | ||
72 | [TOMOYO_MODE_STICKY] = "sticky", | ||
73 | [TOMOYO_MODE_OWNER_READ] = "owner_read", | ||
74 | [TOMOYO_MODE_OWNER_WRITE] = "owner_write", | ||
75 | [TOMOYO_MODE_OWNER_EXECUTE] = "owner_execute", | ||
76 | [TOMOYO_MODE_GROUP_READ] = "group_read", | ||
77 | [TOMOYO_MODE_GROUP_WRITE] = "group_write", | ||
78 | [TOMOYO_MODE_GROUP_EXECUTE] = "group_execute", | ||
79 | [TOMOYO_MODE_OTHERS_READ] = "others_read", | ||
80 | [TOMOYO_MODE_OTHERS_WRITE] = "others_write", | ||
81 | [TOMOYO_MODE_OTHERS_EXECUTE] = "others_execute", | ||
82 | [TOMOYO_EXEC_REALPATH] = "exec.realpath", | ||
83 | [TOMOYO_SYMLINK_TARGET] = "symlink.target", | ||
84 | [TOMOYO_PATH1_UID] = "path1.uid", | ||
85 | [TOMOYO_PATH1_GID] = "path1.gid", | ||
86 | [TOMOYO_PATH1_INO] = "path1.ino", | ||
87 | [TOMOYO_PATH1_MAJOR] = "path1.major", | ||
88 | [TOMOYO_PATH1_MINOR] = "path1.minor", | ||
89 | [TOMOYO_PATH1_PERM] = "path1.perm", | ||
90 | [TOMOYO_PATH1_TYPE] = "path1.type", | ||
91 | [TOMOYO_PATH1_DEV_MAJOR] = "path1.dev_major", | ||
92 | [TOMOYO_PATH1_DEV_MINOR] = "path1.dev_minor", | ||
93 | [TOMOYO_PATH2_UID] = "path2.uid", | ||
94 | [TOMOYO_PATH2_GID] = "path2.gid", | ||
95 | [TOMOYO_PATH2_INO] = "path2.ino", | ||
96 | [TOMOYO_PATH2_MAJOR] = "path2.major", | ||
97 | [TOMOYO_PATH2_MINOR] = "path2.minor", | ||
98 | [TOMOYO_PATH2_PERM] = "path2.perm", | ||
99 | [TOMOYO_PATH2_TYPE] = "path2.type", | ||
100 | [TOMOYO_PATH2_DEV_MAJOR] = "path2.dev_major", | ||
101 | [TOMOYO_PATH2_DEV_MINOR] = "path2.dev_minor", | ||
102 | [TOMOYO_PATH1_PARENT_UID] = "path1.parent.uid", | ||
103 | [TOMOYO_PATH1_PARENT_GID] = "path1.parent.gid", | ||
104 | [TOMOYO_PATH1_PARENT_INO] = "path1.parent.ino", | ||
105 | [TOMOYO_PATH1_PARENT_PERM] = "path1.parent.perm", | ||
106 | [TOMOYO_PATH2_PARENT_UID] = "path2.parent.uid", | ||
107 | [TOMOYO_PATH2_PARENT_GID] = "path2.parent.gid", | ||
108 | [TOMOYO_PATH2_PARENT_INO] = "path2.parent.ino", | ||
109 | [TOMOYO_PATH2_PARENT_PERM] = "path2.parent.perm", | ||
110 | }; | ||
29 | 111 | ||
30 | /* String table for functionality that takes 4 modes. */ | 112 | /* String table for PREFERENCE keyword. */ |
31 | static const char *tomoyo_mode[4] = { | 113 | static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = { |
32 | "disabled", "learning", "permissive", "enforcing" | 114 | [TOMOYO_PREF_MAX_AUDIT_LOG] = "max_audit_log", |
115 | [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry", | ||
33 | }; | 116 | }; |
34 | 117 | ||
35 | /* String table for /sys/kernel/security/tomoyo/profile */ | 118 | /* String table for path operation. */ |
36 | static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | 119 | const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
37 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 120 | [TOMOYO_TYPE_EXECUTE] = "execute", |
38 | [TOMOYO_MAC_FILE_EXECUTE] = "file::execute", | 121 | [TOMOYO_TYPE_READ] = "read", |
39 | [TOMOYO_MAC_FILE_OPEN] = "file::open", | 122 | [TOMOYO_TYPE_WRITE] = "write", |
40 | [TOMOYO_MAC_FILE_CREATE] = "file::create", | 123 | [TOMOYO_TYPE_APPEND] = "append", |
41 | [TOMOYO_MAC_FILE_UNLINK] = "file::unlink", | 124 | [TOMOYO_TYPE_UNLINK] = "unlink", |
42 | [TOMOYO_MAC_FILE_MKDIR] = "file::mkdir", | 125 | [TOMOYO_TYPE_GETATTR] = "getattr", |
43 | [TOMOYO_MAC_FILE_RMDIR] = "file::rmdir", | 126 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
44 | [TOMOYO_MAC_FILE_MKFIFO] = "file::mkfifo", | 127 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
45 | [TOMOYO_MAC_FILE_MKSOCK] = "file::mksock", | 128 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
46 | [TOMOYO_MAC_FILE_TRUNCATE] = "file::truncate", | 129 | [TOMOYO_TYPE_CHROOT] = "chroot", |
47 | [TOMOYO_MAC_FILE_SYMLINK] = "file::symlink", | 130 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
48 | [TOMOYO_MAC_FILE_REWRITE] = "file::rewrite", | 131 | }; |
49 | [TOMOYO_MAC_FILE_MKBLOCK] = "file::mkblock", | 132 | |
50 | [TOMOYO_MAC_FILE_MKCHAR] = "file::mkchar", | 133 | /* String table for categories. */ |
51 | [TOMOYO_MAC_FILE_LINK] = "file::link", | 134 | static const char * const tomoyo_category_keywords |
52 | [TOMOYO_MAC_FILE_RENAME] = "file::rename", | 135 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
53 | [TOMOYO_MAC_FILE_CHMOD] = "file::chmod", | 136 | [TOMOYO_MAC_CATEGORY_FILE] = "file", |
54 | [TOMOYO_MAC_FILE_CHOWN] = "file::chown", | ||
55 | [TOMOYO_MAC_FILE_CHGRP] = "file::chgrp", | ||
56 | [TOMOYO_MAC_FILE_IOCTL] = "file::ioctl", | ||
57 | [TOMOYO_MAC_FILE_CHROOT] = "file::chroot", | ||
58 | [TOMOYO_MAC_FILE_MOUNT] = "file::mount", | ||
59 | [TOMOYO_MAC_FILE_UMOUNT] = "file::umount", | ||
60 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root", | ||
61 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | ||
62 | }; | 137 | }; |
63 | 138 | ||
64 | /* Permit policy management by non-root user? */ | 139 | /* Permit policy management by non-root user? */ |
@@ -71,11 +146,20 @@ static bool tomoyo_manage_by_non_root; | |||
71 | * | 146 | * |
72 | * @value: Bool value. | 147 | * @value: Bool value. |
73 | */ | 148 | */ |
74 | static const char *tomoyo_yesno(const unsigned int value) | 149 | const char *tomoyo_yesno(const unsigned int value) |
75 | { | 150 | { |
76 | return value ? "yes" : "no"; | 151 | return value ? "yes" : "no"; |
77 | } | 152 | } |
78 | 153 | ||
154 | /** | ||
155 | * tomoyo_addprintf - strncat()-like-snprintf(). | ||
156 | * | ||
157 | * @buffer: Buffer to write to. Must be '\0'-terminated. | ||
158 | * @len: Size of @buffer. | ||
159 | * @fmt: The printf()'s format string, followed by parameters. | ||
160 | * | ||
161 | * Returns nothing. | ||
162 | */ | ||
79 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) | 163 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) |
80 | { | 164 | { |
81 | va_list args; | 165 | va_list args; |
@@ -96,7 +180,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head) | |||
96 | { | 180 | { |
97 | while (head->r.w_pos) { | 181 | while (head->r.w_pos) { |
98 | const char *w = head->r.w[0]; | 182 | const char *w = head->r.w[0]; |
99 | int len = strlen(w); | 183 | size_t len = strlen(w); |
100 | if (len) { | 184 | if (len) { |
101 | if (len > head->read_user_buf_avail) | 185 | if (len > head->read_user_buf_avail) |
102 | len = head->read_user_buf_avail; | 186 | len = head->read_user_buf_avail; |
@@ -111,7 +195,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head) | |||
111 | head->r.w[0] = w; | 195 | head->r.w[0] = w; |
112 | if (*w) | 196 | if (*w) |
113 | return false; | 197 | return false; |
114 | /* Add '\0' for query. */ | 198 | /* Add '\0' for audit logs and query. */ |
115 | if (head->poll) { | 199 | if (head->poll) { |
116 | if (!head->read_user_buf_avail || | 200 | if (!head->read_user_buf_avail || |
117 | copy_to_user(head->read_user_buf, "", 1)) | 201 | copy_to_user(head->read_user_buf, "", 1)) |
@@ -155,8 +239,8 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) | |||
155 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 239 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
156 | { | 240 | { |
157 | va_list args; | 241 | va_list args; |
158 | int len; | 242 | size_t len; |
159 | int pos = head->r.avail; | 243 | size_t pos = head->r.avail; |
160 | int size = head->readbuf_size - pos; | 244 | int size = head->readbuf_size - pos; |
161 | if (size <= 0) | 245 | if (size <= 0) |
162 | return; | 246 | return; |
@@ -171,11 +255,25 @@ void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | |||
171 | tomoyo_set_string(head, head->read_buf + pos); | 255 | tomoyo_set_string(head, head->read_buf + pos); |
172 | } | 256 | } |
173 | 257 | ||
258 | /** | ||
259 | * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure. | ||
260 | * | ||
261 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
262 | * | ||
263 | * Returns nothing. | ||
264 | */ | ||
174 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) | 265 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) |
175 | { | 266 | { |
176 | tomoyo_set_string(head, " "); | 267 | tomoyo_set_string(head, " "); |
177 | } | 268 | } |
178 | 269 | ||
270 | /** | ||
271 | * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure. | ||
272 | * | ||
273 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
274 | * | ||
275 | * Returns nothing. | ||
276 | */ | ||
179 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) | 277 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) |
180 | { | 278 | { |
181 | tomoyo_set_string(head, "\n"); | 279 | tomoyo_set_string(head, "\n"); |
@@ -183,6 +281,62 @@ static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) | |||
183 | } | 281 | } |
184 | 282 | ||
185 | /** | 283 | /** |
284 | * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure. | ||
285 | * | ||
286 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
287 | * | ||
288 | * Returns nothing. | ||
289 | */ | ||
290 | static void tomoyo_set_slash(struct tomoyo_io_buffer *head) | ||
291 | { | ||
292 | tomoyo_set_string(head, "/"); | ||
293 | } | ||
294 | |||
295 | /* List of namespaces. */ | ||
296 | LIST_HEAD(tomoyo_namespace_list); | ||
297 | /* True if namespace other than tomoyo_kernel_namespace is defined. */ | ||
298 | static bool tomoyo_namespace_enabled; | ||
299 | |||
300 | /** | ||
301 | * tomoyo_init_policy_namespace - Initialize namespace. | ||
302 | * | ||
303 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
304 | * | ||
305 | * Returns nothing. | ||
306 | */ | ||
307 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) | ||
308 | { | ||
309 | unsigned int idx; | ||
310 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) | ||
311 | INIT_LIST_HEAD(&ns->acl_group[idx]); | ||
312 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | ||
313 | INIT_LIST_HEAD(&ns->group_list[idx]); | ||
314 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | ||
315 | INIT_LIST_HEAD(&ns->policy_list[idx]); | ||
316 | ns->profile_version = 20100903; | ||
317 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); | ||
318 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * tomoyo_print_namespace - Print namespace header. | ||
323 | * | ||
324 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
325 | * | ||
326 | * Returns nothing. | ||
327 | */ | ||
328 | static void tomoyo_print_namespace(struct tomoyo_io_buffer *head) | ||
329 | { | ||
330 | if (!tomoyo_namespace_enabled) | ||
331 | return; | ||
332 | tomoyo_set_string(head, | ||
333 | container_of(head->r.ns, | ||
334 | struct tomoyo_policy_namespace, | ||
335 | namespace_list)->name); | ||
336 | tomoyo_set_space(head); | ||
337 | } | ||
338 | |||
339 | /** | ||
186 | * tomoyo_print_name_union - Print a tomoyo_name_union. | 340 | * tomoyo_print_name_union - Print a tomoyo_name_union. |
187 | * | 341 | * |
188 | * @head: Pointer to "struct tomoyo_io_buffer". | 342 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -192,7 +346,7 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, | |||
192 | const struct tomoyo_name_union *ptr) | 346 | const struct tomoyo_name_union *ptr) |
193 | { | 347 | { |
194 | tomoyo_set_space(head); | 348 | tomoyo_set_space(head); |
195 | if (ptr->is_group) { | 349 | if (ptr->group) { |
196 | tomoyo_set_string(head, "@"); | 350 | tomoyo_set_string(head, "@"); |
197 | tomoyo_set_string(head, ptr->group->group_name->name); | 351 | tomoyo_set_string(head, ptr->group->group_name->name); |
198 | } else { | 352 | } else { |
@@ -201,24 +355,46 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, | |||
201 | } | 355 | } |
202 | 356 | ||
203 | /** | 357 | /** |
204 | * tomoyo_print_number_union - Print a tomoyo_number_union. | 358 | * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote. |
205 | * | 359 | * |
206 | * @head: Pointer to "struct tomoyo_io_buffer". | 360 | * @head: Pointer to "struct tomoyo_io_buffer". |
207 | * @ptr: Pointer to "struct tomoyo_number_union". | 361 | * @ptr: Pointer to "struct tomoyo_name_union". |
362 | * | ||
363 | * Returns nothing. | ||
208 | */ | 364 | */ |
209 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | 365 | static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head, |
210 | const struct tomoyo_number_union *ptr) | 366 | const struct tomoyo_name_union *ptr) |
211 | { | 367 | { |
212 | tomoyo_set_space(head); | 368 | if (ptr->group) { |
213 | if (ptr->is_group) { | 369 | tomoyo_set_string(head, "@"); |
370 | tomoyo_set_string(head, ptr->group->group_name->name); | ||
371 | } else { | ||
372 | tomoyo_set_string(head, "\""); | ||
373 | tomoyo_set_string(head, ptr->filename->name); | ||
374 | tomoyo_set_string(head, "\""); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space. | ||
380 | * | ||
381 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
382 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
383 | * | ||
384 | * Returns nothing. | ||
385 | */ | ||
386 | static void tomoyo_print_number_union_nospace | ||
387 | (struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) | ||
388 | { | ||
389 | if (ptr->group) { | ||
214 | tomoyo_set_string(head, "@"); | 390 | tomoyo_set_string(head, "@"); |
215 | tomoyo_set_string(head, ptr->group->group_name->name); | 391 | tomoyo_set_string(head, ptr->group->group_name->name); |
216 | } else { | 392 | } else { |
217 | int i; | 393 | int i; |
218 | unsigned long min = ptr->values[0]; | 394 | unsigned long min = ptr->values[0]; |
219 | const unsigned long max = ptr->values[1]; | 395 | const unsigned long max = ptr->values[1]; |
220 | u8 min_type = ptr->min_type; | 396 | u8 min_type = ptr->value_type[0]; |
221 | const u8 max_type = ptr->max_type; | 397 | const u8 max_type = ptr->value_type[1]; |
222 | char buffer[128]; | 398 | char buffer[128]; |
223 | buffer[0] = '\0'; | 399 | buffer[0] = '\0'; |
224 | for (i = 0; i < 2; i++) { | 400 | for (i = 0; i < 2; i++) { |
@@ -232,8 +408,8 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
232 | "0%lo", min); | 408 | "0%lo", min); |
233 | break; | 409 | break; |
234 | default: | 410 | default: |
235 | tomoyo_addprintf(buffer, sizeof(buffer), | 411 | tomoyo_addprintf(buffer, sizeof(buffer), "%lu", |
236 | "%lu", min); | 412 | min); |
237 | break; | 413 | break; |
238 | } | 414 | } |
239 | if (min == max && min_type == max_type) | 415 | if (min == max && min_type == max_type) |
@@ -247,35 +423,53 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
247 | } | 423 | } |
248 | 424 | ||
249 | /** | 425 | /** |
426 | * tomoyo_print_number_union - Print a tomoyo_number_union. | ||
427 | * | ||
428 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
429 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
430 | * | ||
431 | * Returns nothing. | ||
432 | */ | ||
433 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | ||
434 | const struct tomoyo_number_union *ptr) | ||
435 | { | ||
436 | tomoyo_set_space(head); | ||
437 | tomoyo_print_number_union_nospace(head, ptr); | ||
438 | } | ||
439 | |||
440 | /** | ||
250 | * tomoyo_assign_profile - Create a new profile. | 441 | * tomoyo_assign_profile - Create a new profile. |
251 | * | 442 | * |
443 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
252 | * @profile: Profile number to create. | 444 | * @profile: Profile number to create. |
253 | * | 445 | * |
254 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. | 446 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. |
255 | */ | 447 | */ |
256 | static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | 448 | static struct tomoyo_profile *tomoyo_assign_profile |
449 | (struct tomoyo_policy_namespace *ns, const unsigned int profile) | ||
257 | { | 450 | { |
258 | struct tomoyo_profile *ptr; | 451 | struct tomoyo_profile *ptr; |
259 | struct tomoyo_profile *entry; | 452 | struct tomoyo_profile *entry; |
260 | if (profile >= TOMOYO_MAX_PROFILES) | 453 | if (profile >= TOMOYO_MAX_PROFILES) |
261 | return NULL; | 454 | return NULL; |
262 | ptr = tomoyo_profile_ptr[profile]; | 455 | ptr = ns->profile_ptr[profile]; |
263 | if (ptr) | 456 | if (ptr) |
264 | return ptr; | 457 | return ptr; |
265 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 458 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
266 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 459 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
267 | goto out; | 460 | goto out; |
268 | ptr = tomoyo_profile_ptr[profile]; | 461 | ptr = ns->profile_ptr[profile]; |
269 | if (!ptr && tomoyo_memory_ok(entry)) { | 462 | if (!ptr && tomoyo_memory_ok(entry)) { |
270 | ptr = entry; | 463 | ptr = entry; |
271 | ptr->learning = &tomoyo_default_profile.preference; | 464 | ptr->default_config = TOMOYO_CONFIG_DISABLED | |
272 | ptr->permissive = &tomoyo_default_profile.preference; | 465 | TOMOYO_CONFIG_WANT_GRANT_LOG | |
273 | ptr->enforcing = &tomoyo_default_profile.preference; | 466 | TOMOYO_CONFIG_WANT_REJECT_LOG; |
274 | ptr->default_config = TOMOYO_CONFIG_DISABLED; | ||
275 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, | 467 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, |
276 | sizeof(ptr->config)); | 468 | sizeof(ptr->config)); |
469 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; | ||
470 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; | ||
277 | mb(); /* Avoid out-of-order execution. */ | 471 | mb(); /* Avoid out-of-order execution. */ |
278 | tomoyo_profile_ptr[profile] = ptr; | 472 | ns->profile_ptr[profile] = ptr; |
279 | entry = NULL; | 473 | entry = NULL; |
280 | } | 474 | } |
281 | mutex_unlock(&tomoyo_policy_lock); | 475 | mutex_unlock(&tomoyo_policy_lock); |
@@ -287,19 +481,29 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | |||
287 | /** | 481 | /** |
288 | * tomoyo_profile - Find a profile. | 482 | * tomoyo_profile - Find a profile. |
289 | * | 483 | * |
484 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
290 | * @profile: Profile number to find. | 485 | * @profile: Profile number to find. |
291 | * | 486 | * |
292 | * Returns pointer to "struct tomoyo_profile". | 487 | * Returns pointer to "struct tomoyo_profile". |
293 | */ | 488 | */ |
294 | struct tomoyo_profile *tomoyo_profile(const u8 profile) | 489 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, |
490 | const u8 profile) | ||
295 | { | 491 | { |
296 | struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; | 492 | static struct tomoyo_profile tomoyo_null_profile; |
297 | if (!tomoyo_policy_loaded) | 493 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; |
298 | return &tomoyo_default_profile; | 494 | if (!ptr) |
299 | BUG_ON(!ptr); | 495 | ptr = &tomoyo_null_profile; |
300 | return ptr; | 496 | return ptr; |
301 | } | 497 | } |
302 | 498 | ||
499 | /** | ||
500 | * tomoyo_find_yesno - Find values for specified keyword. | ||
501 | * | ||
502 | * @string: String to check. | ||
503 | * @find: Name of keyword. | ||
504 | * | ||
505 | * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise. | ||
506 | */ | ||
303 | static s8 tomoyo_find_yesno(const char *string, const char *find) | 507 | static s8 tomoyo_find_yesno(const char *string, const char *find) |
304 | { | 508 | { |
305 | const char *cp = strstr(string, find); | 509 | const char *cp = strstr(string, find); |
@@ -313,18 +517,15 @@ static s8 tomoyo_find_yesno(const char *string, const char *find) | |||
313 | return -1; | 517 | return -1; |
314 | } | 518 | } |
315 | 519 | ||
316 | static void tomoyo_set_bool(bool *b, const char *string, const char *find) | 520 | /** |
317 | { | 521 | * tomoyo_set_uint - Set value for specified preference. |
318 | switch (tomoyo_find_yesno(string, find)) { | 522 | * |
319 | case 1: | 523 | * @i: Pointer to "unsigned int". |
320 | *b = true; | 524 | * @string: String to check. |
321 | break; | 525 | * @find: Name of keyword. |
322 | case 0: | 526 | * |
323 | *b = false; | 527 | * Returns nothing. |
324 | break; | 528 | */ |
325 | } | ||
326 | } | ||
327 | |||
328 | static void tomoyo_set_uint(unsigned int *i, const char *string, | 529 | static void tomoyo_set_uint(unsigned int *i, const char *string, |
329 | const char *find) | 530 | const char *find) |
330 | { | 531 | { |
@@ -333,51 +534,16 @@ static void tomoyo_set_uint(unsigned int *i, const char *string, | |||
333 | sscanf(cp + strlen(find), "=%u", i); | 534 | sscanf(cp + strlen(find), "=%u", i); |
334 | } | 535 | } |
335 | 536 | ||
336 | static void tomoyo_set_pref(const char *name, const char *value, | 537 | /** |
337 | const bool use_default, | 538 | * tomoyo_set_mode - Set mode for specified profile. |
338 | struct tomoyo_profile *profile) | 539 | * |
339 | { | 540 | * @name: Name of functionality. |
340 | struct tomoyo_preference **pref; | 541 | * @value: Mode for @name. |
341 | bool *verbose; | 542 | * @profile: Pointer to "struct tomoyo_profile". |
342 | if (!strcmp(name, "enforcing")) { | 543 | * |
343 | if (use_default) { | 544 | * Returns 0 on success, negative value otherwise. |
344 | pref = &profile->enforcing; | 545 | */ |
345 | goto set_default; | ||
346 | } | ||
347 | profile->enforcing = &profile->preference; | ||
348 | verbose = &profile->preference.enforcing_verbose; | ||
349 | goto set_verbose; | ||
350 | } | ||
351 | if (!strcmp(name, "permissive")) { | ||
352 | if (use_default) { | ||
353 | pref = &profile->permissive; | ||
354 | goto set_default; | ||
355 | } | ||
356 | profile->permissive = &profile->preference; | ||
357 | verbose = &profile->preference.permissive_verbose; | ||
358 | goto set_verbose; | ||
359 | } | ||
360 | if (!strcmp(name, "learning")) { | ||
361 | if (use_default) { | ||
362 | pref = &profile->learning; | ||
363 | goto set_default; | ||
364 | } | ||
365 | profile->learning = &profile->preference; | ||
366 | tomoyo_set_uint(&profile->preference.learning_max_entry, value, | ||
367 | "max_entry"); | ||
368 | verbose = &profile->preference.learning_verbose; | ||
369 | goto set_verbose; | ||
370 | } | ||
371 | return; | ||
372 | set_default: | ||
373 | *pref = &tomoyo_default_profile.preference; | ||
374 | return; | ||
375 | set_verbose: | ||
376 | tomoyo_set_bool(verbose, value, "verbose"); | ||
377 | } | ||
378 | |||
379 | static int tomoyo_set_mode(char *name, const char *value, | 546 | static int tomoyo_set_mode(char *name, const char *value, |
380 | const bool use_default, | ||
381 | struct tomoyo_profile *profile) | 547 | struct tomoyo_profile *profile) |
382 | { | 548 | { |
383 | u8 i; | 549 | u8 i; |
@@ -389,7 +555,17 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
389 | config = 0; | 555 | config = 0; |
390 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX | 556 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX |
391 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { | 557 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { |
392 | if (strcmp(name, tomoyo_mac_keywords[i])) | 558 | int len = 0; |
559 | if (i < TOMOYO_MAX_MAC_INDEX) { | ||
560 | const u8 c = tomoyo_index2category[i]; | ||
561 | const char *category = | ||
562 | tomoyo_category_keywords[c]; | ||
563 | len = strlen(category); | ||
564 | if (strncmp(name, category, len) || | ||
565 | name[len++] != ':' || name[len++] != ':') | ||
566 | continue; | ||
567 | } | ||
568 | if (strcmp(name + len, tomoyo_mac_keywords[i])) | ||
393 | continue; | 569 | continue; |
394 | config = profile->config[i]; | 570 | config = profile->config[i]; |
395 | break; | 571 | break; |
@@ -399,7 +575,7 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
399 | } else { | 575 | } else { |
400 | return -EINVAL; | 576 | return -EINVAL; |
401 | } | 577 | } |
402 | if (use_default) { | 578 | if (strstr(value, "use_default")) { |
403 | config = TOMOYO_CONFIG_USE_DEFAULT; | 579 | config = TOMOYO_CONFIG_USE_DEFAULT; |
404 | } else { | 580 | } else { |
405 | u8 mode; | 581 | u8 mode; |
@@ -410,6 +586,24 @@ static int tomoyo_set_mode(char *name, const char *value, | |||
410 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. | 586 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. |
411 | */ | 587 | */ |
412 | config = (config & ~7) | mode; | 588 | config = (config & ~7) | mode; |
589 | if (config != TOMOYO_CONFIG_USE_DEFAULT) { | ||
590 | switch (tomoyo_find_yesno(value, "grant_log")) { | ||
591 | case 1: | ||
592 | config |= TOMOYO_CONFIG_WANT_GRANT_LOG; | ||
593 | break; | ||
594 | case 0: | ||
595 | config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG; | ||
596 | break; | ||
597 | } | ||
598 | switch (tomoyo_find_yesno(value, "reject_log")) { | ||
599 | case 1: | ||
600 | config |= TOMOYO_CONFIG_WANT_REJECT_LOG; | ||
601 | break; | ||
602 | case 0: | ||
603 | config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG; | ||
604 | break; | ||
605 | } | ||
606 | } | ||
413 | } | 607 | } |
414 | if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) | 608 | if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) |
415 | profile->config[i] = config; | 609 | profile->config[i] = config; |
@@ -429,34 +623,22 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
429 | { | 623 | { |
430 | char *data = head->write_buf; | 624 | char *data = head->write_buf; |
431 | unsigned int i; | 625 | unsigned int i; |
432 | bool use_default = false; | ||
433 | char *cp; | 626 | char *cp; |
434 | struct tomoyo_profile *profile; | 627 | struct tomoyo_profile *profile; |
435 | if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) | 628 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) |
629 | == 1) | ||
436 | return 0; | 630 | return 0; |
437 | i = simple_strtoul(data, &cp, 10); | 631 | i = simple_strtoul(data, &cp, 10); |
438 | if (data == cp) { | 632 | if (*cp != '-') |
439 | profile = &tomoyo_default_profile; | 633 | return -EINVAL; |
440 | } else { | 634 | data = cp + 1; |
441 | if (*cp != '-') | 635 | profile = tomoyo_assign_profile(head->w.ns, i); |
442 | return -EINVAL; | 636 | if (!profile) |
443 | data = cp + 1; | 637 | return -EINVAL; |
444 | profile = tomoyo_assign_profile(i); | ||
445 | if (!profile) | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | cp = strchr(data, '='); | 638 | cp = strchr(data, '='); |
449 | if (!cp) | 639 | if (!cp) |
450 | return -EINVAL; | 640 | return -EINVAL; |
451 | *cp++ = '\0'; | 641 | *cp++ = '\0'; |
452 | if (profile != &tomoyo_default_profile) | ||
453 | use_default = strstr(cp, "use_default") != NULL; | ||
454 | if (tomoyo_str_starts(&data, "PREFERENCE::")) { | ||
455 | tomoyo_set_pref(data, cp, use_default, profile); | ||
456 | return 0; | ||
457 | } | ||
458 | if (profile == &tomoyo_default_profile) | ||
459 | return -EINVAL; | ||
460 | if (!strcmp(data, "COMMENT")) { | 642 | if (!strcmp(data, "COMMENT")) { |
461 | static DEFINE_SPINLOCK(lock); | 643 | static DEFINE_SPINLOCK(lock); |
462 | const struct tomoyo_path_info *new_comment | 644 | const struct tomoyo_path_info *new_comment |
@@ -471,77 +653,62 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
471 | tomoyo_put_name(old_comment); | 653 | tomoyo_put_name(old_comment); |
472 | return 0; | 654 | return 0; |
473 | } | 655 | } |
474 | return tomoyo_set_mode(data, cp, use_default, profile); | 656 | if (!strcmp(data, "PREFERENCE")) { |
475 | } | 657 | for (i = 0; i < TOMOYO_MAX_PREF; i++) |
476 | 658 | tomoyo_set_uint(&profile->pref[i], cp, | |
477 | static void tomoyo_print_preference(struct tomoyo_io_buffer *head, | 659 | tomoyo_pref_keywords[i]); |
478 | const int idx) | 660 | return 0; |
479 | { | ||
480 | struct tomoyo_preference *pref = &tomoyo_default_profile.preference; | ||
481 | const struct tomoyo_profile *profile = idx >= 0 ? | ||
482 | tomoyo_profile_ptr[idx] : NULL; | ||
483 | char buffer[16] = ""; | ||
484 | if (profile) { | ||
485 | buffer[sizeof(buffer) - 1] = '\0'; | ||
486 | snprintf(buffer, sizeof(buffer) - 1, "%u-", idx); | ||
487 | } | ||
488 | if (profile) { | ||
489 | pref = profile->learning; | ||
490 | if (pref == &tomoyo_default_profile.preference) | ||
491 | goto skip1; | ||
492 | } | ||
493 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ " | ||
494 | "verbose=%s max_entry=%u }\n", | ||
495 | buffer, "learning", | ||
496 | tomoyo_yesno(pref->learning_verbose), | ||
497 | pref->learning_max_entry); | ||
498 | skip1: | ||
499 | if (profile) { | ||
500 | pref = profile->permissive; | ||
501 | if (pref == &tomoyo_default_profile.preference) | ||
502 | goto skip2; | ||
503 | } | ||
504 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | ||
505 | buffer, "permissive", | ||
506 | tomoyo_yesno(pref->permissive_verbose)); | ||
507 | skip2: | ||
508 | if (profile) { | ||
509 | pref = profile->enforcing; | ||
510 | if (pref == &tomoyo_default_profile.preference) | ||
511 | return; | ||
512 | } | 661 | } |
513 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | 662 | return tomoyo_set_mode(data, cp, profile); |
514 | buffer, "enforcing", | ||
515 | tomoyo_yesno(pref->enforcing_verbose)); | ||
516 | } | 663 | } |
517 | 664 | ||
665 | /** | ||
666 | * tomoyo_print_config - Print mode for specified functionality. | ||
667 | * | ||
668 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
669 | * @config: Mode for that functionality. | ||
670 | * | ||
671 | * Returns nothing. | ||
672 | * | ||
673 | * Caller prints functionality's name. | ||
674 | */ | ||
518 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) | 675 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) |
519 | { | 676 | { |
520 | tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]); | 677 | tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n", |
678 | tomoyo_mode[config & 3], | ||
679 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG), | ||
680 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG)); | ||
521 | } | 681 | } |
522 | 682 | ||
523 | /** | 683 | /** |
524 | * tomoyo_read_profile - Read profile table. | 684 | * tomoyo_read_profile - Read profile table. |
525 | * | 685 | * |
526 | * @head: Pointer to "struct tomoyo_io_buffer". | 686 | * @head: Pointer to "struct tomoyo_io_buffer". |
687 | * | ||
688 | * Returns nothing. | ||
527 | */ | 689 | */ |
528 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | 690 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) |
529 | { | 691 | { |
530 | u8 index; | 692 | u8 index; |
693 | struct tomoyo_policy_namespace *ns = | ||
694 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
531 | const struct tomoyo_profile *profile; | 695 | const struct tomoyo_profile *profile; |
696 | if (head->r.eof) | ||
697 | return; | ||
532 | next: | 698 | next: |
533 | index = head->r.index; | 699 | index = head->r.index; |
534 | profile = tomoyo_profile_ptr[index]; | 700 | profile = ns->profile_ptr[index]; |
535 | switch (head->r.step) { | 701 | switch (head->r.step) { |
536 | case 0: | 702 | case 0: |
537 | tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); | 703 | tomoyo_print_namespace(head); |
538 | tomoyo_print_preference(head, -1); | 704 | tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", |
705 | ns->profile_version); | ||
539 | head->r.step++; | 706 | head->r.step++; |
540 | break; | 707 | break; |
541 | case 1: | 708 | case 1: |
542 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; | 709 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; |
543 | head->r.index++) | 710 | head->r.index++) |
544 | if (tomoyo_profile_ptr[head->r.index]) | 711 | if (ns->profile_ptr[head->r.index]) |
545 | break; | 712 | break; |
546 | if (head->r.index == TOMOYO_MAX_PROFILES) | 713 | if (head->r.index == TOMOYO_MAX_PROFILES) |
547 | return; | 714 | return; |
@@ -549,16 +716,25 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
549 | break; | 716 | break; |
550 | case 2: | 717 | case 2: |
551 | { | 718 | { |
719 | u8 i; | ||
552 | const struct tomoyo_path_info *comment = | 720 | const struct tomoyo_path_info *comment = |
553 | profile->comment; | 721 | profile->comment; |
722 | tomoyo_print_namespace(head); | ||
554 | tomoyo_io_printf(head, "%u-COMMENT=", index); | 723 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
555 | tomoyo_set_string(head, comment ? comment->name : ""); | 724 | tomoyo_set_string(head, comment ? comment->name : ""); |
556 | tomoyo_set_lf(head); | 725 | tomoyo_set_lf(head); |
726 | tomoyo_io_printf(head, "%u-PREFERENCE={ ", index); | ||
727 | for (i = 0; i < TOMOYO_MAX_PREF; i++) | ||
728 | tomoyo_io_printf(head, "%s=%u ", | ||
729 | tomoyo_pref_keywords[i], | ||
730 | profile->pref[i]); | ||
731 | tomoyo_set_string(head, "}\n"); | ||
557 | head->r.step++; | 732 | head->r.step++; |
558 | } | 733 | } |
559 | break; | 734 | break; |
560 | case 3: | 735 | case 3: |
561 | { | 736 | { |
737 | tomoyo_print_namespace(head); | ||
562 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); | 738 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); |
563 | tomoyo_print_config(head, profile->default_config); | 739 | tomoyo_print_config(head, profile->default_config); |
564 | head->r.bit = 0; | 740 | head->r.bit = 0; |
@@ -572,15 +748,22 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
572 | const u8 config = profile->config[i]; | 748 | const u8 config = profile->config[i]; |
573 | if (config == TOMOYO_CONFIG_USE_DEFAULT) | 749 | if (config == TOMOYO_CONFIG_USE_DEFAULT) |
574 | continue; | 750 | continue; |
575 | tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::", | 751 | tomoyo_print_namespace(head); |
576 | tomoyo_mac_keywords[i]); | 752 | if (i < TOMOYO_MAX_MAC_INDEX) |
753 | tomoyo_io_printf(head, "%u-CONFIG::%s::%s", | ||
754 | index, | ||
755 | tomoyo_category_keywords | ||
756 | [tomoyo_index2category[i]], | ||
757 | tomoyo_mac_keywords[i]); | ||
758 | else | ||
759 | tomoyo_io_printf(head, "%u-CONFIG::%s", index, | ||
760 | tomoyo_mac_keywords[i]); | ||
577 | tomoyo_print_config(head, config); | 761 | tomoyo_print_config(head, config); |
578 | head->r.bit++; | 762 | head->r.bit++; |
579 | break; | 763 | break; |
580 | } | 764 | } |
581 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX | 765 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX |
582 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { | 766 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { |
583 | tomoyo_print_preference(head, index); | ||
584 | head->r.index++; | 767 | head->r.index++; |
585 | head->r.step = 1; | 768 | head->r.step = 1; |
586 | } | 769 | } |
@@ -590,6 +773,14 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
590 | goto next; | 773 | goto next; |
591 | } | 774 | } |
592 | 775 | ||
776 | /** | ||
777 | * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry. | ||
778 | * | ||
779 | * @a: Pointer to "struct tomoyo_acl_head". | ||
780 | * @b: Pointer to "struct tomoyo_acl_head". | ||
781 | * | ||
782 | * Returns true if @a == @b, false otherwise. | ||
783 | */ | ||
593 | static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, | 784 | static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, |
594 | const struct tomoyo_acl_head *b) | 785 | const struct tomoyo_acl_head *b) |
595 | { | 786 | { |
@@ -611,8 +802,13 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
611 | const bool is_delete) | 802 | const bool is_delete) |
612 | { | 803 | { |
613 | struct tomoyo_manager e = { }; | 804 | struct tomoyo_manager e = { }; |
614 | int error; | 805 | struct tomoyo_acl_param param = { |
615 | 806 | /* .ns = &tomoyo_kernel_namespace, */ | |
807 | .is_delete = is_delete, | ||
808 | .list = &tomoyo_kernel_namespace. | ||
809 | policy_list[TOMOYO_ID_MANAGER], | ||
810 | }; | ||
811 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
616 | if (tomoyo_domain_def(manager)) { | 812 | if (tomoyo_domain_def(manager)) { |
617 | if (!tomoyo_correct_domain(manager)) | 813 | if (!tomoyo_correct_domain(manager)) |
618 | return -EINVAL; | 814 | return -EINVAL; |
@@ -622,12 +818,11 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
622 | return -EINVAL; | 818 | return -EINVAL; |
623 | } | 819 | } |
624 | e.manager = tomoyo_get_name(manager); | 820 | e.manager = tomoyo_get_name(manager); |
625 | if (!e.manager) | 821 | if (e.manager) { |
626 | return -ENOMEM; | 822 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, |
627 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 823 | tomoyo_same_manager); |
628 | &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 824 | tomoyo_put_name(e.manager); |
629 | tomoyo_same_manager); | 825 | } |
630 | tomoyo_put_name(e.manager); | ||
631 | return error; | 826 | return error; |
632 | } | 827 | } |
633 | 828 | ||
@@ -643,13 +838,12 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
643 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) | 838 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) |
644 | { | 839 | { |
645 | char *data = head->write_buf; | 840 | char *data = head->write_buf; |
646 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | ||
647 | 841 | ||
648 | if (!strcmp(data, "manage_by_non_root")) { | 842 | if (!strcmp(data, "manage_by_non_root")) { |
649 | tomoyo_manage_by_non_root = !is_delete; | 843 | tomoyo_manage_by_non_root = !head->w.is_delete; |
650 | return 0; | 844 | return 0; |
651 | } | 845 | } |
652 | return tomoyo_update_manager_entry(data, is_delete); | 846 | return tomoyo_update_manager_entry(data, head->w.is_delete); |
653 | } | 847 | } |
654 | 848 | ||
655 | /** | 849 | /** |
@@ -663,8 +857,8 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head) | |||
663 | { | 857 | { |
664 | if (head->r.eof) | 858 | if (head->r.eof) |
665 | return; | 859 | return; |
666 | list_for_each_cookie(head->r.acl, | 860 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace. |
667 | &tomoyo_policy_list[TOMOYO_ID_MANAGER]) { | 861 | policy_list[TOMOYO_ID_MANAGER]) { |
668 | struct tomoyo_manager *ptr = | 862 | struct tomoyo_manager *ptr = |
669 | list_entry(head->r.acl, typeof(*ptr), head.list); | 863 | list_entry(head->r.acl, typeof(*ptr), head.list); |
670 | if (ptr->head.is_deleted) | 864 | if (ptr->head.is_deleted) |
@@ -697,8 +891,8 @@ static bool tomoyo_manager(void) | |||
697 | return true; | 891 | return true; |
698 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 892 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
699 | return false; | 893 | return false; |
700 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 894 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
701 | head.list) { | 895 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
702 | if (!ptr->head.is_deleted && ptr->is_domain | 896 | if (!ptr->head.is_deleted && ptr->is_domain |
703 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 897 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
704 | found = true; | 898 | found = true; |
@@ -710,8 +904,8 @@ static bool tomoyo_manager(void) | |||
710 | exe = tomoyo_get_exe(); | 904 | exe = tomoyo_get_exe(); |
711 | if (!exe) | 905 | if (!exe) |
712 | return false; | 906 | return false; |
713 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 907 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
714 | head.list) { | 908 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
715 | if (!ptr->head.is_deleted && !ptr->is_domain | 909 | if (!ptr->head.is_deleted && !ptr->is_domain |
716 | && !strcmp(exe, ptr->manager->name)) { | 910 | && !strcmp(exe, ptr->manager->name)) { |
717 | found = true; | 911 | found = true; |
@@ -732,7 +926,7 @@ static bool tomoyo_manager(void) | |||
732 | } | 926 | } |
733 | 927 | ||
734 | /** | 928 | /** |
735 | * tomoyo_select_one - Parse select command. | 929 | * tomoyo_select_domain - Parse select command. |
736 | * | 930 | * |
737 | * @head: Pointer to "struct tomoyo_io_buffer". | 931 | * @head: Pointer to "struct tomoyo_io_buffer". |
738 | * @data: String to parse. | 932 | * @data: String to parse. |
@@ -741,16 +935,15 @@ static bool tomoyo_manager(void) | |||
741 | * | 935 | * |
742 | * Caller holds tomoyo_read_lock(). | 936 | * Caller holds tomoyo_read_lock(). |
743 | */ | 937 | */ |
744 | static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | 938 | static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, |
939 | const char *data) | ||
745 | { | 940 | { |
746 | unsigned int pid; | 941 | unsigned int pid; |
747 | struct tomoyo_domain_info *domain = NULL; | 942 | struct tomoyo_domain_info *domain = NULL; |
748 | bool global_pid = false; | 943 | bool global_pid = false; |
749 | 944 | if (strncmp(data, "select ", 7)) | |
750 | if (!strcmp(data, "allow_execute")) { | 945 | return false; |
751 | head->r.print_execute_only = true; | 946 | data += 7; |
752 | return true; | ||
753 | } | ||
754 | if (sscanf(data, "pid=%u", &pid) == 1 || | 947 | if (sscanf(data, "pid=%u", &pid) == 1 || |
755 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { | 948 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { |
756 | struct task_struct *p; | 949 | struct task_struct *p; |
@@ -769,7 +962,7 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | |||
769 | domain = tomoyo_find_domain(data + 7); | 962 | domain = tomoyo_find_domain(data + 7); |
770 | } else | 963 | } else |
771 | return false; | 964 | return false; |
772 | head->write_var1 = domain; | 965 | head->w.domain = domain; |
773 | /* Accessing read_buf is safe because head->io_sem is held. */ | 966 | /* Accessing read_buf is safe because head->io_sem is held. */ |
774 | if (!head->read_buf) | 967 | if (!head->read_buf) |
775 | return true; /* Do nothing if open(O_WRONLY). */ | 968 | return true; /* Do nothing if open(O_WRONLY). */ |
@@ -821,20 +1014,47 @@ static int tomoyo_delete_domain(char *domainname) | |||
821 | /** | 1014 | /** |
822 | * tomoyo_write_domain2 - Write domain policy. | 1015 | * tomoyo_write_domain2 - Write domain policy. |
823 | * | 1016 | * |
824 | * @head: Pointer to "struct tomoyo_io_buffer". | 1017 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
1018 | * @list: Pointer to "struct list_head". | ||
1019 | * @data: Policy to be interpreted. | ||
1020 | * @is_delete: True if it is a delete request. | ||
825 | * | 1021 | * |
826 | * Returns 0 on success, negative value otherwise. | 1022 | * Returns 0 on success, negative value otherwise. |
827 | * | 1023 | * |
828 | * Caller holds tomoyo_read_lock(). | 1024 | * Caller holds tomoyo_read_lock(). |
829 | */ | 1025 | */ |
830 | static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain, | 1026 | static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, |
1027 | struct list_head *list, char *data, | ||
831 | const bool is_delete) | 1028 | const bool is_delete) |
832 | { | 1029 | { |
833 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) | 1030 | struct tomoyo_acl_param param = { |
834 | return tomoyo_write_mount(data, domain, is_delete); | 1031 | .ns = ns, |
835 | return tomoyo_write_file(data, domain, is_delete); | 1032 | .list = list, |
1033 | .data = data, | ||
1034 | .is_delete = is_delete, | ||
1035 | }; | ||
1036 | static const struct { | ||
1037 | const char *keyword; | ||
1038 | int (*write) (struct tomoyo_acl_param *); | ||
1039 | } tomoyo_callback[1] = { | ||
1040 | { "file ", tomoyo_write_file }, | ||
1041 | }; | ||
1042 | u8 i; | ||
1043 | for (i = 0; i < 1; i++) { | ||
1044 | if (!tomoyo_str_starts(¶m.data, | ||
1045 | tomoyo_callback[i].keyword)) | ||
1046 | continue; | ||
1047 | return tomoyo_callback[i].write(¶m); | ||
1048 | } | ||
1049 | return -EINVAL; | ||
836 | } | 1050 | } |
837 | 1051 | ||
1052 | /* String table for domain flags. */ | ||
1053 | const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = { | ||
1054 | [TOMOYO_DIF_QUOTA_WARNED] = "quota_exceeded\n", | ||
1055 | [TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n", | ||
1056 | }; | ||
1057 | |||
838 | /** | 1058 | /** |
839 | * tomoyo_write_domain - Write domain policy. | 1059 | * tomoyo_write_domain - Write domain policy. |
840 | * | 1060 | * |
@@ -847,69 +1067,198 @@ static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain, | |||
847 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | 1067 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) |
848 | { | 1068 | { |
849 | char *data = head->write_buf; | 1069 | char *data = head->write_buf; |
850 | struct tomoyo_domain_info *domain = head->write_var1; | 1070 | struct tomoyo_policy_namespace *ns; |
851 | bool is_delete = false; | 1071 | struct tomoyo_domain_info *domain = head->w.domain; |
852 | bool is_select = false; | 1072 | const bool is_delete = head->w.is_delete; |
1073 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); | ||
853 | unsigned int profile; | 1074 | unsigned int profile; |
854 | 1075 | if (*data == '<') { | |
855 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE)) | ||
856 | is_delete = true; | ||
857 | else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT)) | ||
858 | is_select = true; | ||
859 | if (is_select && tomoyo_select_one(head, data)) | ||
860 | return 0; | ||
861 | /* Don't allow updating policies by non manager programs. */ | ||
862 | if (!tomoyo_manager()) | ||
863 | return -EPERM; | ||
864 | if (tomoyo_domain_def(data)) { | ||
865 | domain = NULL; | 1076 | domain = NULL; |
866 | if (is_delete) | 1077 | if (is_delete) |
867 | tomoyo_delete_domain(data); | 1078 | tomoyo_delete_domain(data); |
868 | else if (is_select) | 1079 | else if (is_select) |
869 | domain = tomoyo_find_domain(data); | 1080 | domain = tomoyo_find_domain(data); |
870 | else | 1081 | else |
871 | domain = tomoyo_assign_domain(data, 0); | 1082 | domain = tomoyo_assign_domain(data, false); |
872 | head->write_var1 = domain; | 1083 | head->w.domain = domain; |
873 | return 0; | 1084 | return 0; |
874 | } | 1085 | } |
875 | if (!domain) | 1086 | if (!domain) |
876 | return -EINVAL; | 1087 | return -EINVAL; |
877 | 1088 | ns = domain->ns; | |
878 | if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1 | 1089 | if (sscanf(data, "use_profile %u", &profile) == 1 |
879 | && profile < TOMOYO_MAX_PROFILES) { | 1090 | && profile < TOMOYO_MAX_PROFILES) { |
880 | if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) | 1091 | if (!tomoyo_policy_loaded || ns->profile_ptr[profile]) |
881 | domain->profile = (u8) profile; | 1092 | domain->profile = (u8) profile; |
882 | return 0; | 1093 | return 0; |
883 | } | 1094 | } |
884 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { | 1095 | if (sscanf(data, "use_group %u\n", &profile) == 1 |
885 | domain->ignore_global_allow_read = !is_delete; | 1096 | && profile < TOMOYO_MAX_ACL_GROUPS) { |
1097 | if (!is_delete) | ||
1098 | domain->group = (u8) profile; | ||
886 | return 0; | 1099 | return 0; |
887 | } | 1100 | } |
888 | if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) { | 1101 | for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) { |
889 | domain->quota_warned = !is_delete; | 1102 | const char *cp = tomoyo_dif[profile]; |
890 | return 0; | 1103 | if (strncmp(data, cp, strlen(cp) - 1)) |
891 | } | 1104 | continue; |
892 | if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) { | 1105 | domain->flags[profile] = !is_delete; |
893 | domain->transition_failed = !is_delete; | ||
894 | return 0; | 1106 | return 0; |
895 | } | 1107 | } |
896 | return tomoyo_write_domain2(data, domain, is_delete); | 1108 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, |
1109 | is_delete); | ||
897 | } | 1110 | } |
898 | 1111 | ||
899 | /** | 1112 | /** |
900 | * tomoyo_fns - Find next set bit. | 1113 | * tomoyo_print_condition - Print condition part. |
901 | * | 1114 | * |
902 | * @perm: 8 bits value. | 1115 | * @head: Pointer to "struct tomoyo_io_buffer". |
903 | * @bit: First bit to find. | 1116 | * @cond: Pointer to "struct tomoyo_condition". |
904 | * | 1117 | * |
905 | * Returns next on-bit on success, 8 otherwise. | 1118 | * Returns true on success, false otherwise. |
906 | */ | 1119 | */ |
907 | static u8 tomoyo_fns(const u8 perm, u8 bit) | 1120 | static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, |
1121 | const struct tomoyo_condition *cond) | ||
908 | { | 1122 | { |
909 | for ( ; bit < 8; bit++) | 1123 | switch (head->r.cond_step) { |
910 | if (perm & (1 << bit)) | 1124 | case 0: |
1125 | head->r.cond_index = 0; | ||
1126 | head->r.cond_step++; | ||
1127 | /* fall through */ | ||
1128 | case 1: | ||
1129 | { | ||
1130 | const u16 condc = cond->condc; | ||
1131 | const struct tomoyo_condition_element *condp = | ||
1132 | (typeof(condp)) (cond + 1); | ||
1133 | const struct tomoyo_number_union *numbers_p = | ||
1134 | (typeof(numbers_p)) (condp + condc); | ||
1135 | const struct tomoyo_name_union *names_p = | ||
1136 | (typeof(names_p)) | ||
1137 | (numbers_p + cond->numbers_count); | ||
1138 | const struct tomoyo_argv *argv = | ||
1139 | (typeof(argv)) (names_p + cond->names_count); | ||
1140 | const struct tomoyo_envp *envp = | ||
1141 | (typeof(envp)) (argv + cond->argc); | ||
1142 | u16 skip; | ||
1143 | for (skip = 0; skip < head->r.cond_index; skip++) { | ||
1144 | const u8 left = condp->left; | ||
1145 | const u8 right = condp->right; | ||
1146 | condp++; | ||
1147 | switch (left) { | ||
1148 | case TOMOYO_ARGV_ENTRY: | ||
1149 | argv++; | ||
1150 | continue; | ||
1151 | case TOMOYO_ENVP_ENTRY: | ||
1152 | envp++; | ||
1153 | continue; | ||
1154 | case TOMOYO_NUMBER_UNION: | ||
1155 | numbers_p++; | ||
1156 | break; | ||
1157 | } | ||
1158 | switch (right) { | ||
1159 | case TOMOYO_NAME_UNION: | ||
1160 | names_p++; | ||
1161 | break; | ||
1162 | case TOMOYO_NUMBER_UNION: | ||
1163 | numbers_p++; | ||
1164 | break; | ||
1165 | } | ||
1166 | } | ||
1167 | while (head->r.cond_index < condc) { | ||
1168 | const u8 match = condp->equals; | ||
1169 | const u8 left = condp->left; | ||
1170 | const u8 right = condp->right; | ||
1171 | if (!tomoyo_flush(head)) | ||
1172 | return false; | ||
1173 | condp++; | ||
1174 | head->r.cond_index++; | ||
1175 | tomoyo_set_space(head); | ||
1176 | switch (left) { | ||
1177 | case TOMOYO_ARGV_ENTRY: | ||
1178 | tomoyo_io_printf(head, | ||
1179 | "exec.argv[%lu]%s=\"", | ||
1180 | argv->index, argv-> | ||
1181 | is_not ? "!" : ""); | ||
1182 | tomoyo_set_string(head, | ||
1183 | argv->value->name); | ||
1184 | tomoyo_set_string(head, "\""); | ||
1185 | argv++; | ||
1186 | continue; | ||
1187 | case TOMOYO_ENVP_ENTRY: | ||
1188 | tomoyo_set_string(head, | ||
1189 | "exec.envp[\""); | ||
1190 | tomoyo_set_string(head, | ||
1191 | envp->name->name); | ||
1192 | tomoyo_io_printf(head, "\"]%s=", envp-> | ||
1193 | is_not ? "!" : ""); | ||
1194 | if (envp->value) { | ||
1195 | tomoyo_set_string(head, "\""); | ||
1196 | tomoyo_set_string(head, envp-> | ||
1197 | value->name); | ||
1198 | tomoyo_set_string(head, "\""); | ||
1199 | } else { | ||
1200 | tomoyo_set_string(head, | ||
1201 | "NULL"); | ||
1202 | } | ||
1203 | envp++; | ||
1204 | continue; | ||
1205 | case TOMOYO_NUMBER_UNION: | ||
1206 | tomoyo_print_number_union_nospace | ||
1207 | (head, numbers_p++); | ||
1208 | break; | ||
1209 | default: | ||
1210 | tomoyo_set_string(head, | ||
1211 | tomoyo_condition_keyword[left]); | ||
1212 | break; | ||
1213 | } | ||
1214 | tomoyo_set_string(head, match ? "=" : "!="); | ||
1215 | switch (right) { | ||
1216 | case TOMOYO_NAME_UNION: | ||
1217 | tomoyo_print_name_union_quoted | ||
1218 | (head, names_p++); | ||
1219 | break; | ||
1220 | case TOMOYO_NUMBER_UNION: | ||
1221 | tomoyo_print_number_union_nospace | ||
1222 | (head, numbers_p++); | ||
1223 | break; | ||
1224 | default: | ||
1225 | tomoyo_set_string(head, | ||
1226 | tomoyo_condition_keyword[right]); | ||
1227 | break; | ||
1228 | } | ||
1229 | } | ||
1230 | } | ||
1231 | head->r.cond_step++; | ||
1232 | /* fall through */ | ||
1233 | case 2: | ||
1234 | if (!tomoyo_flush(head)) | ||
911 | break; | 1235 | break; |
912 | return bit; | 1236 | head->r.cond_step++; |
1237 | /* fall through */ | ||
1238 | case 3: | ||
1239 | tomoyo_set_lf(head); | ||
1240 | return true; | ||
1241 | } | ||
1242 | return false; | ||
1243 | } | ||
1244 | |||
1245 | /** | ||
1246 | * tomoyo_set_group - Print "acl_group " header keyword and category name. | ||
1247 | * | ||
1248 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1249 | * @category: Category name. | ||
1250 | * | ||
1251 | * Returns nothing. | ||
1252 | */ | ||
1253 | static void tomoyo_set_group(struct tomoyo_io_buffer *head, | ||
1254 | const char *category) | ||
1255 | { | ||
1256 | if (head->type == TOMOYO_EXCEPTIONPOLICY) { | ||
1257 | tomoyo_print_namespace(head); | ||
1258 | tomoyo_io_printf(head, "acl_group %u ", | ||
1259 | head->r.acl_group_index); | ||
1260 | } | ||
1261 | tomoyo_set_string(head, category); | ||
913 | } | 1262 | } |
914 | 1263 | ||
915 | /** | 1264 | /** |
@@ -924,63 +1273,96 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
924 | struct tomoyo_acl_info *acl) | 1273 | struct tomoyo_acl_info *acl) |
925 | { | 1274 | { |
926 | const u8 acl_type = acl->type; | 1275 | const u8 acl_type = acl->type; |
1276 | bool first = true; | ||
927 | u8 bit; | 1277 | u8 bit; |
928 | 1278 | ||
1279 | if (head->r.print_cond_part) | ||
1280 | goto print_cond_part; | ||
929 | if (acl->is_deleted) | 1281 | if (acl->is_deleted) |
930 | return true; | 1282 | return true; |
931 | next: | ||
932 | bit = head->r.bit; | ||
933 | if (!tomoyo_flush(head)) | 1283 | if (!tomoyo_flush(head)) |
934 | return false; | 1284 | return false; |
935 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { | 1285 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { |
936 | struct tomoyo_path_acl *ptr = | 1286 | struct tomoyo_path_acl *ptr = |
937 | container_of(acl, typeof(*ptr), head); | 1287 | container_of(acl, typeof(*ptr), head); |
938 | const u16 perm = ptr->perm; | 1288 | const u16 perm = ptr->perm; |
939 | for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1289 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
940 | if (!(perm & (1 << bit))) | 1290 | if (!(perm & (1 << bit))) |
941 | continue; | 1291 | continue; |
942 | if (head->r.print_execute_only && | 1292 | if (head->r.print_transition_related_only && |
943 | bit != TOMOYO_TYPE_EXECUTE) | 1293 | bit != TOMOYO_TYPE_EXECUTE) |
944 | continue; | 1294 | continue; |
945 | /* Print "read/write" instead of "read" and "write". */ | 1295 | if (first) { |
946 | if ((bit == TOMOYO_TYPE_READ || | 1296 | tomoyo_set_group(head, "file "); |
947 | bit == TOMOYO_TYPE_WRITE) | 1297 | first = false; |
948 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) | 1298 | } else { |
949 | continue; | 1299 | tomoyo_set_slash(head); |
950 | break; | 1300 | } |
1301 | tomoyo_set_string(head, tomoyo_path_keyword[bit]); | ||
951 | } | 1302 | } |
952 | if (bit >= TOMOYO_MAX_PATH_OPERATION) | 1303 | if (first) |
953 | goto done; | 1304 | return true; |
954 | tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]); | ||
955 | tomoyo_print_name_union(head, &ptr->name); | 1305 | tomoyo_print_name_union(head, &ptr->name); |
956 | } else if (head->r.print_execute_only) { | 1306 | } else if (head->r.print_transition_related_only) { |
957 | return true; | 1307 | return true; |
958 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { | 1308 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
959 | struct tomoyo_path2_acl *ptr = | 1309 | struct tomoyo_path2_acl *ptr = |
960 | container_of(acl, typeof(*ptr), head); | 1310 | container_of(acl, typeof(*ptr), head); |
961 | bit = tomoyo_fns(ptr->perm, bit); | 1311 | const u8 perm = ptr->perm; |
962 | if (bit >= TOMOYO_MAX_PATH2_OPERATION) | 1312 | for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
963 | goto done; | 1313 | if (!(perm & (1 << bit))) |
964 | tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]); | 1314 | continue; |
1315 | if (first) { | ||
1316 | tomoyo_set_group(head, "file "); | ||
1317 | first = false; | ||
1318 | } else { | ||
1319 | tomoyo_set_slash(head); | ||
1320 | } | ||
1321 | tomoyo_set_string(head, tomoyo_mac_keywords | ||
1322 | [tomoyo_pp2mac[bit]]); | ||
1323 | } | ||
1324 | if (first) | ||
1325 | return true; | ||
965 | tomoyo_print_name_union(head, &ptr->name1); | 1326 | tomoyo_print_name_union(head, &ptr->name1); |
966 | tomoyo_print_name_union(head, &ptr->name2); | 1327 | tomoyo_print_name_union(head, &ptr->name2); |
967 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { | 1328 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { |
968 | struct tomoyo_path_number_acl *ptr = | 1329 | struct tomoyo_path_number_acl *ptr = |
969 | container_of(acl, typeof(*ptr), head); | 1330 | container_of(acl, typeof(*ptr), head); |
970 | bit = tomoyo_fns(ptr->perm, bit); | 1331 | const u8 perm = ptr->perm; |
971 | if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION) | 1332 | for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { |
972 | goto done; | 1333 | if (!(perm & (1 << bit))) |
973 | tomoyo_io_printf(head, "allow_%s", | 1334 | continue; |
974 | tomoyo_path_number_keyword[bit]); | 1335 | if (first) { |
1336 | tomoyo_set_group(head, "file "); | ||
1337 | first = false; | ||
1338 | } else { | ||
1339 | tomoyo_set_slash(head); | ||
1340 | } | ||
1341 | tomoyo_set_string(head, tomoyo_mac_keywords | ||
1342 | [tomoyo_pn2mac[bit]]); | ||
1343 | } | ||
1344 | if (first) | ||
1345 | return true; | ||
975 | tomoyo_print_name_union(head, &ptr->name); | 1346 | tomoyo_print_name_union(head, &ptr->name); |
976 | tomoyo_print_number_union(head, &ptr->number); | 1347 | tomoyo_print_number_union(head, &ptr->number); |
977 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { | 1348 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { |
978 | struct tomoyo_mkdev_acl *ptr = | 1349 | struct tomoyo_mkdev_acl *ptr = |
979 | container_of(acl, typeof(*ptr), head); | 1350 | container_of(acl, typeof(*ptr), head); |
980 | bit = tomoyo_fns(ptr->perm, bit); | 1351 | const u8 perm = ptr->perm; |
981 | if (bit >= TOMOYO_MAX_MKDEV_OPERATION) | 1352 | for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { |
982 | goto done; | 1353 | if (!(perm & (1 << bit))) |
983 | tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]); | 1354 | continue; |
1355 | if (first) { | ||
1356 | tomoyo_set_group(head, "file "); | ||
1357 | first = false; | ||
1358 | } else { | ||
1359 | tomoyo_set_slash(head); | ||
1360 | } | ||
1361 | tomoyo_set_string(head, tomoyo_mac_keywords | ||
1362 | [tomoyo_pnnn2mac[bit]]); | ||
1363 | } | ||
1364 | if (first) | ||
1365 | return true; | ||
984 | tomoyo_print_name_union(head, &ptr->name); | 1366 | tomoyo_print_name_union(head, &ptr->name); |
985 | tomoyo_print_number_union(head, &ptr->mode); | 1367 | tomoyo_print_number_union(head, &ptr->mode); |
986 | tomoyo_print_number_union(head, &ptr->major); | 1368 | tomoyo_print_number_union(head, &ptr->major); |
@@ -988,35 +1370,41 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
988 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 1370 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
989 | struct tomoyo_mount_acl *ptr = | 1371 | struct tomoyo_mount_acl *ptr = |
990 | container_of(acl, typeof(*ptr), head); | 1372 | container_of(acl, typeof(*ptr), head); |
991 | tomoyo_io_printf(head, "allow_mount"); | 1373 | tomoyo_set_group(head, "file mount"); |
992 | tomoyo_print_name_union(head, &ptr->dev_name); | 1374 | tomoyo_print_name_union(head, &ptr->dev_name); |
993 | tomoyo_print_name_union(head, &ptr->dir_name); | 1375 | tomoyo_print_name_union(head, &ptr->dir_name); |
994 | tomoyo_print_name_union(head, &ptr->fs_type); | 1376 | tomoyo_print_name_union(head, &ptr->fs_type); |
995 | tomoyo_print_number_union(head, &ptr->flags); | 1377 | tomoyo_print_number_union(head, &ptr->flags); |
996 | } | 1378 | } |
997 | head->r.bit = bit + 1; | 1379 | if (acl->cond) { |
998 | tomoyo_io_printf(head, "\n"); | 1380 | head->r.print_cond_part = true; |
999 | if (acl_type != TOMOYO_TYPE_MOUNT_ACL) | 1381 | head->r.cond_step = 0; |
1000 | goto next; | 1382 | if (!tomoyo_flush(head)) |
1001 | done: | 1383 | return false; |
1002 | head->r.bit = 0; | 1384 | print_cond_part: |
1385 | if (!tomoyo_print_condition(head, acl->cond)) | ||
1386 | return false; | ||
1387 | head->r.print_cond_part = false; | ||
1388 | } else { | ||
1389 | tomoyo_set_lf(head); | ||
1390 | } | ||
1003 | return true; | 1391 | return true; |
1004 | } | 1392 | } |
1005 | 1393 | ||
1006 | /** | 1394 | /** |
1007 | * tomoyo_read_domain2 - Read domain policy. | 1395 | * tomoyo_read_domain2 - Read domain policy. |
1008 | * | 1396 | * |
1009 | * @head: Pointer to "struct tomoyo_io_buffer". | 1397 | * @head: Pointer to "struct tomoyo_io_buffer". |
1010 | * @domain: Pointer to "struct tomoyo_domain_info". | 1398 | * @list: Pointer to "struct list_head". |
1011 | * | 1399 | * |
1012 | * Caller holds tomoyo_read_lock(). | 1400 | * Caller holds tomoyo_read_lock(). |
1013 | * | 1401 | * |
1014 | * Returns true on success, false otherwise. | 1402 | * Returns true on success, false otherwise. |
1015 | */ | 1403 | */ |
1016 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, | 1404 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, |
1017 | struct tomoyo_domain_info *domain) | 1405 | struct list_head *list) |
1018 | { | 1406 | { |
1019 | list_for_each_cookie(head->r.acl, &domain->acl_info_list) { | 1407 | list_for_each_cookie(head->r.acl, list) { |
1020 | struct tomoyo_acl_info *ptr = | 1408 | struct tomoyo_acl_info *ptr = |
1021 | list_entry(head->r.acl, typeof(*ptr), list); | 1409 | list_entry(head->r.acl, typeof(*ptr), list); |
1022 | if (!tomoyo_print_entry(head, ptr)) | 1410 | if (!tomoyo_print_entry(head, ptr)) |
@@ -1041,6 +1429,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1041 | struct tomoyo_domain_info *domain = | 1429 | struct tomoyo_domain_info *domain = |
1042 | list_entry(head->r.domain, typeof(*domain), list); | 1430 | list_entry(head->r.domain, typeof(*domain), list); |
1043 | switch (head->r.step) { | 1431 | switch (head->r.step) { |
1432 | u8 i; | ||
1044 | case 0: | 1433 | case 0: |
1045 | if (domain->is_deleted && | 1434 | if (domain->is_deleted && |
1046 | !head->r.print_this_domain_only) | 1435 | !head->r.print_this_domain_only) |
@@ -1048,22 +1437,18 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1048 | /* Print domainname and flags. */ | 1437 | /* Print domainname and flags. */ |
1049 | tomoyo_set_string(head, domain->domainname->name); | 1438 | tomoyo_set_string(head, domain->domainname->name); |
1050 | tomoyo_set_lf(head); | 1439 | tomoyo_set_lf(head); |
1051 | tomoyo_io_printf(head, | 1440 | tomoyo_io_printf(head, "use_profile %u\n", |
1052 | TOMOYO_KEYWORD_USE_PROFILE "%u\n", | ||
1053 | domain->profile); | 1441 | domain->profile); |
1054 | if (domain->quota_warned) | 1442 | tomoyo_io_printf(head, "use_group %u\n", |
1055 | tomoyo_set_string(head, "quota_exceeded\n"); | 1443 | domain->group); |
1056 | if (domain->transition_failed) | 1444 | for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) |
1057 | tomoyo_set_string(head, "transition_failed\n"); | 1445 | if (domain->flags[i]) |
1058 | if (domain->ignore_global_allow_read) | 1446 | tomoyo_set_string(head, tomoyo_dif[i]); |
1059 | tomoyo_set_string(head, | ||
1060 | TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ | ||
1061 | "\n"); | ||
1062 | head->r.step++; | 1447 | head->r.step++; |
1063 | tomoyo_set_lf(head); | 1448 | tomoyo_set_lf(head); |
1064 | /* fall through */ | 1449 | /* fall through */ |
1065 | case 1: | 1450 | case 1: |
1066 | if (!tomoyo_read_domain2(head, domain)) | 1451 | if (!tomoyo_read_domain2(head, &domain->acl_info_list)) |
1067 | return; | 1452 | return; |
1068 | head->r.step++; | 1453 | head->r.step++; |
1069 | if (!tomoyo_set_lf(head)) | 1454 | if (!tomoyo_set_lf(head)) |
@@ -1080,73 +1465,6 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | |||
1080 | } | 1465 | } |
1081 | 1466 | ||
1082 | /** | 1467 | /** |
1083 | * tomoyo_write_domain_profile - Assign profile for specified domain. | ||
1084 | * | ||
1085 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1086 | * | ||
1087 | * Returns 0 on success, -EINVAL otherwise. | ||
1088 | * | ||
1089 | * This is equivalent to doing | ||
1090 | * | ||
1091 | * ( echo "select " $domainname; echo "use_profile " $profile ) | | ||
1092 | * /usr/sbin/tomoyo-loadpolicy -d | ||
1093 | * | ||
1094 | * Caller holds tomoyo_read_lock(). | ||
1095 | */ | ||
1096 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | ||
1097 | { | ||
1098 | char *data = head->write_buf; | ||
1099 | char *cp = strchr(data, ' '); | ||
1100 | struct tomoyo_domain_info *domain; | ||
1101 | unsigned long profile; | ||
1102 | |||
1103 | if (!cp) | ||
1104 | return -EINVAL; | ||
1105 | *cp = '\0'; | ||
1106 | domain = tomoyo_find_domain(cp + 1); | ||
1107 | if (strict_strtoul(data, 10, &profile)) | ||
1108 | return -EINVAL; | ||
1109 | if (domain && profile < TOMOYO_MAX_PROFILES | ||
1110 | && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) | ||
1111 | domain->profile = (u8) profile; | ||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | /** | ||
1116 | * tomoyo_read_domain_profile - Read only domainname and profile. | ||
1117 | * | ||
1118 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1119 | * | ||
1120 | * Returns list of profile number and domainname pairs. | ||
1121 | * | ||
1122 | * This is equivalent to doing | ||
1123 | * | ||
1124 | * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | | ||
1125 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) | ||
1126 | * domainname = $0; } else if ( $1 == "use_profile" ) { | ||
1127 | * print $2 " " domainname; domainname = ""; } } ; ' | ||
1128 | * | ||
1129 | * Caller holds tomoyo_read_lock(). | ||
1130 | */ | ||
1131 | static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | ||
1132 | { | ||
1133 | if (head->r.eof) | ||
1134 | return; | ||
1135 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { | ||
1136 | struct tomoyo_domain_info *domain = | ||
1137 | list_entry(head->r.domain, typeof(*domain), list); | ||
1138 | if (domain->is_deleted) | ||
1139 | continue; | ||
1140 | if (!tomoyo_flush(head)) | ||
1141 | return; | ||
1142 | tomoyo_io_printf(head, "%u ", domain->profile); | ||
1143 | tomoyo_set_string(head, domain->domainname->name); | ||
1144 | tomoyo_set_lf(head); | ||
1145 | } | ||
1146 | head->r.eof = true; | ||
1147 | } | ||
1148 | |||
1149 | /** | ||
1150 | * tomoyo_write_pid: Specify PID to obtain domainname. | 1468 | * tomoyo_write_pid: Specify PID to obtain domainname. |
1151 | * | 1469 | * |
1152 | * @head: Pointer to "struct tomoyo_io_buffer". | 1470 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -1204,18 +1522,20 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1204 | tomoyo_set_string(head, domain->domainname->name); | 1522 | tomoyo_set_string(head, domain->domainname->name); |
1205 | } | 1523 | } |
1206 | 1524 | ||
1525 | /* String table for domain transition control keywords. */ | ||
1207 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | 1526 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { |
1208 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] | 1527 | [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ", |
1209 | = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN, | 1528 | [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ", |
1210 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] | 1529 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", |
1211 | = TOMOYO_KEYWORD_INITIALIZE_DOMAIN, | 1530 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", |
1212 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN, | 1531 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", |
1213 | [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN | 1532 | [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ", |
1214 | }; | 1533 | }; |
1215 | 1534 | ||
1535 | /* String table for grouping keywords. */ | ||
1216 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1536 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
1217 | [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP, | 1537 | [TOMOYO_PATH_GROUP] = "path_group ", |
1218 | [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP | 1538 | [TOMOYO_NUMBER_GROUP] = "number_group ", |
1219 | }; | 1539 | }; |
1220 | 1540 | ||
1221 | /** | 1541 | /** |
@@ -1229,29 +1549,30 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | |||
1229 | */ | 1549 | */ |
1230 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | 1550 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) |
1231 | { | 1551 | { |
1232 | char *data = head->write_buf; | 1552 | const bool is_delete = head->w.is_delete; |
1233 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | 1553 | struct tomoyo_acl_param param = { |
1234 | u8 i; | 1554 | .ns = head->w.ns, |
1235 | static const struct { | 1555 | .is_delete = is_delete, |
1236 | const char *keyword; | 1556 | .data = head->write_buf, |
1237 | int (*write) (char *, const bool); | ||
1238 | } tomoyo_callback[4] = { | ||
1239 | { TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator }, | ||
1240 | { TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern }, | ||
1241 | { TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite }, | ||
1242 | { TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable }, | ||
1243 | }; | 1557 | }; |
1244 | 1558 | u8 i; | |
1559 | if (tomoyo_str_starts(¶m.data, "aggregator ")) | ||
1560 | return tomoyo_write_aggregator(¶m); | ||
1245 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) | 1561 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) |
1246 | if (tomoyo_str_starts(&data, tomoyo_transition_type[i])) | 1562 | if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i])) |
1247 | return tomoyo_write_transition_control(data, is_delete, | 1563 | return tomoyo_write_transition_control(¶m, i); |
1248 | i); | ||
1249 | for (i = 0; i < 4; i++) | ||
1250 | if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword)) | ||
1251 | return tomoyo_callback[i].write(data, is_delete); | ||
1252 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) | 1564 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) |
1253 | if (tomoyo_str_starts(&data, tomoyo_group_name[i])) | 1565 | if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) |
1254 | return tomoyo_write_group(data, is_delete, i); | 1566 | return tomoyo_write_group(¶m, i); |
1567 | if (tomoyo_str_starts(¶m.data, "acl_group ")) { | ||
1568 | unsigned int group; | ||
1569 | char *data; | ||
1570 | group = simple_strtoul(param.data, &data, 10); | ||
1571 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') | ||
1572 | return tomoyo_write_domain2 | ||
1573 | (head->w.ns, &head->w.ns->acl_group[group], | ||
1574 | data, is_delete); | ||
1575 | } | ||
1255 | return -EINVAL; | 1576 | return -EINVAL; |
1256 | } | 1577 | } |
1257 | 1578 | ||
@@ -1267,9 +1588,12 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1267 | */ | 1588 | */ |
1268 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | 1589 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) |
1269 | { | 1590 | { |
1270 | list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) { | 1591 | struct tomoyo_policy_namespace *ns = |
1592 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1593 | struct list_head *list = &ns->group_list[idx]; | ||
1594 | list_for_each_cookie(head->r.group, list) { | ||
1271 | struct tomoyo_group *group = | 1595 | struct tomoyo_group *group = |
1272 | list_entry(head->r.group, typeof(*group), list); | 1596 | list_entry(head->r.group, typeof(*group), head.list); |
1273 | list_for_each_cookie(head->r.acl, &group->member_list) { | 1597 | list_for_each_cookie(head->r.acl, &group->member_list) { |
1274 | struct tomoyo_acl_head *ptr = | 1598 | struct tomoyo_acl_head *ptr = |
1275 | list_entry(head->r.acl, typeof(*ptr), list); | 1599 | list_entry(head->r.acl, typeof(*ptr), list); |
@@ -1277,6 +1601,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1277 | continue; | 1601 | continue; |
1278 | if (!tomoyo_flush(head)) | 1602 | if (!tomoyo_flush(head)) |
1279 | return false; | 1603 | return false; |
1604 | tomoyo_print_namespace(head); | ||
1280 | tomoyo_set_string(head, tomoyo_group_name[idx]); | 1605 | tomoyo_set_string(head, tomoyo_group_name[idx]); |
1281 | tomoyo_set_string(head, group->group_name->name); | 1606 | tomoyo_set_string(head, group->group_name->name); |
1282 | if (idx == TOMOYO_PATH_GROUP) { | 1607 | if (idx == TOMOYO_PATH_GROUP) { |
@@ -1310,7 +1635,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1310 | */ | 1635 | */ |
1311 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | 1636 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) |
1312 | { | 1637 | { |
1313 | list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) { | 1638 | struct tomoyo_policy_namespace *ns = |
1639 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1640 | struct list_head *list = &ns->policy_list[idx]; | ||
1641 | list_for_each_cookie(head->r.acl, list) { | ||
1314 | struct tomoyo_acl_head *acl = | 1642 | struct tomoyo_acl_head *acl = |
1315 | container_of(head->r.acl, typeof(*acl), list); | 1643 | container_of(head->r.acl, typeof(*acl), list); |
1316 | if (acl->is_deleted) | 1644 | if (acl->is_deleted) |
@@ -1322,35 +1650,23 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1322 | { | 1650 | { |
1323 | struct tomoyo_transition_control *ptr = | 1651 | struct tomoyo_transition_control *ptr = |
1324 | container_of(acl, typeof(*ptr), head); | 1652 | container_of(acl, typeof(*ptr), head); |
1325 | tomoyo_set_string(head, | 1653 | tomoyo_print_namespace(head); |
1326 | tomoyo_transition_type | 1654 | tomoyo_set_string(head, tomoyo_transition_type |
1327 | [ptr->type]); | 1655 | [ptr->type]); |
1328 | if (ptr->program) | 1656 | tomoyo_set_string(head, ptr->program ? |
1329 | tomoyo_set_string(head, | 1657 | ptr->program->name : "any"); |
1330 | ptr->program->name); | 1658 | tomoyo_set_string(head, " from "); |
1331 | if (ptr->program && ptr->domainname) | 1659 | tomoyo_set_string(head, ptr->domainname ? |
1332 | tomoyo_set_string(head, " from "); | 1660 | ptr->domainname->name : |
1333 | if (ptr->domainname) | 1661 | "any"); |
1334 | tomoyo_set_string(head, | ||
1335 | ptr->domainname-> | ||
1336 | name); | ||
1337 | } | ||
1338 | break; | ||
1339 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
1340 | { | ||
1341 | struct tomoyo_readable_file *ptr = | ||
1342 | container_of(acl, typeof(*ptr), head); | ||
1343 | tomoyo_set_string(head, | ||
1344 | TOMOYO_KEYWORD_ALLOW_READ); | ||
1345 | tomoyo_set_string(head, ptr->filename->name); | ||
1346 | } | 1662 | } |
1347 | break; | 1663 | break; |
1348 | case TOMOYO_ID_AGGREGATOR: | 1664 | case TOMOYO_ID_AGGREGATOR: |
1349 | { | 1665 | { |
1350 | struct tomoyo_aggregator *ptr = | 1666 | struct tomoyo_aggregator *ptr = |
1351 | container_of(acl, typeof(*ptr), head); | 1667 | container_of(acl, typeof(*ptr), head); |
1352 | tomoyo_set_string(head, | 1668 | tomoyo_print_namespace(head); |
1353 | TOMOYO_KEYWORD_AGGREGATOR); | 1669 | tomoyo_set_string(head, "aggregator "); |
1354 | tomoyo_set_string(head, | 1670 | tomoyo_set_string(head, |
1355 | ptr->original_name->name); | 1671 | ptr->original_name->name); |
1356 | tomoyo_set_space(head); | 1672 | tomoyo_set_space(head); |
@@ -1358,24 +1674,6 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1358 | ptr->aggregated_name->name); | 1674 | ptr->aggregated_name->name); |
1359 | } | 1675 | } |
1360 | break; | 1676 | break; |
1361 | case TOMOYO_ID_PATTERN: | ||
1362 | { | ||
1363 | struct tomoyo_no_pattern *ptr = | ||
1364 | container_of(acl, typeof(*ptr), head); | ||
1365 | tomoyo_set_string(head, | ||
1366 | TOMOYO_KEYWORD_FILE_PATTERN); | ||
1367 | tomoyo_set_string(head, ptr->pattern->name); | ||
1368 | } | ||
1369 | break; | ||
1370 | case TOMOYO_ID_NO_REWRITE: | ||
1371 | { | ||
1372 | struct tomoyo_no_rewrite *ptr = | ||
1373 | container_of(acl, typeof(*ptr), head); | ||
1374 | tomoyo_set_string(head, | ||
1375 | TOMOYO_KEYWORD_DENY_REWRITE); | ||
1376 | tomoyo_set_string(head, ptr->pattern->name); | ||
1377 | } | ||
1378 | break; | ||
1379 | default: | 1677 | default: |
1380 | continue; | 1678 | continue; |
1381 | } | 1679 | } |
@@ -1394,6 +1692,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1394 | */ | 1692 | */ |
1395 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | 1693 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) |
1396 | { | 1694 | { |
1695 | struct tomoyo_policy_namespace *ns = | ||
1696 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1397 | if (head->r.eof) | 1697 | if (head->r.eof) |
1398 | return; | 1698 | return; |
1399 | while (head->r.step < TOMOYO_MAX_POLICY && | 1699 | while (head->r.step < TOMOYO_MAX_POLICY && |
@@ -1406,95 +1706,40 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | |||
1406 | head->r.step++; | 1706 | head->r.step++; |
1407 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) | 1707 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) |
1408 | return; | 1708 | return; |
1709 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP | ||
1710 | + TOMOYO_MAX_ACL_GROUPS) { | ||
1711 | head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY | ||
1712 | - TOMOYO_MAX_GROUP; | ||
1713 | if (!tomoyo_read_domain2(head, &ns->acl_group | ||
1714 | [head->r.acl_group_index])) | ||
1715 | return; | ||
1716 | head->r.step++; | ||
1717 | } | ||
1409 | head->r.eof = true; | 1718 | head->r.eof = true; |
1410 | } | 1719 | } |
1411 | 1720 | ||
1412 | /** | 1721 | /* Wait queue for kernel -> userspace notification. */ |
1413 | * tomoyo_print_header - Get header line of audit log. | ||
1414 | * | ||
1415 | * @r: Pointer to "struct tomoyo_request_info". | ||
1416 | * | ||
1417 | * Returns string representation. | ||
1418 | * | ||
1419 | * This function uses kmalloc(), so caller must kfree() if this function | ||
1420 | * didn't return NULL. | ||
1421 | */ | ||
1422 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | ||
1423 | { | ||
1424 | struct timeval tv; | ||
1425 | const pid_t gpid = task_pid_nr(current); | ||
1426 | static const int tomoyo_buffer_len = 4096; | ||
1427 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | ||
1428 | pid_t ppid; | ||
1429 | if (!buffer) | ||
1430 | return NULL; | ||
1431 | do_gettimeofday(&tv); | ||
1432 | rcu_read_lock(); | ||
1433 | ppid = task_tgid_vnr(current->real_parent); | ||
1434 | rcu_read_unlock(); | ||
1435 | snprintf(buffer, tomoyo_buffer_len - 1, | ||
1436 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" | ||
1437 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" | ||
1438 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", | ||
1439 | tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid, | ||
1440 | task_tgid_vnr(current), ppid, | ||
1441 | current_uid(), current_gid(), current_euid(), | ||
1442 | current_egid(), current_suid(), current_sgid(), | ||
1443 | current_fsuid(), current_fsgid()); | ||
1444 | return buffer; | ||
1445 | } | ||
1446 | |||
1447 | /** | ||
1448 | * tomoyo_init_audit_log - Allocate buffer for audit logs. | ||
1449 | * | ||
1450 | * @len: Required size. | ||
1451 | * @r: Pointer to "struct tomoyo_request_info". | ||
1452 | * | ||
1453 | * Returns pointer to allocated memory. | ||
1454 | * | ||
1455 | * The @len is updated to add the header lines' size on success. | ||
1456 | * | ||
1457 | * This function uses kzalloc(), so caller must kfree() if this function | ||
1458 | * didn't return NULL. | ||
1459 | */ | ||
1460 | static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r) | ||
1461 | { | ||
1462 | char *buf = NULL; | ||
1463 | const char *header; | ||
1464 | const char *domainname; | ||
1465 | if (!r->domain) | ||
1466 | r->domain = tomoyo_domain(); | ||
1467 | domainname = r->domain->domainname->name; | ||
1468 | header = tomoyo_print_header(r); | ||
1469 | if (!header) | ||
1470 | return NULL; | ||
1471 | *len += strlen(domainname) + strlen(header) + 10; | ||
1472 | buf = kzalloc(*len, GFP_NOFS); | ||
1473 | if (buf) | ||
1474 | snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname); | ||
1475 | kfree(header); | ||
1476 | return buf; | ||
1477 | } | ||
1478 | |||
1479 | /* Wait queue for tomoyo_query_list. */ | ||
1480 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); | 1722 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); |
1481 | 1723 | /* Wait queue for userspace -> kernel notification. */ | |
1482 | /* Lock for manipulating tomoyo_query_list. */ | 1724 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait); |
1483 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); | ||
1484 | 1725 | ||
1485 | /* Structure for query. */ | 1726 | /* Structure for query. */ |
1486 | struct tomoyo_query { | 1727 | struct tomoyo_query { |
1487 | struct list_head list; | 1728 | struct list_head list; |
1488 | char *query; | 1729 | char *query; |
1489 | int query_len; | 1730 | size_t query_len; |
1490 | unsigned int serial; | 1731 | unsigned int serial; |
1491 | int timer; | 1732 | u8 timer; |
1492 | int answer; | 1733 | u8 answer; |
1734 | u8 retry; | ||
1493 | }; | 1735 | }; |
1494 | 1736 | ||
1495 | /* The list for "struct tomoyo_query". */ | 1737 | /* The list for "struct tomoyo_query". */ |
1496 | static LIST_HEAD(tomoyo_query_list); | 1738 | static LIST_HEAD(tomoyo_query_list); |
1497 | 1739 | ||
1740 | /* Lock for manipulating tomoyo_query_list. */ | ||
1741 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); | ||
1742 | |||
1498 | /* | 1743 | /* |
1499 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query | 1744 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query |
1500 | * interface. | 1745 | * interface. |
@@ -1502,10 +1747,82 @@ static LIST_HEAD(tomoyo_query_list); | |||
1502 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | 1747 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); |
1503 | 1748 | ||
1504 | /** | 1749 | /** |
1750 | * tomoyo_truncate - Truncate a line. | ||
1751 | * | ||
1752 | * @str: String to truncate. | ||
1753 | * | ||
1754 | * Returns length of truncated @str. | ||
1755 | */ | ||
1756 | static int tomoyo_truncate(char *str) | ||
1757 | { | ||
1758 | char *start = str; | ||
1759 | while (*(unsigned char *) str > (unsigned char) ' ') | ||
1760 | str++; | ||
1761 | *str = '\0'; | ||
1762 | return strlen(start) + 1; | ||
1763 | } | ||
1764 | |||
1765 | /** | ||
1766 | * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode. | ||
1767 | * | ||
1768 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1769 | * @header: Lines containing ACL. | ||
1770 | * | ||
1771 | * Returns nothing. | ||
1772 | */ | ||
1773 | static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) | ||
1774 | { | ||
1775 | char *buffer; | ||
1776 | char *realpath = NULL; | ||
1777 | char *argv0 = NULL; | ||
1778 | char *symlink = NULL; | ||
1779 | char *cp = strchr(header, '\n'); | ||
1780 | int len; | ||
1781 | if (!cp) | ||
1782 | return; | ||
1783 | cp = strchr(cp + 1, '\n'); | ||
1784 | if (!cp) | ||
1785 | return; | ||
1786 | *cp++ = '\0'; | ||
1787 | len = strlen(cp) + 1; | ||
1788 | /* strstr() will return NULL if ordering is wrong. */ | ||
1789 | if (*cp == 'f') { | ||
1790 | argv0 = strstr(header, " argv[]={ \""); | ||
1791 | if (argv0) { | ||
1792 | argv0 += 10; | ||
1793 | len += tomoyo_truncate(argv0) + 14; | ||
1794 | } | ||
1795 | realpath = strstr(header, " exec={ realpath=\""); | ||
1796 | if (realpath) { | ||
1797 | realpath += 8; | ||
1798 | len += tomoyo_truncate(realpath) + 6; | ||
1799 | } | ||
1800 | symlink = strstr(header, " symlink.target=\""); | ||
1801 | if (symlink) | ||
1802 | len += tomoyo_truncate(symlink + 1) + 1; | ||
1803 | } | ||
1804 | buffer = kmalloc(len, GFP_NOFS); | ||
1805 | if (!buffer) | ||
1806 | return; | ||
1807 | snprintf(buffer, len - 1, "%s", cp); | ||
1808 | if (realpath) | ||
1809 | tomoyo_addprintf(buffer, len, " exec.%s", realpath); | ||
1810 | if (argv0) | ||
1811 | tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0); | ||
1812 | if (symlink) | ||
1813 | tomoyo_addprintf(buffer, len, "%s", symlink); | ||
1814 | tomoyo_normalize_line(buffer); | ||
1815 | if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer, | ||
1816 | false)) | ||
1817 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | ||
1818 | kfree(buffer); | ||
1819 | } | ||
1820 | |||
1821 | /** | ||
1505 | * tomoyo_supervisor - Ask for the supervisor's decision. | 1822 | * tomoyo_supervisor - Ask for the supervisor's decision. |
1506 | * | 1823 | * |
1507 | * @r: Pointer to "struct tomoyo_request_info". | 1824 | * @r: Pointer to "struct tomoyo_request_info". |
1508 | * @fmt: The printf()'s format string, followed by parameters. | 1825 | * @fmt: The printf()'s format string, followed by parameters. |
1509 | * | 1826 | * |
1510 | * Returns 0 if the supervisor decided to permit the access request which | 1827 | * Returns 0 if the supervisor decided to permit the access request which |
1511 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the | 1828 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the |
@@ -1515,88 +1832,79 @@ static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | |||
1515 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | 1832 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) |
1516 | { | 1833 | { |
1517 | va_list args; | 1834 | va_list args; |
1518 | int error = -EPERM; | 1835 | int error; |
1519 | int pos; | ||
1520 | int len; | 1836 | int len; |
1521 | static unsigned int tomoyo_serial; | 1837 | static unsigned int tomoyo_serial; |
1522 | struct tomoyo_query *entry = NULL; | 1838 | struct tomoyo_query entry = { }; |
1523 | bool quota_exceeded = false; | 1839 | bool quota_exceeded = false; |
1524 | char *header; | 1840 | va_start(args, fmt); |
1841 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | ||
1842 | va_end(args); | ||
1843 | /* Write /sys/kernel/security/tomoyo/audit. */ | ||
1844 | va_start(args, fmt); | ||
1845 | tomoyo_write_log2(r, len, fmt, args); | ||
1846 | va_end(args); | ||
1847 | /* Nothing more to do if granted. */ | ||
1848 | if (r->granted) | ||
1849 | return 0; | ||
1850 | if (r->mode) | ||
1851 | tomoyo_update_stat(r->mode); | ||
1525 | switch (r->mode) { | 1852 | switch (r->mode) { |
1526 | char *buffer; | 1853 | case TOMOYO_CONFIG_ENFORCING: |
1854 | error = -EPERM; | ||
1855 | if (atomic_read(&tomoyo_query_observers)) | ||
1856 | break; | ||
1857 | goto out; | ||
1527 | case TOMOYO_CONFIG_LEARNING: | 1858 | case TOMOYO_CONFIG_LEARNING: |
1528 | if (!tomoyo_domain_quota_is_ok(r)) | 1859 | error = 0; |
1529 | return 0; | 1860 | /* Check max_learning_entry parameter. */ |
1530 | va_start(args, fmt); | 1861 | if (tomoyo_domain_quota_is_ok(r)) |
1531 | len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; | 1862 | break; |
1532 | va_end(args); | ||
1533 | buffer = kmalloc(len, GFP_NOFS); | ||
1534 | if (!buffer) | ||
1535 | return 0; | ||
1536 | va_start(args, fmt); | ||
1537 | vsnprintf(buffer, len - 1, fmt, args); | ||
1538 | va_end(args); | ||
1539 | tomoyo_normalize_line(buffer); | ||
1540 | tomoyo_write_domain2(buffer, r->domain, false); | ||
1541 | kfree(buffer); | ||
1542 | /* fall through */ | 1863 | /* fall through */ |
1543 | case TOMOYO_CONFIG_PERMISSIVE: | 1864 | default: |
1544 | return 0; | 1865 | return 0; |
1545 | } | 1866 | } |
1546 | if (!r->domain) | 1867 | /* Get message. */ |
1547 | r->domain = tomoyo_domain(); | ||
1548 | if (!atomic_read(&tomoyo_query_observers)) | ||
1549 | return -EPERM; | ||
1550 | va_start(args, fmt); | 1868 | va_start(args, fmt); |
1551 | len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; | 1869 | entry.query = tomoyo_init_log(r, len, fmt, args); |
1552 | va_end(args); | 1870 | va_end(args); |
1553 | header = tomoyo_init_audit_log(&len, r); | 1871 | if (!entry.query) |
1554 | if (!header) | ||
1555 | goto out; | 1872 | goto out; |
1556 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 1873 | entry.query_len = strlen(entry.query) + 1; |
1557 | if (!entry) | 1874 | if (!error) { |
1875 | tomoyo_add_entry(r->domain, entry.query); | ||
1558 | goto out; | 1876 | goto out; |
1559 | entry->query = kzalloc(len, GFP_NOFS); | 1877 | } |
1560 | if (!entry->query) | 1878 | len = tomoyo_round2(entry.query_len); |
1561 | goto out; | ||
1562 | len = ksize(entry->query); | ||
1563 | spin_lock(&tomoyo_query_list_lock); | 1879 | spin_lock(&tomoyo_query_list_lock); |
1564 | if (tomoyo_quota_for_query && tomoyo_query_memory_size + len + | 1880 | if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] && |
1565 | sizeof(*entry) >= tomoyo_quota_for_query) { | 1881 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len |
1882 | >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) { | ||
1566 | quota_exceeded = true; | 1883 | quota_exceeded = true; |
1567 | } else { | 1884 | } else { |
1568 | tomoyo_query_memory_size += len + sizeof(*entry); | 1885 | entry.serial = tomoyo_serial++; |
1569 | entry->serial = tomoyo_serial++; | 1886 | entry.retry = r->retry; |
1887 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len; | ||
1888 | list_add_tail(&entry.list, &tomoyo_query_list); | ||
1570 | } | 1889 | } |
1571 | spin_unlock(&tomoyo_query_list_lock); | 1890 | spin_unlock(&tomoyo_query_list_lock); |
1572 | if (quota_exceeded) | 1891 | if (quota_exceeded) |
1573 | goto out; | 1892 | goto out; |
1574 | pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s", | ||
1575 | entry->serial, r->retry, header); | ||
1576 | kfree(header); | ||
1577 | header = NULL; | ||
1578 | va_start(args, fmt); | ||
1579 | vsnprintf(entry->query + pos, len - 1 - pos, fmt, args); | ||
1580 | entry->query_len = strlen(entry->query) + 1; | ||
1581 | va_end(args); | ||
1582 | spin_lock(&tomoyo_query_list_lock); | ||
1583 | list_add_tail(&entry->list, &tomoyo_query_list); | ||
1584 | spin_unlock(&tomoyo_query_list_lock); | ||
1585 | /* Give 10 seconds for supervisor's opinion. */ | 1893 | /* Give 10 seconds for supervisor's opinion. */ |
1586 | for (entry->timer = 0; | 1894 | while (entry.timer < 10) { |
1587 | atomic_read(&tomoyo_query_observers) && entry->timer < 100; | 1895 | wake_up_all(&tomoyo_query_wait); |
1588 | entry->timer++) { | 1896 | if (wait_event_interruptible_timeout |
1589 | wake_up(&tomoyo_query_wait); | 1897 | (tomoyo_answer_wait, entry.answer || |
1590 | set_current_state(TASK_INTERRUPTIBLE); | 1898 | !atomic_read(&tomoyo_query_observers), HZ)) |
1591 | schedule_timeout(HZ / 10); | ||
1592 | if (entry->answer) | ||
1593 | break; | 1899 | break; |
1900 | else | ||
1901 | entry.timer++; | ||
1594 | } | 1902 | } |
1595 | spin_lock(&tomoyo_query_list_lock); | 1903 | spin_lock(&tomoyo_query_list_lock); |
1596 | list_del(&entry->list); | 1904 | list_del(&entry.list); |
1597 | tomoyo_query_memory_size -= len + sizeof(*entry); | 1905 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len; |
1598 | spin_unlock(&tomoyo_query_list_lock); | 1906 | spin_unlock(&tomoyo_query_list_lock); |
1599 | switch (entry->answer) { | 1907 | switch (entry.answer) { |
1600 | case 3: /* Asked to retry by administrator. */ | 1908 | case 3: /* Asked to retry by administrator. */ |
1601 | error = TOMOYO_RETRY_REQUEST; | 1909 | error = TOMOYO_RETRY_REQUEST; |
1602 | r->retry++; | 1910 | r->retry++; |
@@ -1605,18 +1913,12 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | |||
1605 | /* Granted by administrator. */ | 1913 | /* Granted by administrator. */ |
1606 | error = 0; | 1914 | error = 0; |
1607 | break; | 1915 | break; |
1608 | case 0: | ||
1609 | /* Timed out. */ | ||
1610 | break; | ||
1611 | default: | 1916 | default: |
1612 | /* Rejected by administrator. */ | 1917 | /* Timed out or rejected by administrator. */ |
1613 | break; | 1918 | break; |
1614 | } | 1919 | } |
1615 | out: | 1920 | out: |
1616 | if (entry) | 1921 | kfree(entry.query); |
1617 | kfree(entry->query); | ||
1618 | kfree(entry); | ||
1619 | kfree(header); | ||
1620 | return error; | 1922 | return error; |
1621 | } | 1923 | } |
1622 | 1924 | ||
@@ -1663,8 +1965,8 @@ static int tomoyo_poll_query(struct file *file, poll_table *wait) | |||
1663 | static void tomoyo_read_query(struct tomoyo_io_buffer *head) | 1965 | static void tomoyo_read_query(struct tomoyo_io_buffer *head) |
1664 | { | 1966 | { |
1665 | struct list_head *tmp; | 1967 | struct list_head *tmp; |
1666 | int pos = 0; | 1968 | unsigned int pos = 0; |
1667 | int len = 0; | 1969 | size_t len = 0; |
1668 | char *buf; | 1970 | char *buf; |
1669 | if (head->r.w_pos) | 1971 | if (head->r.w_pos) |
1670 | return; | 1972 | return; |
@@ -1687,7 +1989,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1687 | head->r.query_index = 0; | 1989 | head->r.query_index = 0; |
1688 | return; | 1990 | return; |
1689 | } | 1991 | } |
1690 | buf = kzalloc(len, GFP_NOFS); | 1992 | buf = kzalloc(len + 32, GFP_NOFS); |
1691 | if (!buf) | 1993 | if (!buf) |
1692 | return; | 1994 | return; |
1693 | pos = 0; | 1995 | pos = 0; |
@@ -1703,7 +2005,8 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1703 | * can change, but I don't care. | 2005 | * can change, but I don't care. |
1704 | */ | 2006 | */ |
1705 | if (len == ptr->query_len) | 2007 | if (len == ptr->query_len) |
1706 | memmove(buf, ptr->query, len); | 2008 | snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial, |
2009 | ptr->retry, ptr->query); | ||
1707 | break; | 2010 | break; |
1708 | } | 2011 | } |
1709 | spin_unlock(&tomoyo_query_list_lock); | 2012 | spin_unlock(&tomoyo_query_list_lock); |
@@ -1760,7 +2063,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
1760 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 2063 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
1761 | { | 2064 | { |
1762 | if (!head->r.eof) { | 2065 | if (!head->r.eof) { |
1763 | tomoyo_io_printf(head, "2.3.0"); | 2066 | tomoyo_io_printf(head, "2.4.0"); |
1764 | head->r.eof = true; | 2067 | head->r.eof = true; |
1765 | } | 2068 | } |
1766 | } | 2069 | } |
@@ -1785,15 +2088,111 @@ static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
1785 | } | 2088 | } |
1786 | } | 2089 | } |
1787 | 2090 | ||
2091 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ | ||
2092 | static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { | ||
2093 | [TOMOYO_STAT_POLICY_UPDATES] = "update:", | ||
2094 | [TOMOYO_STAT_POLICY_LEARNING] = "violation in learning mode:", | ||
2095 | [TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:", | ||
2096 | [TOMOYO_STAT_POLICY_ENFORCING] = "violation in enforcing mode:", | ||
2097 | }; | ||
2098 | |||
2099 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ | ||
2100 | static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = { | ||
2101 | [TOMOYO_MEMORY_POLICY] = "policy:", | ||
2102 | [TOMOYO_MEMORY_AUDIT] = "audit log:", | ||
2103 | [TOMOYO_MEMORY_QUERY] = "query message:", | ||
2104 | }; | ||
2105 | |||
2106 | /* Timestamp counter for last updated. */ | ||
2107 | static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; | ||
2108 | /* Counter for number of updates. */ | ||
2109 | static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; | ||
2110 | |||
2111 | /** | ||
2112 | * tomoyo_update_stat - Update statistic counters. | ||
2113 | * | ||
2114 | * @index: Index for policy type. | ||
2115 | * | ||
2116 | * Returns nothing. | ||
2117 | */ | ||
2118 | void tomoyo_update_stat(const u8 index) | ||
2119 | { | ||
2120 | struct timeval tv; | ||
2121 | do_gettimeofday(&tv); | ||
2122 | /* | ||
2123 | * I don't use atomic operations because race condition is not fatal. | ||
2124 | */ | ||
2125 | tomoyo_stat_updated[index]++; | ||
2126 | tomoyo_stat_modified[index] = tv.tv_sec; | ||
2127 | } | ||
2128 | |||
2129 | /** | ||
2130 | * tomoyo_read_stat - Read statistic data. | ||
2131 | * | ||
2132 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2133 | * | ||
2134 | * Returns nothing. | ||
2135 | */ | ||
2136 | static void tomoyo_read_stat(struct tomoyo_io_buffer *head) | ||
2137 | { | ||
2138 | u8 i; | ||
2139 | unsigned int total = 0; | ||
2140 | if (head->r.eof) | ||
2141 | return; | ||
2142 | for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { | ||
2143 | tomoyo_io_printf(head, "Policy %-30s %10u", | ||
2144 | tomoyo_policy_headers[i], | ||
2145 | tomoyo_stat_updated[i]); | ||
2146 | if (tomoyo_stat_modified[i]) { | ||
2147 | struct tomoyo_time stamp; | ||
2148 | tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); | ||
2149 | tomoyo_io_printf(head, " (Last: %04u/%02u/%02u " | ||
2150 | "%02u:%02u:%02u)", | ||
2151 | stamp.year, stamp.month, stamp.day, | ||
2152 | stamp.hour, stamp.min, stamp.sec); | ||
2153 | } | ||
2154 | tomoyo_set_lf(head); | ||
2155 | } | ||
2156 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { | ||
2157 | unsigned int used = tomoyo_memory_used[i]; | ||
2158 | total += used; | ||
2159 | tomoyo_io_printf(head, "Memory used by %-22s %10u", | ||
2160 | tomoyo_memory_headers[i], used); | ||
2161 | used = tomoyo_memory_quota[i]; | ||
2162 | if (used) | ||
2163 | tomoyo_io_printf(head, " (Quota: %10u)", used); | ||
2164 | tomoyo_set_lf(head); | ||
2165 | } | ||
2166 | tomoyo_io_printf(head, "Total memory used: %10u\n", | ||
2167 | total); | ||
2168 | head->r.eof = true; | ||
2169 | } | ||
2170 | |||
2171 | /** | ||
2172 | * tomoyo_write_stat - Set memory quota. | ||
2173 | * | ||
2174 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2175 | * | ||
2176 | * Returns 0. | ||
2177 | */ | ||
2178 | static int tomoyo_write_stat(struct tomoyo_io_buffer *head) | ||
2179 | { | ||
2180 | char *data = head->write_buf; | ||
2181 | u8 i; | ||
2182 | if (tomoyo_str_starts(&data, "Memory used by ")) | ||
2183 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) | ||
2184 | if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) | ||
2185 | sscanf(data, "%u", &tomoyo_memory_quota[i]); | ||
2186 | return 0; | ||
2187 | } | ||
2188 | |||
1788 | /** | 2189 | /** |
1789 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. | 2190 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. |
1790 | * | 2191 | * |
1791 | * @type: Type of interface. | 2192 | * @type: Type of interface. |
1792 | * @file: Pointer to "struct file". | 2193 | * @file: Pointer to "struct file". |
1793 | * | 2194 | * |
1794 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. | 2195 | * Returns 0 on success, negative value otherwise. |
1795 | * | ||
1796 | * Caller acquires tomoyo_read_lock(). | ||
1797 | */ | 2196 | */ |
1798 | int tomoyo_open_control(const u8 type, struct file *file) | 2197 | int tomoyo_open_control(const u8 type, struct file *file) |
1799 | { | 2198 | { |
@@ -1814,15 +2213,15 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1814 | head->write = tomoyo_write_exception; | 2213 | head->write = tomoyo_write_exception; |
1815 | head->read = tomoyo_read_exception; | 2214 | head->read = tomoyo_read_exception; |
1816 | break; | 2215 | break; |
2216 | case TOMOYO_AUDIT: | ||
2217 | /* /sys/kernel/security/tomoyo/audit */ | ||
2218 | head->poll = tomoyo_poll_log; | ||
2219 | head->read = tomoyo_read_log; | ||
2220 | break; | ||
1817 | case TOMOYO_SELFDOMAIN: | 2221 | case TOMOYO_SELFDOMAIN: |
1818 | /* /sys/kernel/security/tomoyo/self_domain */ | 2222 | /* /sys/kernel/security/tomoyo/self_domain */ |
1819 | head->read = tomoyo_read_self_domain; | 2223 | head->read = tomoyo_read_self_domain; |
1820 | break; | 2224 | break; |
1821 | case TOMOYO_DOMAIN_STATUS: | ||
1822 | /* /sys/kernel/security/tomoyo/.domain_status */ | ||
1823 | head->write = tomoyo_write_domain_profile; | ||
1824 | head->read = tomoyo_read_domain_profile; | ||
1825 | break; | ||
1826 | case TOMOYO_PROCESS_STATUS: | 2225 | case TOMOYO_PROCESS_STATUS: |
1827 | /* /sys/kernel/security/tomoyo/.process_status */ | 2226 | /* /sys/kernel/security/tomoyo/.process_status */ |
1828 | head->write = tomoyo_write_pid; | 2227 | head->write = tomoyo_write_pid; |
@@ -1833,11 +2232,11 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1833 | head->read = tomoyo_read_version; | 2232 | head->read = tomoyo_read_version; |
1834 | head->readbuf_size = 128; | 2233 | head->readbuf_size = 128; |
1835 | break; | 2234 | break; |
1836 | case TOMOYO_MEMINFO: | 2235 | case TOMOYO_STAT: |
1837 | /* /sys/kernel/security/tomoyo/meminfo */ | 2236 | /* /sys/kernel/security/tomoyo/stat */ |
1838 | head->write = tomoyo_write_memory_quota; | 2237 | head->write = tomoyo_write_stat; |
1839 | head->read = tomoyo_read_memory_counter; | 2238 | head->read = tomoyo_read_stat; |
1840 | head->readbuf_size = 512; | 2239 | head->readbuf_size = 1024; |
1841 | break; | 2240 | break; |
1842 | case TOMOYO_PROFILE: | 2241 | case TOMOYO_PROFILE: |
1843 | /* /sys/kernel/security/tomoyo/profile */ | 2242 | /* /sys/kernel/security/tomoyo/profile */ |
@@ -1887,26 +2286,16 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1887 | return -ENOMEM; | 2286 | return -ENOMEM; |
1888 | } | 2287 | } |
1889 | } | 2288 | } |
1890 | if (type != TOMOYO_QUERY) | ||
1891 | head->reader_idx = tomoyo_read_lock(); | ||
1892 | file->private_data = head; | ||
1893 | /* | ||
1894 | * Call the handler now if the file is | ||
1895 | * /sys/kernel/security/tomoyo/self_domain | ||
1896 | * so that the user can use | ||
1897 | * cat < /sys/kernel/security/tomoyo/self_domain" | ||
1898 | * to know the current process's domainname. | ||
1899 | */ | ||
1900 | if (type == TOMOYO_SELFDOMAIN) | ||
1901 | tomoyo_read_control(file, NULL, 0); | ||
1902 | /* | 2289 | /* |
1903 | * If the file is /sys/kernel/security/tomoyo/query , increment the | 2290 | * If the file is /sys/kernel/security/tomoyo/query , increment the |
1904 | * observer counter. | 2291 | * observer counter. |
1905 | * The obserber counter is used by tomoyo_supervisor() to see if | 2292 | * The obserber counter is used by tomoyo_supervisor() to see if |
1906 | * there is some process monitoring /sys/kernel/security/tomoyo/query. | 2293 | * there is some process monitoring /sys/kernel/security/tomoyo/query. |
1907 | */ | 2294 | */ |
1908 | else if (type == TOMOYO_QUERY) | 2295 | if (type == TOMOYO_QUERY) |
1909 | atomic_inc(&tomoyo_query_observers); | 2296 | atomic_inc(&tomoyo_query_observers); |
2297 | file->private_data = head; | ||
2298 | tomoyo_notify_gc(head, true); | ||
1910 | return 0; | 2299 | return 0; |
1911 | } | 2300 | } |
1912 | 2301 | ||
@@ -1917,7 +2306,8 @@ int tomoyo_open_control(const u8 type, struct file *file) | |||
1917 | * @wait: Pointer to "poll_table". | 2306 | * @wait: Pointer to "poll_table". |
1918 | * | 2307 | * |
1919 | * Waits for read readiness. | 2308 | * Waits for read readiness. |
1920 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd . | 2309 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and |
2310 | * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd. | ||
1921 | */ | 2311 | */ |
1922 | int tomoyo_poll_control(struct file *file, poll_table *wait) | 2312 | int tomoyo_poll_control(struct file *file, poll_table *wait) |
1923 | { | 2313 | { |
@@ -1928,21 +2318,58 @@ int tomoyo_poll_control(struct file *file, poll_table *wait) | |||
1928 | } | 2318 | } |
1929 | 2319 | ||
1930 | /** | 2320 | /** |
2321 | * tomoyo_set_namespace_cursor - Set namespace to read. | ||
2322 | * | ||
2323 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2324 | * | ||
2325 | * Returns nothing. | ||
2326 | */ | ||
2327 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) | ||
2328 | { | ||
2329 | struct list_head *ns; | ||
2330 | if (head->type != TOMOYO_EXCEPTIONPOLICY && | ||
2331 | head->type != TOMOYO_PROFILE) | ||
2332 | return; | ||
2333 | /* | ||
2334 | * If this is the first read, or reading previous namespace finished | ||
2335 | * and has more namespaces to read, update the namespace cursor. | ||
2336 | */ | ||
2337 | ns = head->r.ns; | ||
2338 | if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) { | ||
2339 | /* Clearing is OK because tomoyo_flush() returned true. */ | ||
2340 | memset(&head->r, 0, sizeof(head->r)); | ||
2341 | head->r.ns = ns ? ns->next : tomoyo_namespace_list.next; | ||
2342 | } | ||
2343 | } | ||
2344 | |||
2345 | /** | ||
2346 | * tomoyo_has_more_namespace - Check for unread namespaces. | ||
2347 | * | ||
2348 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
2349 | * | ||
2350 | * Returns true if we have more entries to print, false otherwise. | ||
2351 | */ | ||
2352 | static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head) | ||
2353 | { | ||
2354 | return (head->type == TOMOYO_EXCEPTIONPOLICY || | ||
2355 | head->type == TOMOYO_PROFILE) && head->r.eof && | ||
2356 | head->r.ns->next != &tomoyo_namespace_list; | ||
2357 | } | ||
2358 | |||
2359 | /** | ||
1931 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. | 2360 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. |
1932 | * | 2361 | * |
1933 | * @file: Pointer to "struct file". | 2362 | * @head: Pointer to "struct tomoyo_io_buffer". |
1934 | * @buffer: Poiner to buffer to write to. | 2363 | * @buffer: Poiner to buffer to write to. |
1935 | * @buffer_len: Size of @buffer. | 2364 | * @buffer_len: Size of @buffer. |
1936 | * | 2365 | * |
1937 | * Returns bytes read on success, negative value otherwise. | 2366 | * Returns bytes read on success, negative value otherwise. |
1938 | * | ||
1939 | * Caller holds tomoyo_read_lock(). | ||
1940 | */ | 2367 | */ |
1941 | int tomoyo_read_control(struct file *file, char __user *buffer, | 2368 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, |
1942 | const int buffer_len) | 2369 | const int buffer_len) |
1943 | { | 2370 | { |
1944 | int len; | 2371 | int len; |
1945 | struct tomoyo_io_buffer *head = file->private_data; | 2372 | int idx; |
1946 | 2373 | ||
1947 | if (!head->read) | 2374 | if (!head->read) |
1948 | return -ENOSYS; | 2375 | return -ENOSYS; |
@@ -1950,64 +2377,156 @@ int tomoyo_read_control(struct file *file, char __user *buffer, | |||
1950 | return -EINTR; | 2377 | return -EINTR; |
1951 | head->read_user_buf = buffer; | 2378 | head->read_user_buf = buffer; |
1952 | head->read_user_buf_avail = buffer_len; | 2379 | head->read_user_buf_avail = buffer_len; |
2380 | idx = tomoyo_read_lock(); | ||
1953 | if (tomoyo_flush(head)) | 2381 | if (tomoyo_flush(head)) |
1954 | /* Call the policy handler. */ | 2382 | /* Call the policy handler. */ |
1955 | head->read(head); | 2383 | do { |
1956 | tomoyo_flush(head); | 2384 | tomoyo_set_namespace_cursor(head); |
2385 | head->read(head); | ||
2386 | } while (tomoyo_flush(head) && | ||
2387 | tomoyo_has_more_namespace(head)); | ||
2388 | tomoyo_read_unlock(idx); | ||
1957 | len = head->read_user_buf - buffer; | 2389 | len = head->read_user_buf - buffer; |
1958 | mutex_unlock(&head->io_sem); | 2390 | mutex_unlock(&head->io_sem); |
1959 | return len; | 2391 | return len; |
1960 | } | 2392 | } |
1961 | 2393 | ||
1962 | /** | 2394 | /** |
2395 | * tomoyo_parse_policy - Parse a policy line. | ||
2396 | * | ||
2397 | * @head: Poiter to "struct tomoyo_io_buffer". | ||
2398 | * @line: Line to parse. | ||
2399 | * | ||
2400 | * Returns 0 on success, negative value otherwise. | ||
2401 | * | ||
2402 | * Caller holds tomoyo_read_lock(). | ||
2403 | */ | ||
2404 | static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) | ||
2405 | { | ||
2406 | /* Delete request? */ | ||
2407 | head->w.is_delete = !strncmp(line, "delete ", 7); | ||
2408 | if (head->w.is_delete) | ||
2409 | memmove(line, line + 7, strlen(line + 7) + 1); | ||
2410 | /* Selecting namespace to update. */ | ||
2411 | if (head->type == TOMOYO_EXCEPTIONPOLICY || | ||
2412 | head->type == TOMOYO_PROFILE) { | ||
2413 | if (*line == '<') { | ||
2414 | char *cp = strchr(line, ' '); | ||
2415 | if (cp) { | ||
2416 | *cp++ = '\0'; | ||
2417 | head->w.ns = tomoyo_assign_namespace(line); | ||
2418 | memmove(line, cp, strlen(cp) + 1); | ||
2419 | } else | ||
2420 | head->w.ns = NULL; | ||
2421 | } else | ||
2422 | head->w.ns = &tomoyo_kernel_namespace; | ||
2423 | /* Don't allow updating if namespace is invalid. */ | ||
2424 | if (!head->w.ns) | ||
2425 | return -ENOENT; | ||
2426 | } | ||
2427 | /* Do the update. */ | ||
2428 | return head->write(head); | ||
2429 | } | ||
2430 | |||
2431 | /** | ||
1963 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. | 2432 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. |
1964 | * | 2433 | * |
1965 | * @file: Pointer to "struct file". | 2434 | * @head: Pointer to "struct tomoyo_io_buffer". |
1966 | * @buffer: Pointer to buffer to read from. | 2435 | * @buffer: Pointer to buffer to read from. |
1967 | * @buffer_len: Size of @buffer. | 2436 | * @buffer_len: Size of @buffer. |
1968 | * | 2437 | * |
1969 | * Returns @buffer_len on success, negative value otherwise. | 2438 | * Returns @buffer_len on success, negative value otherwise. |
1970 | * | ||
1971 | * Caller holds tomoyo_read_lock(). | ||
1972 | */ | 2439 | */ |
1973 | int tomoyo_write_control(struct file *file, const char __user *buffer, | 2440 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, |
1974 | const int buffer_len) | 2441 | const char __user *buffer, const int buffer_len) |
1975 | { | 2442 | { |
1976 | struct tomoyo_io_buffer *head = file->private_data; | ||
1977 | int error = buffer_len; | 2443 | int error = buffer_len; |
1978 | int avail_len = buffer_len; | 2444 | size_t avail_len = buffer_len; |
1979 | char *cp0 = head->write_buf; | 2445 | char *cp0 = head->write_buf; |
1980 | 2446 | int idx; | |
1981 | if (!head->write) | 2447 | if (!head->write) |
1982 | return -ENOSYS; | 2448 | return -ENOSYS; |
1983 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) | 2449 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
1984 | return -EFAULT; | 2450 | return -EFAULT; |
1985 | /* Don't allow updating policies by non manager programs. */ | ||
1986 | if (head->write != tomoyo_write_pid && | ||
1987 | head->write != tomoyo_write_domain && !tomoyo_manager()) | ||
1988 | return -EPERM; | ||
1989 | if (mutex_lock_interruptible(&head->io_sem)) | 2451 | if (mutex_lock_interruptible(&head->io_sem)) |
1990 | return -EINTR; | 2452 | return -EINTR; |
2453 | idx = tomoyo_read_lock(); | ||
1991 | /* Read a line and dispatch it to the policy handler. */ | 2454 | /* Read a line and dispatch it to the policy handler. */ |
1992 | while (avail_len > 0) { | 2455 | while (avail_len > 0) { |
1993 | char c; | 2456 | char c; |
1994 | if (head->write_avail >= head->writebuf_size - 1) { | 2457 | if (head->w.avail >= head->writebuf_size - 1) { |
1995 | error = -ENOMEM; | 2458 | const int len = head->writebuf_size * 2; |
1996 | break; | 2459 | char *cp = kzalloc(len, GFP_NOFS); |
1997 | } else if (get_user(c, buffer)) { | 2460 | if (!cp) { |
2461 | error = -ENOMEM; | ||
2462 | break; | ||
2463 | } | ||
2464 | memmove(cp, cp0, head->w.avail); | ||
2465 | kfree(cp0); | ||
2466 | head->write_buf = cp; | ||
2467 | cp0 = cp; | ||
2468 | head->writebuf_size = len; | ||
2469 | } | ||
2470 | if (get_user(c, buffer)) { | ||
1998 | error = -EFAULT; | 2471 | error = -EFAULT; |
1999 | break; | 2472 | break; |
2000 | } | 2473 | } |
2001 | buffer++; | 2474 | buffer++; |
2002 | avail_len--; | 2475 | avail_len--; |
2003 | cp0[head->write_avail++] = c; | 2476 | cp0[head->w.avail++] = c; |
2004 | if (c != '\n') | 2477 | if (c != '\n') |
2005 | continue; | 2478 | continue; |
2006 | cp0[head->write_avail - 1] = '\0'; | 2479 | cp0[head->w.avail - 1] = '\0'; |
2007 | head->write_avail = 0; | 2480 | head->w.avail = 0; |
2008 | tomoyo_normalize_line(cp0); | 2481 | tomoyo_normalize_line(cp0); |
2009 | head->write(head); | 2482 | if (!strcmp(cp0, "reset")) { |
2483 | head->w.ns = &tomoyo_kernel_namespace; | ||
2484 | head->w.domain = NULL; | ||
2485 | memset(&head->r, 0, sizeof(head->r)); | ||
2486 | continue; | ||
2487 | } | ||
2488 | /* Don't allow updating policies by non manager programs. */ | ||
2489 | switch (head->type) { | ||
2490 | case TOMOYO_PROCESS_STATUS: | ||
2491 | /* This does not write anything. */ | ||
2492 | break; | ||
2493 | case TOMOYO_DOMAINPOLICY: | ||
2494 | if (tomoyo_select_domain(head, cp0)) | ||
2495 | continue; | ||
2496 | /* fall through */ | ||
2497 | case TOMOYO_EXCEPTIONPOLICY: | ||
2498 | if (!strcmp(cp0, "select transition_only")) { | ||
2499 | head->r.print_transition_related_only = true; | ||
2500 | continue; | ||
2501 | } | ||
2502 | /* fall through */ | ||
2503 | default: | ||
2504 | if (!tomoyo_manager()) { | ||
2505 | error = -EPERM; | ||
2506 | goto out; | ||
2507 | } | ||
2508 | } | ||
2509 | switch (tomoyo_parse_policy(head, cp0)) { | ||
2510 | case -EPERM: | ||
2511 | error = -EPERM; | ||
2512 | goto out; | ||
2513 | case 0: | ||
2514 | switch (head->type) { | ||
2515 | case TOMOYO_DOMAINPOLICY: | ||
2516 | case TOMOYO_EXCEPTIONPOLICY: | ||
2517 | case TOMOYO_STAT: | ||
2518 | case TOMOYO_PROFILE: | ||
2519 | case TOMOYO_MANAGER: | ||
2520 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | ||
2521 | break; | ||
2522 | default: | ||
2523 | break; | ||
2524 | } | ||
2525 | break; | ||
2526 | } | ||
2010 | } | 2527 | } |
2528 | out: | ||
2529 | tomoyo_read_unlock(idx); | ||
2011 | mutex_unlock(&head->io_sem); | 2530 | mutex_unlock(&head->io_sem); |
2012 | return error; | 2531 | return error; |
2013 | } | 2532 | } |
@@ -2015,35 +2534,20 @@ int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
2015 | /** | 2534 | /** |
2016 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. | 2535 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. |
2017 | * | 2536 | * |
2018 | * @file: Pointer to "struct file". | 2537 | * @head: Pointer to "struct tomoyo_io_buffer". |
2019 | * | ||
2020 | * Releases memory and returns 0. | ||
2021 | * | 2538 | * |
2022 | * Caller looses tomoyo_read_lock(). | 2539 | * Returns 0. |
2023 | */ | 2540 | */ |
2024 | int tomoyo_close_control(struct file *file) | 2541 | int tomoyo_close_control(struct tomoyo_io_buffer *head) |
2025 | { | 2542 | { |
2026 | struct tomoyo_io_buffer *head = file->private_data; | ||
2027 | const bool is_write = !!head->write_buf; | ||
2028 | |||
2029 | /* | 2543 | /* |
2030 | * If the file is /sys/kernel/security/tomoyo/query , decrement the | 2544 | * If the file is /sys/kernel/security/tomoyo/query , decrement the |
2031 | * observer counter. | 2545 | * observer counter. |
2032 | */ | 2546 | */ |
2033 | if (head->type == TOMOYO_QUERY) | 2547 | if (head->type == TOMOYO_QUERY && |
2034 | atomic_dec(&tomoyo_query_observers); | 2548 | atomic_dec_and_test(&tomoyo_query_observers)) |
2035 | else | 2549 | wake_up_all(&tomoyo_answer_wait); |
2036 | tomoyo_read_unlock(head->reader_idx); | 2550 | tomoyo_notify_gc(head, false); |
2037 | /* Release memory used for policy I/O. */ | ||
2038 | kfree(head->read_buf); | ||
2039 | head->read_buf = NULL; | ||
2040 | kfree(head->write_buf); | ||
2041 | head->write_buf = NULL; | ||
2042 | kfree(head); | ||
2043 | head = NULL; | ||
2044 | file->private_data = NULL; | ||
2045 | if (is_write) | ||
2046 | tomoyo_run_gc(); | ||
2047 | return 0; | 2551 | return 0; |
2048 | } | 2552 | } |
2049 | 2553 | ||
@@ -2055,27 +2559,90 @@ void tomoyo_check_profile(void) | |||
2055 | struct tomoyo_domain_info *domain; | 2559 | struct tomoyo_domain_info *domain; |
2056 | const int idx = tomoyo_read_lock(); | 2560 | const int idx = tomoyo_read_lock(); |
2057 | tomoyo_policy_loaded = true; | 2561 | tomoyo_policy_loaded = true; |
2058 | /* Check all profiles currently assigned to domains are defined. */ | 2562 | printk(KERN_INFO "TOMOYO: 2.4.0\n"); |
2059 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 2563 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
2060 | const u8 profile = domain->profile; | 2564 | const u8 profile = domain->profile; |
2061 | if (tomoyo_profile_ptr[profile]) | 2565 | const struct tomoyo_policy_namespace *ns = domain->ns; |
2566 | if (ns->profile_version != 20100903) | ||
2567 | printk(KERN_ERR | ||
2568 | "Profile version %u is not supported.\n", | ||
2569 | ns->profile_version); | ||
2570 | else if (!ns->profile_ptr[profile]) | ||
2571 | printk(KERN_ERR | ||
2572 | "Profile %u (used by '%s') is not defined.\n", | ||
2573 | profile, domain->domainname->name); | ||
2574 | else | ||
2062 | continue; | 2575 | continue; |
2063 | printk(KERN_ERR "You need to define profile %u before using it.\n", | 2576 | printk(KERN_ERR |
2064 | profile); | 2577 | "Userland tools for TOMOYO 2.4 must be installed and " |
2065 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | 2578 | "policy must be initialized.\n"); |
2579 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " | ||
2066 | "for more information.\n"); | 2580 | "for more information.\n"); |
2067 | panic("Profile %u (used by '%s') not defined.\n", | 2581 | panic("STOP!"); |
2068 | profile, domain->domainname->name); | ||
2069 | } | 2582 | } |
2070 | tomoyo_read_unlock(idx); | 2583 | tomoyo_read_unlock(idx); |
2071 | if (tomoyo_profile_version != 20090903) { | ||
2072 | printk(KERN_ERR "You need to install userland programs for " | ||
2073 | "TOMOYO 2.3 and initialize policy configuration.\n"); | ||
2074 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2075 | "for more information.\n"); | ||
2076 | panic("Profile version %u is not supported.\n", | ||
2077 | tomoyo_profile_version); | ||
2078 | } | ||
2079 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); | ||
2080 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2584 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2081 | } | 2585 | } |
2586 | |||
2587 | /** | ||
2588 | * tomoyo_load_builtin_policy - Load built-in policy. | ||
2589 | * | ||
2590 | * Returns nothing. | ||
2591 | */ | ||
2592 | void __init tomoyo_load_builtin_policy(void) | ||
2593 | { | ||
2594 | /* | ||
2595 | * This include file is manually created and contains built-in policy | ||
2596 | * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy", | ||
2597 | * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager", | ||
2598 | * "tomoyo_builtin_stat" in the form of "static char [] __initdata". | ||
2599 | */ | ||
2600 | #include "builtin-policy.h" | ||
2601 | u8 i; | ||
2602 | const int idx = tomoyo_read_lock(); | ||
2603 | for (i = 0; i < 5; i++) { | ||
2604 | struct tomoyo_io_buffer head = { }; | ||
2605 | char *start = ""; | ||
2606 | switch (i) { | ||
2607 | case 0: | ||
2608 | start = tomoyo_builtin_profile; | ||
2609 | head.type = TOMOYO_PROFILE; | ||
2610 | head.write = tomoyo_write_profile; | ||
2611 | break; | ||
2612 | case 1: | ||
2613 | start = tomoyo_builtin_exception_policy; | ||
2614 | head.type = TOMOYO_EXCEPTIONPOLICY; | ||
2615 | head.write = tomoyo_write_exception; | ||
2616 | break; | ||
2617 | case 2: | ||
2618 | start = tomoyo_builtin_domain_policy; | ||
2619 | head.type = TOMOYO_DOMAINPOLICY; | ||
2620 | head.write = tomoyo_write_domain; | ||
2621 | break; | ||
2622 | case 3: | ||
2623 | start = tomoyo_builtin_manager; | ||
2624 | head.type = TOMOYO_MANAGER; | ||
2625 | head.write = tomoyo_write_manager; | ||
2626 | break; | ||
2627 | case 4: | ||
2628 | start = tomoyo_builtin_stat; | ||
2629 | head.type = TOMOYO_STAT; | ||
2630 | head.write = tomoyo_write_stat; | ||
2631 | break; | ||
2632 | } | ||
2633 | while (1) { | ||
2634 | char *end = strchr(start, '\n'); | ||
2635 | if (!end) | ||
2636 | break; | ||
2637 | *end = '\0'; | ||
2638 | tomoyo_normalize_line(start); | ||
2639 | head.write_buf = start; | ||
2640 | tomoyo_parse_policy(&head, start); | ||
2641 | start = end + 1; | ||
2642 | } | ||
2643 | } | ||
2644 | tomoyo_read_unlock(idx); | ||
2645 | #ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
2646 | tomoyo_check_profile(); | ||
2647 | #endif | ||
2648 | } | ||
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 7c66bd898782..f7fbaa66e443 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -21,7 +21,8 @@ | |||
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/cred.h> | 22 | #include <linux/cred.h> |
23 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
24 | struct linux_binprm; | 24 | #include <linux/binfmts.h> |
25 | #include <linux/highmem.h> | ||
25 | 26 | ||
26 | /********** Constants definitions. **********/ | 27 | /********** Constants definitions. **********/ |
27 | 28 | ||
@@ -38,66 +39,149 @@ struct linux_binprm; | |||
38 | /* Profile number is an integer between 0 and 255. */ | 39 | /* Profile number is an integer between 0 and 255. */ |
39 | #define TOMOYO_MAX_PROFILES 256 | 40 | #define TOMOYO_MAX_PROFILES 256 |
40 | 41 | ||
42 | /* Group number is an integer between 0 and 255. */ | ||
43 | #define TOMOYO_MAX_ACL_GROUPS 256 | ||
44 | |||
45 | /* Index numbers for "struct tomoyo_condition". */ | ||
46 | enum tomoyo_conditions_index { | ||
47 | TOMOYO_TASK_UID, /* current_uid() */ | ||
48 | TOMOYO_TASK_EUID, /* current_euid() */ | ||
49 | TOMOYO_TASK_SUID, /* current_suid() */ | ||
50 | TOMOYO_TASK_FSUID, /* current_fsuid() */ | ||
51 | TOMOYO_TASK_GID, /* current_gid() */ | ||
52 | TOMOYO_TASK_EGID, /* current_egid() */ | ||
53 | TOMOYO_TASK_SGID, /* current_sgid() */ | ||
54 | TOMOYO_TASK_FSGID, /* current_fsgid() */ | ||
55 | TOMOYO_TASK_PID, /* sys_getpid() */ | ||
56 | TOMOYO_TASK_PPID, /* sys_getppid() */ | ||
57 | TOMOYO_EXEC_ARGC, /* "struct linux_binprm *"->argc */ | ||
58 | TOMOYO_EXEC_ENVC, /* "struct linux_binprm *"->envc */ | ||
59 | TOMOYO_TYPE_IS_SOCKET, /* S_IFSOCK */ | ||
60 | TOMOYO_TYPE_IS_SYMLINK, /* S_IFLNK */ | ||
61 | TOMOYO_TYPE_IS_FILE, /* S_IFREG */ | ||
62 | TOMOYO_TYPE_IS_BLOCK_DEV, /* S_IFBLK */ | ||
63 | TOMOYO_TYPE_IS_DIRECTORY, /* S_IFDIR */ | ||
64 | TOMOYO_TYPE_IS_CHAR_DEV, /* S_IFCHR */ | ||
65 | TOMOYO_TYPE_IS_FIFO, /* S_IFIFO */ | ||
66 | TOMOYO_MODE_SETUID, /* S_ISUID */ | ||
67 | TOMOYO_MODE_SETGID, /* S_ISGID */ | ||
68 | TOMOYO_MODE_STICKY, /* S_ISVTX */ | ||
69 | TOMOYO_MODE_OWNER_READ, /* S_IRUSR */ | ||
70 | TOMOYO_MODE_OWNER_WRITE, /* S_IWUSR */ | ||
71 | TOMOYO_MODE_OWNER_EXECUTE, /* S_IXUSR */ | ||
72 | TOMOYO_MODE_GROUP_READ, /* S_IRGRP */ | ||
73 | TOMOYO_MODE_GROUP_WRITE, /* S_IWGRP */ | ||
74 | TOMOYO_MODE_GROUP_EXECUTE, /* S_IXGRP */ | ||
75 | TOMOYO_MODE_OTHERS_READ, /* S_IROTH */ | ||
76 | TOMOYO_MODE_OTHERS_WRITE, /* S_IWOTH */ | ||
77 | TOMOYO_MODE_OTHERS_EXECUTE, /* S_IXOTH */ | ||
78 | TOMOYO_EXEC_REALPATH, | ||
79 | TOMOYO_SYMLINK_TARGET, | ||
80 | TOMOYO_PATH1_UID, | ||
81 | TOMOYO_PATH1_GID, | ||
82 | TOMOYO_PATH1_INO, | ||
83 | TOMOYO_PATH1_MAJOR, | ||
84 | TOMOYO_PATH1_MINOR, | ||
85 | TOMOYO_PATH1_PERM, | ||
86 | TOMOYO_PATH1_TYPE, | ||
87 | TOMOYO_PATH1_DEV_MAJOR, | ||
88 | TOMOYO_PATH1_DEV_MINOR, | ||
89 | TOMOYO_PATH2_UID, | ||
90 | TOMOYO_PATH2_GID, | ||
91 | TOMOYO_PATH2_INO, | ||
92 | TOMOYO_PATH2_MAJOR, | ||
93 | TOMOYO_PATH2_MINOR, | ||
94 | TOMOYO_PATH2_PERM, | ||
95 | TOMOYO_PATH2_TYPE, | ||
96 | TOMOYO_PATH2_DEV_MAJOR, | ||
97 | TOMOYO_PATH2_DEV_MINOR, | ||
98 | TOMOYO_PATH1_PARENT_UID, | ||
99 | TOMOYO_PATH1_PARENT_GID, | ||
100 | TOMOYO_PATH1_PARENT_INO, | ||
101 | TOMOYO_PATH1_PARENT_PERM, | ||
102 | TOMOYO_PATH2_PARENT_UID, | ||
103 | TOMOYO_PATH2_PARENT_GID, | ||
104 | TOMOYO_PATH2_PARENT_INO, | ||
105 | TOMOYO_PATH2_PARENT_PERM, | ||
106 | TOMOYO_MAX_CONDITION_KEYWORD, | ||
107 | TOMOYO_NUMBER_UNION, | ||
108 | TOMOYO_NAME_UNION, | ||
109 | TOMOYO_ARGV_ENTRY, | ||
110 | TOMOYO_ENVP_ENTRY, | ||
111 | }; | ||
112 | |||
113 | |||
114 | /* Index numbers for stat(). */ | ||
115 | enum tomoyo_path_stat_index { | ||
116 | /* Do not change this order. */ | ||
117 | TOMOYO_PATH1, | ||
118 | TOMOYO_PATH1_PARENT, | ||
119 | TOMOYO_PATH2, | ||
120 | TOMOYO_PATH2_PARENT, | ||
121 | TOMOYO_MAX_PATH_STAT | ||
122 | }; | ||
123 | |||
124 | /* Index numbers for operation mode. */ | ||
41 | enum tomoyo_mode_index { | 125 | enum tomoyo_mode_index { |
42 | TOMOYO_CONFIG_DISABLED, | 126 | TOMOYO_CONFIG_DISABLED, |
43 | TOMOYO_CONFIG_LEARNING, | 127 | TOMOYO_CONFIG_LEARNING, |
44 | TOMOYO_CONFIG_PERMISSIVE, | 128 | TOMOYO_CONFIG_PERMISSIVE, |
45 | TOMOYO_CONFIG_ENFORCING, | 129 | TOMOYO_CONFIG_ENFORCING, |
46 | TOMOYO_CONFIG_USE_DEFAULT = 255 | 130 | TOMOYO_CONFIG_MAX_MODE, |
131 | TOMOYO_CONFIG_WANT_REJECT_LOG = 64, | ||
132 | TOMOYO_CONFIG_WANT_GRANT_LOG = 128, | ||
133 | TOMOYO_CONFIG_USE_DEFAULT = 255, | ||
47 | }; | 134 | }; |
48 | 135 | ||
136 | /* Index numbers for entry type. */ | ||
49 | enum tomoyo_policy_id { | 137 | enum tomoyo_policy_id { |
50 | TOMOYO_ID_GROUP, | 138 | TOMOYO_ID_GROUP, |
51 | TOMOYO_ID_PATH_GROUP, | 139 | TOMOYO_ID_PATH_GROUP, |
52 | TOMOYO_ID_NUMBER_GROUP, | 140 | TOMOYO_ID_NUMBER_GROUP, |
53 | TOMOYO_ID_TRANSITION_CONTROL, | 141 | TOMOYO_ID_TRANSITION_CONTROL, |
54 | TOMOYO_ID_AGGREGATOR, | 142 | TOMOYO_ID_AGGREGATOR, |
55 | TOMOYO_ID_GLOBALLY_READABLE, | ||
56 | TOMOYO_ID_PATTERN, | ||
57 | TOMOYO_ID_NO_REWRITE, | ||
58 | TOMOYO_ID_MANAGER, | 143 | TOMOYO_ID_MANAGER, |
144 | TOMOYO_ID_CONDITION, | ||
59 | TOMOYO_ID_NAME, | 145 | TOMOYO_ID_NAME, |
60 | TOMOYO_ID_ACL, | 146 | TOMOYO_ID_ACL, |
61 | TOMOYO_ID_DOMAIN, | 147 | TOMOYO_ID_DOMAIN, |
62 | TOMOYO_MAX_POLICY | 148 | TOMOYO_MAX_POLICY |
63 | }; | 149 | }; |
64 | 150 | ||
151 | /* Index numbers for domain's attributes. */ | ||
152 | enum tomoyo_domain_info_flags_index { | ||
153 | /* Quota warnning flag. */ | ||
154 | TOMOYO_DIF_QUOTA_WARNED, | ||
155 | /* | ||
156 | * This domain was unable to create a new domain at | ||
157 | * tomoyo_find_next_domain() because the name of the domain to be | ||
158 | * created was too long or it could not allocate memory. | ||
159 | * More than one process continued execve() without domain transition. | ||
160 | */ | ||
161 | TOMOYO_DIF_TRANSITION_FAILED, | ||
162 | TOMOYO_MAX_DOMAIN_INFO_FLAGS | ||
163 | }; | ||
164 | |||
165 | /* Index numbers for group entries. */ | ||
65 | enum tomoyo_group_id { | 166 | enum tomoyo_group_id { |
66 | TOMOYO_PATH_GROUP, | 167 | TOMOYO_PATH_GROUP, |
67 | TOMOYO_NUMBER_GROUP, | 168 | TOMOYO_NUMBER_GROUP, |
68 | TOMOYO_MAX_GROUP | 169 | TOMOYO_MAX_GROUP |
69 | }; | 170 | }; |
70 | 171 | ||
71 | /* Keywords for ACLs. */ | 172 | /* Index numbers for type of numeric values. */ |
72 | #define TOMOYO_KEYWORD_AGGREGATOR "aggregator " | 173 | enum tomoyo_value_type { |
73 | #define TOMOYO_KEYWORD_ALLOW_MOUNT "allow_mount " | 174 | TOMOYO_VALUE_TYPE_INVALID, |
74 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | 175 | TOMOYO_VALUE_TYPE_DECIMAL, |
75 | #define TOMOYO_KEYWORD_DELETE "delete " | 176 | TOMOYO_VALUE_TYPE_OCTAL, |
76 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | 177 | TOMOYO_VALUE_TYPE_HEXADECIMAL, |
77 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " | 178 | }; |
78 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " | ||
79 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | ||
80 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | ||
81 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | ||
82 | #define TOMOYO_KEYWORD_PATH_GROUP "path_group " | ||
83 | #define TOMOYO_KEYWORD_NUMBER_GROUP "number_group " | ||
84 | #define TOMOYO_KEYWORD_SELECT "select " | ||
85 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | ||
86 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | ||
87 | #define TOMOYO_KEYWORD_QUOTA_EXCEEDED "quota_exceeded" | ||
88 | #define TOMOYO_KEYWORD_TRANSITION_FAILED "transition_failed" | ||
89 | /* A domain definition starts with <kernel>. */ | ||
90 | #define TOMOYO_ROOT_NAME "<kernel>" | ||
91 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | ||
92 | |||
93 | /* Value type definition. */ | ||
94 | #define TOMOYO_VALUE_TYPE_INVALID 0 | ||
95 | #define TOMOYO_VALUE_TYPE_DECIMAL 1 | ||
96 | #define TOMOYO_VALUE_TYPE_OCTAL 2 | ||
97 | #define TOMOYO_VALUE_TYPE_HEXADECIMAL 3 | ||
98 | 179 | ||
180 | /* Index numbers for domain transition control keywords. */ | ||
99 | enum tomoyo_transition_type { | 181 | enum tomoyo_transition_type { |
100 | /* Do not change this order, */ | 182 | /* Do not change this order, */ |
183 | TOMOYO_TRANSITION_CONTROL_NO_RESET, | ||
184 | TOMOYO_TRANSITION_CONTROL_RESET, | ||
101 | TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE, | 185 | TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE, |
102 | TOMOYO_TRANSITION_CONTROL_INITIALIZE, | 186 | TOMOYO_TRANSITION_CONTROL_INITIALIZE, |
103 | TOMOYO_TRANSITION_CONTROL_NO_KEEP, | 187 | TOMOYO_TRANSITION_CONTROL_NO_KEEP, |
@@ -114,35 +198,29 @@ enum tomoyo_acl_entry_type_index { | |||
114 | TOMOYO_TYPE_MOUNT_ACL, | 198 | TOMOYO_TYPE_MOUNT_ACL, |
115 | }; | 199 | }; |
116 | 200 | ||
117 | /* Index numbers for File Controls. */ | 201 | /* Index numbers for access controls with one pathname. */ |
118 | |||
119 | /* | ||
120 | * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically | ||
121 | * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set. | ||
122 | * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if | ||
123 | * TOMOYO_TYPE_READ_WRITE is set. | ||
124 | * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ | ||
125 | * or TOMOYO_TYPE_WRITE is cleared. | ||
126 | * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if | ||
127 | * TOMOYO_TYPE_READ_WRITE is cleared. | ||
128 | */ | ||
129 | |||
130 | enum tomoyo_path_acl_index { | 202 | enum tomoyo_path_acl_index { |
131 | TOMOYO_TYPE_READ_WRITE, | ||
132 | TOMOYO_TYPE_EXECUTE, | 203 | TOMOYO_TYPE_EXECUTE, |
133 | TOMOYO_TYPE_READ, | 204 | TOMOYO_TYPE_READ, |
134 | TOMOYO_TYPE_WRITE, | 205 | TOMOYO_TYPE_WRITE, |
206 | TOMOYO_TYPE_APPEND, | ||
135 | TOMOYO_TYPE_UNLINK, | 207 | TOMOYO_TYPE_UNLINK, |
208 | TOMOYO_TYPE_GETATTR, | ||
136 | TOMOYO_TYPE_RMDIR, | 209 | TOMOYO_TYPE_RMDIR, |
137 | TOMOYO_TYPE_TRUNCATE, | 210 | TOMOYO_TYPE_TRUNCATE, |
138 | TOMOYO_TYPE_SYMLINK, | 211 | TOMOYO_TYPE_SYMLINK, |
139 | TOMOYO_TYPE_REWRITE, | ||
140 | TOMOYO_TYPE_CHROOT, | 212 | TOMOYO_TYPE_CHROOT, |
141 | TOMOYO_TYPE_UMOUNT, | 213 | TOMOYO_TYPE_UMOUNT, |
142 | TOMOYO_MAX_PATH_OPERATION | 214 | TOMOYO_MAX_PATH_OPERATION |
143 | }; | 215 | }; |
144 | 216 | ||
145 | #define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE)) | 217 | /* Index numbers for /sys/kernel/security/tomoyo/stat interface. */ |
218 | enum tomoyo_memory_stat_type { | ||
219 | TOMOYO_MEMORY_POLICY, | ||
220 | TOMOYO_MEMORY_AUDIT, | ||
221 | TOMOYO_MEMORY_QUERY, | ||
222 | TOMOYO_MAX_MEMORY_STAT | ||
223 | }; | ||
146 | 224 | ||
147 | enum tomoyo_mkdev_acl_index { | 225 | enum tomoyo_mkdev_acl_index { |
148 | TOMOYO_TYPE_MKBLOCK, | 226 | TOMOYO_TYPE_MKBLOCK, |
@@ -150,6 +228,7 @@ enum tomoyo_mkdev_acl_index { | |||
150 | TOMOYO_MAX_MKDEV_OPERATION | 228 | TOMOYO_MAX_MKDEV_OPERATION |
151 | }; | 229 | }; |
152 | 230 | ||
231 | /* Index numbers for access controls with two pathnames. */ | ||
153 | enum tomoyo_path2_acl_index { | 232 | enum tomoyo_path2_acl_index { |
154 | TOMOYO_TYPE_LINK, | 233 | TOMOYO_TYPE_LINK, |
155 | TOMOYO_TYPE_RENAME, | 234 | TOMOYO_TYPE_RENAME, |
@@ -157,6 +236,7 @@ enum tomoyo_path2_acl_index { | |||
157 | TOMOYO_MAX_PATH2_OPERATION | 236 | TOMOYO_MAX_PATH2_OPERATION |
158 | }; | 237 | }; |
159 | 238 | ||
239 | /* Index numbers for access controls with one pathname and one number. */ | ||
160 | enum tomoyo_path_number_acl_index { | 240 | enum tomoyo_path_number_acl_index { |
161 | TOMOYO_TYPE_CREATE, | 241 | TOMOYO_TYPE_CREATE, |
162 | TOMOYO_TYPE_MKDIR, | 242 | TOMOYO_TYPE_MKDIR, |
@@ -169,31 +249,45 @@ enum tomoyo_path_number_acl_index { | |||
169 | TOMOYO_MAX_PATH_NUMBER_OPERATION | 249 | TOMOYO_MAX_PATH_NUMBER_OPERATION |
170 | }; | 250 | }; |
171 | 251 | ||
252 | /* Index numbers for /sys/kernel/security/tomoyo/ interfaces. */ | ||
172 | enum tomoyo_securityfs_interface_index { | 253 | enum tomoyo_securityfs_interface_index { |
173 | TOMOYO_DOMAINPOLICY, | 254 | TOMOYO_DOMAINPOLICY, |
174 | TOMOYO_EXCEPTIONPOLICY, | 255 | TOMOYO_EXCEPTIONPOLICY, |
175 | TOMOYO_DOMAIN_STATUS, | ||
176 | TOMOYO_PROCESS_STATUS, | 256 | TOMOYO_PROCESS_STATUS, |
177 | TOMOYO_MEMINFO, | 257 | TOMOYO_STAT, |
178 | TOMOYO_SELFDOMAIN, | 258 | TOMOYO_SELFDOMAIN, |
259 | TOMOYO_AUDIT, | ||
179 | TOMOYO_VERSION, | 260 | TOMOYO_VERSION, |
180 | TOMOYO_PROFILE, | 261 | TOMOYO_PROFILE, |
181 | TOMOYO_QUERY, | 262 | TOMOYO_QUERY, |
182 | TOMOYO_MANAGER | 263 | TOMOYO_MANAGER |
183 | }; | 264 | }; |
184 | 265 | ||
266 | /* Index numbers for special mount operations. */ | ||
267 | enum tomoyo_special_mount { | ||
268 | TOMOYO_MOUNT_BIND, /* mount --bind /source /dest */ | ||
269 | TOMOYO_MOUNT_MOVE, /* mount --move /old /new */ | ||
270 | TOMOYO_MOUNT_REMOUNT, /* mount -o remount /dir */ | ||
271 | TOMOYO_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */ | ||
272 | TOMOYO_MOUNT_MAKE_PRIVATE, /* mount --make-private /dir */ | ||
273 | TOMOYO_MOUNT_MAKE_SLAVE, /* mount --make-slave /dir */ | ||
274 | TOMOYO_MOUNT_MAKE_SHARED, /* mount --make-shared /dir */ | ||
275 | TOMOYO_MAX_SPECIAL_MOUNT | ||
276 | }; | ||
277 | |||
278 | /* Index numbers for functionality. */ | ||
185 | enum tomoyo_mac_index { | 279 | enum tomoyo_mac_index { |
186 | TOMOYO_MAC_FILE_EXECUTE, | 280 | TOMOYO_MAC_FILE_EXECUTE, |
187 | TOMOYO_MAC_FILE_OPEN, | 281 | TOMOYO_MAC_FILE_OPEN, |
188 | TOMOYO_MAC_FILE_CREATE, | 282 | TOMOYO_MAC_FILE_CREATE, |
189 | TOMOYO_MAC_FILE_UNLINK, | 283 | TOMOYO_MAC_FILE_UNLINK, |
284 | TOMOYO_MAC_FILE_GETATTR, | ||
190 | TOMOYO_MAC_FILE_MKDIR, | 285 | TOMOYO_MAC_FILE_MKDIR, |
191 | TOMOYO_MAC_FILE_RMDIR, | 286 | TOMOYO_MAC_FILE_RMDIR, |
192 | TOMOYO_MAC_FILE_MKFIFO, | 287 | TOMOYO_MAC_FILE_MKFIFO, |
193 | TOMOYO_MAC_FILE_MKSOCK, | 288 | TOMOYO_MAC_FILE_MKSOCK, |
194 | TOMOYO_MAC_FILE_TRUNCATE, | 289 | TOMOYO_MAC_FILE_TRUNCATE, |
195 | TOMOYO_MAC_FILE_SYMLINK, | 290 | TOMOYO_MAC_FILE_SYMLINK, |
196 | TOMOYO_MAC_FILE_REWRITE, | ||
197 | TOMOYO_MAC_FILE_MKBLOCK, | 291 | TOMOYO_MAC_FILE_MKBLOCK, |
198 | TOMOYO_MAC_FILE_MKCHAR, | 292 | TOMOYO_MAC_FILE_MKCHAR, |
199 | TOMOYO_MAC_FILE_LINK, | 293 | TOMOYO_MAC_FILE_LINK, |
@@ -209,38 +303,66 @@ enum tomoyo_mac_index { | |||
209 | TOMOYO_MAX_MAC_INDEX | 303 | TOMOYO_MAX_MAC_INDEX |
210 | }; | 304 | }; |
211 | 305 | ||
306 | /* Index numbers for category of functionality. */ | ||
212 | enum tomoyo_mac_category_index { | 307 | enum tomoyo_mac_category_index { |
213 | TOMOYO_MAC_CATEGORY_FILE, | 308 | TOMOYO_MAC_CATEGORY_FILE, |
214 | TOMOYO_MAX_MAC_CATEGORY_INDEX | 309 | TOMOYO_MAX_MAC_CATEGORY_INDEX |
215 | }; | 310 | }; |
216 | 311 | ||
217 | #define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */ | ||
218 | |||
219 | /********** Structure definitions. **********/ | ||
220 | |||
221 | /* | 312 | /* |
222 | * tomoyo_acl_head is a structure which is used for holding elements not in | 313 | * Retry this request. Returned by tomoyo_supervisor() if policy violation has |
223 | * domain policy. | 314 | * occurred in enforcing mode and the userspace daemon decided to retry. |
224 | * It has following fields. | ||
225 | * | 315 | * |
226 | * (1) "list" which is linked to tomoyo_policy_list[] . | 316 | * We must choose a positive value in order to distinguish "granted" (which is |
227 | * (2) "is_deleted" is a bool which is true if marked as deleted, false | 317 | * 0) and "rejected" (which is a negative value) and "retry". |
228 | * otherwise. | ||
229 | */ | 318 | */ |
319 | #define TOMOYO_RETRY_REQUEST 1 | ||
320 | |||
321 | /* Index numbers for /sys/kernel/security/tomoyo/stat interface. */ | ||
322 | enum tomoyo_policy_stat_type { | ||
323 | /* Do not change this order. */ | ||
324 | TOMOYO_STAT_POLICY_UPDATES, | ||
325 | TOMOYO_STAT_POLICY_LEARNING, /* == TOMOYO_CONFIG_LEARNING */ | ||
326 | TOMOYO_STAT_POLICY_PERMISSIVE, /* == TOMOYO_CONFIG_PERMISSIVE */ | ||
327 | TOMOYO_STAT_POLICY_ENFORCING, /* == TOMOYO_CONFIG_ENFORCING */ | ||
328 | TOMOYO_MAX_POLICY_STAT | ||
329 | }; | ||
330 | |||
331 | /* Index numbers for profile's PREFERENCE values. */ | ||
332 | enum tomoyo_pref_index { | ||
333 | TOMOYO_PREF_MAX_AUDIT_LOG, | ||
334 | TOMOYO_PREF_MAX_LEARNING_ENTRY, | ||
335 | TOMOYO_MAX_PREF | ||
336 | }; | ||
337 | |||
338 | /********** Structure definitions. **********/ | ||
339 | |||
340 | /* Common header for holding ACL entries. */ | ||
230 | struct tomoyo_acl_head { | 341 | struct tomoyo_acl_head { |
231 | struct list_head list; | 342 | struct list_head list; |
232 | bool is_deleted; | 343 | bool is_deleted; |
233 | } __packed; | 344 | } __packed; |
234 | 345 | ||
235 | /* | 346 | /* Common header for shared entries. */ |
236 | * tomoyo_request_info is a structure which is used for holding | 347 | struct tomoyo_shared_acl_head { |
237 | * | 348 | struct list_head list; |
238 | * (1) Domain information of current process. | 349 | atomic_t users; |
239 | * (2) How many retries are made for this request. | 350 | } __packed; |
240 | * (3) Profile number used for this request. | 351 | |
241 | * (4) Access control mode of the profile. | 352 | struct tomoyo_policy_namespace; |
242 | */ | 353 | |
354 | /* Structure for request info. */ | ||
243 | struct tomoyo_request_info { | 355 | struct tomoyo_request_info { |
356 | /* | ||
357 | * For holding parameters specific to operations which deal files. | ||
358 | * NULL if not dealing files. | ||
359 | */ | ||
360 | struct tomoyo_obj_info *obj; | ||
361 | /* | ||
362 | * For holding parameters specific to execve() request. | ||
363 | * NULL if not dealing do_execve(). | ||
364 | */ | ||
365 | struct tomoyo_execve *ee; | ||
244 | struct tomoyo_domain_info *domain; | 366 | struct tomoyo_domain_info *domain; |
245 | /* For holding parameters. */ | 367 | /* For holding parameters. */ |
246 | union { | 368 | union { |
@@ -248,11 +370,13 @@ struct tomoyo_request_info { | |||
248 | const struct tomoyo_path_info *filename; | 370 | const struct tomoyo_path_info *filename; |
249 | /* For using wildcards at tomoyo_find_next_domain(). */ | 371 | /* For using wildcards at tomoyo_find_next_domain(). */ |
250 | const struct tomoyo_path_info *matched_path; | 372 | const struct tomoyo_path_info *matched_path; |
373 | /* One of values in "enum tomoyo_path_acl_index". */ | ||
251 | u8 operation; | 374 | u8 operation; |
252 | } path; | 375 | } path; |
253 | struct { | 376 | struct { |
254 | const struct tomoyo_path_info *filename1; | 377 | const struct tomoyo_path_info *filename1; |
255 | const struct tomoyo_path_info *filename2; | 378 | const struct tomoyo_path_info *filename2; |
379 | /* One of values in "enum tomoyo_path2_acl_index". */ | ||
256 | u8 operation; | 380 | u8 operation; |
257 | } path2; | 381 | } path2; |
258 | struct { | 382 | struct { |
@@ -260,11 +384,16 @@ struct tomoyo_request_info { | |||
260 | unsigned int mode; | 384 | unsigned int mode; |
261 | unsigned int major; | 385 | unsigned int major; |
262 | unsigned int minor; | 386 | unsigned int minor; |
387 | /* One of values in "enum tomoyo_mkdev_acl_index". */ | ||
263 | u8 operation; | 388 | u8 operation; |
264 | } mkdev; | 389 | } mkdev; |
265 | struct { | 390 | struct { |
266 | const struct tomoyo_path_info *filename; | 391 | const struct tomoyo_path_info *filename; |
267 | unsigned long number; | 392 | unsigned long number; |
393 | /* | ||
394 | * One of values in | ||
395 | * "enum tomoyo_path_number_acl_index". | ||
396 | */ | ||
268 | u8 operation; | 397 | u8 operation; |
269 | } path_number; | 398 | } path_number; |
270 | struct { | 399 | struct { |
@@ -283,26 +412,7 @@ struct tomoyo_request_info { | |||
283 | u8 type; | 412 | u8 type; |
284 | }; | 413 | }; |
285 | 414 | ||
286 | /* | 415 | /* Structure for holding a token. */ |
287 | * tomoyo_path_info is a structure which is used for holding a string data | ||
288 | * used by TOMOYO. | ||
289 | * This structure has several fields for supporting pattern matching. | ||
290 | * | ||
291 | * (1) "name" is the '\0' terminated string data. | ||
292 | * (2) "hash" is full_name_hash(name, strlen(name)). | ||
293 | * This allows tomoyo_pathcmp() to compare by hash before actually compare | ||
294 | * using strcmp(). | ||
295 | * (3) "const_len" is the length of the initial segment of "name" which | ||
296 | * consists entirely of non wildcard characters. In other words, the length | ||
297 | * which we can compare two strings using strncmp(). | ||
298 | * (4) "is_dir" is a bool which is true if "name" ends with "/", | ||
299 | * false otherwise. | ||
300 | * TOMOYO distinguishes directory and non-directory. A directory ends with | ||
301 | * "/" and non-directory does not end with "/". | ||
302 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard | ||
303 | * characters, false otherwise. This allows TOMOYO to use "hash" and | ||
304 | * strcmp() for string comparison if "is_patterned" is false. | ||
305 | */ | ||
306 | struct tomoyo_path_info { | 416 | struct tomoyo_path_info { |
307 | const char *name; | 417 | const char *name; |
308 | u32 hash; /* = full_name_hash(name, strlen(name)) */ | 418 | u32 hash; /* = full_name_hash(name, strlen(name)) */ |
@@ -311,36 +421,32 @@ struct tomoyo_path_info { | |||
311 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ | 421 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ |
312 | }; | 422 | }; |
313 | 423 | ||
314 | /* | 424 | /* Structure for holding string data. */ |
315 | * tomoyo_name is a structure which is used for linking | ||
316 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
317 | */ | ||
318 | struct tomoyo_name { | 425 | struct tomoyo_name { |
319 | struct list_head list; | 426 | struct tomoyo_shared_acl_head head; |
320 | atomic_t users; | ||
321 | struct tomoyo_path_info entry; | 427 | struct tomoyo_path_info entry; |
322 | }; | 428 | }; |
323 | 429 | ||
430 | /* Structure for holding a word. */ | ||
324 | struct tomoyo_name_union { | 431 | struct tomoyo_name_union { |
432 | /* Either @filename or @group is NULL. */ | ||
325 | const struct tomoyo_path_info *filename; | 433 | const struct tomoyo_path_info *filename; |
326 | struct tomoyo_group *group; | 434 | struct tomoyo_group *group; |
327 | u8 is_group; | ||
328 | }; | 435 | }; |
329 | 436 | ||
437 | /* Structure for holding a number. */ | ||
330 | struct tomoyo_number_union { | 438 | struct tomoyo_number_union { |
331 | unsigned long values[2]; | 439 | unsigned long values[2]; |
332 | struct tomoyo_group *group; | 440 | struct tomoyo_group *group; /* Maybe NULL. */ |
333 | u8 min_type; | 441 | /* One of values in "enum tomoyo_value_type". */ |
334 | u8 max_type; | 442 | u8 value_type[2]; |
335 | u8 is_group; | ||
336 | }; | 443 | }; |
337 | 444 | ||
338 | /* Structure for "path_group"/"number_group" directive. */ | 445 | /* Structure for "path_group"/"number_group" directive. */ |
339 | struct tomoyo_group { | 446 | struct tomoyo_group { |
340 | struct list_head list; | 447 | struct tomoyo_shared_acl_head head; |
341 | const struct tomoyo_path_info *group_name; | 448 | const struct tomoyo_path_info *group_name; |
342 | struct list_head member_list; | 449 | struct list_head member_list; |
343 | atomic_t users; | ||
344 | }; | 450 | }; |
345 | 451 | ||
346 | /* Structure for "path_group" directive. */ | 452 | /* Structure for "path_group" directive. */ |
@@ -355,130 +461,158 @@ struct tomoyo_number_group { | |||
355 | struct tomoyo_number_union number; | 461 | struct tomoyo_number_union number; |
356 | }; | 462 | }; |
357 | 463 | ||
358 | /* | 464 | /* Subset of "struct stat". Used by conditional ACL and audit logs. */ |
359 | * tomoyo_acl_info is a structure which is used for holding | 465 | struct tomoyo_mini_stat { |
360 | * | 466 | uid_t uid; |
361 | * (1) "list" which is linked to the ->acl_info_list of | 467 | gid_t gid; |
362 | * "struct tomoyo_domain_info" | 468 | ino_t ino; |
363 | * (2) "is_deleted" is a bool which is true if this domain is marked as | 469 | mode_t mode; |
364 | * "deleted", false otherwise. | 470 | dev_t dev; |
365 | * (3) "type" which tells type of the entry. | 471 | dev_t rdev; |
366 | * | 472 | }; |
367 | * Packing "struct tomoyo_acl_info" allows | 473 | |
368 | * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl" | 474 | /* Structure for dumping argv[] and envp[] of "struct linux_binprm". */ |
369 | * "struct tomoyo_path_number_acl" "struct tomoyo_mkdev_acl" to embed | 475 | struct tomoyo_page_dump { |
370 | * "u8" without enlarging their structure size. | 476 | struct page *page; /* Previously dumped page. */ |
371 | */ | 477 | char *data; /* Contents of "page". Size is PAGE_SIZE. */ |
478 | }; | ||
479 | |||
480 | /* Structure for attribute checks in addition to pathname checks. */ | ||
481 | struct tomoyo_obj_info { | ||
482 | /* | ||
483 | * True if tomoyo_get_attributes() was already called, false otherwise. | ||
484 | */ | ||
485 | bool validate_done; | ||
486 | /* True if @stat[] is valid. */ | ||
487 | bool stat_valid[TOMOYO_MAX_PATH_STAT]; | ||
488 | /* First pathname. Initialized with { NULL, NULL } if no path. */ | ||
489 | struct path path1; | ||
490 | /* Second pathname. Initialized with { NULL, NULL } if no path. */ | ||
491 | struct path path2; | ||
492 | /* | ||
493 | * Information on @path1, @path1's parent directory, @path2, @path2's | ||
494 | * parent directory. | ||
495 | */ | ||
496 | struct tomoyo_mini_stat stat[TOMOYO_MAX_PATH_STAT]; | ||
497 | /* | ||
498 | * Content of symbolic link to be created. NULL for operations other | ||
499 | * than symlink(). | ||
500 | */ | ||
501 | struct tomoyo_path_info *symlink_target; | ||
502 | }; | ||
503 | |||
504 | /* Structure for argv[]. */ | ||
505 | struct tomoyo_argv { | ||
506 | unsigned long index; | ||
507 | const struct tomoyo_path_info *value; | ||
508 | bool is_not; | ||
509 | }; | ||
510 | |||
511 | /* Structure for envp[]. */ | ||
512 | struct tomoyo_envp { | ||
513 | const struct tomoyo_path_info *name; | ||
514 | const struct tomoyo_path_info *value; | ||
515 | bool is_not; | ||
516 | }; | ||
517 | |||
518 | /* Structure for execve() operation. */ | ||
519 | struct tomoyo_execve { | ||
520 | struct tomoyo_request_info r; | ||
521 | struct tomoyo_obj_info obj; | ||
522 | struct linux_binprm *bprm; | ||
523 | /* For dumping argv[] and envp[]. */ | ||
524 | struct tomoyo_page_dump dump; | ||
525 | /* For temporary use. */ | ||
526 | char *tmp; /* Size is TOMOYO_EXEC_TMPSIZE bytes */ | ||
527 | }; | ||
528 | |||
529 | /* Structure for entries which follows "struct tomoyo_condition". */ | ||
530 | struct tomoyo_condition_element { | ||
531 | /* | ||
532 | * Left hand operand. A "struct tomoyo_argv" for TOMOYO_ARGV_ENTRY, a | ||
533 | * "struct tomoyo_envp" for TOMOYO_ENVP_ENTRY is attached to the tail | ||
534 | * of the array of this struct. | ||
535 | */ | ||
536 | u8 left; | ||
537 | /* | ||
538 | * Right hand operand. A "struct tomoyo_number_union" for | ||
539 | * TOMOYO_NUMBER_UNION, a "struct tomoyo_name_union" for | ||
540 | * TOMOYO_NAME_UNION is attached to the tail of the array of this | ||
541 | * struct. | ||
542 | */ | ||
543 | u8 right; | ||
544 | /* Equation operator. True if equals or overlaps, false otherwise. */ | ||
545 | bool equals; | ||
546 | }; | ||
547 | |||
548 | /* Structure for optional arguments. */ | ||
549 | struct tomoyo_condition { | ||
550 | struct tomoyo_shared_acl_head head; | ||
551 | u32 size; /* Memory size allocated for this entry. */ | ||
552 | u16 condc; /* Number of conditions in this struct. */ | ||
553 | u16 numbers_count; /* Number of "struct tomoyo_number_union values". */ | ||
554 | u16 names_count; /* Number of "struct tomoyo_name_union names". */ | ||
555 | u16 argc; /* Number of "struct tomoyo_argv". */ | ||
556 | u16 envc; /* Number of "struct tomoyo_envp". */ | ||
557 | /* | ||
558 | * struct tomoyo_condition_element condition[condc]; | ||
559 | * struct tomoyo_number_union values[numbers_count]; | ||
560 | * struct tomoyo_name_union names[names_count]; | ||
561 | * struct tomoyo_argv argv[argc]; | ||
562 | * struct tomoyo_envp envp[envc]; | ||
563 | */ | ||
564 | }; | ||
565 | |||
566 | /* Common header for individual entries. */ | ||
372 | struct tomoyo_acl_info { | 567 | struct tomoyo_acl_info { |
373 | struct list_head list; | 568 | struct list_head list; |
569 | struct tomoyo_condition *cond; /* Maybe NULL. */ | ||
374 | bool is_deleted; | 570 | bool is_deleted; |
375 | u8 type; /* = one of values in "enum tomoyo_acl_entry_type_index". */ | 571 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ |
376 | } __packed; | 572 | } __packed; |
377 | 573 | ||
378 | /* | 574 | /* Structure for domain information. */ |
379 | * tomoyo_domain_info is a structure which is used for holding permissions | ||
380 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
381 | * It has following fields. | ||
382 | * | ||
383 | * (1) "list" which is linked to tomoyo_domain_list . | ||
384 | * (2) "acl_info_list" which is linked to "struct tomoyo_acl_info". | ||
385 | * (3) "domainname" which holds the name of the domain. | ||
386 | * (4) "profile" which remembers profile number assigned to this domain. | ||
387 | * (5) "is_deleted" is a bool which is true if this domain is marked as | ||
388 | * "deleted", false otherwise. | ||
389 | * (6) "quota_warned" is a bool which is used for suppressing warning message | ||
390 | * when learning mode learned too much entries. | ||
391 | * (7) "ignore_global_allow_read" is a bool which is true if this domain | ||
392 | * should ignore "allow_read" directive in exception policy. | ||
393 | * (8) "transition_failed" is a bool which is set to true when this domain was | ||
394 | * unable to create a new domain at tomoyo_find_next_domain() because the | ||
395 | * name of the domain to be created was too long or it could not allocate | ||
396 | * memory. If set to true, more than one process continued execve() | ||
397 | * without domain transition. | ||
398 | * (9) "users" is an atomic_t that holds how many "struct cred"->security | ||
399 | * are referring this "struct tomoyo_domain_info". If is_deleted == true | ||
400 | * and users == 0, this struct will be kfree()d upon next garbage | ||
401 | * collection. | ||
402 | * | ||
403 | * A domain's lifecycle is an analogy of files on / directory. | ||
404 | * Multiple domains with the same domainname cannot be created (as with | ||
405 | * creating files with the same filename fails with -EEXIST). | ||
406 | * If a process reached a domain, that process can reside in that domain after | ||
407 | * that domain is marked as "deleted" (as with a process can access an already | ||
408 | * open()ed file after that file was unlink()ed). | ||
409 | */ | ||
410 | struct tomoyo_domain_info { | 575 | struct tomoyo_domain_info { |
411 | struct list_head list; | 576 | struct list_head list; |
412 | struct list_head acl_info_list; | 577 | struct list_head acl_info_list; |
413 | /* Name of this domain. Never NULL. */ | 578 | /* Name of this domain. Never NULL. */ |
414 | const struct tomoyo_path_info *domainname; | 579 | const struct tomoyo_path_info *domainname; |
580 | /* Namespace for this domain. Never NULL. */ | ||
581 | struct tomoyo_policy_namespace *ns; | ||
415 | u8 profile; /* Profile number to use. */ | 582 | u8 profile; /* Profile number to use. */ |
583 | u8 group; /* Group number to use. */ | ||
416 | bool is_deleted; /* Delete flag. */ | 584 | bool is_deleted; /* Delete flag. */ |
417 | bool quota_warned; /* Quota warnning flag. */ | 585 | bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; |
418 | bool ignore_global_allow_read; /* Ignore "allow_read" flag. */ | ||
419 | bool transition_failed; /* Domain transition failed flag. */ | ||
420 | atomic_t users; /* Number of referring credentials. */ | 586 | atomic_t users; /* Number of referring credentials. */ |
421 | }; | 587 | }; |
422 | 588 | ||
423 | /* | 589 | /* |
424 | * tomoyo_path_acl is a structure which is used for holding an | 590 | * Structure for "file execute", "file read", "file write", "file append", |
425 | * entry with one pathname operation (e.g. open(), mkdir()). | 591 | * "file unlink", "file getattr", "file rmdir", "file truncate", |
426 | * It has following fields. | 592 | * "file symlink", "file chroot" and "file unmount" directive. |
427 | * | ||
428 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
429 | * (2) "perm" which is a bitmask of permitted operations. | ||
430 | * (3) "name" is the pathname. | ||
431 | * | ||
432 | * Directives held by this structure are "allow_read/write", "allow_execute", | ||
433 | * "allow_read", "allow_write", "allow_unlink", "allow_rmdir", | ||
434 | * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and | ||
435 | * "allow_unmount". | ||
436 | */ | 593 | */ |
437 | struct tomoyo_path_acl { | 594 | struct tomoyo_path_acl { |
438 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ | 595 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ |
439 | u16 perm; | 596 | u16 perm; /* Bitmask of values in "enum tomoyo_path_acl_index". */ |
440 | struct tomoyo_name_union name; | 597 | struct tomoyo_name_union name; |
441 | }; | 598 | }; |
442 | 599 | ||
443 | /* | 600 | /* |
444 | * tomoyo_path_number_acl is a structure which is used for holding an | 601 | * Structure for "file create", "file mkdir", "file mkfifo", "file mksock", |
445 | * entry with one pathname and one number operation. | 602 | * "file ioctl", "file chmod", "file chown" and "file chgrp" directive. |
446 | * It has following fields. | ||
447 | * | ||
448 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
449 | * (2) "perm" which is a bitmask of permitted operations. | ||
450 | * (3) "name" is the pathname. | ||
451 | * (4) "number" is the numeric value. | ||
452 | * | ||
453 | * Directives held by this structure are "allow_create", "allow_mkdir", | ||
454 | * "allow_ioctl", "allow_mkfifo", "allow_mksock", "allow_chmod", "allow_chown" | ||
455 | * and "allow_chgrp". | ||
456 | * | ||
457 | */ | 603 | */ |
458 | struct tomoyo_path_number_acl { | 604 | struct tomoyo_path_number_acl { |
459 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */ | 605 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */ |
606 | /* Bitmask of values in "enum tomoyo_path_number_acl_index". */ | ||
460 | u8 perm; | 607 | u8 perm; |
461 | struct tomoyo_name_union name; | 608 | struct tomoyo_name_union name; |
462 | struct tomoyo_number_union number; | 609 | struct tomoyo_number_union number; |
463 | }; | 610 | }; |
464 | 611 | ||
465 | /* | 612 | /* Structure for "file mkblock" and "file mkchar" directive. */ |
466 | * tomoyo_mkdev_acl is a structure which is used for holding an | ||
467 | * entry with one pathname and three numbers operation. | ||
468 | * It has following fields. | ||
469 | * | ||
470 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
471 | * (2) "perm" which is a bitmask of permitted operations. | ||
472 | * (3) "mode" is the create mode. | ||
473 | * (4) "major" is the major number of device node. | ||
474 | * (5) "minor" is the minor number of device node. | ||
475 | * | ||
476 | * Directives held by this structure are "allow_mkchar", "allow_mkblock". | ||
477 | * | ||
478 | */ | ||
479 | struct tomoyo_mkdev_acl { | 613 | struct tomoyo_mkdev_acl { |
480 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */ | 614 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */ |
481 | u8 perm; | 615 | u8 perm; /* Bitmask of values in "enum tomoyo_mkdev_acl_index". */ |
482 | struct tomoyo_name_union name; | 616 | struct tomoyo_name_union name; |
483 | struct tomoyo_number_union mode; | 617 | struct tomoyo_number_union mode; |
484 | struct tomoyo_number_union major; | 618 | struct tomoyo_number_union major; |
@@ -486,38 +620,16 @@ struct tomoyo_mkdev_acl { | |||
486 | }; | 620 | }; |
487 | 621 | ||
488 | /* | 622 | /* |
489 | * tomoyo_path2_acl is a structure which is used for holding an | 623 | * Structure for "file rename", "file link" and "file pivot_root" directive. |
490 | * entry with two pathnames operation (i.e. link(), rename() and pivot_root()). | ||
491 | * It has following fields. | ||
492 | * | ||
493 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
494 | * (2) "perm" which is a bitmask of permitted operations. | ||
495 | * (3) "name1" is the source/old pathname. | ||
496 | * (4) "name2" is the destination/new pathname. | ||
497 | * | ||
498 | * Directives held by this structure are "allow_rename", "allow_link" and | ||
499 | * "allow_pivot_root". | ||
500 | */ | 624 | */ |
501 | struct tomoyo_path2_acl { | 625 | struct tomoyo_path2_acl { |
502 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ | 626 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ |
503 | u8 perm; | 627 | u8 perm; /* Bitmask of values in "enum tomoyo_path2_acl_index". */ |
504 | struct tomoyo_name_union name1; | 628 | struct tomoyo_name_union name1; |
505 | struct tomoyo_name_union name2; | 629 | struct tomoyo_name_union name2; |
506 | }; | 630 | }; |
507 | 631 | ||
508 | /* | 632 | /* Structure for "file mount" directive. */ |
509 | * tomoyo_mount_acl is a structure which is used for holding an | ||
510 | * entry for mount operation. | ||
511 | * It has following fields. | ||
512 | * | ||
513 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
514 | * (2) "dev_name" is the device name. | ||
515 | * (3) "dir_name" is the mount point. | ||
516 | * (4) "fs_type" is the filesystem type. | ||
517 | * (5) "flags" is the mount flags. | ||
518 | * | ||
519 | * Directive held by this structure is "allow_mount". | ||
520 | */ | ||
521 | struct tomoyo_mount_acl { | 633 | struct tomoyo_mount_acl { |
522 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */ | 634 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */ |
523 | struct tomoyo_name_union dev_name; | 635 | struct tomoyo_name_union dev_name; |
@@ -526,7 +638,15 @@ struct tomoyo_mount_acl { | |||
526 | struct tomoyo_number_union flags; | 638 | struct tomoyo_number_union flags; |
527 | }; | 639 | }; |
528 | 640 | ||
529 | #define TOMOYO_MAX_IO_READ_QUEUE 32 | 641 | /* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */ |
642 | struct tomoyo_acl_param { | ||
643 | char *data; | ||
644 | struct list_head *list; | ||
645 | struct tomoyo_policy_namespace *ns; | ||
646 | bool is_delete; | ||
647 | }; | ||
648 | |||
649 | #define TOMOYO_MAX_IO_READ_QUEUE 64 | ||
530 | 650 | ||
531 | /* | 651 | /* |
532 | * Structure for reading/writing policy via /sys/kernel/security/tomoyo | 652 | * Structure for reading/writing policy via /sys/kernel/security/tomoyo |
@@ -538,95 +658,55 @@ struct tomoyo_io_buffer { | |||
538 | int (*poll) (struct file *file, poll_table *wait); | 658 | int (*poll) (struct file *file, poll_table *wait); |
539 | /* Exclusive lock for this structure. */ | 659 | /* Exclusive lock for this structure. */ |
540 | struct mutex io_sem; | 660 | struct mutex io_sem; |
541 | /* Index returned by tomoyo_read_lock(). */ | ||
542 | int reader_idx; | ||
543 | char __user *read_user_buf; | 661 | char __user *read_user_buf; |
544 | int read_user_buf_avail; | 662 | size_t read_user_buf_avail; |
545 | struct { | 663 | struct { |
664 | struct list_head *ns; | ||
546 | struct list_head *domain; | 665 | struct list_head *domain; |
547 | struct list_head *group; | 666 | struct list_head *group; |
548 | struct list_head *acl; | 667 | struct list_head *acl; |
549 | int avail; | 668 | size_t avail; |
550 | int step; | 669 | unsigned int step; |
551 | int query_index; | 670 | unsigned int query_index; |
552 | u16 index; | 671 | u16 index; |
672 | u16 cond_index; | ||
673 | u8 acl_group_index; | ||
674 | u8 cond_step; | ||
553 | u8 bit; | 675 | u8 bit; |
554 | u8 w_pos; | 676 | u8 w_pos; |
555 | bool eof; | 677 | bool eof; |
556 | bool print_this_domain_only; | 678 | bool print_this_domain_only; |
557 | bool print_execute_only; | 679 | bool print_transition_related_only; |
680 | bool print_cond_part; | ||
558 | const char *w[TOMOYO_MAX_IO_READ_QUEUE]; | 681 | const char *w[TOMOYO_MAX_IO_READ_QUEUE]; |
559 | } r; | 682 | } r; |
560 | /* The position currently writing to. */ | 683 | struct { |
561 | struct tomoyo_domain_info *write_var1; | 684 | struct tomoyo_policy_namespace *ns; |
685 | /* The position currently writing to. */ | ||
686 | struct tomoyo_domain_info *domain; | ||
687 | /* Bytes available for writing. */ | ||
688 | size_t avail; | ||
689 | bool is_delete; | ||
690 | } w; | ||
562 | /* Buffer for reading. */ | 691 | /* Buffer for reading. */ |
563 | char *read_buf; | 692 | char *read_buf; |
564 | /* Size of read buffer. */ | 693 | /* Size of read buffer. */ |
565 | int readbuf_size; | 694 | size_t readbuf_size; |
566 | /* Buffer for writing. */ | 695 | /* Buffer for writing. */ |
567 | char *write_buf; | 696 | char *write_buf; |
568 | /* Bytes available for writing. */ | ||
569 | int write_avail; | ||
570 | /* Size of write buffer. */ | 697 | /* Size of write buffer. */ |
571 | int writebuf_size; | 698 | size_t writebuf_size; |
572 | /* Type of this interface. */ | 699 | /* Type of this interface. */ |
573 | u8 type; | 700 | enum tomoyo_securityfs_interface_index type; |
574 | }; | 701 | /* Users counter protected by tomoyo_io_buffer_list_lock. */ |
575 | 702 | u8 users; | |
576 | /* | 703 | /* List for telling GC not to kfree() elements. */ |
577 | * tomoyo_readable_file is a structure which is used for holding | 704 | struct list_head list; |
578 | * "allow_read" entries. | ||
579 | * It has following fields. | ||
580 | * | ||
581 | * (1) "head" is "struct tomoyo_acl_head". | ||
582 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
583 | */ | ||
584 | struct tomoyo_readable_file { | ||
585 | struct tomoyo_acl_head head; | ||
586 | const struct tomoyo_path_info *filename; | ||
587 | }; | ||
588 | |||
589 | /* | ||
590 | * tomoyo_no_pattern is a structure which is used for holding | ||
591 | * "file_pattern" entries. | ||
592 | * It has following fields. | ||
593 | * | ||
594 | * (1) "head" is "struct tomoyo_acl_head". | ||
595 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
596 | * to pathname patterns during learning mode. | ||
597 | */ | ||
598 | struct tomoyo_no_pattern { | ||
599 | struct tomoyo_acl_head head; | ||
600 | const struct tomoyo_path_info *pattern; | ||
601 | }; | ||
602 | |||
603 | /* | ||
604 | * tomoyo_no_rewrite is a structure which is used for holding | ||
605 | * "deny_rewrite" entries. | ||
606 | * It has following fields. | ||
607 | * | ||
608 | * (1) "head" is "struct tomoyo_acl_head". | ||
609 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
610 | * already existing content. | ||
611 | */ | ||
612 | struct tomoyo_no_rewrite { | ||
613 | struct tomoyo_acl_head head; | ||
614 | const struct tomoyo_path_info *pattern; | ||
615 | }; | 705 | }; |
616 | 706 | ||
617 | /* | 707 | /* |
618 | * tomoyo_transition_control is a structure which is used for holding | 708 | * Structure for "initialize_domain"/"no_initialize_domain"/"keep_domain"/ |
619 | * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain" | 709 | * "no_keep_domain" keyword. |
620 | * entries. | ||
621 | * It has following fields. | ||
622 | * | ||
623 | * (1) "head" is "struct tomoyo_acl_head". | ||
624 | * (2) "type" is type of this entry. | ||
625 | * (3) "is_last_name" is a bool which is true if "domainname" is "the last | ||
626 | * component of a domainname", false otherwise. | ||
627 | * (4) "domainname" which is "a domainname" or "the last component of a | ||
628 | * domainname". | ||
629 | * (5) "program" which is a program's pathname. | ||
630 | */ | 710 | */ |
631 | struct tomoyo_transition_control { | 711 | struct tomoyo_transition_control { |
632 | struct tomoyo_acl_head head; | 712 | struct tomoyo_acl_head head; |
@@ -637,32 +717,14 @@ struct tomoyo_transition_control { | |||
637 | const struct tomoyo_path_info *program; /* Maybe NULL */ | 717 | const struct tomoyo_path_info *program; /* Maybe NULL */ |
638 | }; | 718 | }; |
639 | 719 | ||
640 | /* | 720 | /* Structure for "aggregator" keyword. */ |
641 | * tomoyo_aggregator is a structure which is used for holding | ||
642 | * "aggregator" entries. | ||
643 | * It has following fields. | ||
644 | * | ||
645 | * (1) "head" is "struct tomoyo_acl_head". | ||
646 | * (2) "original_name" which is originally requested name. | ||
647 | * (3) "aggregated_name" which is name to rewrite. | ||
648 | */ | ||
649 | struct tomoyo_aggregator { | 721 | struct tomoyo_aggregator { |
650 | struct tomoyo_acl_head head; | 722 | struct tomoyo_acl_head head; |
651 | const struct tomoyo_path_info *original_name; | 723 | const struct tomoyo_path_info *original_name; |
652 | const struct tomoyo_path_info *aggregated_name; | 724 | const struct tomoyo_path_info *aggregated_name; |
653 | }; | 725 | }; |
654 | 726 | ||
655 | /* | 727 | /* Structure for policy manager. */ |
656 | * tomoyo_manager is a structure which is used for holding list of | ||
657 | * domainnames or programs which are permitted to modify configuration via | ||
658 | * /sys/kernel/security/tomoyo/ interface. | ||
659 | * It has following fields. | ||
660 | * | ||
661 | * (1) "head" is "struct tomoyo_acl_head". | ||
662 | * (2) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
663 | * otherwise. | ||
664 | * (3) "manager" is a domainname or a program's pathname. | ||
665 | */ | ||
666 | struct tomoyo_manager { | 728 | struct tomoyo_manager { |
667 | struct tomoyo_acl_head head; | 729 | struct tomoyo_acl_head head; |
668 | bool is_domain; /* True if manager is a domainname. */ | 730 | bool is_domain; /* True if manager is a domainname. */ |
@@ -677,6 +739,7 @@ struct tomoyo_preference { | |||
677 | bool permissive_verbose; | 739 | bool permissive_verbose; |
678 | }; | 740 | }; |
679 | 741 | ||
742 | /* Structure for /sys/kernel/security/tomnoyo/profile interface. */ | ||
680 | struct tomoyo_profile { | 743 | struct tomoyo_profile { |
681 | const struct tomoyo_path_info *comment; | 744 | const struct tomoyo_path_info *comment; |
682 | struct tomoyo_preference *learning; | 745 | struct tomoyo_preference *learning; |
@@ -685,323 +748,409 @@ struct tomoyo_profile { | |||
685 | struct tomoyo_preference preference; | 748 | struct tomoyo_preference preference; |
686 | u8 default_config; | 749 | u8 default_config; |
687 | u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX]; | 750 | u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX]; |
751 | unsigned int pref[TOMOYO_MAX_PREF]; | ||
752 | }; | ||
753 | |||
754 | /* Structure for representing YYYY/MM/DD hh/mm/ss. */ | ||
755 | struct tomoyo_time { | ||
756 | u16 year; | ||
757 | u8 month; | ||
758 | u8 day; | ||
759 | u8 hour; | ||
760 | u8 min; | ||
761 | u8 sec; | ||
762 | }; | ||
763 | |||
764 | /* Structure for policy namespace. */ | ||
765 | struct tomoyo_policy_namespace { | ||
766 | /* Profile table. Memory is allocated as needed. */ | ||
767 | struct tomoyo_profile *profile_ptr[TOMOYO_MAX_PROFILES]; | ||
768 | /* List of "struct tomoyo_group". */ | ||
769 | struct list_head group_list[TOMOYO_MAX_GROUP]; | ||
770 | /* List of policy. */ | ||
771 | struct list_head policy_list[TOMOYO_MAX_POLICY]; | ||
772 | /* The global ACL referred by "use_group" keyword. */ | ||
773 | struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; | ||
774 | /* List for connecting to tomoyo_namespace_list list. */ | ||
775 | struct list_head namespace_list; | ||
776 | /* Profile version. Currently only 20100903 is defined. */ | ||
777 | unsigned int profile_version; | ||
778 | /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ | ||
779 | const char *name; | ||
688 | }; | 780 | }; |
689 | 781 | ||
690 | /********** Function prototypes. **********/ | 782 | /********** Function prototypes. **********/ |
691 | 783 | ||
692 | /* Check whether the given string starts with the given keyword. */ | ||
693 | bool tomoyo_str_starts(char **src, const char *find); | ||
694 | /* Get tomoyo_realpath() of current process. */ | ||
695 | const char *tomoyo_get_exe(void); | ||
696 | /* Format string. */ | ||
697 | void tomoyo_normalize_line(unsigned char *buffer); | ||
698 | /* Print warning or error message on console. */ | ||
699 | void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
700 | __attribute__ ((format(printf, 2, 3))); | ||
701 | /* Check all profiles currently assigned to domains are defined. */ | ||
702 | void tomoyo_check_profile(void); | ||
703 | /* Open operation for /sys/kernel/security/tomoyo/ interface. */ | ||
704 | int tomoyo_open_control(const u8 type, struct file *file); | ||
705 | /* Close /sys/kernel/security/tomoyo/ interface. */ | ||
706 | int tomoyo_close_control(struct file *file); | ||
707 | /* Poll operation for /sys/kernel/security/tomoyo/ interface. */ | ||
708 | int tomoyo_poll_control(struct file *file, poll_table *wait); | ||
709 | /* Read operation for /sys/kernel/security/tomoyo/ interface. */ | ||
710 | int tomoyo_read_control(struct file *file, char __user *buffer, | ||
711 | const int buffer_len); | ||
712 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ | ||
713 | int tomoyo_write_control(struct file *file, const char __user *buffer, | ||
714 | const int buffer_len); | ||
715 | /* Check whether the domain has too many ACL entries to hold. */ | ||
716 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); | ||
717 | /* Print out of memory warning message. */ | ||
718 | void tomoyo_warn_oom(const char *function); | ||
719 | /* Check whether the given name matches the given name_union. */ | ||
720 | const struct tomoyo_path_info * | ||
721 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, | ||
722 | const struct tomoyo_name_union *ptr); | ||
723 | /* Check whether the given number matches the given number_union. */ | ||
724 | bool tomoyo_compare_number_union(const unsigned long value, | 784 | bool tomoyo_compare_number_union(const unsigned long value, |
725 | const struct tomoyo_number_union *ptr); | 785 | const struct tomoyo_number_union *ptr); |
726 | int tomoyo_get_mode(const u8 profile, const u8 index); | 786 | bool tomoyo_condition(struct tomoyo_request_info *r, |
727 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 787 | const struct tomoyo_condition *cond); |
728 | __attribute__ ((format(printf, 2, 3))); | ||
729 | /* Check whether the domainname is correct. */ | ||
730 | bool tomoyo_correct_domain(const unsigned char *domainname); | 788 | bool tomoyo_correct_domain(const unsigned char *domainname); |
731 | /* Check whether the token is correct. */ | ||
732 | bool tomoyo_correct_path(const char *filename); | 789 | bool tomoyo_correct_path(const char *filename); |
733 | bool tomoyo_correct_word(const char *string); | 790 | bool tomoyo_correct_word(const char *string); |
734 | /* Check whether the token can be a domainname. */ | ||
735 | bool tomoyo_domain_def(const unsigned char *buffer); | 791 | bool tomoyo_domain_def(const unsigned char *buffer); |
736 | bool tomoyo_parse_name_union(const char *filename, | 792 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); |
737 | struct tomoyo_name_union *ptr); | 793 | bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, |
738 | /* Check whether the given filename matches the given path_group. */ | 794 | struct tomoyo_page_dump *dump); |
739 | const struct tomoyo_path_info * | 795 | bool tomoyo_memory_ok(void *ptr); |
740 | tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, | ||
741 | const struct tomoyo_group *group); | ||
742 | /* Check whether the given value matches the given number_group. */ | ||
743 | bool tomoyo_number_matches_group(const unsigned long min, | 796 | bool tomoyo_number_matches_group(const unsigned long min, |
744 | const unsigned long max, | 797 | const unsigned long max, |
745 | const struct tomoyo_group *group); | 798 | const struct tomoyo_group *group); |
746 | /* Check whether the given filename matches the given pattern. */ | 799 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, |
800 | struct tomoyo_name_union *ptr); | ||
801 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, | ||
802 | struct tomoyo_number_union *ptr); | ||
747 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | 803 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, |
748 | const struct tomoyo_path_info *pattern); | 804 | const struct tomoyo_path_info *pattern); |
749 | 805 | bool tomoyo_permstr(const char *string, const char *keyword); | |
750 | bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num); | 806 | bool tomoyo_str_starts(char **src, const char *find); |
751 | /* Tokenize a line. */ | ||
752 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size); | ||
753 | /* Write domain policy violation warning message to console? */ | ||
754 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); | ||
755 | /* Fill "struct tomoyo_request_info". */ | ||
756 | int tomoyo_init_request_info(struct tomoyo_request_info *r, | ||
757 | struct tomoyo_domain_info *domain, | ||
758 | const u8 index); | ||
759 | /* Check permission for mount operation. */ | ||
760 | int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | ||
761 | unsigned long flags, void *data_page); | ||
762 | /* Create "aggregator" entry in exception policy. */ | ||
763 | int tomoyo_write_aggregator(char *data, const bool is_delete); | ||
764 | int tomoyo_write_transition_control(char *data, const bool is_delete, | ||
765 | const u8 type); | ||
766 | /* | ||
767 | * Create "allow_read/write", "allow_execute", "allow_read", "allow_write", | ||
768 | * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | ||
769 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", | ||
770 | * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and | ||
771 | * "allow_link" entry in domain policy. | ||
772 | */ | ||
773 | int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain, | ||
774 | const bool is_delete); | ||
775 | /* Create "allow_read" entry in exception policy. */ | ||
776 | int tomoyo_write_globally_readable(char *data, const bool is_delete); | ||
777 | /* Create "allow_mount" entry in domain policy. */ | ||
778 | int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain, | ||
779 | const bool is_delete); | ||
780 | /* Create "deny_rewrite" entry in exception policy. */ | ||
781 | int tomoyo_write_no_rewrite(char *data, const bool is_delete); | ||
782 | /* Create "file_pattern" entry in exception policy. */ | ||
783 | int tomoyo_write_pattern(char *data, const bool is_delete); | ||
784 | /* Create "path_group"/"number_group" entry in exception policy. */ | ||
785 | int tomoyo_write_group(char *data, const bool is_delete, const u8 type); | ||
786 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | ||
787 | __attribute__ ((format(printf, 2, 3))); | ||
788 | /* Find a domain by the given name. */ | ||
789 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | ||
790 | /* Find or create a domain by the given name. */ | ||
791 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | ||
792 | const u8 profile); | ||
793 | struct tomoyo_profile *tomoyo_profile(const u8 profile); | ||
794 | /* | ||
795 | * Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". | ||
796 | */ | ||
797 | struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type); | ||
798 | |||
799 | /* Check mode for specified functionality. */ | ||
800 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | ||
801 | const u8 index); | ||
802 | /* Fill in "struct tomoyo_path_info" members. */ | ||
803 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | ||
804 | /* Run policy loader when /sbin/init starts. */ | ||
805 | void tomoyo_load_policy(const char *filename); | ||
806 | |||
807 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr); | ||
808 | |||
809 | /* Convert binary string to ascii string. */ | ||
810 | char *tomoyo_encode(const char *str); | 807 | char *tomoyo_encode(const char *str); |
811 | 808 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | |
812 | /* | 809 | va_list args); |
813 | * Returns realpath(3) of the given pathname except that | 810 | char *tomoyo_read_token(struct tomoyo_acl_param *param); |
814 | * ignores chroot'ed root and does not follow the final symlink. | ||
815 | */ | ||
816 | char *tomoyo_realpath_nofollow(const char *pathname); | ||
817 | /* | ||
818 | * Returns realpath(3) of the given pathname except that | ||
819 | * ignores chroot'ed root and the pathname is already solved. | ||
820 | */ | ||
821 | char *tomoyo_realpath_from_path(struct path *path); | 811 | char *tomoyo_realpath_from_path(struct path *path); |
822 | /* Get patterned pathname. */ | 812 | char *tomoyo_realpath_nofollow(const char *pathname); |
823 | const char *tomoyo_pattern(const struct tomoyo_path_info *filename); | 813 | const char *tomoyo_get_exe(void); |
824 | 814 | const char *tomoyo_yesno(const unsigned int value); | |
825 | /* Check memory quota. */ | 815 | const struct tomoyo_path_info *tomoyo_compare_name_union |
826 | bool tomoyo_memory_ok(void *ptr); | 816 | (const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr); |
827 | void *tomoyo_commit_ok(void *data, const unsigned int size); | ||
828 | |||
829 | /* | ||
830 | * Keep the given name on the RAM. | ||
831 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
832 | */ | ||
833 | const struct tomoyo_path_info *tomoyo_get_name(const char *name); | 817 | const struct tomoyo_path_info *tomoyo_get_name(const char *name); |
834 | 818 | const struct tomoyo_path_info *tomoyo_path_matches_group | |
835 | /* Check for memory usage. */ | 819 | (const struct tomoyo_path_info *pathname, const struct tomoyo_group *group); |
836 | void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); | ||
837 | |||
838 | /* Set memory quota. */ | ||
839 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); | ||
840 | |||
841 | /* Initialize mm related code. */ | ||
842 | void __init tomoyo_mm_init(void); | ||
843 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | ||
844 | const struct tomoyo_path_info *filename); | ||
845 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 820 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
846 | struct path *path, const int flag); | 821 | struct path *path, const int flag); |
847 | int tomoyo_path_number_perm(const u8 operation, struct path *path, | 822 | int tomoyo_close_control(struct tomoyo_io_buffer *head); |
848 | unsigned long number); | 823 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
824 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, | ||
825 | const u8 index); | ||
826 | int tomoyo_init_request_info(struct tomoyo_request_info *r, | ||
827 | struct tomoyo_domain_info *domain, | ||
828 | const u8 index); | ||
849 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, | 829 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, |
850 | const unsigned int mode, unsigned int dev); | 830 | const unsigned int mode, unsigned int dev); |
851 | int tomoyo_path_perm(const u8 operation, struct path *path); | 831 | int tomoyo_mount_permission(char *dev_name, struct path *path, |
832 | const char *type, unsigned long flags, | ||
833 | void *data_page); | ||
834 | int tomoyo_open_control(const u8 type, struct file *file); | ||
852 | int tomoyo_path2_perm(const u8 operation, struct path *path1, | 835 | int tomoyo_path2_perm(const u8 operation, struct path *path1, |
853 | struct path *path2); | 836 | struct path *path2); |
854 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | 837 | int tomoyo_path_number_perm(const u8 operation, struct path *path, |
855 | 838 | unsigned long number); | |
856 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | 839 | int tomoyo_path_perm(const u8 operation, struct path *path, |
857 | const unsigned long value, const u8 type); | 840 | const char *target); |
858 | 841 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |
859 | /* Drop refcount on tomoyo_name_union. */ | 842 | const struct tomoyo_path_info *filename); |
860 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); | 843 | int tomoyo_poll_control(struct file *file, poll_table *wait); |
861 | 844 | int tomoyo_poll_log(struct file *file, poll_table *wait); | |
862 | /* Run garbage collector. */ | 845 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) |
863 | void tomoyo_run_gc(void); | 846 | __printf(2, 3); |
864 | |||
865 | void tomoyo_memory_free(void *ptr); | ||
866 | |||
867 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 847 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
868 | bool is_delete, struct tomoyo_domain_info *domain, | 848 | struct tomoyo_acl_param *param, |
869 | bool (*check_duplicate) (const struct tomoyo_acl_info | 849 | bool (*check_duplicate) |
870 | *, | 850 | (const struct tomoyo_acl_info *, |
871 | const struct tomoyo_acl_info | 851 | const struct tomoyo_acl_info *), |
872 | *), | 852 | bool (*merge_duplicate) |
873 | bool (*merge_duplicate) (struct tomoyo_acl_info *, | 853 | (struct tomoyo_acl_info *, struct tomoyo_acl_info *, |
874 | struct tomoyo_acl_info *, | 854 | const bool)); |
875 | const bool)); | ||
876 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | 855 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
877 | bool is_delete, struct list_head *list, | 856 | struct tomoyo_acl_param *param, |
878 | bool (*check_duplicate) (const struct tomoyo_acl_head | 857 | bool (*check_duplicate) |
879 | *, | 858 | (const struct tomoyo_acl_head *, |
880 | const struct tomoyo_acl_head | 859 | const struct tomoyo_acl_head *)); |
881 | *)); | 860 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param); |
861 | int tomoyo_write_file(struct tomoyo_acl_param *param); | ||
862 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type); | ||
863 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, | ||
864 | const u8 type); | ||
865 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, | ||
866 | const int buffer_len); | ||
867 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | ||
868 | const char __user *buffer, const int buffer_len); | ||
869 | struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param); | ||
870 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | ||
871 | const bool transit); | ||
872 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | ||
873 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | ||
874 | const u8 idx); | ||
875 | struct tomoyo_policy_namespace *tomoyo_assign_namespace | ||
876 | (const char *domainname); | ||
877 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, | ||
878 | const u8 profile); | ||
879 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | ||
880 | const u8 index); | ||
881 | u8 tomoyo_parse_ulong(unsigned long *result, char **str); | ||
882 | void *tomoyo_commit_ok(void *data, const unsigned int size); | ||
883 | void __init tomoyo_load_builtin_policy(void); | ||
884 | void __init tomoyo_mm_init(void); | ||
882 | void tomoyo_check_acl(struct tomoyo_request_info *r, | 885 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
883 | bool (*check_entry) (struct tomoyo_request_info *, | 886 | bool (*check_entry) (struct tomoyo_request_info *, |
884 | const struct tomoyo_acl_info *)); | 887 | const struct tomoyo_acl_info *)); |
888 | void tomoyo_check_profile(void); | ||
889 | void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp); | ||
890 | void tomoyo_del_condition(struct list_head *element); | ||
891 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | ||
892 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); | ||
893 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); | ||
894 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | ||
895 | __printf(2, 3); | ||
896 | void tomoyo_load_policy(const char *filename); | ||
897 | void tomoyo_memory_free(void *ptr); | ||
898 | void tomoyo_normalize_line(unsigned char *buffer); | ||
899 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); | ||
900 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | ||
901 | const unsigned long value, const u8 type); | ||
902 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); | ||
903 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr); | ||
904 | void tomoyo_read_log(struct tomoyo_io_buffer *head); | ||
905 | void tomoyo_update_stat(const u8 index); | ||
906 | void tomoyo_warn_oom(const char *function); | ||
907 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
908 | __printf(2, 3); | ||
909 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | ||
910 | va_list args); | ||
885 | 911 | ||
886 | /********** External variable definitions. **********/ | 912 | /********** External variable definitions. **********/ |
887 | 913 | ||
888 | /* Lock for GC. */ | 914 | extern bool tomoyo_policy_loaded; |
889 | extern struct srcu_struct tomoyo_ss; | 915 | extern const char * const tomoyo_condition_keyword |
890 | 916 | [TOMOYO_MAX_CONDITION_KEYWORD]; | |
891 | /* The list for "struct tomoyo_domain_info". */ | 917 | extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; |
918 | extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | ||
919 | + TOMOYO_MAX_MAC_CATEGORY_INDEX]; | ||
920 | extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; | ||
921 | extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; | ||
922 | extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; | ||
923 | extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; | ||
924 | extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; | ||
925 | extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION]; | ||
926 | extern struct list_head tomoyo_condition_list; | ||
892 | extern struct list_head tomoyo_domain_list; | 927 | extern struct list_head tomoyo_domain_list; |
893 | |||
894 | extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; | ||
895 | extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; | ||
896 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 928 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
897 | 929 | extern struct list_head tomoyo_namespace_list; | |
898 | /* Lock for protecting policy. */ | ||
899 | extern struct mutex tomoyo_policy_lock; | 930 | extern struct mutex tomoyo_policy_lock; |
900 | 931 | extern struct srcu_struct tomoyo_ss; | |
901 | /* Has /sbin/init started? */ | ||
902 | extern bool tomoyo_policy_loaded; | ||
903 | |||
904 | /* The kernel's domain. */ | ||
905 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | 932 | extern struct tomoyo_domain_info tomoyo_kernel_domain; |
906 | 933 | extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; | |
907 | extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; | 934 | extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; |
908 | extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION]; | 935 | extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; |
909 | extern const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION]; | ||
910 | extern const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION]; | ||
911 | |||
912 | extern unsigned int tomoyo_quota_for_query; | ||
913 | extern unsigned int tomoyo_query_memory_size; | ||
914 | 936 | ||
915 | /********** Inlined functions. **********/ | 937 | /********** Inlined functions. **********/ |
916 | 938 | ||
939 | /** | ||
940 | * tomoyo_read_lock - Take lock for protecting policy. | ||
941 | * | ||
942 | * Returns index number for tomoyo_read_unlock(). | ||
943 | */ | ||
917 | static inline int tomoyo_read_lock(void) | 944 | static inline int tomoyo_read_lock(void) |
918 | { | 945 | { |
919 | return srcu_read_lock(&tomoyo_ss); | 946 | return srcu_read_lock(&tomoyo_ss); |
920 | } | 947 | } |
921 | 948 | ||
949 | /** | ||
950 | * tomoyo_read_unlock - Release lock for protecting policy. | ||
951 | * | ||
952 | * @idx: Index number returned by tomoyo_read_lock(). | ||
953 | * | ||
954 | * Returns nothing. | ||
955 | */ | ||
922 | static inline void tomoyo_read_unlock(int idx) | 956 | static inline void tomoyo_read_unlock(int idx) |
923 | { | 957 | { |
924 | srcu_read_unlock(&tomoyo_ss, idx); | 958 | srcu_read_unlock(&tomoyo_ss, idx); |
925 | } | 959 | } |
926 | 960 | ||
927 | /* strcmp() for "struct tomoyo_path_info" structure. */ | 961 | /** |
928 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, | 962 | * tomoyo_sys_getppid - Copy of getppid(). |
929 | const struct tomoyo_path_info *b) | 963 | * |
964 | * Returns parent process's PID. | ||
965 | * | ||
966 | * Alpha does not have getppid() defined. To be able to build this module on | ||
967 | * Alpha, I have to copy getppid() from kernel/timer.c. | ||
968 | */ | ||
969 | static inline pid_t tomoyo_sys_getppid(void) | ||
930 | { | 970 | { |
931 | return a->hash != b->hash || strcmp(a->name, b->name); | 971 | pid_t pid; |
972 | rcu_read_lock(); | ||
973 | pid = task_tgid_vnr(current->real_parent); | ||
974 | rcu_read_unlock(); | ||
975 | return pid; | ||
932 | } | 976 | } |
933 | 977 | ||
934 | /** | 978 | /** |
935 | * tomoyo_valid - Check whether the character is a valid char. | 979 | * tomoyo_sys_getpid - Copy of getpid(). |
936 | * | 980 | * |
937 | * @c: The character to check. | 981 | * Returns current thread's PID. |
938 | * | 982 | * |
939 | * Returns true if @c is a valid character, false otherwise. | 983 | * Alpha does not have getpid() defined. To be able to build this module on |
984 | * Alpha, I have to copy getpid() from kernel/timer.c. | ||
940 | */ | 985 | */ |
941 | static inline bool tomoyo_valid(const unsigned char c) | 986 | static inline pid_t tomoyo_sys_getpid(void) |
942 | { | 987 | { |
943 | return c > ' ' && c < 127; | 988 | return task_tgid_vnr(current); |
944 | } | 989 | } |
945 | 990 | ||
946 | /** | 991 | /** |
947 | * tomoyo_invalid - Check whether the character is an invalid char. | 992 | * tomoyo_pathcmp - strcmp() for "struct tomoyo_path_info" structure. |
948 | * | 993 | * |
949 | * @c: The character to check. | 994 | * @a: Pointer to "struct tomoyo_path_info". |
995 | * @b: Pointer to "struct tomoyo_path_info". | ||
950 | * | 996 | * |
951 | * Returns true if @c is an invalid character, false otherwise. | 997 | * Returns true if @a == @b, false otherwise. |
952 | */ | 998 | */ |
953 | static inline bool tomoyo_invalid(const unsigned char c) | 999 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, |
1000 | const struct tomoyo_path_info *b) | ||
954 | { | 1001 | { |
955 | return c && (c <= ' ' || c >= 127); | 1002 | return a->hash != b->hash || strcmp(a->name, b->name); |
956 | } | 1003 | } |
957 | 1004 | ||
1005 | /** | ||
1006 | * tomoyo_put_name - Drop reference on "struct tomoyo_name". | ||
1007 | * | ||
1008 | * @name: Pointer to "struct tomoyo_path_info". Maybe NULL. | ||
1009 | * | ||
1010 | * Returns nothing. | ||
1011 | */ | ||
958 | static inline void tomoyo_put_name(const struct tomoyo_path_info *name) | 1012 | static inline void tomoyo_put_name(const struct tomoyo_path_info *name) |
959 | { | 1013 | { |
960 | if (name) { | 1014 | if (name) { |
961 | struct tomoyo_name *ptr = | 1015 | struct tomoyo_name *ptr = |
962 | container_of(name, typeof(*ptr), entry); | 1016 | container_of(name, typeof(*ptr), entry); |
963 | atomic_dec(&ptr->users); | 1017 | atomic_dec(&ptr->head.users); |
964 | } | 1018 | } |
965 | } | 1019 | } |
966 | 1020 | ||
1021 | /** | ||
1022 | * tomoyo_put_condition - Drop reference on "struct tomoyo_condition". | ||
1023 | * | ||
1024 | * @cond: Pointer to "struct tomoyo_condition". Maybe NULL. | ||
1025 | * | ||
1026 | * Returns nothing. | ||
1027 | */ | ||
1028 | static inline void tomoyo_put_condition(struct tomoyo_condition *cond) | ||
1029 | { | ||
1030 | if (cond) | ||
1031 | atomic_dec(&cond->head.users); | ||
1032 | } | ||
1033 | |||
1034 | /** | ||
1035 | * tomoyo_put_group - Drop reference on "struct tomoyo_group". | ||
1036 | * | ||
1037 | * @group: Pointer to "struct tomoyo_group". Maybe NULL. | ||
1038 | * | ||
1039 | * Returns nothing. | ||
1040 | */ | ||
967 | static inline void tomoyo_put_group(struct tomoyo_group *group) | 1041 | static inline void tomoyo_put_group(struct tomoyo_group *group) |
968 | { | 1042 | { |
969 | if (group) | 1043 | if (group) |
970 | atomic_dec(&group->users); | 1044 | atomic_dec(&group->head.users); |
971 | } | 1045 | } |
972 | 1046 | ||
1047 | /** | ||
1048 | * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. | ||
1049 | * | ||
1050 | * Returns pointer to "struct tomoyo_domain_info" for current thread. | ||
1051 | */ | ||
973 | static inline struct tomoyo_domain_info *tomoyo_domain(void) | 1052 | static inline struct tomoyo_domain_info *tomoyo_domain(void) |
974 | { | 1053 | { |
975 | return current_cred()->security; | 1054 | return current_cred()->security; |
976 | } | 1055 | } |
977 | 1056 | ||
1057 | /** | ||
1058 | * tomoyo_real_domain - Get "struct tomoyo_domain_info" for specified thread. | ||
1059 | * | ||
1060 | * @task: Pointer to "struct task_struct". | ||
1061 | * | ||
1062 | * Returns pointer to "struct tomoyo_security" for specified thread. | ||
1063 | */ | ||
978 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | 1064 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct |
979 | *task) | 1065 | *task) |
980 | { | 1066 | { |
981 | return task_cred_xxx(task, security); | 1067 | return task_cred_xxx(task, security); |
982 | } | 1068 | } |
983 | 1069 | ||
984 | static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *p1, | 1070 | /** |
985 | const struct tomoyo_acl_info *p2) | 1071 | * tomoyo_same_name_union - Check for duplicated "struct tomoyo_name_union" entry. |
1072 | * | ||
1073 | * @a: Pointer to "struct tomoyo_name_union". | ||
1074 | * @b: Pointer to "struct tomoyo_name_union". | ||
1075 | * | ||
1076 | * Returns true if @a == @b, false otherwise. | ||
1077 | */ | ||
1078 | static inline bool tomoyo_same_name_union | ||
1079 | (const struct tomoyo_name_union *a, const struct tomoyo_name_union *b) | ||
986 | { | 1080 | { |
987 | return p1->type == p2->type; | 1081 | return a->filename == b->filename && a->group == b->group; |
988 | } | 1082 | } |
989 | 1083 | ||
990 | static inline bool tomoyo_same_name_union | 1084 | /** |
991 | (const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2) | 1085 | * tomoyo_same_number_union - Check for duplicated "struct tomoyo_number_union" entry. |
1086 | * | ||
1087 | * @a: Pointer to "struct tomoyo_number_union". | ||
1088 | * @b: Pointer to "struct tomoyo_number_union". | ||
1089 | * | ||
1090 | * Returns true if @a == @b, false otherwise. | ||
1091 | */ | ||
1092 | static inline bool tomoyo_same_number_union | ||
1093 | (const struct tomoyo_number_union *a, const struct tomoyo_number_union *b) | ||
992 | { | 1094 | { |
993 | return p1->filename == p2->filename && p1->group == p2->group && | 1095 | return a->values[0] == b->values[0] && a->values[1] == b->values[1] && |
994 | p1->is_group == p2->is_group; | 1096 | a->group == b->group && a->value_type[0] == b->value_type[0] && |
1097 | a->value_type[1] == b->value_type[1]; | ||
995 | } | 1098 | } |
996 | 1099 | ||
997 | static inline bool tomoyo_same_number_union | 1100 | /** |
998 | (const struct tomoyo_number_union *p1, const struct tomoyo_number_union *p2) | 1101 | * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. |
1102 | * | ||
1103 | * Returns pointer to "struct tomoyo_policy_namespace" for current thread. | ||
1104 | */ | ||
1105 | static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void) | ||
1106 | { | ||
1107 | return tomoyo_domain()->ns; | ||
1108 | } | ||
1109 | |||
1110 | #if defined(CONFIG_SLOB) | ||
1111 | |||
1112 | /** | ||
1113 | * tomoyo_round2 - Round up to power of 2 for calculating memory usage. | ||
1114 | * | ||
1115 | * @size: Size to be rounded up. | ||
1116 | * | ||
1117 | * Returns @size. | ||
1118 | * | ||
1119 | * Since SLOB does not round up, this function simply returns @size. | ||
1120 | */ | ||
1121 | static inline int tomoyo_round2(size_t size) | ||
1122 | { | ||
1123 | return size; | ||
1124 | } | ||
1125 | |||
1126 | #else | ||
1127 | |||
1128 | /** | ||
1129 | * tomoyo_round2 - Round up to power of 2 for calculating memory usage. | ||
1130 | * | ||
1131 | * @size: Size to be rounded up. | ||
1132 | * | ||
1133 | * Returns rounded size. | ||
1134 | * | ||
1135 | * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of | ||
1136 | * (e.g.) 128 bytes. | ||
1137 | */ | ||
1138 | static inline int tomoyo_round2(size_t size) | ||
999 | { | 1139 | { |
1000 | return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1] | 1140 | #if PAGE_SIZE == 4096 |
1001 | && p1->group == p2->group && p1->min_type == p2->min_type && | 1141 | size_t bsize = 32; |
1002 | p1->max_type == p2->max_type && p1->is_group == p2->is_group; | 1142 | #else |
1143 | size_t bsize = 64; | ||
1144 | #endif | ||
1145 | if (!size) | ||
1146 | return 0; | ||
1147 | while (size > bsize) | ||
1148 | bsize <<= 1; | ||
1149 | return bsize; | ||
1003 | } | 1150 | } |
1004 | 1151 | ||
1152 | #endif | ||
1153 | |||
1005 | /** | 1154 | /** |
1006 | * list_for_each_cookie - iterate over a list with cookie. | 1155 | * list_for_each_cookie - iterate over a list with cookie. |
1007 | * @pos: the &struct list_head to use as a loop cursor. | 1156 | * @pos: the &struct list_head to use as a loop cursor. |
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c new file mode 100644 index 000000000000..8a05f71eaf67 --- /dev/null +++ b/security/tomoyo/condition.c | |||
@@ -0,0 +1,1035 @@ | |||
1 | /* | ||
2 | * security/tomoyo/condition.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION | ||
5 | */ | ||
6 | |||
7 | #include "common.h" | ||
8 | #include <linux/slab.h> | ||
9 | |||
10 | /* List of "struct tomoyo_condition". */ | ||
11 | LIST_HEAD(tomoyo_condition_list); | ||
12 | |||
13 | /** | ||
14 | * tomoyo_argv - Check argv[] in "struct linux_binbrm". | ||
15 | * | ||
16 | * @index: Index number of @arg_ptr. | ||
17 | * @arg_ptr: Contents of argv[@index]. | ||
18 | * @argc: Length of @argv. | ||
19 | * @argv: Pointer to "struct tomoyo_argv". | ||
20 | * @checked: Set to true if @argv[@index] was found. | ||
21 | * | ||
22 | * Returns true on success, false otherwise. | ||
23 | */ | ||
24 | static bool tomoyo_argv(const unsigned int index, const char *arg_ptr, | ||
25 | const int argc, const struct tomoyo_argv *argv, | ||
26 | u8 *checked) | ||
27 | { | ||
28 | int i; | ||
29 | struct tomoyo_path_info arg; | ||
30 | arg.name = arg_ptr; | ||
31 | for (i = 0; i < argc; argv++, checked++, i++) { | ||
32 | bool result; | ||
33 | if (index != argv->index) | ||
34 | continue; | ||
35 | *checked = 1; | ||
36 | tomoyo_fill_path_info(&arg); | ||
37 | result = tomoyo_path_matches_pattern(&arg, argv->value); | ||
38 | if (argv->is_not) | ||
39 | result = !result; | ||
40 | if (!result) | ||
41 | return false; | ||
42 | } | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * tomoyo_envp - Check envp[] in "struct linux_binbrm". | ||
48 | * | ||
49 | * @env_name: The name of environment variable. | ||
50 | * @env_value: The value of environment variable. | ||
51 | * @envc: Length of @envp. | ||
52 | * @envp: Pointer to "struct tomoyo_envp". | ||
53 | * @checked: Set to true if @envp[@env_name] was found. | ||
54 | * | ||
55 | * Returns true on success, false otherwise. | ||
56 | */ | ||
57 | static bool tomoyo_envp(const char *env_name, const char *env_value, | ||
58 | const int envc, const struct tomoyo_envp *envp, | ||
59 | u8 *checked) | ||
60 | { | ||
61 | int i; | ||
62 | struct tomoyo_path_info name; | ||
63 | struct tomoyo_path_info value; | ||
64 | name.name = env_name; | ||
65 | tomoyo_fill_path_info(&name); | ||
66 | value.name = env_value; | ||
67 | tomoyo_fill_path_info(&value); | ||
68 | for (i = 0; i < envc; envp++, checked++, i++) { | ||
69 | bool result; | ||
70 | if (!tomoyo_path_matches_pattern(&name, envp->name)) | ||
71 | continue; | ||
72 | *checked = 1; | ||
73 | if (envp->value) { | ||
74 | result = tomoyo_path_matches_pattern(&value, | ||
75 | envp->value); | ||
76 | if (envp->is_not) | ||
77 | result = !result; | ||
78 | } else { | ||
79 | result = true; | ||
80 | if (!envp->is_not) | ||
81 | result = !result; | ||
82 | } | ||
83 | if (!result) | ||
84 | return false; | ||
85 | } | ||
86 | return true; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * tomoyo_scan_bprm - Scan "struct linux_binprm". | ||
91 | * | ||
92 | * @ee: Pointer to "struct tomoyo_execve". | ||
93 | * @argc: Length of @argc. | ||
94 | * @argv: Pointer to "struct tomoyo_argv". | ||
95 | * @envc: Length of @envp. | ||
96 | * @envp: Poiner to "struct tomoyo_envp". | ||
97 | * | ||
98 | * Returns true on success, false otherwise. | ||
99 | */ | ||
100 | static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, | ||
101 | const u16 argc, const struct tomoyo_argv *argv, | ||
102 | const u16 envc, const struct tomoyo_envp *envp) | ||
103 | { | ||
104 | struct linux_binprm *bprm = ee->bprm; | ||
105 | struct tomoyo_page_dump *dump = &ee->dump; | ||
106 | char *arg_ptr = ee->tmp; | ||
107 | int arg_len = 0; | ||
108 | unsigned long pos = bprm->p; | ||
109 | int offset = pos % PAGE_SIZE; | ||
110 | int argv_count = bprm->argc; | ||
111 | int envp_count = bprm->envc; | ||
112 | bool result = true; | ||
113 | u8 local_checked[32]; | ||
114 | u8 *checked; | ||
115 | if (argc + envc <= sizeof(local_checked)) { | ||
116 | checked = local_checked; | ||
117 | memset(local_checked, 0, sizeof(local_checked)); | ||
118 | } else { | ||
119 | checked = kzalloc(argc + envc, GFP_NOFS); | ||
120 | if (!checked) | ||
121 | return false; | ||
122 | } | ||
123 | while (argv_count || envp_count) { | ||
124 | if (!tomoyo_dump_page(bprm, pos, dump)) { | ||
125 | result = false; | ||
126 | goto out; | ||
127 | } | ||
128 | pos += PAGE_SIZE - offset; | ||
129 | while (offset < PAGE_SIZE) { | ||
130 | /* Read. */ | ||
131 | const char *kaddr = dump->data; | ||
132 | const unsigned char c = kaddr[offset++]; | ||
133 | if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { | ||
134 | if (c == '\\') { | ||
135 | arg_ptr[arg_len++] = '\\'; | ||
136 | arg_ptr[arg_len++] = '\\'; | ||
137 | } else if (c > ' ' && c < 127) { | ||
138 | arg_ptr[arg_len++] = c; | ||
139 | } else { | ||
140 | arg_ptr[arg_len++] = '\\'; | ||
141 | arg_ptr[arg_len++] = (c >> 6) + '0'; | ||
142 | arg_ptr[arg_len++] = | ||
143 | ((c >> 3) & 7) + '0'; | ||
144 | arg_ptr[arg_len++] = (c & 7) + '0'; | ||
145 | } | ||
146 | } else { | ||
147 | arg_ptr[arg_len] = '\0'; | ||
148 | } | ||
149 | if (c) | ||
150 | continue; | ||
151 | /* Check. */ | ||
152 | if (argv_count) { | ||
153 | if (!tomoyo_argv(bprm->argc - argv_count, | ||
154 | arg_ptr, argc, argv, | ||
155 | checked)) { | ||
156 | result = false; | ||
157 | break; | ||
158 | } | ||
159 | argv_count--; | ||
160 | } else if (envp_count) { | ||
161 | char *cp = strchr(arg_ptr, '='); | ||
162 | if (cp) { | ||
163 | *cp = '\0'; | ||
164 | if (!tomoyo_envp(arg_ptr, cp + 1, | ||
165 | envc, envp, | ||
166 | checked + argc)) { | ||
167 | result = false; | ||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | envp_count--; | ||
172 | } else { | ||
173 | break; | ||
174 | } | ||
175 | arg_len = 0; | ||
176 | } | ||
177 | offset = 0; | ||
178 | if (!result) | ||
179 | break; | ||
180 | } | ||
181 | out: | ||
182 | if (result) { | ||
183 | int i; | ||
184 | /* Check not-yet-checked entries. */ | ||
185 | for (i = 0; i < argc; i++) { | ||
186 | if (checked[i]) | ||
187 | continue; | ||
188 | /* | ||
189 | * Return true only if all unchecked indexes in | ||
190 | * bprm->argv[] are not matched. | ||
191 | */ | ||
192 | if (argv[i].is_not) | ||
193 | continue; | ||
194 | result = false; | ||
195 | break; | ||
196 | } | ||
197 | for (i = 0; i < envc; envp++, i++) { | ||
198 | if (checked[argc + i]) | ||
199 | continue; | ||
200 | /* | ||
201 | * Return true only if all unchecked environ variables | ||
202 | * in bprm->envp[] are either undefined or not matched. | ||
203 | */ | ||
204 | if ((!envp->value && !envp->is_not) || | ||
205 | (envp->value && envp->is_not)) | ||
206 | continue; | ||
207 | result = false; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | if (checked != local_checked) | ||
212 | kfree(checked); | ||
213 | return result; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". | ||
218 | * | ||
219 | * @file: Pointer to "struct file". | ||
220 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
221 | * @match: True if "exec.realpath=", false if "exec.realpath!=". | ||
222 | * | ||
223 | * Returns true on success, false otherwise. | ||
224 | */ | ||
225 | static bool tomoyo_scan_exec_realpath(struct file *file, | ||
226 | const struct tomoyo_name_union *ptr, | ||
227 | const bool match) | ||
228 | { | ||
229 | bool result; | ||
230 | struct tomoyo_path_info exe; | ||
231 | if (!file) | ||
232 | return false; | ||
233 | exe.name = tomoyo_realpath_from_path(&file->f_path); | ||
234 | if (!exe.name) | ||
235 | return false; | ||
236 | tomoyo_fill_path_info(&exe); | ||
237 | result = tomoyo_compare_name_union(&exe, ptr); | ||
238 | kfree(exe.name); | ||
239 | return result == match; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * tomoyo_get_dqword - tomoyo_get_name() for a quoted string. | ||
244 | * | ||
245 | * @start: String to save. | ||
246 | * | ||
247 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | ||
248 | */ | ||
249 | static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) | ||
250 | { | ||
251 | char *cp = start + strlen(start) - 1; | ||
252 | if (cp == start || *start++ != '"' || *cp != '"') | ||
253 | return NULL; | ||
254 | *cp = '\0'; | ||
255 | if (*start && !tomoyo_correct_word(start)) | ||
256 | return NULL; | ||
257 | return tomoyo_get_name(start); | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * tomoyo_parse_name_union_quoted - Parse a quoted word. | ||
262 | * | ||
263 | * @param: Pointer to "struct tomoyo_acl_param". | ||
264 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
265 | * | ||
266 | * Returns true on success, false otherwise. | ||
267 | */ | ||
268 | static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, | ||
269 | struct tomoyo_name_union *ptr) | ||
270 | { | ||
271 | char *filename = param->data; | ||
272 | if (*filename == '@') | ||
273 | return tomoyo_parse_name_union(param, ptr); | ||
274 | ptr->filename = tomoyo_get_dqword(filename); | ||
275 | return ptr->filename != NULL; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * tomoyo_parse_argv - Parse an argv[] condition part. | ||
280 | * | ||
281 | * @left: Lefthand value. | ||
282 | * @right: Righthand value. | ||
283 | * @argv: Pointer to "struct tomoyo_argv". | ||
284 | * | ||
285 | * Returns true on success, false otherwise. | ||
286 | */ | ||
287 | static bool tomoyo_parse_argv(char *left, char *right, | ||
288 | struct tomoyo_argv *argv) | ||
289 | { | ||
290 | if (tomoyo_parse_ulong(&argv->index, &left) != | ||
291 | TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left) | ||
292 | return false; | ||
293 | argv->value = tomoyo_get_dqword(right); | ||
294 | return argv->value != NULL; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * tomoyo_parse_envp - Parse an envp[] condition part. | ||
299 | * | ||
300 | * @left: Lefthand value. | ||
301 | * @right: Righthand value. | ||
302 | * @envp: Pointer to "struct tomoyo_envp". | ||
303 | * | ||
304 | * Returns true on success, false otherwise. | ||
305 | */ | ||
306 | static bool tomoyo_parse_envp(char *left, char *right, | ||
307 | struct tomoyo_envp *envp) | ||
308 | { | ||
309 | const struct tomoyo_path_info *name; | ||
310 | const struct tomoyo_path_info *value; | ||
311 | char *cp = left + strlen(left) - 1; | ||
312 | if (*cp-- != ']' || *cp != '"') | ||
313 | goto out; | ||
314 | *cp = '\0'; | ||
315 | if (!tomoyo_correct_word(left)) | ||
316 | goto out; | ||
317 | name = tomoyo_get_name(left); | ||
318 | if (!name) | ||
319 | goto out; | ||
320 | if (!strcmp(right, "NULL")) { | ||
321 | value = NULL; | ||
322 | } else { | ||
323 | value = tomoyo_get_dqword(right); | ||
324 | if (!value) { | ||
325 | tomoyo_put_name(name); | ||
326 | goto out; | ||
327 | } | ||
328 | } | ||
329 | envp->name = name; | ||
330 | envp->value = value; | ||
331 | return true; | ||
332 | out: | ||
333 | return false; | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. | ||
338 | * | ||
339 | * @a: Pointer to "struct tomoyo_condition". | ||
340 | * @b: Pointer to "struct tomoyo_condition". | ||
341 | * | ||
342 | * Returns true if @a == @b, false otherwise. | ||
343 | */ | ||
344 | static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | ||
345 | const struct tomoyo_condition *b) | ||
346 | { | ||
347 | return a->size == b->size && a->condc == b->condc && | ||
348 | a->numbers_count == b->numbers_count && | ||
349 | a->names_count == b->names_count && | ||
350 | a->argc == b->argc && a->envc == b->envc && | ||
351 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * tomoyo_condition_type - Get condition type. | ||
356 | * | ||
357 | * @word: Keyword string. | ||
358 | * | ||
359 | * Returns one of values in "enum tomoyo_conditions_index" on success, | ||
360 | * TOMOYO_MAX_CONDITION_KEYWORD otherwise. | ||
361 | */ | ||
362 | static u8 tomoyo_condition_type(const char *word) | ||
363 | { | ||
364 | u8 i; | ||
365 | for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) { | ||
366 | if (!strcmp(word, tomoyo_condition_keyword[i])) | ||
367 | break; | ||
368 | } | ||
369 | return i; | ||
370 | } | ||
371 | |||
372 | /* Define this to enable debug mode. */ | ||
373 | /* #define DEBUG_CONDITION */ | ||
374 | |||
375 | #ifdef DEBUG_CONDITION | ||
376 | #define dprintk printk | ||
377 | #else | ||
378 | #define dprintk(...) do { } while (0) | ||
379 | #endif | ||
380 | |||
381 | /** | ||
382 | * tomoyo_commit_condition - Commit "struct tomoyo_condition". | ||
383 | * | ||
384 | * @entry: Pointer to "struct tomoyo_condition". | ||
385 | * | ||
386 | * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. | ||
387 | * | ||
388 | * This function merges duplicated entries. This function returns NULL if | ||
389 | * @entry is not duplicated but memory quota for policy has exceeded. | ||
390 | */ | ||
391 | static struct tomoyo_condition *tomoyo_commit_condition | ||
392 | (struct tomoyo_condition *entry) | ||
393 | { | ||
394 | struct tomoyo_condition *ptr; | ||
395 | bool found = false; | ||
396 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) { | ||
397 | dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); | ||
398 | ptr = NULL; | ||
399 | found = true; | ||
400 | goto out; | ||
401 | } | ||
402 | list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) { | ||
403 | if (!tomoyo_same_condition(ptr, entry)) | ||
404 | continue; | ||
405 | /* Same entry found. Share this entry. */ | ||
406 | atomic_inc(&ptr->head.users); | ||
407 | found = true; | ||
408 | break; | ||
409 | } | ||
410 | if (!found) { | ||
411 | if (tomoyo_memory_ok(entry)) { | ||
412 | atomic_set(&entry->head.users, 1); | ||
413 | list_add_rcu(&entry->head.list, | ||
414 | &tomoyo_condition_list); | ||
415 | } else { | ||
416 | found = true; | ||
417 | ptr = NULL; | ||
418 | } | ||
419 | } | ||
420 | mutex_unlock(&tomoyo_policy_lock); | ||
421 | out: | ||
422 | if (found) { | ||
423 | tomoyo_del_condition(&entry->head.list); | ||
424 | kfree(entry); | ||
425 | entry = ptr; | ||
426 | } | ||
427 | return entry; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * tomoyo_get_condition - Parse condition part. | ||
432 | * | ||
433 | * @param: Pointer to "struct tomoyo_acl_param". | ||
434 | * | ||
435 | * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. | ||
436 | */ | ||
437 | struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | ||
438 | { | ||
439 | struct tomoyo_condition *entry = NULL; | ||
440 | struct tomoyo_condition_element *condp = NULL; | ||
441 | struct tomoyo_number_union *numbers_p = NULL; | ||
442 | struct tomoyo_name_union *names_p = NULL; | ||
443 | struct tomoyo_argv *argv = NULL; | ||
444 | struct tomoyo_envp *envp = NULL; | ||
445 | struct tomoyo_condition e = { }; | ||
446 | char * const start_of_string = param->data; | ||
447 | char * const end_of_string = start_of_string + strlen(start_of_string); | ||
448 | char *pos; | ||
449 | rerun: | ||
450 | pos = start_of_string; | ||
451 | while (1) { | ||
452 | u8 left = -1; | ||
453 | u8 right = -1; | ||
454 | char *left_word = pos; | ||
455 | char *cp; | ||
456 | char *right_word; | ||
457 | bool is_not; | ||
458 | if (!*left_word) | ||
459 | break; | ||
460 | /* | ||
461 | * Since left-hand condition does not allow use of "path_group" | ||
462 | * or "number_group" and environment variable's names do not | ||
463 | * accept '=', it is guaranteed that the original line consists | ||
464 | * of one or more repetition of $left$operator$right blocks | ||
465 | * where "$left is free from '=' and ' '" and "$operator is | ||
466 | * either '=' or '!='" and "$right is free from ' '". | ||
467 | * Therefore, we can reconstruct the original line at the end | ||
468 | * of dry run even if we overwrite $operator with '\0'. | ||
469 | */ | ||
470 | cp = strchr(pos, ' '); | ||
471 | if (cp) { | ||
472 | *cp = '\0'; /* Will restore later. */ | ||
473 | pos = cp + 1; | ||
474 | } else { | ||
475 | pos = ""; | ||
476 | } | ||
477 | right_word = strchr(left_word, '='); | ||
478 | if (!right_word || right_word == left_word) | ||
479 | goto out; | ||
480 | is_not = *(right_word - 1) == '!'; | ||
481 | if (is_not) | ||
482 | *(right_word++ - 1) = '\0'; /* Will restore later. */ | ||
483 | else if (*(right_word + 1) != '=') | ||
484 | *right_word++ = '\0'; /* Will restore later. */ | ||
485 | else | ||
486 | goto out; | ||
487 | dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, | ||
488 | is_not ? "!" : "", right_word); | ||
489 | if (!strncmp(left_word, "exec.argv[", 10)) { | ||
490 | if (!argv) { | ||
491 | e.argc++; | ||
492 | e.condc++; | ||
493 | } else { | ||
494 | e.argc--; | ||
495 | e.condc--; | ||
496 | left = TOMOYO_ARGV_ENTRY; | ||
497 | argv->is_not = is_not; | ||
498 | if (!tomoyo_parse_argv(left_word + 10, | ||
499 | right_word, argv++)) | ||
500 | goto out; | ||
501 | } | ||
502 | goto store_value; | ||
503 | } | ||
504 | if (!strncmp(left_word, "exec.envp[\"", 11)) { | ||
505 | if (!envp) { | ||
506 | e.envc++; | ||
507 | e.condc++; | ||
508 | } else { | ||
509 | e.envc--; | ||
510 | e.condc--; | ||
511 | left = TOMOYO_ENVP_ENTRY; | ||
512 | envp->is_not = is_not; | ||
513 | if (!tomoyo_parse_envp(left_word + 11, | ||
514 | right_word, envp++)) | ||
515 | goto out; | ||
516 | } | ||
517 | goto store_value; | ||
518 | } | ||
519 | left = tomoyo_condition_type(left_word); | ||
520 | dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word, | ||
521 | left); | ||
522 | if (left == TOMOYO_MAX_CONDITION_KEYWORD) { | ||
523 | if (!numbers_p) { | ||
524 | e.numbers_count++; | ||
525 | } else { | ||
526 | e.numbers_count--; | ||
527 | left = TOMOYO_NUMBER_UNION; | ||
528 | param->data = left_word; | ||
529 | if (*left_word == '@' || | ||
530 | !tomoyo_parse_number_union(param, | ||
531 | numbers_p++)) | ||
532 | goto out; | ||
533 | } | ||
534 | } | ||
535 | if (!condp) | ||
536 | e.condc++; | ||
537 | else | ||
538 | e.condc--; | ||
539 | if (left == TOMOYO_EXEC_REALPATH || | ||
540 | left == TOMOYO_SYMLINK_TARGET) { | ||
541 | if (!names_p) { | ||
542 | e.names_count++; | ||
543 | } else { | ||
544 | e.names_count--; | ||
545 | right = TOMOYO_NAME_UNION; | ||
546 | param->data = right_word; | ||
547 | if (!tomoyo_parse_name_union_quoted(param, | ||
548 | names_p++)) | ||
549 | goto out; | ||
550 | } | ||
551 | goto store_value; | ||
552 | } | ||
553 | right = tomoyo_condition_type(right_word); | ||
554 | if (right == TOMOYO_MAX_CONDITION_KEYWORD) { | ||
555 | if (!numbers_p) { | ||
556 | e.numbers_count++; | ||
557 | } else { | ||
558 | e.numbers_count--; | ||
559 | right = TOMOYO_NUMBER_UNION; | ||
560 | param->data = right_word; | ||
561 | if (!tomoyo_parse_number_union(param, | ||
562 | numbers_p++)) | ||
563 | goto out; | ||
564 | } | ||
565 | } | ||
566 | store_value: | ||
567 | if (!condp) { | ||
568 | dprintk(KERN_WARNING "%u: dry_run left=%u right=%u " | ||
569 | "match=%u\n", __LINE__, left, right, !is_not); | ||
570 | continue; | ||
571 | } | ||
572 | condp->left = left; | ||
573 | condp->right = right; | ||
574 | condp->equals = !is_not; | ||
575 | dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n", | ||
576 | __LINE__, condp->left, condp->right, | ||
577 | condp->equals); | ||
578 | condp++; | ||
579 | } | ||
580 | dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n", | ||
581 | __LINE__, e.condc, e.numbers_count, e.names_count, e.argc, | ||
582 | e.envc); | ||
583 | if (entry) { | ||
584 | BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc | | ||
585 | e.condc); | ||
586 | return tomoyo_commit_condition(entry); | ||
587 | } | ||
588 | e.size = sizeof(*entry) | ||
589 | + e.condc * sizeof(struct tomoyo_condition_element) | ||
590 | + e.numbers_count * sizeof(struct tomoyo_number_union) | ||
591 | + e.names_count * sizeof(struct tomoyo_name_union) | ||
592 | + e.argc * sizeof(struct tomoyo_argv) | ||
593 | + e.envc * sizeof(struct tomoyo_envp); | ||
594 | entry = kzalloc(e.size, GFP_NOFS); | ||
595 | if (!entry) | ||
596 | return NULL; | ||
597 | *entry = e; | ||
598 | condp = (struct tomoyo_condition_element *) (entry + 1); | ||
599 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); | ||
600 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); | ||
601 | argv = (struct tomoyo_argv *) (names_p + e.names_count); | ||
602 | envp = (struct tomoyo_envp *) (argv + e.argc); | ||
603 | { | ||
604 | bool flag = false; | ||
605 | for (pos = start_of_string; pos < end_of_string; pos++) { | ||
606 | if (*pos) | ||
607 | continue; | ||
608 | if (flag) /* Restore " ". */ | ||
609 | *pos = ' '; | ||
610 | else if (*(pos + 1) == '=') /* Restore "!=". */ | ||
611 | *pos = '!'; | ||
612 | else /* Restore "=". */ | ||
613 | *pos = '='; | ||
614 | flag = !flag; | ||
615 | } | ||
616 | } | ||
617 | goto rerun; | ||
618 | out: | ||
619 | dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); | ||
620 | if (entry) { | ||
621 | tomoyo_del_condition(&entry->head.list); | ||
622 | kfree(entry); | ||
623 | } | ||
624 | return NULL; | ||
625 | } | ||
626 | |||
627 | /** | ||
628 | * tomoyo_get_attributes - Revalidate "struct inode". | ||
629 | * | ||
630 | * @obj: Pointer to "struct tomoyo_obj_info". | ||
631 | * | ||
632 | * Returns nothing. | ||
633 | */ | ||
634 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj) | ||
635 | { | ||
636 | u8 i; | ||
637 | struct dentry *dentry = NULL; | ||
638 | |||
639 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { | ||
640 | struct inode *inode; | ||
641 | switch (i) { | ||
642 | case TOMOYO_PATH1: | ||
643 | dentry = obj->path1.dentry; | ||
644 | if (!dentry) | ||
645 | continue; | ||
646 | break; | ||
647 | case TOMOYO_PATH2: | ||
648 | dentry = obj->path2.dentry; | ||
649 | if (!dentry) | ||
650 | continue; | ||
651 | break; | ||
652 | default: | ||
653 | if (!dentry) | ||
654 | continue; | ||
655 | dentry = dget_parent(dentry); | ||
656 | break; | ||
657 | } | ||
658 | inode = dentry->d_inode; | ||
659 | if (inode) { | ||
660 | struct tomoyo_mini_stat *stat = &obj->stat[i]; | ||
661 | stat->uid = inode->i_uid; | ||
662 | stat->gid = inode->i_gid; | ||
663 | stat->ino = inode->i_ino; | ||
664 | stat->mode = inode->i_mode; | ||
665 | stat->dev = inode->i_sb->s_dev; | ||
666 | stat->rdev = inode->i_rdev; | ||
667 | obj->stat_valid[i] = true; | ||
668 | } | ||
669 | if (i & 1) /* i == TOMOYO_PATH1_PARENT || | ||
670 | i == TOMOYO_PATH2_PARENT */ | ||
671 | dput(dentry); | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * tomoyo_condition - Check condition part. | ||
677 | * | ||
678 | * @r: Pointer to "struct tomoyo_request_info". | ||
679 | * @cond: Pointer to "struct tomoyo_condition". Maybe NULL. | ||
680 | * | ||
681 | * Returns true on success, false otherwise. | ||
682 | * | ||
683 | * Caller holds tomoyo_read_lock(). | ||
684 | */ | ||
685 | bool tomoyo_condition(struct tomoyo_request_info *r, | ||
686 | const struct tomoyo_condition *cond) | ||
687 | { | ||
688 | u32 i; | ||
689 | unsigned long min_v[2] = { 0, 0 }; | ||
690 | unsigned long max_v[2] = { 0, 0 }; | ||
691 | const struct tomoyo_condition_element *condp; | ||
692 | const struct tomoyo_number_union *numbers_p; | ||
693 | const struct tomoyo_name_union *names_p; | ||
694 | const struct tomoyo_argv *argv; | ||
695 | const struct tomoyo_envp *envp; | ||
696 | struct tomoyo_obj_info *obj; | ||
697 | u16 condc; | ||
698 | u16 argc; | ||
699 | u16 envc; | ||
700 | struct linux_binprm *bprm = NULL; | ||
701 | if (!cond) | ||
702 | return true; | ||
703 | condc = cond->condc; | ||
704 | argc = cond->argc; | ||
705 | envc = cond->envc; | ||
706 | obj = r->obj; | ||
707 | if (r->ee) | ||
708 | bprm = r->ee->bprm; | ||
709 | if (!bprm && (argc || envc)) | ||
710 | return false; | ||
711 | condp = (struct tomoyo_condition_element *) (cond + 1); | ||
712 | numbers_p = (const struct tomoyo_number_union *) (condp + condc); | ||
713 | names_p = (const struct tomoyo_name_union *) | ||
714 | (numbers_p + cond->numbers_count); | ||
715 | argv = (const struct tomoyo_argv *) (names_p + cond->names_count); | ||
716 | envp = (const struct tomoyo_envp *) (argv + argc); | ||
717 | for (i = 0; i < condc; i++) { | ||
718 | const bool match = condp->equals; | ||
719 | const u8 left = condp->left; | ||
720 | const u8 right = condp->right; | ||
721 | bool is_bitop[2] = { false, false }; | ||
722 | u8 j; | ||
723 | condp++; | ||
724 | /* Check argv[] and envp[] later. */ | ||
725 | if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY) | ||
726 | continue; | ||
727 | /* Check string expressions. */ | ||
728 | if (right == TOMOYO_NAME_UNION) { | ||
729 | const struct tomoyo_name_union *ptr = names_p++; | ||
730 | switch (left) { | ||
731 | struct tomoyo_path_info *symlink; | ||
732 | struct tomoyo_execve *ee; | ||
733 | struct file *file; | ||
734 | case TOMOYO_SYMLINK_TARGET: | ||
735 | symlink = obj ? obj->symlink_target : NULL; | ||
736 | if (!symlink || | ||
737 | !tomoyo_compare_name_union(symlink, ptr) | ||
738 | == match) | ||
739 | goto out; | ||
740 | break; | ||
741 | case TOMOYO_EXEC_REALPATH: | ||
742 | ee = r->ee; | ||
743 | file = ee ? ee->bprm->file : NULL; | ||
744 | if (!tomoyo_scan_exec_realpath(file, ptr, | ||
745 | match)) | ||
746 | goto out; | ||
747 | break; | ||
748 | } | ||
749 | continue; | ||
750 | } | ||
751 | /* Check numeric or bit-op expressions. */ | ||
752 | for (j = 0; j < 2; j++) { | ||
753 | const u8 index = j ? right : left; | ||
754 | unsigned long value = 0; | ||
755 | switch (index) { | ||
756 | case TOMOYO_TASK_UID: | ||
757 | value = current_uid(); | ||
758 | break; | ||
759 | case TOMOYO_TASK_EUID: | ||
760 | value = current_euid(); | ||
761 | break; | ||
762 | case TOMOYO_TASK_SUID: | ||
763 | value = current_suid(); | ||
764 | break; | ||
765 | case TOMOYO_TASK_FSUID: | ||
766 | value = current_fsuid(); | ||
767 | break; | ||
768 | case TOMOYO_TASK_GID: | ||
769 | value = current_gid(); | ||
770 | break; | ||
771 | case TOMOYO_TASK_EGID: | ||
772 | value = current_egid(); | ||
773 | break; | ||
774 | case TOMOYO_TASK_SGID: | ||
775 | value = current_sgid(); | ||
776 | break; | ||
777 | case TOMOYO_TASK_FSGID: | ||
778 | value = current_fsgid(); | ||
779 | break; | ||
780 | case TOMOYO_TASK_PID: | ||
781 | value = tomoyo_sys_getpid(); | ||
782 | break; | ||
783 | case TOMOYO_TASK_PPID: | ||
784 | value = tomoyo_sys_getppid(); | ||
785 | break; | ||
786 | case TOMOYO_TYPE_IS_SOCKET: | ||
787 | value = S_IFSOCK; | ||
788 | break; | ||
789 | case TOMOYO_TYPE_IS_SYMLINK: | ||
790 | value = S_IFLNK; | ||
791 | break; | ||
792 | case TOMOYO_TYPE_IS_FILE: | ||
793 | value = S_IFREG; | ||
794 | break; | ||
795 | case TOMOYO_TYPE_IS_BLOCK_DEV: | ||
796 | value = S_IFBLK; | ||
797 | break; | ||
798 | case TOMOYO_TYPE_IS_DIRECTORY: | ||
799 | value = S_IFDIR; | ||
800 | break; | ||
801 | case TOMOYO_TYPE_IS_CHAR_DEV: | ||
802 | value = S_IFCHR; | ||
803 | break; | ||
804 | case TOMOYO_TYPE_IS_FIFO: | ||
805 | value = S_IFIFO; | ||
806 | break; | ||
807 | case TOMOYO_MODE_SETUID: | ||
808 | value = S_ISUID; | ||
809 | break; | ||
810 | case TOMOYO_MODE_SETGID: | ||
811 | value = S_ISGID; | ||
812 | break; | ||
813 | case TOMOYO_MODE_STICKY: | ||
814 | value = S_ISVTX; | ||
815 | break; | ||
816 | case TOMOYO_MODE_OWNER_READ: | ||
817 | value = S_IRUSR; | ||
818 | break; | ||
819 | case TOMOYO_MODE_OWNER_WRITE: | ||
820 | value = S_IWUSR; | ||
821 | break; | ||
822 | case TOMOYO_MODE_OWNER_EXECUTE: | ||
823 | value = S_IXUSR; | ||
824 | break; | ||
825 | case TOMOYO_MODE_GROUP_READ: | ||
826 | value = S_IRGRP; | ||
827 | break; | ||
828 | case TOMOYO_MODE_GROUP_WRITE: | ||
829 | value = S_IWGRP; | ||
830 | break; | ||
831 | case TOMOYO_MODE_GROUP_EXECUTE: | ||
832 | value = S_IXGRP; | ||
833 | break; | ||
834 | case TOMOYO_MODE_OTHERS_READ: | ||
835 | value = S_IROTH; | ||
836 | break; | ||
837 | case TOMOYO_MODE_OTHERS_WRITE: | ||
838 | value = S_IWOTH; | ||
839 | break; | ||
840 | case TOMOYO_MODE_OTHERS_EXECUTE: | ||
841 | value = S_IXOTH; | ||
842 | break; | ||
843 | case TOMOYO_EXEC_ARGC: | ||
844 | if (!bprm) | ||
845 | goto out; | ||
846 | value = bprm->argc; | ||
847 | break; | ||
848 | case TOMOYO_EXEC_ENVC: | ||
849 | if (!bprm) | ||
850 | goto out; | ||
851 | value = bprm->envc; | ||
852 | break; | ||
853 | case TOMOYO_NUMBER_UNION: | ||
854 | /* Fetch values later. */ | ||
855 | break; | ||
856 | default: | ||
857 | if (!obj) | ||
858 | goto out; | ||
859 | if (!obj->validate_done) { | ||
860 | tomoyo_get_attributes(obj); | ||
861 | obj->validate_done = true; | ||
862 | } | ||
863 | { | ||
864 | u8 stat_index; | ||
865 | struct tomoyo_mini_stat *stat; | ||
866 | switch (index) { | ||
867 | case TOMOYO_PATH1_UID: | ||
868 | case TOMOYO_PATH1_GID: | ||
869 | case TOMOYO_PATH1_INO: | ||
870 | case TOMOYO_PATH1_MAJOR: | ||
871 | case TOMOYO_PATH1_MINOR: | ||
872 | case TOMOYO_PATH1_TYPE: | ||
873 | case TOMOYO_PATH1_DEV_MAJOR: | ||
874 | case TOMOYO_PATH1_DEV_MINOR: | ||
875 | case TOMOYO_PATH1_PERM: | ||
876 | stat_index = TOMOYO_PATH1; | ||
877 | break; | ||
878 | case TOMOYO_PATH2_UID: | ||
879 | case TOMOYO_PATH2_GID: | ||
880 | case TOMOYO_PATH2_INO: | ||
881 | case TOMOYO_PATH2_MAJOR: | ||
882 | case TOMOYO_PATH2_MINOR: | ||
883 | case TOMOYO_PATH2_TYPE: | ||
884 | case TOMOYO_PATH2_DEV_MAJOR: | ||
885 | case TOMOYO_PATH2_DEV_MINOR: | ||
886 | case TOMOYO_PATH2_PERM: | ||
887 | stat_index = TOMOYO_PATH2; | ||
888 | break; | ||
889 | case TOMOYO_PATH1_PARENT_UID: | ||
890 | case TOMOYO_PATH1_PARENT_GID: | ||
891 | case TOMOYO_PATH1_PARENT_INO: | ||
892 | case TOMOYO_PATH1_PARENT_PERM: | ||
893 | stat_index = | ||
894 | TOMOYO_PATH1_PARENT; | ||
895 | break; | ||
896 | case TOMOYO_PATH2_PARENT_UID: | ||
897 | case TOMOYO_PATH2_PARENT_GID: | ||
898 | case TOMOYO_PATH2_PARENT_INO: | ||
899 | case TOMOYO_PATH2_PARENT_PERM: | ||
900 | stat_index = | ||
901 | TOMOYO_PATH2_PARENT; | ||
902 | break; | ||
903 | default: | ||
904 | goto out; | ||
905 | } | ||
906 | if (!obj->stat_valid[stat_index]) | ||
907 | goto out; | ||
908 | stat = &obj->stat[stat_index]; | ||
909 | switch (index) { | ||
910 | case TOMOYO_PATH1_UID: | ||
911 | case TOMOYO_PATH2_UID: | ||
912 | case TOMOYO_PATH1_PARENT_UID: | ||
913 | case TOMOYO_PATH2_PARENT_UID: | ||
914 | value = stat->uid; | ||
915 | break; | ||
916 | case TOMOYO_PATH1_GID: | ||
917 | case TOMOYO_PATH2_GID: | ||
918 | case TOMOYO_PATH1_PARENT_GID: | ||
919 | case TOMOYO_PATH2_PARENT_GID: | ||
920 | value = stat->gid; | ||
921 | break; | ||
922 | case TOMOYO_PATH1_INO: | ||
923 | case TOMOYO_PATH2_INO: | ||
924 | case TOMOYO_PATH1_PARENT_INO: | ||
925 | case TOMOYO_PATH2_PARENT_INO: | ||
926 | value = stat->ino; | ||
927 | break; | ||
928 | case TOMOYO_PATH1_MAJOR: | ||
929 | case TOMOYO_PATH2_MAJOR: | ||
930 | value = MAJOR(stat->dev); | ||
931 | break; | ||
932 | case TOMOYO_PATH1_MINOR: | ||
933 | case TOMOYO_PATH2_MINOR: | ||
934 | value = MINOR(stat->dev); | ||
935 | break; | ||
936 | case TOMOYO_PATH1_TYPE: | ||
937 | case TOMOYO_PATH2_TYPE: | ||
938 | value = stat->mode & S_IFMT; | ||
939 | break; | ||
940 | case TOMOYO_PATH1_DEV_MAJOR: | ||
941 | case TOMOYO_PATH2_DEV_MAJOR: | ||
942 | value = MAJOR(stat->rdev); | ||
943 | break; | ||
944 | case TOMOYO_PATH1_DEV_MINOR: | ||
945 | case TOMOYO_PATH2_DEV_MINOR: | ||
946 | value = MINOR(stat->rdev); | ||
947 | break; | ||
948 | case TOMOYO_PATH1_PERM: | ||
949 | case TOMOYO_PATH2_PERM: | ||
950 | case TOMOYO_PATH1_PARENT_PERM: | ||
951 | case TOMOYO_PATH2_PARENT_PERM: | ||
952 | value = stat->mode & S_IALLUGO; | ||
953 | break; | ||
954 | } | ||
955 | } | ||
956 | break; | ||
957 | } | ||
958 | max_v[j] = value; | ||
959 | min_v[j] = value; | ||
960 | switch (index) { | ||
961 | case TOMOYO_MODE_SETUID: | ||
962 | case TOMOYO_MODE_SETGID: | ||
963 | case TOMOYO_MODE_STICKY: | ||
964 | case TOMOYO_MODE_OWNER_READ: | ||
965 | case TOMOYO_MODE_OWNER_WRITE: | ||
966 | case TOMOYO_MODE_OWNER_EXECUTE: | ||
967 | case TOMOYO_MODE_GROUP_READ: | ||
968 | case TOMOYO_MODE_GROUP_WRITE: | ||
969 | case TOMOYO_MODE_GROUP_EXECUTE: | ||
970 | case TOMOYO_MODE_OTHERS_READ: | ||
971 | case TOMOYO_MODE_OTHERS_WRITE: | ||
972 | case TOMOYO_MODE_OTHERS_EXECUTE: | ||
973 | is_bitop[j] = true; | ||
974 | } | ||
975 | } | ||
976 | if (left == TOMOYO_NUMBER_UNION) { | ||
977 | /* Fetch values now. */ | ||
978 | const struct tomoyo_number_union *ptr = numbers_p++; | ||
979 | min_v[0] = ptr->values[0]; | ||
980 | max_v[0] = ptr->values[1]; | ||
981 | } | ||
982 | if (right == TOMOYO_NUMBER_UNION) { | ||
983 | /* Fetch values now. */ | ||
984 | const struct tomoyo_number_union *ptr = numbers_p++; | ||
985 | if (ptr->group) { | ||
986 | if (tomoyo_number_matches_group(min_v[0], | ||
987 | max_v[0], | ||
988 | ptr->group) | ||
989 | == match) | ||
990 | continue; | ||
991 | } else { | ||
992 | if ((min_v[0] <= ptr->values[1] && | ||
993 | max_v[0] >= ptr->values[0]) == match) | ||
994 | continue; | ||
995 | } | ||
996 | goto out; | ||
997 | } | ||
998 | /* | ||
999 | * Bit operation is valid only when counterpart value | ||
1000 | * represents permission. | ||
1001 | */ | ||
1002 | if (is_bitop[0] && is_bitop[1]) { | ||
1003 | goto out; | ||
1004 | } else if (is_bitop[0]) { | ||
1005 | switch (right) { | ||
1006 | case TOMOYO_PATH1_PERM: | ||
1007 | case TOMOYO_PATH1_PARENT_PERM: | ||
1008 | case TOMOYO_PATH2_PERM: | ||
1009 | case TOMOYO_PATH2_PARENT_PERM: | ||
1010 | if (!(max_v[0] & max_v[1]) == !match) | ||
1011 | continue; | ||
1012 | } | ||
1013 | goto out; | ||
1014 | } else if (is_bitop[1]) { | ||
1015 | switch (left) { | ||
1016 | case TOMOYO_PATH1_PERM: | ||
1017 | case TOMOYO_PATH1_PARENT_PERM: | ||
1018 | case TOMOYO_PATH2_PERM: | ||
1019 | case TOMOYO_PATH2_PARENT_PERM: | ||
1020 | if (!(max_v[0] & max_v[1]) == !match) | ||
1021 | continue; | ||
1022 | } | ||
1023 | goto out; | ||
1024 | } | ||
1025 | /* Normal value range comparison. */ | ||
1026 | if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match) | ||
1027 | continue; | ||
1028 | out: | ||
1029 | return false; | ||
1030 | } | ||
1031 | /* Check argv[] and envp[] now. */ | ||
1032 | if (r->ee && (argc || envc)) | ||
1033 | return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp); | ||
1034 | return true; | ||
1035 | } | ||
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 35388408e475..cd0f92d88bb4 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/domain.c | 2 | * security/tomoyo/domain.c |
3 | * | 3 | * |
4 | * Domain transition functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
@@ -20,8 +18,7 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
20 | * | 18 | * |
21 | * @new_entry: Pointer to "struct tomoyo_acl_info". | 19 | * @new_entry: Pointer to "struct tomoyo_acl_info". |
22 | * @size: Size of @new_entry in bytes. | 20 | * @size: Size of @new_entry in bytes. |
23 | * @is_delete: True if it is a delete request. | 21 | * @param: Pointer to "struct tomoyo_acl_param". |
24 | * @list: Pointer to "struct list_head". | ||
25 | * @check_duplicate: Callback function to find duplicated entry. | 22 | * @check_duplicate: Callback function to find duplicated entry. |
26 | * | 23 | * |
27 | * Returns 0 on success, negative value otherwise. | 24 | * Returns 0 on success, negative value otherwise. |
@@ -29,25 +26,26 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
29 | * Caller holds tomoyo_read_lock(). | 26 | * Caller holds tomoyo_read_lock(). |
30 | */ | 27 | */ |
31 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | 28 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
32 | bool is_delete, struct list_head *list, | 29 | struct tomoyo_acl_param *param, |
33 | bool (*check_duplicate) (const struct tomoyo_acl_head | 30 | bool (*check_duplicate) (const struct tomoyo_acl_head |
34 | *, | 31 | *, |
35 | const struct tomoyo_acl_head | 32 | const struct tomoyo_acl_head |
36 | *)) | 33 | *)) |
37 | { | 34 | { |
38 | int error = is_delete ? -ENOENT : -ENOMEM; | 35 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
39 | struct tomoyo_acl_head *entry; | 36 | struct tomoyo_acl_head *entry; |
37 | struct list_head *list = param->list; | ||
40 | 38 | ||
41 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
42 | return -ENOMEM; | 40 | return -ENOMEM; |
43 | list_for_each_entry_rcu(entry, list, list) { | 41 | list_for_each_entry_rcu(entry, list, list) { |
44 | if (!check_duplicate(entry, new_entry)) | 42 | if (!check_duplicate(entry, new_entry)) |
45 | continue; | 43 | continue; |
46 | entry->is_deleted = is_delete; | 44 | entry->is_deleted = param->is_delete; |
47 | error = 0; | 45 | error = 0; |
48 | break; | 46 | break; |
49 | } | 47 | } |
50 | if (error && !is_delete) { | 48 | if (error && !param->is_delete) { |
51 | entry = tomoyo_commit_ok(new_entry, size); | 49 | entry = tomoyo_commit_ok(new_entry, size); |
52 | if (entry) { | 50 | if (entry) { |
53 | list_add_tail_rcu(&entry->list, list); | 51 | list_add_tail_rcu(&entry->list, list); |
@@ -59,12 +57,25 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
59 | } | 57 | } |
60 | 58 | ||
61 | /** | 59 | /** |
60 | * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry. | ||
61 | * | ||
62 | * @a: Pointer to "struct tomoyo_acl_info". | ||
63 | * @b: Pointer to "struct tomoyo_acl_info". | ||
64 | * | ||
65 | * Returns true if @a == @b, false otherwise. | ||
66 | */ | ||
67 | static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, | ||
68 | const struct tomoyo_acl_info *b) | ||
69 | { | ||
70 | return a->type == b->type && a->cond == b->cond; | ||
71 | } | ||
72 | |||
73 | /** | ||
62 | * tomoyo_update_domain - Update an entry for domain policy. | 74 | * tomoyo_update_domain - Update an entry for domain policy. |
63 | * | 75 | * |
64 | * @new_entry: Pointer to "struct tomoyo_acl_info". | 76 | * @new_entry: Pointer to "struct tomoyo_acl_info". |
65 | * @size: Size of @new_entry in bytes. | 77 | * @size: Size of @new_entry in bytes. |
66 | * @is_delete: True if it is a delete request. | 78 | * @param: Pointer to "struct tomoyo_acl_param". |
67 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
68 | * @check_duplicate: Callback function to find duplicated entry. | 79 | * @check_duplicate: Callback function to find duplicated entry. |
69 | * @merge_duplicate: Callback function to merge duplicated entry. | 80 | * @merge_duplicate: Callback function to merge duplicated entry. |
70 | * | 81 | * |
@@ -73,7 +84,7 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
73 | * Caller holds tomoyo_read_lock(). | 84 | * Caller holds tomoyo_read_lock(). |
74 | */ | 85 | */ |
75 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 86 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
76 | bool is_delete, struct tomoyo_domain_info *domain, | 87 | struct tomoyo_acl_param *param, |
77 | bool (*check_duplicate) (const struct tomoyo_acl_info | 88 | bool (*check_duplicate) (const struct tomoyo_acl_info |
78 | *, | 89 | *, |
79 | const struct tomoyo_acl_info | 90 | const struct tomoyo_acl_info |
@@ -82,13 +93,21 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
82 | struct tomoyo_acl_info *, | 93 | struct tomoyo_acl_info *, |
83 | const bool)) | 94 | const bool)) |
84 | { | 95 | { |
96 | const bool is_delete = param->is_delete; | ||
85 | int error = is_delete ? -ENOENT : -ENOMEM; | 97 | int error = is_delete ? -ENOENT : -ENOMEM; |
86 | struct tomoyo_acl_info *entry; | 98 | struct tomoyo_acl_info *entry; |
99 | struct list_head * const list = param->list; | ||
87 | 100 | ||
101 | if (param->data[0]) { | ||
102 | new_entry->cond = tomoyo_get_condition(param); | ||
103 | if (!new_entry->cond) | ||
104 | return -EINVAL; | ||
105 | } | ||
88 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 106 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
89 | return error; | 107 | goto out; |
90 | list_for_each_entry_rcu(entry, &domain->acl_info_list, list) { | 108 | list_for_each_entry_rcu(entry, list, list) { |
91 | if (!check_duplicate(entry, new_entry)) | 109 | if (!tomoyo_same_acl_head(entry, new_entry) || |
110 | !check_duplicate(entry, new_entry)) | ||
92 | continue; | 111 | continue; |
93 | if (merge_duplicate) | 112 | if (merge_duplicate) |
94 | entry->is_deleted = merge_duplicate(entry, new_entry, | 113 | entry->is_deleted = merge_duplicate(entry, new_entry, |
@@ -101,28 +120,50 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
101 | if (error && !is_delete) { | 120 | if (error && !is_delete) { |
102 | entry = tomoyo_commit_ok(new_entry, size); | 121 | entry = tomoyo_commit_ok(new_entry, size); |
103 | if (entry) { | 122 | if (entry) { |
104 | list_add_tail_rcu(&entry->list, &domain->acl_info_list); | 123 | list_add_tail_rcu(&entry->list, list); |
105 | error = 0; | 124 | error = 0; |
106 | } | 125 | } |
107 | } | 126 | } |
108 | mutex_unlock(&tomoyo_policy_lock); | 127 | mutex_unlock(&tomoyo_policy_lock); |
128 | out: | ||
129 | tomoyo_put_condition(new_entry->cond); | ||
109 | return error; | 130 | return error; |
110 | } | 131 | } |
111 | 132 | ||
133 | /** | ||
134 | * tomoyo_check_acl - Do permission check. | ||
135 | * | ||
136 | * @r: Pointer to "struct tomoyo_request_info". | ||
137 | * @check_entry: Callback function to check type specific parameters. | ||
138 | * | ||
139 | * Returns 0 on success, negative value otherwise. | ||
140 | * | ||
141 | * Caller holds tomoyo_read_lock(). | ||
142 | */ | ||
112 | void tomoyo_check_acl(struct tomoyo_request_info *r, | 143 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
113 | bool (*check_entry) (struct tomoyo_request_info *, | 144 | bool (*check_entry) (struct tomoyo_request_info *, |
114 | const struct tomoyo_acl_info *)) | 145 | const struct tomoyo_acl_info *)) |
115 | { | 146 | { |
116 | const struct tomoyo_domain_info *domain = r->domain; | 147 | const struct tomoyo_domain_info *domain = r->domain; |
117 | struct tomoyo_acl_info *ptr; | 148 | struct tomoyo_acl_info *ptr; |
149 | bool retried = false; | ||
150 | const struct list_head *list = &domain->acl_info_list; | ||
118 | 151 | ||
119 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 152 | retry: |
153 | list_for_each_entry_rcu(ptr, list, list) { | ||
120 | if (ptr->is_deleted || ptr->type != r->param_type) | 154 | if (ptr->is_deleted || ptr->type != r->param_type) |
121 | continue; | 155 | continue; |
122 | if (check_entry(r, ptr)) { | 156 | if (!check_entry(r, ptr)) |
123 | r->granted = true; | 157 | continue; |
124 | return; | 158 | if (!tomoyo_condition(r, ptr->cond)) |
125 | } | 159 | continue; |
160 | r->granted = true; | ||
161 | return; | ||
162 | } | ||
163 | if (!retried) { | ||
164 | retried = true; | ||
165 | list = &domain->ns->acl_group[domain->group]; | ||
166 | goto retry; | ||
126 | } | 167 | } |
127 | r->granted = false; | 168 | r->granted = false; |
128 | } | 169 | } |
@@ -130,24 +171,29 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, | |||
130 | /* The list for "struct tomoyo_domain_info". */ | 171 | /* The list for "struct tomoyo_domain_info". */ |
131 | LIST_HEAD(tomoyo_domain_list); | 172 | LIST_HEAD(tomoyo_domain_list); |
132 | 173 | ||
133 | struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; | ||
134 | struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; | ||
135 | |||
136 | /** | 174 | /** |
137 | * tomoyo_last_word - Get last component of a domainname. | 175 | * tomoyo_last_word - Get last component of a domainname. |
138 | * | 176 | * |
139 | * @domainname: Domainname to check. | 177 | * @name: Domainname to check. |
140 | * | 178 | * |
141 | * Returns the last word of @domainname. | 179 | * Returns the last word of @domainname. |
142 | */ | 180 | */ |
143 | static const char *tomoyo_last_word(const char *name) | 181 | static const char *tomoyo_last_word(const char *name) |
144 | { | 182 | { |
145 | const char *cp = strrchr(name, ' '); | 183 | const char *cp = strrchr(name, ' '); |
146 | if (cp) | 184 | if (cp) |
147 | return cp + 1; | 185 | return cp + 1; |
148 | return name; | 186 | return name; |
149 | } | 187 | } |
150 | 188 | ||
189 | /** | ||
190 | * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry. | ||
191 | * | ||
192 | * @a: Pointer to "struct tomoyo_acl_head". | ||
193 | * @b: Pointer to "struct tomoyo_acl_head". | ||
194 | * | ||
195 | * Returns true if @a == @b, false otherwise. | ||
196 | */ | ||
151 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, | 197 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, |
152 | const struct tomoyo_acl_head *b) | 198 | const struct tomoyo_acl_head *b) |
153 | { | 199 | { |
@@ -163,30 +209,36 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, | |||
163 | } | 209 | } |
164 | 210 | ||
165 | /** | 211 | /** |
166 | * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list. | 212 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
167 | * | 213 | * |
168 | * @domainname: The name of domain. Maybe NULL. | 214 | * @param: Pointer to "struct tomoyo_acl_param". |
169 | * @program: The name of program. Maybe NULL. | 215 | * @type: Type of this entry. |
170 | * @type: Type of transition. | ||
171 | * @is_delete: True if it is a delete request. | ||
172 | * | 216 | * |
173 | * Returns 0 on success, negative value otherwise. | 217 | * Returns 0 on success, negative value otherwise. |
174 | */ | 218 | */ |
175 | static int tomoyo_update_transition_control_entry(const char *domainname, | 219 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, |
176 | const char *program, | 220 | const u8 type) |
177 | const u8 type, | ||
178 | const bool is_delete) | ||
179 | { | 221 | { |
180 | struct tomoyo_transition_control e = { .type = type }; | 222 | struct tomoyo_transition_control e = { .type = type }; |
181 | int error = is_delete ? -ENOENT : -ENOMEM; | 223 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
182 | if (program) { | 224 | char *program = param->data; |
225 | char *domainname = strstr(program, " from "); | ||
226 | if (domainname) { | ||
227 | *domainname = '\0'; | ||
228 | domainname += 6; | ||
229 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || | ||
230 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { | ||
231 | domainname = program; | ||
232 | program = NULL; | ||
233 | } | ||
234 | if (program && strcmp(program, "any")) { | ||
183 | if (!tomoyo_correct_path(program)) | 235 | if (!tomoyo_correct_path(program)) |
184 | return -EINVAL; | 236 | return -EINVAL; |
185 | e.program = tomoyo_get_name(program); | 237 | e.program = tomoyo_get_name(program); |
186 | if (!e.program) | 238 | if (!e.program) |
187 | goto out; | 239 | goto out; |
188 | } | 240 | } |
189 | if (domainname) { | 241 | if (domainname && strcmp(domainname, "any")) { |
190 | if (!tomoyo_correct_domain(domainname)) { | 242 | if (!tomoyo_correct_domain(domainname)) { |
191 | if (!tomoyo_correct_path(domainname)) | 243 | if (!tomoyo_correct_path(domainname)) |
192 | goto out; | 244 | goto out; |
@@ -196,126 +248,136 @@ static int tomoyo_update_transition_control_entry(const char *domainname, | |||
196 | if (!e.domainname) | 248 | if (!e.domainname) |
197 | goto out; | 249 | goto out; |
198 | } | 250 | } |
199 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 251 | param->list = ¶m->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
200 | &tomoyo_policy_list | 252 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
201 | [TOMOYO_ID_TRANSITION_CONTROL], | ||
202 | tomoyo_same_transition_control); | 253 | tomoyo_same_transition_control); |
203 | out: | 254 | out: |
204 | tomoyo_put_name(e.domainname); | 255 | tomoyo_put_name(e.domainname); |
205 | tomoyo_put_name(e.program); | 256 | tomoyo_put_name(e.program); |
206 | return error; | 257 | return error; |
207 | } | 258 | } |
208 | 259 | ||
209 | /** | 260 | /** |
210 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. | 261 | * tomoyo_scan_transition - Try to find specific domain transition type. |
211 | * | 262 | * |
212 | * @data: String to parse. | 263 | * @list: Pointer to "struct list_head". |
213 | * @is_delete: True if it is a delete request. | 264 | * @domainname: The name of current domain. |
214 | * @type: Type of this entry. | 265 | * @program: The name of requested program. |
266 | * @last_name: The last component of @domainname. | ||
267 | * @type: One of values in "enum tomoyo_transition_type". | ||
215 | * | 268 | * |
216 | * Returns 0 on success, negative value otherwise. | 269 | * Returns true if found one, false otherwise. |
270 | * | ||
271 | * Caller holds tomoyo_read_lock(). | ||
217 | */ | 272 | */ |
218 | int tomoyo_write_transition_control(char *data, const bool is_delete, | 273 | static inline bool tomoyo_scan_transition |
219 | const u8 type) | 274 | (const struct list_head *list, const struct tomoyo_path_info *domainname, |
275 | const struct tomoyo_path_info *program, const char *last_name, | ||
276 | const enum tomoyo_transition_type type) | ||
220 | { | 277 | { |
221 | char *domainname = strstr(data, " from "); | 278 | const struct tomoyo_transition_control *ptr; |
222 | if (domainname) { | 279 | list_for_each_entry_rcu(ptr, list, head.list) { |
223 | *domainname = '\0'; | 280 | if (ptr->head.is_deleted || ptr->type != type) |
224 | domainname += 6; | 281 | continue; |
225 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || | 282 | if (ptr->domainname) { |
226 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { | 283 | if (!ptr->is_last_name) { |
227 | domainname = data; | 284 | if (ptr->domainname != domainname) |
228 | data = NULL; | 285 | continue; |
286 | } else { | ||
287 | /* | ||
288 | * Use direct strcmp() since this is | ||
289 | * unlikely used. | ||
290 | */ | ||
291 | if (strcmp(ptr->domainname->name, last_name)) | ||
292 | continue; | ||
293 | } | ||
294 | } | ||
295 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) | ||
296 | continue; | ||
297 | return true; | ||
229 | } | 298 | } |
230 | return tomoyo_update_transition_control_entry(domainname, data, type, | 299 | return false; |
231 | is_delete); | ||
232 | } | 300 | } |
233 | 301 | ||
234 | /** | 302 | /** |
235 | * tomoyo_transition_type - Get domain transition type. | 303 | * tomoyo_transition_type - Get domain transition type. |
236 | * | 304 | * |
237 | * @domainname: The name of domain. | 305 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
238 | * @program: The name of program. | 306 | * @domainname: The name of current domain. |
307 | * @program: The name of requested program. | ||
239 | * | 308 | * |
240 | * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program | 309 | * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes |
241 | * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing | 310 | * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if |
242 | * @program suppresses domain transition, others otherwise. | 311 | * executing @program reinitializes domain transition within that namespace, |
312 | * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname , | ||
313 | * others otherwise. | ||
243 | * | 314 | * |
244 | * Caller holds tomoyo_read_lock(). | 315 | * Caller holds tomoyo_read_lock(). |
245 | */ | 316 | */ |
246 | static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, | 317 | static enum tomoyo_transition_type tomoyo_transition_type |
247 | const struct tomoyo_path_info *program) | 318 | (const struct tomoyo_policy_namespace *ns, |
319 | const struct tomoyo_path_info *domainname, | ||
320 | const struct tomoyo_path_info *program) | ||
248 | { | 321 | { |
249 | const struct tomoyo_transition_control *ptr; | ||
250 | const char *last_name = tomoyo_last_word(domainname->name); | 322 | const char *last_name = tomoyo_last_word(domainname->name); |
251 | u8 type; | 323 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; |
252 | for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { | 324 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { |
253 | next: | 325 | const struct list_head * const list = |
254 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | 326 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
255 | [TOMOYO_ID_TRANSITION_CONTROL], | 327 | if (!tomoyo_scan_transition(list, domainname, program, |
256 | head.list) { | 328 | last_name, type)) { |
257 | if (ptr->head.is_deleted || ptr->type != type) | 329 | type++; |
258 | continue; | 330 | continue; |
259 | if (ptr->domainname) { | ||
260 | if (!ptr->is_last_name) { | ||
261 | if (ptr->domainname != domainname) | ||
262 | continue; | ||
263 | } else { | ||
264 | /* | ||
265 | * Use direct strcmp() since this is | ||
266 | * unlikely used. | ||
267 | */ | ||
268 | if (strcmp(ptr->domainname->name, | ||
269 | last_name)) | ||
270 | continue; | ||
271 | } | ||
272 | } | ||
273 | if (ptr->program && | ||
274 | tomoyo_pathcmp(ptr->program, program)) | ||
275 | continue; | ||
276 | if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) { | ||
277 | /* | ||
278 | * Do not check for initialize_domain if | ||
279 | * no_initialize_domain matched. | ||
280 | */ | ||
281 | type = TOMOYO_TRANSITION_CONTROL_NO_KEEP; | ||
282 | goto next; | ||
283 | } | ||
284 | goto done; | ||
285 | } | 331 | } |
332 | if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET && | ||
333 | type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) | ||
334 | break; | ||
335 | /* | ||
336 | * Do not check for reset_domain if no_reset_domain matched. | ||
337 | * Do not check for initialize_domain if no_initialize_domain | ||
338 | * matched. | ||
339 | */ | ||
340 | type++; | ||
341 | type++; | ||
286 | } | 342 | } |
287 | done: | ||
288 | return type; | 343 | return type; |
289 | } | 344 | } |
290 | 345 | ||
346 | /** | ||
347 | * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry. | ||
348 | * | ||
349 | * @a: Pointer to "struct tomoyo_acl_head". | ||
350 | * @b: Pointer to "struct tomoyo_acl_head". | ||
351 | * | ||
352 | * Returns true if @a == @b, false otherwise. | ||
353 | */ | ||
291 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, | 354 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, |
292 | const struct tomoyo_acl_head *b) | 355 | const struct tomoyo_acl_head *b) |
293 | { | 356 | { |
294 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head); | 357 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), |
295 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head); | 358 | head); |
359 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), | ||
360 | head); | ||
296 | return p1->original_name == p2->original_name && | 361 | return p1->original_name == p2->original_name && |
297 | p1->aggregated_name == p2->aggregated_name; | 362 | p1->aggregated_name == p2->aggregated_name; |
298 | } | 363 | } |
299 | 364 | ||
300 | /** | 365 | /** |
301 | * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list. | 366 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. |
302 | * | 367 | * |
303 | * @original_name: The original program's name. | 368 | * @param: Pointer to "struct tomoyo_acl_param". |
304 | * @aggregated_name: The program name to use. | ||
305 | * @is_delete: True if it is a delete request. | ||
306 | * | 369 | * |
307 | * Returns 0 on success, negative value otherwise. | 370 | * Returns 0 on success, negative value otherwise. |
308 | * | 371 | * |
309 | * Caller holds tomoyo_read_lock(). | 372 | * Caller holds tomoyo_read_lock(). |
310 | */ | 373 | */ |
311 | static int tomoyo_update_aggregator_entry(const char *original_name, | 374 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param) |
312 | const char *aggregated_name, | ||
313 | const bool is_delete) | ||
314 | { | 375 | { |
315 | struct tomoyo_aggregator e = { }; | 376 | struct tomoyo_aggregator e = { }; |
316 | int error = is_delete ? -ENOENT : -ENOMEM; | 377 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
317 | 378 | const char *original_name = tomoyo_read_token(param); | |
318 | if (!tomoyo_correct_path(original_name) || | 379 | const char *aggregated_name = tomoyo_read_token(param); |
380 | if (!tomoyo_correct_word(original_name) || | ||
319 | !tomoyo_correct_path(aggregated_name)) | 381 | !tomoyo_correct_path(aggregated_name)) |
320 | return -EINVAL; | 382 | return -EINVAL; |
321 | e.original_name = tomoyo_get_name(original_name); | 383 | e.original_name = tomoyo_get_name(original_name); |
@@ -323,83 +385,181 @@ static int tomoyo_update_aggregator_entry(const char *original_name, | |||
323 | if (!e.original_name || !e.aggregated_name || | 385 | if (!e.original_name || !e.aggregated_name || |
324 | e.aggregated_name->is_patterned) /* No patterns allowed. */ | 386 | e.aggregated_name->is_patterned) /* No patterns allowed. */ |
325 | goto out; | 387 | goto out; |
326 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 388 | param->list = ¶m->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
327 | &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR], | 389 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
328 | tomoyo_same_aggregator); | 390 | tomoyo_same_aggregator); |
329 | out: | 391 | out: |
330 | tomoyo_put_name(e.original_name); | 392 | tomoyo_put_name(e.original_name); |
331 | tomoyo_put_name(e.aggregated_name); | 393 | tomoyo_put_name(e.aggregated_name); |
332 | return error; | 394 | return error; |
333 | } | 395 | } |
334 | 396 | ||
335 | /** | 397 | /** |
336 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. | 398 | * tomoyo_find_namespace - Find specified namespace. |
337 | * | 399 | * |
338 | * @data: String to parse. | 400 | * @name: Name of namespace to find. |
339 | * @is_delete: True if it is a delete request. | 401 | * @len: Length of @name. |
340 | * | 402 | * |
341 | * Returns 0 on success, negative value otherwise. | 403 | * Returns pointer to "struct tomoyo_policy_namespace" if found, |
404 | * NULL otherwise. | ||
342 | * | 405 | * |
343 | * Caller holds tomoyo_read_lock(). | 406 | * Caller holds tomoyo_read_lock(). |
344 | */ | 407 | */ |
345 | int tomoyo_write_aggregator(char *data, const bool is_delete) | 408 | static struct tomoyo_policy_namespace *tomoyo_find_namespace |
409 | (const char *name, const unsigned int len) | ||
346 | { | 410 | { |
347 | char *cp = strchr(data, ' '); | 411 | struct tomoyo_policy_namespace *ns; |
412 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { | ||
413 | if (strncmp(name, ns->name, len) || | ||
414 | (name[len] && name[len] != ' ')) | ||
415 | continue; | ||
416 | return ns; | ||
417 | } | ||
418 | return NULL; | ||
419 | } | ||
348 | 420 | ||
349 | if (!cp) | 421 | /** |
350 | return -EINVAL; | 422 | * tomoyo_assign_namespace - Create a new namespace. |
351 | *cp++ = '\0'; | 423 | * |
352 | return tomoyo_update_aggregator_entry(data, cp, is_delete); | 424 | * @domainname: Name of namespace to create. |
425 | * | ||
426 | * Returns pointer to "struct tomoyo_policy_namespace" on success, | ||
427 | * NULL otherwise. | ||
428 | * | ||
429 | * Caller holds tomoyo_read_lock(). | ||
430 | */ | ||
431 | struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) | ||
432 | { | ||
433 | struct tomoyo_policy_namespace *ptr; | ||
434 | struct tomoyo_policy_namespace *entry; | ||
435 | const char *cp = domainname; | ||
436 | unsigned int len = 0; | ||
437 | while (*cp && *cp++ != ' ') | ||
438 | len++; | ||
439 | ptr = tomoyo_find_namespace(domainname, len); | ||
440 | if (ptr) | ||
441 | return ptr; | ||
442 | if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname)) | ||
443 | return NULL; | ||
444 | entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS); | ||
445 | if (!entry) | ||
446 | return NULL; | ||
447 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
448 | goto out; | ||
449 | ptr = tomoyo_find_namespace(domainname, len); | ||
450 | if (!ptr && tomoyo_memory_ok(entry)) { | ||
451 | char *name = (char *) (entry + 1); | ||
452 | ptr = entry; | ||
453 | memmove(name, domainname, len); | ||
454 | name[len] = '\0'; | ||
455 | entry->name = name; | ||
456 | tomoyo_init_policy_namespace(entry); | ||
457 | entry = NULL; | ||
458 | } | ||
459 | mutex_unlock(&tomoyo_policy_lock); | ||
460 | out: | ||
461 | kfree(entry); | ||
462 | return ptr; | ||
353 | } | 463 | } |
354 | 464 | ||
355 | /** | 465 | /** |
356 | * tomoyo_assign_domain - Create a domain. | 466 | * tomoyo_namespace_jump - Check for namespace jump. |
467 | * | ||
468 | * @domainname: Name of domain. | ||
469 | * | ||
470 | * Returns true if namespace differs, false otherwise. | ||
471 | */ | ||
472 | static bool tomoyo_namespace_jump(const char *domainname) | ||
473 | { | ||
474 | const char *namespace = tomoyo_current_namespace()->name; | ||
475 | const int len = strlen(namespace); | ||
476 | return strncmp(domainname, namespace, len) || | ||
477 | (domainname[len] && domainname[len] != ' '); | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * tomoyo_assign_domain - Create a domain or a namespace. | ||
357 | * | 482 | * |
358 | * @domainname: The name of domain. | 483 | * @domainname: The name of domain. |
359 | * @profile: Profile number to assign if the domain was newly created. | 484 | * @transit: True if transit to domain found or created. |
360 | * | 485 | * |
361 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 486 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. |
362 | * | 487 | * |
363 | * Caller holds tomoyo_read_lock(). | 488 | * Caller holds tomoyo_read_lock(). |
364 | */ | 489 | */ |
365 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | 490 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, |
366 | const u8 profile) | 491 | const bool transit) |
367 | { | 492 | { |
368 | struct tomoyo_domain_info *entry; | 493 | struct tomoyo_domain_info e = { }; |
369 | struct tomoyo_domain_info *domain = NULL; | 494 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); |
370 | const struct tomoyo_path_info *saved_domainname; | 495 | bool created = false; |
371 | bool found = false; | 496 | if (entry) { |
372 | 497 | if (transit) { | |
373 | if (!tomoyo_correct_domain(domainname)) | 498 | /* |
499 | * Since namespace is created at runtime, profiles may | ||
500 | * not be created by the moment the process transits to | ||
501 | * that domain. Do not perform domain transition if | ||
502 | * profile for that domain is not yet created. | ||
503 | */ | ||
504 | if (!entry->ns->profile_ptr[entry->profile]) | ||
505 | return NULL; | ||
506 | } | ||
507 | return entry; | ||
508 | } | ||
509 | /* Requested domain does not exist. */ | ||
510 | /* Don't create requested domain if domainname is invalid. */ | ||
511 | if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 || | ||
512 | !tomoyo_correct_domain(domainname)) | ||
513 | return NULL; | ||
514 | /* | ||
515 | * Since definition of profiles and acl_groups may differ across | ||
516 | * namespaces, do not inherit "use_profile" and "use_group" settings | ||
517 | * by automatically creating requested domain upon domain transition. | ||
518 | */ | ||
519 | if (transit && tomoyo_namespace_jump(domainname)) | ||
520 | return NULL; | ||
521 | e.ns = tomoyo_assign_namespace(domainname); | ||
522 | if (!e.ns) | ||
374 | return NULL; | 523 | return NULL; |
375 | saved_domainname = tomoyo_get_name(domainname); | 524 | /* |
376 | if (!saved_domainname) | 525 | * "use_profile" and "use_group" settings for automatically created |
526 | * domains are inherited from current domain. These are 0 for manually | ||
527 | * created domains. | ||
528 | */ | ||
529 | if (transit) { | ||
530 | const struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
531 | e.profile = domain->profile; | ||
532 | e.group = domain->group; | ||
533 | } | ||
534 | e.domainname = tomoyo_get_name(domainname); | ||
535 | if (!e.domainname) | ||
377 | return NULL; | 536 | return NULL; |
378 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | ||
379 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 537 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
380 | goto out; | 538 | goto out; |
381 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 539 | entry = tomoyo_find_domain(domainname); |
382 | if (domain->is_deleted || | 540 | if (!entry) { |
383 | tomoyo_pathcmp(saved_domainname, domain->domainname)) | 541 | entry = tomoyo_commit_ok(&e, sizeof(e)); |
384 | continue; | 542 | if (entry) { |
385 | found = true; | 543 | INIT_LIST_HEAD(&entry->acl_info_list); |
386 | break; | 544 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); |
387 | } | 545 | created = true; |
388 | if (!found && tomoyo_memory_ok(entry)) { | 546 | } |
389 | INIT_LIST_HEAD(&entry->acl_info_list); | ||
390 | entry->domainname = saved_domainname; | ||
391 | saved_domainname = NULL; | ||
392 | entry->profile = profile; | ||
393 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); | ||
394 | domain = entry; | ||
395 | entry = NULL; | ||
396 | found = true; | ||
397 | } | 547 | } |
398 | mutex_unlock(&tomoyo_policy_lock); | 548 | mutex_unlock(&tomoyo_policy_lock); |
399 | out: | 549 | out: |
400 | tomoyo_put_name(saved_domainname); | 550 | tomoyo_put_name(e.domainname); |
401 | kfree(entry); | 551 | if (entry && transit) { |
402 | return found ? domain : NULL; | 552 | if (created) { |
553 | struct tomoyo_request_info r; | ||
554 | tomoyo_init_request_info(&r, entry, | ||
555 | TOMOYO_MAC_FILE_EXECUTE); | ||
556 | r.granted = false; | ||
557 | tomoyo_write_log(&r, "use_profile %u\n", | ||
558 | entry->profile); | ||
559 | tomoyo_write_log(&r, "use_group %u\n", entry->group); | ||
560 | } | ||
561 | } | ||
562 | return entry; | ||
403 | } | 563 | } |
404 | 564 | ||
405 | /** | 565 | /** |
@@ -413,22 +573,27 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | |||
413 | */ | 573 | */ |
414 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 574 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
415 | { | 575 | { |
416 | struct tomoyo_request_info r; | ||
417 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | ||
418 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 576 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
419 | struct tomoyo_domain_info *domain = NULL; | 577 | struct tomoyo_domain_info *domain = NULL; |
420 | const char *original_name = bprm->filename; | 578 | const char *original_name = bprm->filename; |
421 | u8 mode; | ||
422 | bool is_enforce; | ||
423 | int retval = -ENOMEM; | 579 | int retval = -ENOMEM; |
424 | bool need_kfree = false; | 580 | bool need_kfree = false; |
581 | bool reject_on_transition_failure = false; | ||
425 | struct tomoyo_path_info rn = { }; /* real name */ | 582 | struct tomoyo_path_info rn = { }; /* real name */ |
426 | 583 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); | |
427 | mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); | 584 | if (!ee) |
428 | is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); | 585 | return -ENOMEM; |
429 | if (!tmp) | 586 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
430 | goto out; | 587 | if (!ee->tmp) { |
431 | 588 | kfree(ee); | |
589 | return -ENOMEM; | ||
590 | } | ||
591 | /* ee->dump->data is allocated by tomoyo_dump_page(). */ | ||
592 | tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE); | ||
593 | ee->r.ee = ee; | ||
594 | ee->bprm = bprm; | ||
595 | ee->r.obj = &ee->obj; | ||
596 | ee->obj.path1 = bprm->file->f_path; | ||
432 | retry: | 597 | retry: |
433 | if (need_kfree) { | 598 | if (need_kfree) { |
434 | kfree(rn.name); | 599 | kfree(rn.name); |
@@ -445,8 +610,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
445 | /* Check 'aggregator' directive. */ | 610 | /* Check 'aggregator' directive. */ |
446 | { | 611 | { |
447 | struct tomoyo_aggregator *ptr; | 612 | struct tomoyo_aggregator *ptr; |
448 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | 613 | struct list_head *list = |
449 | [TOMOYO_ID_AGGREGATOR], head.list) { | 614 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
615 | /* Check 'aggregator' directive. */ | ||
616 | list_for_each_entry_rcu(ptr, list, head.list) { | ||
450 | if (ptr->head.is_deleted || | 617 | if (ptr->head.is_deleted || |
451 | !tomoyo_path_matches_pattern(&rn, | 618 | !tomoyo_path_matches_pattern(&rn, |
452 | ptr->original_name)) | 619 | ptr->original_name)) |
@@ -460,7 +627,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
460 | } | 627 | } |
461 | 628 | ||
462 | /* Check execute permission. */ | 629 | /* Check execute permission. */ |
463 | retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn); | 630 | retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); |
464 | if (retval == TOMOYO_RETRY_REQUEST) | 631 | if (retval == TOMOYO_RETRY_REQUEST) |
465 | goto retry; | 632 | goto retry; |
466 | if (retval < 0) | 633 | if (retval < 0) |
@@ -471,20 +638,30 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
471 | * wildcard) rather than the pathname passed to execve() | 638 | * wildcard) rather than the pathname passed to execve() |
472 | * (which never contains wildcard). | 639 | * (which never contains wildcard). |
473 | */ | 640 | */ |
474 | if (r.param.path.matched_path) { | 641 | if (ee->r.param.path.matched_path) { |
475 | if (need_kfree) | 642 | if (need_kfree) |
476 | kfree(rn.name); | 643 | kfree(rn.name); |
477 | need_kfree = false; | 644 | need_kfree = false; |
478 | /* This is OK because it is read only. */ | 645 | /* This is OK because it is read only. */ |
479 | rn = *r.param.path.matched_path; | 646 | rn = *ee->r.param.path.matched_path; |
480 | } | 647 | } |
481 | 648 | ||
482 | /* Calculate domain to transit to. */ | 649 | /* Calculate domain to transit to. */ |
483 | switch (tomoyo_transition_type(old_domain->domainname, &rn)) { | 650 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, |
651 | &rn)) { | ||
652 | case TOMOYO_TRANSITION_CONTROL_RESET: | ||
653 | /* Transit to the root of specified namespace. */ | ||
654 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); | ||
655 | /* | ||
656 | * Make do_execve() fail if domain transition across namespaces | ||
657 | * has failed. | ||
658 | */ | ||
659 | reject_on_transition_failure = true; | ||
660 | break; | ||
484 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | 661 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: |
485 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 662 | /* Transit to the child of current namespace's root. */ |
486 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " | 663 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
487 | "%s", rn.name); | 664 | old_domain->ns->name, rn.name); |
488 | break; | 665 | break; |
489 | case TOMOYO_TRANSITION_CONTROL_KEEP: | 666 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
490 | /* Keep current domain. */ | 667 | /* Keep current domain. */ |
@@ -502,33 +679,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
502 | domain = old_domain; | 679 | domain = old_domain; |
503 | } else { | 680 | } else { |
504 | /* Normal domain transition. */ | 681 | /* Normal domain transition. */ |
505 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | 682 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
506 | old_domain->domainname->name, rn.name); | 683 | old_domain->domainname->name, rn.name); |
507 | } | 684 | } |
508 | break; | 685 | break; |
509 | } | 686 | } |
510 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) | 687 | if (!domain) |
511 | goto done; | 688 | domain = tomoyo_assign_domain(ee->tmp, true); |
512 | domain = tomoyo_find_domain(tmp); | ||
513 | if (domain) | 689 | if (domain) |
514 | goto done; | 690 | retval = 0; |
515 | if (is_enforce) { | 691 | else if (reject_on_transition_failure) { |
516 | int error = tomoyo_supervisor(&r, "# wants to create domain\n" | 692 | printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", |
517 | "%s\n", tmp); | 693 | ee->tmp); |
518 | if (error == TOMOYO_RETRY_REQUEST) | 694 | retval = -ENOMEM; |
519 | goto retry; | 695 | } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) |
520 | if (error < 0) | 696 | retval = -ENOMEM; |
521 | goto done; | 697 | else { |
698 | retval = 0; | ||
699 | if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) { | ||
700 | old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true; | ||
701 | ee->r.granted = false; | ||
702 | tomoyo_write_log(&ee->r, "%s", tomoyo_dif | ||
703 | [TOMOYO_DIF_TRANSITION_FAILED]); | ||
704 | printk(KERN_WARNING | ||
705 | "ERROR: Domain '%s' not defined.\n", ee->tmp); | ||
706 | } | ||
522 | } | 707 | } |
523 | domain = tomoyo_assign_domain(tmp, old_domain->profile); | ||
524 | done: | ||
525 | if (domain) | ||
526 | goto out; | ||
527 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); | ||
528 | if (is_enforce) | ||
529 | retval = -EPERM; | ||
530 | else | ||
531 | old_domain->transition_failed = true; | ||
532 | out: | 708 | out: |
533 | if (!domain) | 709 | if (!domain) |
534 | domain = old_domain; | 710 | domain = old_domain; |
@@ -537,6 +713,54 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
537 | bprm->cred->security = domain; | 713 | bprm->cred->security = domain; |
538 | if (need_kfree) | 714 | if (need_kfree) |
539 | kfree(rn.name); | 715 | kfree(rn.name); |
540 | kfree(tmp); | 716 | kfree(ee->tmp); |
717 | kfree(ee->dump.data); | ||
718 | kfree(ee); | ||
541 | return retval; | 719 | return retval; |
542 | } | 720 | } |
721 | |||
722 | /** | ||
723 | * tomoyo_dump_page - Dump a page to buffer. | ||
724 | * | ||
725 | * @bprm: Pointer to "struct linux_binprm". | ||
726 | * @pos: Location to dump. | ||
727 | * @dump: Poiner to "struct tomoyo_page_dump". | ||
728 | * | ||
729 | * Returns true on success, false otherwise. | ||
730 | */ | ||
731 | bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, | ||
732 | struct tomoyo_page_dump *dump) | ||
733 | { | ||
734 | struct page *page; | ||
735 | /* dump->data is released by tomoyo_finish_execve(). */ | ||
736 | if (!dump->data) { | ||
737 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); | ||
738 | if (!dump->data) | ||
739 | return false; | ||
740 | } | ||
741 | /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ | ||
742 | #ifdef CONFIG_MMU | ||
743 | if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0) | ||
744 | return false; | ||
745 | #else | ||
746 | page = bprm->page[pos / PAGE_SIZE]; | ||
747 | #endif | ||
748 | if (page != dump->page) { | ||
749 | const unsigned int offset = pos % PAGE_SIZE; | ||
750 | /* | ||
751 | * Maybe kmap()/kunmap() should be used here. | ||
752 | * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic(). | ||
753 | * So do I. | ||
754 | */ | ||
755 | char *kaddr = kmap_atomic(page, KM_USER0); | ||
756 | dump->page = page; | ||
757 | memcpy(dump->data + offset, kaddr + offset, | ||
758 | PAGE_SIZE - offset); | ||
759 | kunmap_atomic(kaddr, KM_USER0); | ||
760 | } | ||
761 | /* Same with put_arg_page(page) in fs/exec.c */ | ||
762 | #ifdef CONFIG_MMU | ||
763 | put_page(page); | ||
764 | #endif | ||
765 | return true; | ||
766 | } | ||
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index d64e8ecb6fb3..743c35f5084a 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -1,80 +1,51 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/file.c | 2 | * security/tomoyo/file.c |
3 | * | 3 | * |
4 | * Pathname restriction functions. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
11 | 9 | ||
12 | /* Keyword array for operations with one pathname. */ | 10 | /* |
13 | const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | 11 | * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index". |
14 | [TOMOYO_TYPE_READ_WRITE] = "read/write", | 12 | */ |
15 | [TOMOYO_TYPE_EXECUTE] = "execute", | ||
16 | [TOMOYO_TYPE_READ] = "read", | ||
17 | [TOMOYO_TYPE_WRITE] = "write", | ||
18 | [TOMOYO_TYPE_UNLINK] = "unlink", | ||
19 | [TOMOYO_TYPE_RMDIR] = "rmdir", | ||
20 | [TOMOYO_TYPE_TRUNCATE] = "truncate", | ||
21 | [TOMOYO_TYPE_SYMLINK] = "symlink", | ||
22 | [TOMOYO_TYPE_REWRITE] = "rewrite", | ||
23 | [TOMOYO_TYPE_CHROOT] = "chroot", | ||
24 | [TOMOYO_TYPE_UMOUNT] = "unmount", | ||
25 | }; | ||
26 | |||
27 | /* Keyword array for operations with one pathname and three numbers. */ | ||
28 | const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = { | ||
29 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", | ||
30 | [TOMOYO_TYPE_MKCHAR] = "mkchar", | ||
31 | }; | ||
32 | |||
33 | /* Keyword array for operations with two pathnames. */ | ||
34 | const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { | ||
35 | [TOMOYO_TYPE_LINK] = "link", | ||
36 | [TOMOYO_TYPE_RENAME] = "rename", | ||
37 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | ||
38 | }; | ||
39 | |||
40 | /* Keyword array for operations with one pathname and one number. */ | ||
41 | const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | ||
42 | [TOMOYO_TYPE_CREATE] = "create", | ||
43 | [TOMOYO_TYPE_MKDIR] = "mkdir", | ||
44 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", | ||
45 | [TOMOYO_TYPE_MKSOCK] = "mksock", | ||
46 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
47 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
48 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
49 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
50 | }; | ||
51 | |||
52 | static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { | 13 | static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { |
53 | [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN, | ||
54 | [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, | 14 | [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, |
55 | [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, | 15 | [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, |
56 | [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, | 16 | [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, |
17 | [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN, | ||
57 | [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, | 18 | [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, |
19 | [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR, | ||
58 | [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, | 20 | [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, |
59 | [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, | 21 | [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, |
60 | [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, | 22 | [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, |
61 | [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE, | ||
62 | [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, | 23 | [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, |
63 | [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, | 24 | [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, |
64 | }; | 25 | }; |
65 | 26 | ||
66 | static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { | 27 | /* |
28 | * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index". | ||
29 | */ | ||
30 | const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { | ||
67 | [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, | 31 | [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, |
68 | [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, | 32 | [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, |
69 | }; | 33 | }; |
70 | 34 | ||
71 | static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { | 35 | /* |
36 | * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index". | ||
37 | */ | ||
38 | const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { | ||
72 | [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, | 39 | [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, |
73 | [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, | 40 | [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, |
74 | [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, | 41 | [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, |
75 | }; | 42 | }; |
76 | 43 | ||
77 | static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | 44 | /* |
45 | * Mapping table from "enum tomoyo_path_number_acl_index" to | ||
46 | * "enum tomoyo_mac_index". | ||
47 | */ | ||
48 | const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | ||
78 | [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, | 49 | [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, |
79 | [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, | 50 | [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, |
80 | [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, | 51 | [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, |
@@ -85,41 +56,76 @@ static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | |||
85 | [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, | 56 | [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, |
86 | }; | 57 | }; |
87 | 58 | ||
59 | /** | ||
60 | * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union". | ||
61 | * | ||
62 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
63 | * | ||
64 | * Returns nothing. | ||
65 | */ | ||
88 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) | 66 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) |
89 | { | 67 | { |
90 | if (!ptr) | 68 | tomoyo_put_group(ptr->group); |
91 | return; | 69 | tomoyo_put_name(ptr->filename); |
92 | if (ptr->is_group) | ||
93 | tomoyo_put_group(ptr->group); | ||
94 | else | ||
95 | tomoyo_put_name(ptr->filename); | ||
96 | } | 70 | } |
97 | 71 | ||
72 | /** | ||
73 | * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not. | ||
74 | * | ||
75 | * @name: Pointer to "struct tomoyo_path_info". | ||
76 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
77 | * | ||
78 | * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise. | ||
79 | */ | ||
98 | const struct tomoyo_path_info * | 80 | const struct tomoyo_path_info * |
99 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, | 81 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
100 | const struct tomoyo_name_union *ptr) | 82 | const struct tomoyo_name_union *ptr) |
101 | { | 83 | { |
102 | if (ptr->is_group) | 84 | if (ptr->group) |
103 | return tomoyo_path_matches_group(name, ptr->group); | 85 | return tomoyo_path_matches_group(name, ptr->group); |
104 | if (tomoyo_path_matches_pattern(name, ptr->filename)) | 86 | if (tomoyo_path_matches_pattern(name, ptr->filename)) |
105 | return ptr->filename; | 87 | return ptr->filename; |
106 | return NULL; | 88 | return NULL; |
107 | } | 89 | } |
108 | 90 | ||
91 | /** | ||
92 | * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union". | ||
93 | * | ||
94 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
95 | * | ||
96 | * Returns nothing. | ||
97 | */ | ||
109 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr) | 98 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr) |
110 | { | 99 | { |
111 | if (ptr && ptr->is_group) | 100 | tomoyo_put_group(ptr->group); |
112 | tomoyo_put_group(ptr->group); | ||
113 | } | 101 | } |
114 | 102 | ||
103 | /** | ||
104 | * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not. | ||
105 | * | ||
106 | * @value: Number to check. | ||
107 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
108 | * | ||
109 | * Returns true if @value matches @ptr, false otherwise. | ||
110 | */ | ||
115 | bool tomoyo_compare_number_union(const unsigned long value, | 111 | bool tomoyo_compare_number_union(const unsigned long value, |
116 | const struct tomoyo_number_union *ptr) | 112 | const struct tomoyo_number_union *ptr) |
117 | { | 113 | { |
118 | if (ptr->is_group) | 114 | if (ptr->group) |
119 | return tomoyo_number_matches_group(value, value, ptr->group); | 115 | return tomoyo_number_matches_group(value, value, ptr->group); |
120 | return value >= ptr->values[0] && value <= ptr->values[1]; | 116 | return value >= ptr->values[0] && value <= ptr->values[1]; |
121 | } | 117 | } |
122 | 118 | ||
119 | /** | ||
120 | * tomoyo_add_slash - Add trailing '/' if needed. | ||
121 | * | ||
122 | * @buf: Pointer to "struct tomoyo_path_info". | ||
123 | * | ||
124 | * Returns nothing. | ||
125 | * | ||
126 | * @buf must be generated by tomoyo_encode() because this function does not | ||
127 | * allocate memory for adding '/'. | ||
128 | */ | ||
123 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) | 129 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) |
124 | { | 130 | { |
125 | if (buf->is_dir) | 131 | if (buf->is_dir) |
@@ -132,24 +138,6 @@ static void tomoyo_add_slash(struct tomoyo_path_info *buf) | |||
132 | } | 138 | } |
133 | 139 | ||
134 | /** | 140 | /** |
135 | * tomoyo_strendswith - Check whether the token ends with the given token. | ||
136 | * | ||
137 | * @name: The token to check. | ||
138 | * @tail: The token to find. | ||
139 | * | ||
140 | * Returns true if @name ends with @tail, false otherwise. | ||
141 | */ | ||
142 | static bool tomoyo_strendswith(const char *name, const char *tail) | ||
143 | { | ||
144 | int len; | ||
145 | |||
146 | if (!name || !tail) | ||
147 | return false; | ||
148 | len = strlen(name) - strlen(tail); | ||
149 | return len >= 0 && !strcmp(name + len, tail); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * tomoyo_get_realpath - Get realpath. | 141 | * tomoyo_get_realpath - Get realpath. |
154 | * | 142 | * |
155 | * @buf: Pointer to "struct tomoyo_path_info". | 143 | * @buf: Pointer to "struct tomoyo_path_info". |
@@ -164,7 +152,7 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) | |||
164 | tomoyo_fill_path_info(buf); | 152 | tomoyo_fill_path_info(buf); |
165 | return true; | 153 | return true; |
166 | } | 154 | } |
167 | return false; | 155 | return false; |
168 | } | 156 | } |
169 | 157 | ||
170 | /** | 158 | /** |
@@ -176,13 +164,9 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) | |||
176 | */ | 164 | */ |
177 | static int tomoyo_audit_path_log(struct tomoyo_request_info *r) | 165 | static int tomoyo_audit_path_log(struct tomoyo_request_info *r) |
178 | { | 166 | { |
179 | const char *operation = tomoyo_path_keyword[r->param.path.operation]; | 167 | return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword |
180 | const struct tomoyo_path_info *filename = r->param.path.filename; | 168 | [r->param.path.operation], |
181 | if (r->granted) | 169 | r->param.path.filename->name); |
182 | return 0; | ||
183 | tomoyo_warn_log(r, "%s %s", operation, filename->name); | ||
184 | return tomoyo_supervisor(r, "allow_%s %s\n", operation, | ||
185 | tomoyo_pattern(filename)); | ||
186 | } | 170 | } |
187 | 171 | ||
188 | /** | 172 | /** |
@@ -194,16 +178,10 @@ static int tomoyo_audit_path_log(struct tomoyo_request_info *r) | |||
194 | */ | 178 | */ |
195 | static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) | 179 | static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) |
196 | { | 180 | { |
197 | const char *operation = tomoyo_path2_keyword[r->param.path2.operation]; | 181 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords |
198 | const struct tomoyo_path_info *filename1 = r->param.path2.filename1; | 182 | [tomoyo_pp2mac[r->param.path2.operation]], |
199 | const struct tomoyo_path_info *filename2 = r->param.path2.filename2; | 183 | r->param.path2.filename1->name, |
200 | if (r->granted) | 184 | r->param.path2.filename2->name); |
201 | return 0; | ||
202 | tomoyo_warn_log(r, "%s %s %s", operation, filename1->name, | ||
203 | filename2->name); | ||
204 | return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, | ||
205 | tomoyo_pattern(filename1), | ||
206 | tomoyo_pattern(filename2)); | ||
207 | } | 185 | } |
208 | 186 | ||
209 | /** | 187 | /** |
@@ -215,24 +193,18 @@ static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) | |||
215 | */ | 193 | */ |
216 | static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) | 194 | static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) |
217 | { | 195 | { |
218 | const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation]; | 196 | return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", |
219 | const struct tomoyo_path_info *filename = r->param.mkdev.filename; | 197 | tomoyo_mac_keywords |
220 | const unsigned int major = r->param.mkdev.major; | 198 | [tomoyo_pnnn2mac[r->param.mkdev.operation]], |
221 | const unsigned int minor = r->param.mkdev.minor; | 199 | r->param.mkdev.filename->name, |
222 | const unsigned int mode = r->param.mkdev.mode; | 200 | r->param.mkdev.mode, r->param.mkdev.major, |
223 | if (r->granted) | 201 | r->param.mkdev.minor); |
224 | return 0; | ||
225 | tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode, | ||
226 | major, minor); | ||
227 | return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation, | ||
228 | tomoyo_pattern(filename), mode, major, minor); | ||
229 | } | 202 | } |
230 | 203 | ||
231 | /** | 204 | /** |
232 | * tomoyo_audit_path_number_log - Audit path/number request log. | 205 | * tomoyo_audit_path_number_log - Audit path/number request log. |
233 | * | 206 | * |
234 | * @r: Pointer to "struct tomoyo_request_info". | 207 | * @r: Pointer to "struct tomoyo_request_info". |
235 | * @error: Error code. | ||
236 | * | 208 | * |
237 | * Returns 0 on success, negative value otherwise. | 209 | * Returns 0 on success, negative value otherwise. |
238 | */ | 210 | */ |
@@ -240,11 +212,7 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) | |||
240 | { | 212 | { |
241 | const u8 type = r->param.path_number.operation; | 213 | const u8 type = r->param.path_number.operation; |
242 | u8 radix; | 214 | u8 radix; |
243 | const struct tomoyo_path_info *filename = r->param.path_number.filename; | ||
244 | const char *operation = tomoyo_path_number_keyword[type]; | ||
245 | char buffer[64]; | 215 | char buffer[64]; |
246 | if (r->granted) | ||
247 | return 0; | ||
248 | switch (type) { | 216 | switch (type) { |
249 | case TOMOYO_TYPE_CREATE: | 217 | case TOMOYO_TYPE_CREATE: |
250 | case TOMOYO_TYPE_MKDIR: | 218 | case TOMOYO_TYPE_MKDIR: |
@@ -262,251 +230,23 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) | |||
262 | } | 230 | } |
263 | tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, | 231 | tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, |
264 | radix); | 232 | radix); |
265 | tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer); | 233 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords |
266 | return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, | 234 | [tomoyo_pn2mac[type]], |
267 | tomoyo_pattern(filename), buffer); | 235 | r->param.path_number.filename->name, buffer); |
268 | } | ||
269 | |||
270 | static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, | ||
271 | const struct tomoyo_acl_head *b) | ||
272 | { | ||
273 | return container_of(a, struct tomoyo_readable_file, | ||
274 | head)->filename == | ||
275 | container_of(b, struct tomoyo_readable_file, | ||
276 | head)->filename; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list. | ||
281 | * | ||
282 | * @filename: Filename unconditionally permitted to open() for reading. | ||
283 | * @is_delete: True if it is a delete request. | ||
284 | * | ||
285 | * Returns 0 on success, negative value otherwise. | ||
286 | * | ||
287 | * Caller holds tomoyo_read_lock(). | ||
288 | */ | ||
289 | static int tomoyo_update_globally_readable_entry(const char *filename, | ||
290 | const bool is_delete) | ||
291 | { | ||
292 | struct tomoyo_readable_file e = { }; | ||
293 | int error; | ||
294 | |||
295 | if (!tomoyo_correct_word(filename)) | ||
296 | return -EINVAL; | ||
297 | e.filename = tomoyo_get_name(filename); | ||
298 | if (!e.filename) | ||
299 | return -ENOMEM; | ||
300 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
301 | &tomoyo_policy_list | ||
302 | [TOMOYO_ID_GLOBALLY_READABLE], | ||
303 | tomoyo_same_globally_readable); | ||
304 | tomoyo_put_name(e.filename); | ||
305 | return error; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. | ||
310 | * | ||
311 | * @filename: The filename to check. | ||
312 | * | ||
313 | * Returns true if any domain can open @filename for reading, false otherwise. | ||
314 | * | ||
315 | * Caller holds tomoyo_read_lock(). | ||
316 | */ | ||
317 | static bool tomoyo_globally_readable_file(const struct tomoyo_path_info * | ||
318 | filename) | ||
319 | { | ||
320 | struct tomoyo_readable_file *ptr; | ||
321 | bool found = false; | ||
322 | |||
323 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | ||
324 | [TOMOYO_ID_GLOBALLY_READABLE], head.list) { | ||
325 | if (!ptr->head.is_deleted && | ||
326 | tomoyo_path_matches_pattern(filename, ptr->filename)) { | ||
327 | found = true; | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | return found; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list. | ||
336 | * | ||
337 | * @data: String to parse. | ||
338 | * @is_delete: True if it is a delete request. | ||
339 | * | ||
340 | * Returns 0 on success, negative value otherwise. | ||
341 | * | ||
342 | * Caller holds tomoyo_read_lock(). | ||
343 | */ | ||
344 | int tomoyo_write_globally_readable(char *data, const bool is_delete) | ||
345 | { | ||
346 | return tomoyo_update_globally_readable_entry(data, is_delete); | ||
347 | } | ||
348 | |||
349 | static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, | ||
350 | const struct tomoyo_acl_head *b) | ||
351 | { | ||
352 | return container_of(a, struct tomoyo_no_pattern, head)->pattern == | ||
353 | container_of(b, struct tomoyo_no_pattern, head)->pattern; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list. | ||
358 | * | ||
359 | * @pattern: Pathname pattern. | ||
360 | * @is_delete: True if it is a delete request. | ||
361 | * | ||
362 | * Returns 0 on success, negative value otherwise. | ||
363 | * | ||
364 | * Caller holds tomoyo_read_lock(). | ||
365 | */ | ||
366 | static int tomoyo_update_file_pattern_entry(const char *pattern, | ||
367 | const bool is_delete) | ||
368 | { | ||
369 | struct tomoyo_no_pattern e = { }; | ||
370 | int error; | ||
371 | |||
372 | if (!tomoyo_correct_word(pattern)) | ||
373 | return -EINVAL; | ||
374 | e.pattern = tomoyo_get_name(pattern); | ||
375 | if (!e.pattern) | ||
376 | return -ENOMEM; | ||
377 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
378 | &tomoyo_policy_list[TOMOYO_ID_PATTERN], | ||
379 | tomoyo_same_pattern); | ||
380 | tomoyo_put_name(e.pattern); | ||
381 | return error; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * tomoyo_pattern - Get patterned pathname. | ||
386 | * | ||
387 | * @filename: The filename to find patterned pathname. | ||
388 | * | ||
389 | * Returns pointer to pathname pattern if matched, @filename otherwise. | ||
390 | * | ||
391 | * Caller holds tomoyo_read_lock(). | ||
392 | */ | ||
393 | const char *tomoyo_pattern(const struct tomoyo_path_info *filename) | ||
394 | { | ||
395 | struct tomoyo_no_pattern *ptr; | ||
396 | const struct tomoyo_path_info *pattern = NULL; | ||
397 | |||
398 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN], | ||
399 | head.list) { | ||
400 | if (ptr->head.is_deleted) | ||
401 | continue; | ||
402 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | ||
403 | continue; | ||
404 | pattern = ptr->pattern; | ||
405 | if (tomoyo_strendswith(pattern->name, "/\\*")) { | ||
406 | /* Do nothing. Try to find the better match. */ | ||
407 | } else { | ||
408 | /* This would be the better match. Use this. */ | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | if (pattern) | ||
413 | filename = pattern; | ||
414 | return filename->name; | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list. | ||
419 | * | ||
420 | * @data: String to parse. | ||
421 | * @is_delete: True if it is a delete request. | ||
422 | * | ||
423 | * Returns 0 on success, negative value otherwise. | ||
424 | * | ||
425 | * Caller holds tomoyo_read_lock(). | ||
426 | */ | ||
427 | int tomoyo_write_pattern(char *data, const bool is_delete) | ||
428 | { | ||
429 | return tomoyo_update_file_pattern_entry(data, is_delete); | ||
430 | } | ||
431 | |||
432 | static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, | ||
433 | const struct tomoyo_acl_head *b) | ||
434 | { | ||
435 | return container_of(a, struct tomoyo_no_rewrite, head)->pattern | ||
436 | == container_of(b, struct tomoyo_no_rewrite, head) | ||
437 | ->pattern; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list. | ||
442 | * | ||
443 | * @pattern: Pathname pattern that are not rewritable by default. | ||
444 | * @is_delete: True if it is a delete request. | ||
445 | * | ||
446 | * Returns 0 on success, negative value otherwise. | ||
447 | * | ||
448 | * Caller holds tomoyo_read_lock(). | ||
449 | */ | ||
450 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | ||
451 | const bool is_delete) | ||
452 | { | ||
453 | struct tomoyo_no_rewrite e = { }; | ||
454 | int error; | ||
455 | |||
456 | if (!tomoyo_correct_word(pattern)) | ||
457 | return -EINVAL; | ||
458 | e.pattern = tomoyo_get_name(pattern); | ||
459 | if (!e.pattern) | ||
460 | return -ENOMEM; | ||
461 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
462 | &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], | ||
463 | tomoyo_same_no_rewrite); | ||
464 | tomoyo_put_name(e.pattern); | ||
465 | return error; | ||
466 | } | 236 | } |
467 | 237 | ||
468 | /** | 238 | /** |
469 | * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. | 239 | * tomoyo_check_path_acl - Check permission for path operation. |
470 | * | 240 | * |
471 | * @filename: Filename to check. | 241 | * @r: Pointer to "struct tomoyo_request_info". |
242 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
472 | * | 243 | * |
473 | * Returns true if @filename is specified by "deny_rewrite" directive, | 244 | * Returns true if granted, false otherwise. |
474 | * false otherwise. | ||
475 | * | 245 | * |
476 | * Caller holds tomoyo_read_lock(). | 246 | * To be able to use wildcard for domain transition, this function sets |
247 | * matching entry on success. Since the caller holds tomoyo_read_lock(), | ||
248 | * it is safe to set matching entry. | ||
477 | */ | 249 | */ |
478 | static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename) | ||
479 | { | ||
480 | struct tomoyo_no_rewrite *ptr; | ||
481 | bool found = false; | ||
482 | |||
483 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], | ||
484 | head.list) { | ||
485 | if (ptr->head.is_deleted) | ||
486 | continue; | ||
487 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | ||
488 | continue; | ||
489 | found = true; | ||
490 | break; | ||
491 | } | ||
492 | return found; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list. | ||
497 | * | ||
498 | * @data: String to parse. | ||
499 | * @is_delete: True if it is a delete request. | ||
500 | * | ||
501 | * Returns 0 on success, negative value otherwise. | ||
502 | * | ||
503 | * Caller holds tomoyo_read_lock(). | ||
504 | */ | ||
505 | int tomoyo_write_no_rewrite(char *data, const bool is_delete) | ||
506 | { | ||
507 | return tomoyo_update_no_rewrite_entry(data, is_delete); | ||
508 | } | ||
509 | |||
510 | static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, | 250 | static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, |
511 | const struct tomoyo_acl_info *ptr) | 251 | const struct tomoyo_acl_info *ptr) |
512 | { | 252 | { |
@@ -521,6 +261,14 @@ static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, | |||
521 | return false; | 261 | return false; |
522 | } | 262 | } |
523 | 263 | ||
264 | /** | ||
265 | * tomoyo_check_path_number_acl - Check permission for path number operation. | ||
266 | * | ||
267 | * @r: Pointer to "struct tomoyo_request_info". | ||
268 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
269 | * | ||
270 | * Returns true if granted, false otherwise. | ||
271 | */ | ||
524 | static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, | 272 | static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, |
525 | const struct tomoyo_acl_info *ptr) | 273 | const struct tomoyo_acl_info *ptr) |
526 | { | 274 | { |
@@ -533,6 +281,14 @@ static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, | |||
533 | &acl->name); | 281 | &acl->name); |
534 | } | 282 | } |
535 | 283 | ||
284 | /** | ||
285 | * tomoyo_check_path2_acl - Check permission for path path operation. | ||
286 | * | ||
287 | * @r: Pointer to "struct tomoyo_request_info". | ||
288 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
289 | * | ||
290 | * Returns true if granted, false otherwise. | ||
291 | */ | ||
536 | static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, | 292 | static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, |
537 | const struct tomoyo_acl_info *ptr) | 293 | const struct tomoyo_acl_info *ptr) |
538 | { | 294 | { |
@@ -544,8 +300,16 @@ static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, | |||
544 | &acl->name2); | 300 | &acl->name2); |
545 | } | 301 | } |
546 | 302 | ||
303 | /** | ||
304 | * tomoyo_check_mkdev_acl - Check permission for path number number number operation. | ||
305 | * | ||
306 | * @r: Pointer to "struct tomoyo_request_info". | ||
307 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
308 | * | ||
309 | * Returns true if granted, false otherwise. | ||
310 | */ | ||
547 | static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, | 311 | static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, |
548 | const struct tomoyo_acl_info *ptr) | 312 | const struct tomoyo_acl_info *ptr) |
549 | { | 313 | { |
550 | const struct tomoyo_mkdev_acl *acl = | 314 | const struct tomoyo_mkdev_acl *acl = |
551 | container_of(ptr, typeof(*acl), head); | 315 | container_of(ptr, typeof(*acl), head); |
@@ -560,15 +324,31 @@ static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, | |||
560 | &acl->name); | 324 | &acl->name); |
561 | } | 325 | } |
562 | 326 | ||
327 | /** | ||
328 | * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry. | ||
329 | * | ||
330 | * @a: Pointer to "struct tomoyo_acl_info". | ||
331 | * @b: Pointer to "struct tomoyo_acl_info". | ||
332 | * | ||
333 | * Returns true if @a == @b except permission bits, false otherwise. | ||
334 | */ | ||
563 | static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, | 335 | static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, |
564 | const struct tomoyo_acl_info *b) | 336 | const struct tomoyo_acl_info *b) |
565 | { | 337 | { |
566 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); | 338 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); |
567 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); | 339 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); |
568 | return tomoyo_same_acl_head(&p1->head, &p2->head) && | 340 | return tomoyo_same_name_union(&p1->name, &p2->name); |
569 | tomoyo_same_name_union(&p1->name, &p2->name); | ||
570 | } | 341 | } |
571 | 342 | ||
343 | /** | ||
344 | * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry. | ||
345 | * | ||
346 | * @a: Pointer to "struct tomoyo_acl_info". | ||
347 | * @b: Pointer to "struct tomoyo_acl_info". | ||
348 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
349 | * | ||
350 | * Returns true if @a is empty, false otherwise. | ||
351 | */ | ||
572 | static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | 352 | static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, |
573 | struct tomoyo_acl_info *b, | 353 | struct tomoyo_acl_info *b, |
574 | const bool is_delete) | 354 | const bool is_delete) |
@@ -577,19 +357,10 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | |||
577 | ->perm; | 357 | ->perm; |
578 | u16 perm = *a_perm; | 358 | u16 perm = *a_perm; |
579 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; | 359 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; |
580 | if (is_delete) { | 360 | if (is_delete) |
581 | perm &= ~b_perm; | 361 | perm &= ~b_perm; |
582 | if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) | 362 | else |
583 | perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); | ||
584 | else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) | ||
585 | perm &= ~TOMOYO_RW_MASK; | ||
586 | } else { | ||
587 | perm |= b_perm; | 363 | perm |= b_perm; |
588 | if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) | ||
589 | perm |= (1 << TOMOYO_TYPE_READ_WRITE); | ||
590 | else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
591 | perm |= TOMOYO_RW_MASK; | ||
592 | } | ||
593 | *a_perm = perm; | 364 | *a_perm = perm; |
594 | return !perm; | 365 | return !perm; |
595 | } | 366 | } |
@@ -597,52 +368,62 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | |||
597 | /** | 368 | /** |
598 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. | 369 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
599 | * | 370 | * |
600 | * @type: Type of operation. | 371 | * @perm: Permission. |
601 | * @filename: Filename. | 372 | * @param: Pointer to "struct tomoyo_acl_param". |
602 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
603 | * @is_delete: True if it is a delete request. | ||
604 | * | 373 | * |
605 | * Returns 0 on success, negative value otherwise. | 374 | * Returns 0 on success, negative value otherwise. |
606 | * | 375 | * |
607 | * Caller holds tomoyo_read_lock(). | 376 | * Caller holds tomoyo_read_lock(). |
608 | */ | 377 | */ |
609 | static int tomoyo_update_path_acl(const u8 type, const char *filename, | 378 | static int tomoyo_update_path_acl(const u16 perm, |
610 | struct tomoyo_domain_info * const domain, | 379 | struct tomoyo_acl_param *param) |
611 | const bool is_delete) | ||
612 | { | 380 | { |
613 | struct tomoyo_path_acl e = { | 381 | struct tomoyo_path_acl e = { |
614 | .head.type = TOMOYO_TYPE_PATH_ACL, | 382 | .head.type = TOMOYO_TYPE_PATH_ACL, |
615 | .perm = 1 << type | 383 | .perm = perm |
616 | }; | 384 | }; |
617 | int error; | 385 | int error; |
618 | if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) | 386 | if (!tomoyo_parse_name_union(param, &e.name)) |
619 | e.perm |= TOMOYO_RW_MASK; | 387 | error = -EINVAL; |
620 | if (!tomoyo_parse_name_union(filename, &e.name)) | 388 | else |
621 | return -EINVAL; | 389 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
622 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 390 | tomoyo_same_path_acl, |
623 | tomoyo_same_path_acl, | 391 | tomoyo_merge_path_acl); |
624 | tomoyo_merge_path_acl); | ||
625 | tomoyo_put_name_union(&e.name); | 392 | tomoyo_put_name_union(&e.name); |
626 | return error; | 393 | return error; |
627 | } | 394 | } |
628 | 395 | ||
396 | /** | ||
397 | * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry. | ||
398 | * | ||
399 | * @a: Pointer to "struct tomoyo_acl_info". | ||
400 | * @b: Pointer to "struct tomoyo_acl_info". | ||
401 | * | ||
402 | * Returns true if @a == @b except permission bits, false otherwise. | ||
403 | */ | ||
629 | static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, | 404 | static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, |
630 | const struct tomoyo_acl_info *b) | 405 | const struct tomoyo_acl_info *b) |
631 | { | 406 | { |
632 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), | 407 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); |
633 | head); | 408 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); |
634 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), | 409 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
635 | head); | 410 | tomoyo_same_number_union(&p1->mode, &p2->mode) && |
636 | return tomoyo_same_acl_head(&p1->head, &p2->head) | 411 | tomoyo_same_number_union(&p1->major, &p2->major) && |
637 | && tomoyo_same_name_union(&p1->name, &p2->name) | 412 | tomoyo_same_number_union(&p1->minor, &p2->minor); |
638 | && tomoyo_same_number_union(&p1->mode, &p2->mode) | ||
639 | && tomoyo_same_number_union(&p1->major, &p2->major) | ||
640 | && tomoyo_same_number_union(&p1->minor, &p2->minor); | ||
641 | } | 413 | } |
642 | 414 | ||
415 | /** | ||
416 | * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry. | ||
417 | * | ||
418 | * @a: Pointer to "struct tomoyo_acl_info". | ||
419 | * @b: Pointer to "struct tomoyo_acl_info". | ||
420 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
421 | * | ||
422 | * Returns true if @a is empty, false otherwise. | ||
423 | */ | ||
643 | static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, | 424 | static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, |
644 | struct tomoyo_acl_info *b, | 425 | struct tomoyo_acl_info *b, |
645 | const bool is_delete) | 426 | const bool is_delete) |
646 | { | 427 | { |
647 | u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, | 428 | u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, |
648 | head)->perm; | 429 | head)->perm; |
@@ -660,37 +441,30 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, | |||
660 | /** | 441 | /** |
661 | * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. | 442 | * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. |
662 | * | 443 | * |
663 | * @type: Type of operation. | 444 | * @perm: Permission. |
664 | * @filename: Filename. | 445 | * @param: Pointer to "struct tomoyo_acl_param". |
665 | * @mode: Create mode. | ||
666 | * @major: Device major number. | ||
667 | * @minor: Device minor number. | ||
668 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
669 | * @is_delete: True if it is a delete request. | ||
670 | * | 446 | * |
671 | * Returns 0 on success, negative value otherwise. | 447 | * Returns 0 on success, negative value otherwise. |
672 | * | 448 | * |
673 | * Caller holds tomoyo_read_lock(). | 449 | * Caller holds tomoyo_read_lock(). |
674 | */ | 450 | */ |
675 | static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, | 451 | static int tomoyo_update_mkdev_acl(const u8 perm, |
676 | char *mode, char *major, char *minor, | 452 | struct tomoyo_acl_param *param) |
677 | struct tomoyo_domain_info * const | ||
678 | domain, const bool is_delete) | ||
679 | { | 453 | { |
680 | struct tomoyo_mkdev_acl e = { | 454 | struct tomoyo_mkdev_acl e = { |
681 | .head.type = TOMOYO_TYPE_MKDEV_ACL, | 455 | .head.type = TOMOYO_TYPE_MKDEV_ACL, |
682 | .perm = 1 << type | 456 | .perm = perm |
683 | }; | 457 | }; |
684 | int error = is_delete ? -ENOENT : -ENOMEM; | 458 | int error; |
685 | if (!tomoyo_parse_name_union(filename, &e.name) || | 459 | if (!tomoyo_parse_name_union(param, &e.name) || |
686 | !tomoyo_parse_number_union(mode, &e.mode) || | 460 | !tomoyo_parse_number_union(param, &e.mode) || |
687 | !tomoyo_parse_number_union(major, &e.major) || | 461 | !tomoyo_parse_number_union(param, &e.major) || |
688 | !tomoyo_parse_number_union(minor, &e.minor)) | 462 | !tomoyo_parse_number_union(param, &e.minor)) |
689 | goto out; | 463 | error = -EINVAL; |
690 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 464 | else |
691 | tomoyo_same_mkdev_acl, | 465 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
692 | tomoyo_merge_mkdev_acl); | 466 | tomoyo_same_mkdev_acl, |
693 | out: | 467 | tomoyo_merge_mkdev_acl); |
694 | tomoyo_put_name_union(&e.name); | 468 | tomoyo_put_name_union(&e.name); |
695 | tomoyo_put_number_union(&e.mode); | 469 | tomoyo_put_number_union(&e.mode); |
696 | tomoyo_put_number_union(&e.major); | 470 | tomoyo_put_number_union(&e.major); |
@@ -698,16 +472,32 @@ static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, | |||
698 | return error; | 472 | return error; |
699 | } | 473 | } |
700 | 474 | ||
475 | /** | ||
476 | * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry. | ||
477 | * | ||
478 | * @a: Pointer to "struct tomoyo_acl_info". | ||
479 | * @b: Pointer to "struct tomoyo_acl_info". | ||
480 | * | ||
481 | * Returns true if @a == @b except permission bits, false otherwise. | ||
482 | */ | ||
701 | static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, | 483 | static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, |
702 | const struct tomoyo_acl_info *b) | 484 | const struct tomoyo_acl_info *b) |
703 | { | 485 | { |
704 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); | 486 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); |
705 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); | 487 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); |
706 | return tomoyo_same_acl_head(&p1->head, &p2->head) | 488 | return tomoyo_same_name_union(&p1->name1, &p2->name1) && |
707 | && tomoyo_same_name_union(&p1->name1, &p2->name1) | 489 | tomoyo_same_name_union(&p1->name2, &p2->name2); |
708 | && tomoyo_same_name_union(&p1->name2, &p2->name2); | ||
709 | } | 490 | } |
710 | 491 | ||
492 | /** | ||
493 | * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry. | ||
494 | * | ||
495 | * @a: Pointer to "struct tomoyo_acl_info". | ||
496 | * @b: Pointer to "struct tomoyo_acl_info". | ||
497 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
498 | * | ||
499 | * Returns true if @a is empty, false otherwise. | ||
500 | */ | ||
711 | static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, | 501 | static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, |
712 | struct tomoyo_acl_info *b, | 502 | struct tomoyo_acl_info *b, |
713 | const bool is_delete) | 503 | const bool is_delete) |
@@ -727,33 +517,28 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, | |||
727 | /** | 517 | /** |
728 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. | 518 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
729 | * | 519 | * |
730 | * @type: Type of operation. | 520 | * @perm: Permission. |
731 | * @filename1: First filename. | 521 | * @param: Pointer to "struct tomoyo_acl_param". |
732 | * @filename2: Second filename. | ||
733 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
734 | * @is_delete: True if it is a delete request. | ||
735 | * | 522 | * |
736 | * Returns 0 on success, negative value otherwise. | 523 | * Returns 0 on success, negative value otherwise. |
737 | * | 524 | * |
738 | * Caller holds tomoyo_read_lock(). | 525 | * Caller holds tomoyo_read_lock(). |
739 | */ | 526 | */ |
740 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, | 527 | static int tomoyo_update_path2_acl(const u8 perm, |
741 | const char *filename2, | 528 | struct tomoyo_acl_param *param) |
742 | struct tomoyo_domain_info * const domain, | ||
743 | const bool is_delete) | ||
744 | { | 529 | { |
745 | struct tomoyo_path2_acl e = { | 530 | struct tomoyo_path2_acl e = { |
746 | .head.type = TOMOYO_TYPE_PATH2_ACL, | 531 | .head.type = TOMOYO_TYPE_PATH2_ACL, |
747 | .perm = 1 << type | 532 | .perm = perm |
748 | }; | 533 | }; |
749 | int error = is_delete ? -ENOENT : -ENOMEM; | 534 | int error; |
750 | if (!tomoyo_parse_name_union(filename1, &e.name1) || | 535 | if (!tomoyo_parse_name_union(param, &e.name1) || |
751 | !tomoyo_parse_name_union(filename2, &e.name2)) | 536 | !tomoyo_parse_name_union(param, &e.name2)) |
752 | goto out; | 537 | error = -EINVAL; |
753 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 538 | else |
754 | tomoyo_same_path2_acl, | 539 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
755 | tomoyo_merge_path2_acl); | 540 | tomoyo_same_path2_acl, |
756 | out: | 541 | tomoyo_merge_path2_acl); |
757 | tomoyo_put_name_union(&e.name1); | 542 | tomoyo_put_name_union(&e.name1); |
758 | tomoyo_put_name_union(&e.name2); | 543 | tomoyo_put_name_union(&e.name2); |
759 | return error; | 544 | return error; |
@@ -775,9 +560,8 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
775 | { | 560 | { |
776 | int error; | 561 | int error; |
777 | 562 | ||
778 | next: | ||
779 | r->type = tomoyo_p2mac[operation]; | 563 | r->type = tomoyo_p2mac[operation]; |
780 | r->mode = tomoyo_get_mode(r->profile, r->type); | 564 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); |
781 | if (r->mode == TOMOYO_CONFIG_DISABLED) | 565 | if (r->mode == TOMOYO_CONFIG_DISABLED) |
782 | return 0; | 566 | return 0; |
783 | r->param_type = TOMOYO_TYPE_PATH_ACL; | 567 | r->param_type = TOMOYO_TYPE_PATH_ACL; |
@@ -785,10 +569,6 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
785 | r->param.path.operation = operation; | 569 | r->param.path.operation = operation; |
786 | do { | 570 | do { |
787 | tomoyo_check_acl(r, tomoyo_check_path_acl); | 571 | tomoyo_check_acl(r, tomoyo_check_path_acl); |
788 | if (!r->granted && operation == TOMOYO_TYPE_READ && | ||
789 | !r->domain->ignore_global_allow_read && | ||
790 | tomoyo_globally_readable_file(filename)) | ||
791 | r->granted = true; | ||
792 | error = tomoyo_audit_path_log(r); | 572 | error = tomoyo_audit_path_log(r); |
793 | /* | 573 | /* |
794 | * Do not retry for execute request, for alias may have | 574 | * Do not retry for execute request, for alias may have |
@@ -796,19 +576,17 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
796 | */ | 576 | */ |
797 | } while (error == TOMOYO_RETRY_REQUEST && | 577 | } while (error == TOMOYO_RETRY_REQUEST && |
798 | operation != TOMOYO_TYPE_EXECUTE); | 578 | operation != TOMOYO_TYPE_EXECUTE); |
799 | /* | ||
800 | * Since "allow_truncate" doesn't imply "allow_rewrite" permission, | ||
801 | * we need to check "allow_rewrite" permission if the filename is | ||
802 | * specified by "deny_rewrite" keyword. | ||
803 | */ | ||
804 | if (!error && operation == TOMOYO_TYPE_TRUNCATE && | ||
805 | tomoyo_no_rewrite_file(filename)) { | ||
806 | operation = TOMOYO_TYPE_REWRITE; | ||
807 | goto next; | ||
808 | } | ||
809 | return error; | 579 | return error; |
810 | } | 580 | } |
811 | 581 | ||
582 | /** | ||
583 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. | ||
584 | * | ||
585 | * @a: Pointer to "struct tomoyo_acl_info". | ||
586 | * @b: Pointer to "struct tomoyo_acl_info". | ||
587 | * | ||
588 | * Returns true if @a == @b except permission bits, false otherwise. | ||
589 | */ | ||
812 | static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, | 590 | static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, |
813 | const struct tomoyo_acl_info *b) | 591 | const struct tomoyo_acl_info *b) |
814 | { | 592 | { |
@@ -816,11 +594,19 @@ static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, | |||
816 | head); | 594 | head); |
817 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), | 595 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), |
818 | head); | 596 | head); |
819 | return tomoyo_same_acl_head(&p1->head, &p2->head) | 597 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
820 | && tomoyo_same_name_union(&p1->name, &p2->name) | 598 | tomoyo_same_number_union(&p1->number, &p2->number); |
821 | && tomoyo_same_number_union(&p1->number, &p2->number); | ||
822 | } | 599 | } |
823 | 600 | ||
601 | /** | ||
602 | * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry. | ||
603 | * | ||
604 | * @a: Pointer to "struct tomoyo_acl_info". | ||
605 | * @b: Pointer to "struct tomoyo_acl_info". | ||
606 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
607 | * | ||
608 | * Returns true if @a is empty, false otherwise. | ||
609 | */ | ||
824 | static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, | 610 | static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, |
825 | struct tomoyo_acl_info *b, | 611 | struct tomoyo_acl_info *b, |
826 | const bool is_delete) | 612 | const bool is_delete) |
@@ -841,33 +627,26 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, | |||
841 | /** | 627 | /** |
842 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. | 628 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. |
843 | * | 629 | * |
844 | * @type: Type of operation. | 630 | * @perm: Permission. |
845 | * @filename: Filename. | 631 | * @param: Pointer to "struct tomoyo_acl_param". |
846 | * @number: Number. | ||
847 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
848 | * @is_delete: True if it is a delete request. | ||
849 | * | 632 | * |
850 | * Returns 0 on success, negative value otherwise. | 633 | * Returns 0 on success, negative value otherwise. |
851 | */ | 634 | */ |
852 | static int tomoyo_update_path_number_acl(const u8 type, const char *filename, | 635 | static int tomoyo_update_path_number_acl(const u8 perm, |
853 | char *number, | 636 | struct tomoyo_acl_param *param) |
854 | struct tomoyo_domain_info * const | ||
855 | domain, | ||
856 | const bool is_delete) | ||
857 | { | 637 | { |
858 | struct tomoyo_path_number_acl e = { | 638 | struct tomoyo_path_number_acl e = { |
859 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, | 639 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, |
860 | .perm = 1 << type | 640 | .perm = perm |
861 | }; | 641 | }; |
862 | int error = is_delete ? -ENOENT : -ENOMEM; | 642 | int error; |
863 | if (!tomoyo_parse_name_union(filename, &e.name)) | 643 | if (!tomoyo_parse_name_union(param, &e.name) || |
864 | return -EINVAL; | 644 | !tomoyo_parse_number_union(param, &e.number)) |
865 | if (!tomoyo_parse_number_union(number, &e.number)) | 645 | error = -EINVAL; |
866 | goto out; | 646 | else |
867 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 647 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
868 | tomoyo_same_path_number_acl, | 648 | tomoyo_same_path_number_acl, |
869 | tomoyo_merge_path_number_acl); | 649 | tomoyo_merge_path_number_acl); |
870 | out: | ||
871 | tomoyo_put_name_union(&e.name); | 650 | tomoyo_put_name_union(&e.name); |
872 | tomoyo_put_number_union(&e.number); | 651 | tomoyo_put_number_union(&e.number); |
873 | return error; | 652 | return error; |
@@ -886,16 +665,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, | |||
886 | unsigned long number) | 665 | unsigned long number) |
887 | { | 666 | { |
888 | struct tomoyo_request_info r; | 667 | struct tomoyo_request_info r; |
668 | struct tomoyo_obj_info obj = { | ||
669 | .path1 = *path, | ||
670 | }; | ||
889 | int error = -ENOMEM; | 671 | int error = -ENOMEM; |
890 | struct tomoyo_path_info buf; | 672 | struct tomoyo_path_info buf; |
891 | int idx; | 673 | int idx; |
892 | 674 | ||
893 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) | 675 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) |
894 | == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) | 676 | == TOMOYO_CONFIG_DISABLED || !path->dentry) |
895 | return 0; | 677 | return 0; |
896 | idx = tomoyo_read_lock(); | 678 | idx = tomoyo_read_lock(); |
897 | if (!tomoyo_get_realpath(&buf, path)) | 679 | if (!tomoyo_get_realpath(&buf, path)) |
898 | goto out; | 680 | goto out; |
681 | r.obj = &obj; | ||
899 | if (type == TOMOYO_TYPE_MKDIR) | 682 | if (type == TOMOYO_TYPE_MKDIR) |
900 | tomoyo_add_slash(&buf); | 683 | tomoyo_add_slash(&buf); |
901 | r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; | 684 | r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; |
@@ -930,45 +713,30 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
930 | int error = 0; | 713 | int error = 0; |
931 | struct tomoyo_path_info buf; | 714 | struct tomoyo_path_info buf; |
932 | struct tomoyo_request_info r; | 715 | struct tomoyo_request_info r; |
716 | struct tomoyo_obj_info obj = { | ||
717 | .path1 = *path, | ||
718 | }; | ||
933 | int idx; | 719 | int idx; |
934 | 720 | ||
935 | if (!path->mnt || | ||
936 | (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) | ||
937 | return 0; | ||
938 | buf.name = NULL; | 721 | buf.name = NULL; |
939 | r.mode = TOMOYO_CONFIG_DISABLED; | 722 | r.mode = TOMOYO_CONFIG_DISABLED; |
940 | idx = tomoyo_read_lock(); | 723 | idx = tomoyo_read_lock(); |
941 | /* | 724 | if (acc_mode && |
942 | * If the filename is specified by "deny_rewrite" keyword, | 725 | tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) |
943 | * we need to check "allow_rewrite" permission when the filename is not | ||
944 | * opened for append mode or the filename is truncated at open time. | ||
945 | */ | ||
946 | if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) | ||
947 | && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) | ||
948 | != TOMOYO_CONFIG_DISABLED) { | 726 | != TOMOYO_CONFIG_DISABLED) { |
949 | if (!tomoyo_get_realpath(&buf, path)) { | 727 | if (!tomoyo_get_realpath(&buf, path)) { |
950 | error = -ENOMEM; | 728 | error = -ENOMEM; |
951 | goto out; | 729 | goto out; |
952 | } | 730 | } |
953 | if (tomoyo_no_rewrite_file(&buf)) | 731 | r.obj = &obj; |
954 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, | 732 | if (acc_mode & MAY_READ) |
733 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, | ||
734 | &buf); | ||
735 | if (!error && (acc_mode & MAY_WRITE)) | ||
736 | error = tomoyo_path_permission(&r, (flag & O_APPEND) ? | ||
737 | TOMOYO_TYPE_APPEND : | ||
738 | TOMOYO_TYPE_WRITE, | ||
955 | &buf); | 739 | &buf); |
956 | } | ||
957 | if (!error && acc_mode && | ||
958 | tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) | ||
959 | != TOMOYO_CONFIG_DISABLED) { | ||
960 | u8 operation; | ||
961 | if (!buf.name && !tomoyo_get_realpath(&buf, path)) { | ||
962 | error = -ENOMEM; | ||
963 | goto out; | ||
964 | } | ||
965 | if (acc_mode == (MAY_READ | MAY_WRITE)) | ||
966 | operation = TOMOYO_TYPE_READ_WRITE; | ||
967 | else if (acc_mode == MAY_READ) | ||
968 | operation = TOMOYO_TYPE_READ; | ||
969 | else | ||
970 | operation = TOMOYO_TYPE_WRITE; | ||
971 | error = tomoyo_path_permission(&r, operation, &buf); | ||
972 | } | 740 | } |
973 | out: | 741 | out: |
974 | kfree(buf.name); | 742 | kfree(buf.name); |
@@ -979,46 +747,57 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
979 | } | 747 | } |
980 | 748 | ||
981 | /** | 749 | /** |
982 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". | 750 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount". |
983 | * | 751 | * |
984 | * @operation: Type of operation. | 752 | * @operation: Type of operation. |
985 | * @path: Pointer to "struct path". | 753 | * @path: Pointer to "struct path". |
754 | * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK, | ||
755 | * NULL otherwise. | ||
986 | * | 756 | * |
987 | * Returns 0 on success, negative value otherwise. | 757 | * Returns 0 on success, negative value otherwise. |
988 | */ | 758 | */ |
989 | int tomoyo_path_perm(const u8 operation, struct path *path) | 759 | int tomoyo_path_perm(const u8 operation, struct path *path, const char *target) |
990 | { | 760 | { |
991 | int error = -ENOMEM; | ||
992 | struct tomoyo_path_info buf; | ||
993 | struct tomoyo_request_info r; | 761 | struct tomoyo_request_info r; |
762 | struct tomoyo_obj_info obj = { | ||
763 | .path1 = *path, | ||
764 | }; | ||
765 | int error; | ||
766 | struct tomoyo_path_info buf; | ||
767 | bool is_enforce; | ||
768 | struct tomoyo_path_info symlink_target; | ||
994 | int idx; | 769 | int idx; |
995 | 770 | ||
996 | if (!path->mnt) | ||
997 | return 0; | ||
998 | if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) | 771 | if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) |
999 | == TOMOYO_CONFIG_DISABLED) | 772 | == TOMOYO_CONFIG_DISABLED) |
1000 | return 0; | 773 | return 0; |
774 | is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING); | ||
775 | error = -ENOMEM; | ||
1001 | buf.name = NULL; | 776 | buf.name = NULL; |
1002 | idx = tomoyo_read_lock(); | 777 | idx = tomoyo_read_lock(); |
1003 | if (!tomoyo_get_realpath(&buf, path)) | 778 | if (!tomoyo_get_realpath(&buf, path)) |
1004 | goto out; | 779 | goto out; |
780 | r.obj = &obj; | ||
1005 | switch (operation) { | 781 | switch (operation) { |
1006 | case TOMOYO_TYPE_REWRITE: | ||
1007 | if (!tomoyo_no_rewrite_file(&buf)) { | ||
1008 | error = 0; | ||
1009 | goto out; | ||
1010 | } | ||
1011 | break; | ||
1012 | case TOMOYO_TYPE_RMDIR: | 782 | case TOMOYO_TYPE_RMDIR: |
1013 | case TOMOYO_TYPE_CHROOT: | 783 | case TOMOYO_TYPE_CHROOT: |
1014 | tomoyo_add_slash(&buf); | 784 | tomoyo_add_slash(&buf); |
1015 | break; | 785 | break; |
786 | case TOMOYO_TYPE_SYMLINK: | ||
787 | symlink_target.name = tomoyo_encode(target); | ||
788 | if (!symlink_target.name) | ||
789 | goto out; | ||
790 | tomoyo_fill_path_info(&symlink_target); | ||
791 | obj.symlink_target = &symlink_target; | ||
792 | break; | ||
1016 | } | 793 | } |
1017 | error = tomoyo_path_permission(&r, operation, &buf); | 794 | error = tomoyo_path_permission(&r, operation, &buf); |
795 | if (operation == TOMOYO_TYPE_SYMLINK) | ||
796 | kfree(symlink_target.name); | ||
1018 | out: | 797 | out: |
1019 | kfree(buf.name); | 798 | kfree(buf.name); |
1020 | tomoyo_read_unlock(idx); | 799 | tomoyo_read_unlock(idx); |
1021 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 800 | if (!is_enforce) |
1022 | error = 0; | 801 | error = 0; |
1023 | return error; | 802 | return error; |
1024 | } | 803 | } |
@@ -1034,20 +813,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path) | |||
1034 | * Returns 0 on success, negative value otherwise. | 813 | * Returns 0 on success, negative value otherwise. |
1035 | */ | 814 | */ |
1036 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, | 815 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, |
1037 | const unsigned int mode, unsigned int dev) | 816 | const unsigned int mode, unsigned int dev) |
1038 | { | 817 | { |
1039 | struct tomoyo_request_info r; | 818 | struct tomoyo_request_info r; |
819 | struct tomoyo_obj_info obj = { | ||
820 | .path1 = *path, | ||
821 | }; | ||
1040 | int error = -ENOMEM; | 822 | int error = -ENOMEM; |
1041 | struct tomoyo_path_info buf; | 823 | struct tomoyo_path_info buf; |
1042 | int idx; | 824 | int idx; |
1043 | 825 | ||
1044 | if (!path->mnt || | 826 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) |
1045 | tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) | ||
1046 | == TOMOYO_CONFIG_DISABLED) | 827 | == TOMOYO_CONFIG_DISABLED) |
1047 | return 0; | 828 | return 0; |
1048 | idx = tomoyo_read_lock(); | 829 | idx = tomoyo_read_lock(); |
1049 | error = -ENOMEM; | 830 | error = -ENOMEM; |
1050 | if (tomoyo_get_realpath(&buf, path)) { | 831 | if (tomoyo_get_realpath(&buf, path)) { |
832 | r.obj = &obj; | ||
1051 | dev = new_decode_dev(dev); | 833 | dev = new_decode_dev(dev); |
1052 | r.param_type = TOMOYO_TYPE_MKDEV_ACL; | 834 | r.param_type = TOMOYO_TYPE_MKDEV_ACL; |
1053 | r.param.mkdev.filename = &buf; | 835 | r.param.mkdev.filename = &buf; |
@@ -1081,10 +863,13 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1081 | struct tomoyo_path_info buf1; | 863 | struct tomoyo_path_info buf1; |
1082 | struct tomoyo_path_info buf2; | 864 | struct tomoyo_path_info buf2; |
1083 | struct tomoyo_request_info r; | 865 | struct tomoyo_request_info r; |
866 | struct tomoyo_obj_info obj = { | ||
867 | .path1 = *path1, | ||
868 | .path2 = *path2, | ||
869 | }; | ||
1084 | int idx; | 870 | int idx; |
1085 | 871 | ||
1086 | if (!path1->mnt || !path2->mnt || | 872 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) |
1087 | tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) | ||
1088 | == TOMOYO_CONFIG_DISABLED) | 873 | == TOMOYO_CONFIG_DISABLED) |
1089 | return 0; | 874 | return 0; |
1090 | buf1.name = NULL; | 875 | buf1.name = NULL; |
@@ -1096,16 +881,17 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1096 | switch (operation) { | 881 | switch (operation) { |
1097 | struct dentry *dentry; | 882 | struct dentry *dentry; |
1098 | case TOMOYO_TYPE_RENAME: | 883 | case TOMOYO_TYPE_RENAME: |
1099 | case TOMOYO_TYPE_LINK: | 884 | case TOMOYO_TYPE_LINK: |
1100 | dentry = path1->dentry; | 885 | dentry = path1->dentry; |
1101 | if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) | 886 | if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) |
1102 | break; | 887 | break; |
1103 | /* fall through */ | 888 | /* fall through */ |
1104 | case TOMOYO_TYPE_PIVOT_ROOT: | 889 | case TOMOYO_TYPE_PIVOT_ROOT: |
1105 | tomoyo_add_slash(&buf1); | 890 | tomoyo_add_slash(&buf1); |
1106 | tomoyo_add_slash(&buf2); | 891 | tomoyo_add_slash(&buf2); |
1107 | break; | 892 | break; |
1108 | } | 893 | } |
894 | r.obj = &obj; | ||
1109 | r.param_type = TOMOYO_TYPE_PATH2_ACL; | 895 | r.param_type = TOMOYO_TYPE_PATH2_ACL; |
1110 | r.param.path2.operation = operation; | 896 | r.param.path2.operation = operation; |
1111 | r.param.path2.filename1 = &buf1; | 897 | r.param.path2.filename1 = &buf1; |
@@ -1124,53 +910,91 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1124 | } | 910 | } |
1125 | 911 | ||
1126 | /** | 912 | /** |
913 | * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. | ||
914 | * | ||
915 | * @a: Pointer to "struct tomoyo_acl_info". | ||
916 | * @b: Pointer to "struct tomoyo_acl_info". | ||
917 | * | ||
918 | * Returns true if @a == @b, false otherwise. | ||
919 | */ | ||
920 | static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, | ||
921 | const struct tomoyo_acl_info *b) | ||
922 | { | ||
923 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); | ||
924 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); | ||
925 | return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && | ||
926 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && | ||
927 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && | ||
928 | tomoyo_same_number_union(&p1->flags, &p2->flags); | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. | ||
933 | * | ||
934 | * @param: Pointer to "struct tomoyo_acl_param". | ||
935 | * | ||
936 | * Returns 0 on success, negative value otherwise. | ||
937 | * | ||
938 | * Caller holds tomoyo_read_lock(). | ||
939 | */ | ||
940 | static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) | ||
941 | { | ||
942 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; | ||
943 | int error; | ||
944 | if (!tomoyo_parse_name_union(param, &e.dev_name) || | ||
945 | !tomoyo_parse_name_union(param, &e.dir_name) || | ||
946 | !tomoyo_parse_name_union(param, &e.fs_type) || | ||
947 | !tomoyo_parse_number_union(param, &e.flags)) | ||
948 | error = -EINVAL; | ||
949 | else | ||
950 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | ||
951 | tomoyo_same_mount_acl, NULL); | ||
952 | tomoyo_put_name_union(&e.dev_name); | ||
953 | tomoyo_put_name_union(&e.dir_name); | ||
954 | tomoyo_put_name_union(&e.fs_type); | ||
955 | tomoyo_put_number_union(&e.flags); | ||
956 | return error; | ||
957 | } | ||
958 | |||
959 | /** | ||
1127 | * tomoyo_write_file - Update file related list. | 960 | * tomoyo_write_file - Update file related list. |
1128 | * | 961 | * |
1129 | * @data: String to parse. | 962 | * @param: Pointer to "struct tomoyo_acl_param". |
1130 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1131 | * @is_delete: True if it is a delete request. | ||
1132 | * | 963 | * |
1133 | * Returns 0 on success, negative value otherwise. | 964 | * Returns 0 on success, negative value otherwise. |
1134 | * | 965 | * |
1135 | * Caller holds tomoyo_read_lock(). | 966 | * Caller holds tomoyo_read_lock(). |
1136 | */ | 967 | */ |
1137 | int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain, | 968 | int tomoyo_write_file(struct tomoyo_acl_param *param) |
1138 | const bool is_delete) | ||
1139 | { | 969 | { |
1140 | char *w[5]; | 970 | u16 perm = 0; |
1141 | u8 type; | 971 | u8 type; |
1142 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) | 972 | const char *operation = tomoyo_read_token(param); |
1143 | return -EINVAL; | 973 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) |
1144 | if (strncmp(w[0], "allow_", 6)) | 974 | if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) |
1145 | goto out; | 975 | perm |= 1 << type; |
1146 | w[0] += 6; | 976 | if (perm) |
1147 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { | 977 | return tomoyo_update_path_acl(perm, param); |
1148 | if (strcmp(w[0], tomoyo_path_keyword[type])) | 978 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) |
1149 | continue; | 979 | if (tomoyo_permstr(operation, |
1150 | return tomoyo_update_path_acl(type, w[1], domain, is_delete); | 980 | tomoyo_mac_keywords[tomoyo_pp2mac[type]])) |
1151 | } | 981 | perm |= 1 << type; |
1152 | if (!w[2][0]) | 982 | if (perm) |
1153 | goto out; | 983 | return tomoyo_update_path2_acl(perm, param); |
1154 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { | 984 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) |
1155 | if (strcmp(w[0], tomoyo_path2_keyword[type])) | 985 | if (tomoyo_permstr(operation, |
1156 | continue; | 986 | tomoyo_mac_keywords[tomoyo_pn2mac[type]])) |
1157 | return tomoyo_update_path2_acl(type, w[1], w[2], domain, | 987 | perm |= 1 << type; |
1158 | is_delete); | 988 | if (perm) |
1159 | } | 989 | return tomoyo_update_path_number_acl(perm, param); |
1160 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { | 990 | for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) |
1161 | if (strcmp(w[0], tomoyo_path_number_keyword[type])) | 991 | if (tomoyo_permstr(operation, |
1162 | continue; | 992 | tomoyo_mac_keywords[tomoyo_pnnn2mac[type]])) |
1163 | return tomoyo_update_path_number_acl(type, w[1], w[2], domain, | 993 | perm |= 1 << type; |
1164 | is_delete); | 994 | if (perm) |
1165 | } | 995 | return tomoyo_update_mkdev_acl(perm, param); |
1166 | if (!w[3][0] || !w[4][0]) | 996 | if (tomoyo_permstr(operation, |
1167 | goto out; | 997 | tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT])) |
1168 | for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { | 998 | return tomoyo_update_mount_acl(param); |
1169 | if (strcmp(w[0], tomoyo_mkdev_keyword[type])) | ||
1170 | continue; | ||
1171 | return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], | ||
1172 | w[4], domain, is_delete); | ||
1173 | } | ||
1174 | out: | ||
1175 | return -EINVAL; | 999 | return -EINVAL; |
1176 | } | 1000 | } |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index a877e4c3b101..ae135fbbbe95 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -1,58 +1,205 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/gc.c | 2 | * security/tomoyo/gc.c |
3 | * | 3 | * |
4 | * Implementation of the Domain-Based Mandatory Access Control. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | * | ||
8 | */ | 5 | */ |
9 | 6 | ||
10 | #include "common.h" | 7 | #include "common.h" |
11 | #include <linux/kthread.h> | 8 | #include <linux/kthread.h> |
12 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
13 | 10 | ||
11 | /* The list for "struct tomoyo_io_buffer". */ | ||
12 | static LIST_HEAD(tomoyo_io_buffer_list); | ||
13 | /* Lock for protecting tomoyo_io_buffer_list. */ | ||
14 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); | ||
15 | |||
16 | /* Size of an element. */ | ||
17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { | ||
18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), | ||
19 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), | ||
20 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), | ||
21 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), | ||
22 | [TOMOYO_ID_TRANSITION_CONTROL] = | ||
23 | sizeof(struct tomoyo_transition_control), | ||
24 | [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), | ||
25 | /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ | ||
26 | /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ | ||
27 | /* [TOMOYO_ID_ACL] = | ||
28 | tomoyo_acl_size["struct tomoyo_acl_info"->type], */ | ||
29 | [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), | ||
30 | }; | ||
31 | |||
32 | /* Size of a domain ACL element. */ | ||
33 | static const u8 tomoyo_acl_size[] = { | ||
34 | [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), | ||
35 | [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), | ||
36 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), | ||
37 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), | ||
38 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. | ||
43 | * | ||
44 | * @element: Pointer to "struct list_head". | ||
45 | * | ||
46 | * Returns true if @element is used by /sys/kernel/security/tomoyo/ users, | ||
47 | * false otherwise. | ||
48 | */ | ||
49 | static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) | ||
50 | { | ||
51 | struct tomoyo_io_buffer *head; | ||
52 | bool in_use = false; | ||
53 | |||
54 | spin_lock(&tomoyo_io_buffer_list_lock); | ||
55 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | ||
56 | head->users++; | ||
57 | spin_unlock(&tomoyo_io_buffer_list_lock); | ||
58 | if (mutex_lock_interruptible(&head->io_sem)) { | ||
59 | in_use = true; | ||
60 | goto out; | ||
61 | } | ||
62 | if (head->r.domain == element || head->r.group == element || | ||
63 | head->r.acl == element || &head->w.domain->list == element) | ||
64 | in_use = true; | ||
65 | mutex_unlock(&head->io_sem); | ||
66 | out: | ||
67 | spin_lock(&tomoyo_io_buffer_list_lock); | ||
68 | head->users--; | ||
69 | if (in_use) | ||
70 | break; | ||
71 | } | ||
72 | spin_unlock(&tomoyo_io_buffer_list_lock); | ||
73 | return in_use; | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. | ||
78 | * | ||
79 | * @string: String to check. | ||
80 | * @size: Memory allocated for @string . | ||
81 | * | ||
82 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, | ||
83 | * false otherwise. | ||
84 | */ | ||
85 | static bool tomoyo_name_used_by_io_buffer(const char *string, | ||
86 | const size_t size) | ||
87 | { | ||
88 | struct tomoyo_io_buffer *head; | ||
89 | bool in_use = false; | ||
90 | |||
91 | spin_lock(&tomoyo_io_buffer_list_lock); | ||
92 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | ||
93 | int i; | ||
94 | head->users++; | ||
95 | spin_unlock(&tomoyo_io_buffer_list_lock); | ||
96 | if (mutex_lock_interruptible(&head->io_sem)) { | ||
97 | in_use = true; | ||
98 | goto out; | ||
99 | } | ||
100 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { | ||
101 | const char *w = head->r.w[i]; | ||
102 | if (w < string || w > string + size) | ||
103 | continue; | ||
104 | in_use = true; | ||
105 | break; | ||
106 | } | ||
107 | mutex_unlock(&head->io_sem); | ||
108 | out: | ||
109 | spin_lock(&tomoyo_io_buffer_list_lock); | ||
110 | head->users--; | ||
111 | if (in_use) | ||
112 | break; | ||
113 | } | ||
114 | spin_unlock(&tomoyo_io_buffer_list_lock); | ||
115 | return in_use; | ||
116 | } | ||
117 | |||
118 | /* Structure for garbage collection. */ | ||
14 | struct tomoyo_gc { | 119 | struct tomoyo_gc { |
15 | struct list_head list; | 120 | struct list_head list; |
16 | int type; | 121 | enum tomoyo_policy_id type; |
122 | size_t size; | ||
17 | struct list_head *element; | 123 | struct list_head *element; |
18 | }; | 124 | }; |
19 | static LIST_HEAD(tomoyo_gc_queue); | 125 | /* List of entries to be deleted. */ |
20 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 126 | static LIST_HEAD(tomoyo_gc_list); |
127 | /* Length of tomoyo_gc_list. */ | ||
128 | static int tomoyo_gc_list_len; | ||
21 | 129 | ||
22 | /* Caller holds tomoyo_policy_lock mutex. */ | 130 | /** |
131 | * tomoyo_add_to_gc - Add an entry to to be deleted list. | ||
132 | * | ||
133 | * @type: One of values in "enum tomoyo_policy_id". | ||
134 | * @element: Pointer to "struct list_head". | ||
135 | * | ||
136 | * Returns true on success, false otherwise. | ||
137 | * | ||
138 | * Caller holds tomoyo_policy_lock mutex. | ||
139 | * | ||
140 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of | ||
141 | * entries at once, it will take too long time. Thus, do not add more than 128 | ||
142 | * entries per a scan. But to be able to handle worst case where all entries | ||
143 | * are in-use, we accept one more entry per a scan. | ||
144 | * | ||
145 | * If we use singly linked list using "struct list_head"->prev (which is | ||
146 | * LIST_POISON2), we can avoid kmalloc(). | ||
147 | */ | ||
23 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) | 148 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) |
24 | { | 149 | { |
25 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 150 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
26 | if (!entry) | 151 | if (!entry) |
27 | return false; | 152 | return false; |
28 | entry->type = type; | 153 | entry->type = type; |
154 | if (type == TOMOYO_ID_ACL) | ||
155 | entry->size = tomoyo_acl_size[ | ||
156 | container_of(element, | ||
157 | typeof(struct tomoyo_acl_info), | ||
158 | list)->type]; | ||
159 | else if (type == TOMOYO_ID_NAME) | ||
160 | entry->size = strlen(container_of(element, | ||
161 | typeof(struct tomoyo_name), | ||
162 | head.list)->entry.name) + 1; | ||
163 | else if (type == TOMOYO_ID_CONDITION) | ||
164 | entry->size = | ||
165 | container_of(element, typeof(struct tomoyo_condition), | ||
166 | head.list)->size; | ||
167 | else | ||
168 | entry->size = tomoyo_element_size[type]; | ||
29 | entry->element = element; | 169 | entry->element = element; |
30 | list_add(&entry->list, &tomoyo_gc_queue); | 170 | list_add(&entry->list, &tomoyo_gc_list); |
31 | list_del_rcu(element); | 171 | list_del_rcu(element); |
32 | return true; | 172 | return tomoyo_gc_list_len++ < 128; |
33 | } | 173 | } |
34 | 174 | ||
35 | static void tomoyo_del_allow_read(struct list_head *element) | 175 | /** |
36 | { | 176 | * tomoyo_element_linked_by_gc - Validate next element of an entry. |
37 | struct tomoyo_readable_file *ptr = | 177 | * |
38 | container_of(element, typeof(*ptr), head.list); | 178 | * @element: Pointer to an element. |
39 | tomoyo_put_name(ptr->filename); | 179 | * @size: Size of @element in byte. |
40 | } | 180 | * |
41 | 181 | * Returns true if @element is linked by other elements in the garbage | |
42 | static void tomoyo_del_file_pattern(struct list_head *element) | 182 | * collector's queue, false otherwise. |
43 | { | 183 | */ |
44 | struct tomoyo_no_pattern *ptr = | 184 | static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) |
45 | container_of(element, typeof(*ptr), head.list); | ||
46 | tomoyo_put_name(ptr->pattern); | ||
47 | } | ||
48 | |||
49 | static void tomoyo_del_no_rewrite(struct list_head *element) | ||
50 | { | 185 | { |
51 | struct tomoyo_no_rewrite *ptr = | 186 | struct tomoyo_gc *p; |
52 | container_of(element, typeof(*ptr), head.list); | 187 | list_for_each_entry(p, &tomoyo_gc_list, list) { |
53 | tomoyo_put_name(ptr->pattern); | 188 | const u8 *ptr = (const u8 *) p->element->next; |
189 | if (ptr < element || element + size < ptr) | ||
190 | continue; | ||
191 | return true; | ||
192 | } | ||
193 | return false; | ||
54 | } | 194 | } |
55 | 195 | ||
196 | /** | ||
197 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". | ||
198 | * | ||
199 | * @element: Pointer to "struct list_head". | ||
200 | * | ||
201 | * Returns nothing. | ||
202 | */ | ||
56 | static void tomoyo_del_transition_control(struct list_head *element) | 203 | static void tomoyo_del_transition_control(struct list_head *element) |
57 | { | 204 | { |
58 | struct tomoyo_transition_control *ptr = | 205 | struct tomoyo_transition_control *ptr = |
@@ -61,6 +208,13 @@ static void tomoyo_del_transition_control(struct list_head *element) | |||
61 | tomoyo_put_name(ptr->program); | 208 | tomoyo_put_name(ptr->program); |
62 | } | 209 | } |
63 | 210 | ||
211 | /** | ||
212 | * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator". | ||
213 | * | ||
214 | * @element: Pointer to "struct list_head". | ||
215 | * | ||
216 | * Returns nothing. | ||
217 | */ | ||
64 | static void tomoyo_del_aggregator(struct list_head *element) | 218 | static void tomoyo_del_aggregator(struct list_head *element) |
65 | { | 219 | { |
66 | struct tomoyo_aggregator *ptr = | 220 | struct tomoyo_aggregator *ptr = |
@@ -69,6 +223,13 @@ static void tomoyo_del_aggregator(struct list_head *element) | |||
69 | tomoyo_put_name(ptr->aggregated_name); | 223 | tomoyo_put_name(ptr->aggregated_name); |
70 | } | 224 | } |
71 | 225 | ||
226 | /** | ||
227 | * tomoyo_del_manager - Delete members in "struct tomoyo_manager". | ||
228 | * | ||
229 | * @element: Pointer to "struct list_head". | ||
230 | * | ||
231 | * Returns nothing. | ||
232 | */ | ||
72 | static void tomoyo_del_manager(struct list_head *element) | 233 | static void tomoyo_del_manager(struct list_head *element) |
73 | { | 234 | { |
74 | struct tomoyo_manager *ptr = | 235 | struct tomoyo_manager *ptr = |
@@ -76,10 +237,18 @@ static void tomoyo_del_manager(struct list_head *element) | |||
76 | tomoyo_put_name(ptr->manager); | 237 | tomoyo_put_name(ptr->manager); |
77 | } | 238 | } |
78 | 239 | ||
240 | /** | ||
241 | * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info". | ||
242 | * | ||
243 | * @element: Pointer to "struct list_head". | ||
244 | * | ||
245 | * Returns nothing. | ||
246 | */ | ||
79 | static void tomoyo_del_acl(struct list_head *element) | 247 | static void tomoyo_del_acl(struct list_head *element) |
80 | { | 248 | { |
81 | struct tomoyo_acl_info *acl = | 249 | struct tomoyo_acl_info *acl = |
82 | container_of(element, typeof(*acl), list); | 250 | container_of(element, typeof(*acl), list); |
251 | tomoyo_put_condition(acl->cond); | ||
83 | switch (acl->type) { | 252 | switch (acl->type) { |
84 | case TOMOYO_TYPE_PATH_ACL: | 253 | case TOMOYO_TYPE_PATH_ACL: |
85 | { | 254 | { |
@@ -127,6 +296,13 @@ static void tomoyo_del_acl(struct list_head *element) | |||
127 | } | 296 | } |
128 | } | 297 | } |
129 | 298 | ||
299 | /** | ||
300 | * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info". | ||
301 | * | ||
302 | * @element: Pointer to "struct list_head". | ||
303 | * | ||
304 | * Returns true if deleted, false otherwise. | ||
305 | */ | ||
130 | static bool tomoyo_del_domain(struct list_head *element) | 306 | static bool tomoyo_del_domain(struct list_head *element) |
131 | { | 307 | { |
132 | struct tomoyo_domain_info *domain = | 308 | struct tomoyo_domain_info *domain = |
@@ -165,13 +341,65 @@ static bool tomoyo_del_domain(struct list_head *element) | |||
165 | return true; | 341 | return true; |
166 | } | 342 | } |
167 | 343 | ||
344 | /** | ||
345 | * tomoyo_del_condition - Delete members in "struct tomoyo_condition". | ||
346 | * | ||
347 | * @element: Pointer to "struct list_head". | ||
348 | * | ||
349 | * Returns nothing. | ||
350 | */ | ||
351 | void tomoyo_del_condition(struct list_head *element) | ||
352 | { | ||
353 | struct tomoyo_condition *cond = container_of(element, typeof(*cond), | ||
354 | head.list); | ||
355 | const u16 condc = cond->condc; | ||
356 | const u16 numbers_count = cond->numbers_count; | ||
357 | const u16 names_count = cond->names_count; | ||
358 | const u16 argc = cond->argc; | ||
359 | const u16 envc = cond->envc; | ||
360 | unsigned int i; | ||
361 | const struct tomoyo_condition_element *condp | ||
362 | = (const struct tomoyo_condition_element *) (cond + 1); | ||
363 | struct tomoyo_number_union *numbers_p | ||
364 | = (struct tomoyo_number_union *) (condp + condc); | ||
365 | struct tomoyo_name_union *names_p | ||
366 | = (struct tomoyo_name_union *) (numbers_p + numbers_count); | ||
367 | const struct tomoyo_argv *argv | ||
368 | = (const struct tomoyo_argv *) (names_p + names_count); | ||
369 | const struct tomoyo_envp *envp | ||
370 | = (const struct tomoyo_envp *) (argv + argc); | ||
371 | for (i = 0; i < numbers_count; i++) | ||
372 | tomoyo_put_number_union(numbers_p++); | ||
373 | for (i = 0; i < names_count; i++) | ||
374 | tomoyo_put_name_union(names_p++); | ||
375 | for (i = 0; i < argc; argv++, i++) | ||
376 | tomoyo_put_name(argv->value); | ||
377 | for (i = 0; i < envc; envp++, i++) { | ||
378 | tomoyo_put_name(envp->name); | ||
379 | tomoyo_put_name(envp->value); | ||
380 | } | ||
381 | } | ||
168 | 382 | ||
383 | /** | ||
384 | * tomoyo_del_name - Delete members in "struct tomoyo_name". | ||
385 | * | ||
386 | * @element: Pointer to "struct list_head". | ||
387 | * | ||
388 | * Returns nothing. | ||
389 | */ | ||
169 | static void tomoyo_del_name(struct list_head *element) | 390 | static void tomoyo_del_name(struct list_head *element) |
170 | { | 391 | { |
171 | const struct tomoyo_name *ptr = | 392 | const struct tomoyo_name *ptr = |
172 | container_of(element, typeof(*ptr), list); | 393 | container_of(element, typeof(*ptr), head.list); |
173 | } | 394 | } |
174 | 395 | ||
396 | /** | ||
397 | * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group". | ||
398 | * | ||
399 | * @element: Pointer to "struct list_head". | ||
400 | * | ||
401 | * Returns nothing. | ||
402 | */ | ||
175 | static void tomoyo_del_path_group(struct list_head *element) | 403 | static void tomoyo_del_path_group(struct list_head *element) |
176 | { | 404 | { |
177 | struct tomoyo_path_group *member = | 405 | struct tomoyo_path_group *member = |
@@ -179,20 +407,43 @@ static void tomoyo_del_path_group(struct list_head *element) | |||
179 | tomoyo_put_name(member->member_name); | 407 | tomoyo_put_name(member->member_name); |
180 | } | 408 | } |
181 | 409 | ||
410 | /** | ||
411 | * tomoyo_del_group - Delete "struct tomoyo_group". | ||
412 | * | ||
413 | * @element: Pointer to "struct list_head". | ||
414 | * | ||
415 | * Returns nothing. | ||
416 | */ | ||
182 | static void tomoyo_del_group(struct list_head *element) | 417 | static void tomoyo_del_group(struct list_head *element) |
183 | { | 418 | { |
184 | struct tomoyo_group *group = | 419 | struct tomoyo_group *group = |
185 | container_of(element, typeof(*group), list); | 420 | container_of(element, typeof(*group), head.list); |
186 | tomoyo_put_name(group->group_name); | 421 | tomoyo_put_name(group->group_name); |
187 | } | 422 | } |
188 | 423 | ||
424 | /** | ||
425 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". | ||
426 | * | ||
427 | * @element: Pointer to "struct list_head". | ||
428 | * | ||
429 | * Returns nothing. | ||
430 | */ | ||
189 | static void tomoyo_del_number_group(struct list_head *element) | 431 | static void tomoyo_del_number_group(struct list_head *element) |
190 | { | 432 | { |
191 | struct tomoyo_number_group *member = | 433 | struct tomoyo_number_group *member = |
192 | container_of(element, typeof(*member), head.list); | 434 | container_of(element, typeof(*member), head.list); |
193 | } | 435 | } |
194 | 436 | ||
195 | static bool tomoyo_collect_member(struct list_head *member_list, int id) | 437 | /** |
438 | * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head". | ||
439 | * | ||
440 | * @id: One of values in "enum tomoyo_policy_id". | ||
441 | * @member_list: Pointer to "struct list_head". | ||
442 | * | ||
443 | * Returns true if some elements are deleted, false otherwise. | ||
444 | */ | ||
445 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | ||
446 | struct list_head *member_list) | ||
196 | { | 447 | { |
197 | struct tomoyo_acl_head *member; | 448 | struct tomoyo_acl_head *member; |
198 | list_for_each_entry(member, member_list, list) { | 449 | list_for_each_entry(member, member_list, list) { |
@@ -201,13 +452,20 @@ static bool tomoyo_collect_member(struct list_head *member_list, int id) | |||
201 | if (!tomoyo_add_to_gc(id, &member->list)) | 452 | if (!tomoyo_add_to_gc(id, &member->list)) |
202 | return false; | 453 | return false; |
203 | } | 454 | } |
204 | return true; | 455 | return true; |
205 | } | 456 | } |
206 | 457 | ||
207 | static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain) | 458 | /** |
459 | * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info". | ||
460 | * | ||
461 | * @list: Pointer to "struct list_head". | ||
462 | * | ||
463 | * Returns true if some elements are deleted, false otherwise. | ||
464 | */ | ||
465 | static bool tomoyo_collect_acl(struct list_head *list) | ||
208 | { | 466 | { |
209 | struct tomoyo_acl_info *acl; | 467 | struct tomoyo_acl_info *acl; |
210 | list_for_each_entry(acl, &domain->acl_info_list, list) { | 468 | list_for_each_entry(acl, list, list) { |
211 | if (!acl->is_deleted) | 469 | if (!acl->is_deleted) |
212 | continue; | 470 | continue; |
213 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) | 471 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) |
@@ -216,19 +474,24 @@ static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain) | |||
216 | return true; | 474 | return true; |
217 | } | 475 | } |
218 | 476 | ||
477 | /** | ||
478 | * tomoyo_collect_entry - Scan lists for deleted elements. | ||
479 | * | ||
480 | * Returns nothing. | ||
481 | */ | ||
219 | static void tomoyo_collect_entry(void) | 482 | static void tomoyo_collect_entry(void) |
220 | { | 483 | { |
221 | int i; | 484 | int i; |
485 | enum tomoyo_policy_id id; | ||
486 | struct tomoyo_policy_namespace *ns; | ||
487 | int idx; | ||
222 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 488 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
223 | return; | 489 | return; |
224 | for (i = 0; i < TOMOYO_MAX_POLICY; i++) { | 490 | idx = tomoyo_read_lock(); |
225 | if (!tomoyo_collect_member(&tomoyo_policy_list[i], i)) | ||
226 | goto unlock; | ||
227 | } | ||
228 | { | 491 | { |
229 | struct tomoyo_domain_info *domain; | 492 | struct tomoyo_domain_info *domain; |
230 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 493 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
231 | if (!tomoyo_collect_acl(domain)) | 494 | if (!tomoyo_collect_acl(&domain->acl_info_list)) |
232 | goto unlock; | 495 | goto unlock; |
233 | if (!domain->is_deleted || atomic_read(&domain->users)) | 496 | if (!domain->is_deleted || atomic_read(&domain->users)) |
234 | continue; | 497 | continue; |
@@ -241,48 +504,93 @@ static void tomoyo_collect_entry(void) | |||
241 | goto unlock; | 504 | goto unlock; |
242 | } | 505 | } |
243 | } | 506 | } |
244 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | 507 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { |
245 | struct tomoyo_name *ptr; | 508 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) |
246 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) { | 509 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) |
247 | if (atomic_read(&ptr->users)) | ||
248 | continue; | ||
249 | if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list)) | ||
250 | goto unlock; | 510 | goto unlock; |
511 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | ||
512 | if (!tomoyo_collect_acl(&ns->acl_group[i])) | ||
513 | goto unlock; | ||
514 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | ||
515 | struct list_head *list = &ns->group_list[i]; | ||
516 | struct tomoyo_group *group; | ||
517 | switch (i) { | ||
518 | case 0: | ||
519 | id = TOMOYO_ID_PATH_GROUP; | ||
520 | break; | ||
521 | default: | ||
522 | id = TOMOYO_ID_NUMBER_GROUP; | ||
523 | break; | ||
524 | } | ||
525 | list_for_each_entry(group, list, head.list) { | ||
526 | if (!tomoyo_collect_member | ||
527 | (id, &group->member_list)) | ||
528 | goto unlock; | ||
529 | if (!list_empty(&group->member_list) || | ||
530 | atomic_read(&group->head.users)) | ||
531 | continue; | ||
532 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | ||
533 | &group->head.list)) | ||
534 | goto unlock; | ||
535 | } | ||
251 | } | 536 | } |
252 | } | 537 | } |
253 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | 538 | id = TOMOYO_ID_CONDITION; |
254 | struct list_head *list = &tomoyo_group_list[i]; | 539 | for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { |
255 | int id; | 540 | struct list_head *list = !i ? |
256 | struct tomoyo_group *group; | 541 | &tomoyo_condition_list : &tomoyo_name_list[i - 1]; |
257 | switch (i) { | 542 | struct tomoyo_shared_acl_head *ptr; |
258 | case 0: | 543 | list_for_each_entry(ptr, list, list) { |
259 | id = TOMOYO_ID_PATH_GROUP; | 544 | if (atomic_read(&ptr->users)) |
260 | break; | ||
261 | default: | ||
262 | id = TOMOYO_ID_NUMBER_GROUP; | ||
263 | break; | ||
264 | } | ||
265 | list_for_each_entry(group, list, list) { | ||
266 | if (!tomoyo_collect_member(&group->member_list, id)) | ||
267 | goto unlock; | ||
268 | if (!list_empty(&group->member_list) || | ||
269 | atomic_read(&group->users)) | ||
270 | continue; | 545 | continue; |
271 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list)) | 546 | if (!tomoyo_add_to_gc(id, &ptr->list)) |
272 | goto unlock; | 547 | goto unlock; |
273 | } | 548 | } |
549 | id = TOMOYO_ID_NAME; | ||
274 | } | 550 | } |
275 | unlock: | 551 | unlock: |
552 | tomoyo_read_unlock(idx); | ||
276 | mutex_unlock(&tomoyo_policy_lock); | 553 | mutex_unlock(&tomoyo_policy_lock); |
277 | } | 554 | } |
278 | 555 | ||
279 | static void tomoyo_kfree_entry(void) | 556 | /** |
557 | * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. | ||
558 | * | ||
559 | * Returns true if some entries were kfree()d, false otherwise. | ||
560 | */ | ||
561 | static bool tomoyo_kfree_entry(void) | ||
280 | { | 562 | { |
281 | struct tomoyo_gc *p; | 563 | struct tomoyo_gc *p; |
282 | struct tomoyo_gc *tmp; | 564 | struct tomoyo_gc *tmp; |
565 | bool result = false; | ||
283 | 566 | ||
284 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { | 567 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { |
285 | struct list_head *element = p->element; | 568 | struct list_head *element = p->element; |
569 | |||
570 | /* | ||
571 | * list_del_rcu() in tomoyo_add_to_gc() guarantees that the | ||
572 | * list element became no longer reachable from the list which | ||
573 | * the element was originally on (e.g. tomoyo_domain_list). | ||
574 | * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees | ||
575 | * that the list element became no longer referenced by syscall | ||
576 | * users. | ||
577 | * | ||
578 | * However, there are three users which may still be using the | ||
579 | * list element. We need to defer until all of these users | ||
580 | * forget the list element. | ||
581 | * | ||
582 | * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, | ||
583 | * group,acl} and "struct tomoyo_io_buffer"->w.domain forget | ||
584 | * the list element. | ||
585 | */ | ||
586 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
587 | continue; | ||
588 | /* | ||
589 | * Secondly, defer until all other elements in the | ||
590 | * tomoyo_gc_list list forget the list element. | ||
591 | */ | ||
592 | if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) | ||
593 | continue; | ||
286 | switch (p->type) { | 594 | switch (p->type) { |
287 | case TOMOYO_ID_TRANSITION_CONTROL: | 595 | case TOMOYO_ID_TRANSITION_CONTROL: |
288 | tomoyo_del_transition_control(element); | 596 | tomoyo_del_transition_control(element); |
@@ -290,19 +598,21 @@ static void tomoyo_kfree_entry(void) | |||
290 | case TOMOYO_ID_AGGREGATOR: | 598 | case TOMOYO_ID_AGGREGATOR: |
291 | tomoyo_del_aggregator(element); | 599 | tomoyo_del_aggregator(element); |
292 | break; | 600 | break; |
293 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
294 | tomoyo_del_allow_read(element); | ||
295 | break; | ||
296 | case TOMOYO_ID_PATTERN: | ||
297 | tomoyo_del_file_pattern(element); | ||
298 | break; | ||
299 | case TOMOYO_ID_NO_REWRITE: | ||
300 | tomoyo_del_no_rewrite(element); | ||
301 | break; | ||
302 | case TOMOYO_ID_MANAGER: | 601 | case TOMOYO_ID_MANAGER: |
303 | tomoyo_del_manager(element); | 602 | tomoyo_del_manager(element); |
304 | break; | 603 | break; |
604 | case TOMOYO_ID_CONDITION: | ||
605 | tomoyo_del_condition(element); | ||
606 | break; | ||
305 | case TOMOYO_ID_NAME: | 607 | case TOMOYO_ID_NAME: |
608 | /* | ||
609 | * Thirdly, defer until all "struct tomoyo_io_buffer" | ||
610 | * ->r.w[] forget the list element. | ||
611 | */ | ||
612 | if (tomoyo_name_used_by_io_buffer( | ||
613 | container_of(element, typeof(struct tomoyo_name), | ||
614 | head.list)->entry.name, p->size)) | ||
615 | continue; | ||
306 | tomoyo_del_name(element); | 616 | tomoyo_del_name(element); |
307 | break; | 617 | break; |
308 | case TOMOYO_ID_ACL: | 618 | case TOMOYO_ID_ACL: |
@@ -321,34 +631,95 @@ static void tomoyo_kfree_entry(void) | |||
321 | case TOMOYO_ID_NUMBER_GROUP: | 631 | case TOMOYO_ID_NUMBER_GROUP: |
322 | tomoyo_del_number_group(element); | 632 | tomoyo_del_number_group(element); |
323 | break; | 633 | break; |
634 | case TOMOYO_MAX_POLICY: | ||
635 | break; | ||
324 | } | 636 | } |
325 | tomoyo_memory_free(element); | 637 | tomoyo_memory_free(element); |
326 | list_del(&p->list); | 638 | list_del(&p->list); |
327 | kfree(p); | 639 | kfree(p); |
640 | tomoyo_gc_list_len--; | ||
641 | result = true; | ||
328 | } | 642 | } |
643 | return result; | ||
329 | } | 644 | } |
330 | 645 | ||
646 | /** | ||
647 | * tomoyo_gc_thread - Garbage collector thread function. | ||
648 | * | ||
649 | * @unused: Unused. | ||
650 | * | ||
651 | * In case OOM-killer choose this thread for termination, we create this thread | ||
652 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was | ||
653 | * close()d. | ||
654 | * | ||
655 | * Returns 0. | ||
656 | */ | ||
331 | static int tomoyo_gc_thread(void *unused) | 657 | static int tomoyo_gc_thread(void *unused) |
332 | { | 658 | { |
659 | /* Garbage collector thread is exclusive. */ | ||
660 | static DEFINE_MUTEX(tomoyo_gc_mutex); | ||
661 | if (!mutex_trylock(&tomoyo_gc_mutex)) | ||
662 | goto out; | ||
333 | daemonize("GC for TOMOYO"); | 663 | daemonize("GC for TOMOYO"); |
334 | if (mutex_trylock(&tomoyo_gc_mutex)) { | 664 | do { |
335 | int i; | 665 | tomoyo_collect_entry(); |
336 | for (i = 0; i < 10; i++) { | 666 | if (list_empty(&tomoyo_gc_list)) |
337 | tomoyo_collect_entry(); | 667 | break; |
338 | if (list_empty(&tomoyo_gc_queue)) | 668 | synchronize_srcu(&tomoyo_ss); |
339 | break; | 669 | } while (tomoyo_kfree_entry()); |
340 | synchronize_srcu(&tomoyo_ss); | 670 | { |
341 | tomoyo_kfree_entry(); | 671 | struct tomoyo_io_buffer *head; |
672 | struct tomoyo_io_buffer *tmp; | ||
673 | |||
674 | spin_lock(&tomoyo_io_buffer_list_lock); | ||
675 | list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list, | ||
676 | list) { | ||
677 | if (head->users) | ||
678 | continue; | ||
679 | list_del(&head->list); | ||
680 | kfree(head->read_buf); | ||
681 | kfree(head->write_buf); | ||
682 | kfree(head); | ||
342 | } | 683 | } |
343 | mutex_unlock(&tomoyo_gc_mutex); | 684 | spin_unlock(&tomoyo_io_buffer_list_lock); |
344 | } | 685 | } |
345 | do_exit(0); | 686 | mutex_unlock(&tomoyo_gc_mutex); |
687 | out: | ||
688 | /* This acts as do_exit(0). */ | ||
689 | return 0; | ||
346 | } | 690 | } |
347 | 691 | ||
348 | void tomoyo_run_gc(void) | 692 | /** |
693 | * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users. | ||
694 | * | ||
695 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
696 | * @is_register: True if register, false if unregister. | ||
697 | * | ||
698 | * Returns nothing. | ||
699 | */ | ||
700 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register) | ||
349 | { | 701 | { |
350 | struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, | 702 | bool is_write = false; |
351 | "GC for TOMOYO"); | 703 | |
352 | if (!IS_ERR(task)) | 704 | spin_lock(&tomoyo_io_buffer_list_lock); |
353 | wake_up_process(task); | 705 | if (is_register) { |
706 | head->users = 1; | ||
707 | list_add(&head->list, &tomoyo_io_buffer_list); | ||
708 | } else { | ||
709 | is_write = head->write_buf != NULL; | ||
710 | if (!--head->users) { | ||
711 | list_del(&head->list); | ||
712 | kfree(head->read_buf); | ||
713 | kfree(head->write_buf); | ||
714 | kfree(head); | ||
715 | } | ||
716 | } | ||
717 | spin_unlock(&tomoyo_io_buffer_list_lock); | ||
718 | if (is_write) { | ||
719 | struct task_struct *task = kthread_create(tomoyo_gc_thread, | ||
720 | NULL, | ||
721 | "GC for TOMOYO"); | ||
722 | if (!IS_ERR(task)) | ||
723 | wake_up_process(task); | ||
724 | } | ||
354 | } | 725 | } |
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c index e94352ce723f..5fb0e1298400 100644 --- a/security/tomoyo/group.c +++ b/security/tomoyo/group.c | |||
@@ -1,21 +1,37 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/group.c | 2 | * security/tomoyo/group.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include "common.h" | 8 | #include "common.h" |
9 | 9 | ||
10 | /** | ||
11 | * tomoyo_same_path_group - Check for duplicated "struct tomoyo_path_group" entry. | ||
12 | * | ||
13 | * @a: Pointer to "struct tomoyo_acl_head". | ||
14 | * @b: Pointer to "struct tomoyo_acl_head". | ||
15 | * | ||
16 | * Returns true if @a == @b, false otherwise. | ||
17 | */ | ||
10 | static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a, | 18 | static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a, |
11 | const struct tomoyo_acl_head *b) | 19 | const struct tomoyo_acl_head *b) |
12 | { | 20 | { |
13 | return container_of(a, struct tomoyo_path_group, head)->member_name == | 21 | return container_of(a, struct tomoyo_path_group, head)->member_name == |
14 | container_of(b, struct tomoyo_path_group, head)->member_name; | 22 | container_of(b, struct tomoyo_path_group, head)->member_name; |
15 | } | 23 | } |
16 | 24 | ||
25 | /** | ||
26 | * tomoyo_same_number_group - Check for duplicated "struct tomoyo_number_group" entry. | ||
27 | * | ||
28 | * @a: Pointer to "struct tomoyo_acl_head". | ||
29 | * @b: Pointer to "struct tomoyo_acl_head". | ||
30 | * | ||
31 | * Returns true if @a == @b, false otherwise. | ||
32 | */ | ||
17 | static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, | 33 | static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, |
18 | const struct tomoyo_acl_head *b) | 34 | const struct tomoyo_acl_head *b) |
19 | { | 35 | { |
20 | return !memcmp(&container_of(a, struct tomoyo_number_group, head) | 36 | return !memcmp(&container_of(a, struct tomoyo_number_group, head) |
21 | ->number, | 37 | ->number, |
@@ -28,48 +44,41 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, | |||
28 | /** | 44 | /** |
29 | * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. | 45 | * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. |
30 | * | 46 | * |
31 | * @data: String to parse. | 47 | * @param: Pointer to "struct tomoyo_acl_param". |
32 | * @is_delete: True if it is a delete request. | 48 | * @type: Type of this group. |
33 | * @type: Type of this group. | ||
34 | * | 49 | * |
35 | * Returns 0 on success, negative value otherwise. | 50 | * Returns 0 on success, negative value otherwise. |
36 | */ | 51 | */ |
37 | int tomoyo_write_group(char *data, const bool is_delete, const u8 type) | 52 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) |
38 | { | 53 | { |
39 | struct tomoyo_group *group; | 54 | struct tomoyo_group *group = tomoyo_get_group(param, type); |
40 | struct list_head *member; | ||
41 | char *w[2]; | ||
42 | int error = -EINVAL; | 55 | int error = -EINVAL; |
43 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) | ||
44 | return -EINVAL; | ||
45 | group = tomoyo_get_group(w[0], type); | ||
46 | if (!group) | 56 | if (!group) |
47 | return -ENOMEM; | 57 | return -ENOMEM; |
48 | member = &group->member_list; | 58 | param->list = &group->member_list; |
49 | if (type == TOMOYO_PATH_GROUP) { | 59 | if (type == TOMOYO_PATH_GROUP) { |
50 | struct tomoyo_path_group e = { }; | 60 | struct tomoyo_path_group e = { }; |
51 | e.member_name = tomoyo_get_name(w[1]); | 61 | e.member_name = tomoyo_get_name(tomoyo_read_token(param)); |
52 | if (!e.member_name) { | 62 | if (!e.member_name) { |
53 | error = -ENOMEM; | 63 | error = -ENOMEM; |
54 | goto out; | 64 | goto out; |
55 | } | 65 | } |
56 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 66 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
57 | member, tomoyo_same_path_group); | 67 | tomoyo_same_path_group); |
58 | tomoyo_put_name(e.member_name); | 68 | tomoyo_put_name(e.member_name); |
59 | } else if (type == TOMOYO_NUMBER_GROUP) { | 69 | } else if (type == TOMOYO_NUMBER_GROUP) { |
60 | struct tomoyo_number_group e = { }; | 70 | struct tomoyo_number_group e = { }; |
61 | if (w[1][0] == '@' | 71 | if (param->data[0] == '@' || |
62 | || !tomoyo_parse_number_union(w[1], &e.number) | 72 | !tomoyo_parse_number_union(param, &e.number)) |
63 | || e.number.values[0] > e.number.values[1]) | ||
64 | goto out; | 73 | goto out; |
65 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 74 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
66 | member, tomoyo_same_number_group); | 75 | tomoyo_same_number_group); |
67 | /* | 76 | /* |
68 | * tomoyo_put_number_union() is not needed because | 77 | * tomoyo_put_number_union() is not needed because |
69 | * w[1][0] != '@'. | 78 | * param->data[0] != '@'. |
70 | */ | 79 | */ |
71 | } | 80 | } |
72 | out: | 81 | out: |
73 | tomoyo_put_group(group); | 82 | tomoyo_put_group(group); |
74 | return error; | 83 | return error; |
75 | } | 84 | } |
@@ -77,8 +86,8 @@ int tomoyo_write_group(char *data, const bool is_delete, const u8 type) | |||
77 | /** | 86 | /** |
78 | * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. | 87 | * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. |
79 | * | 88 | * |
80 | * @pathname: The name of pathname. | 89 | * @pathname: The name of pathname. |
81 | * @group: Pointer to "struct tomoyo_path_group". | 90 | * @group: Pointer to "struct tomoyo_path_group". |
82 | * | 91 | * |
83 | * Returns matched member's pathname if @pathname matches pathnames in @group, | 92 | * Returns matched member's pathname if @pathname matches pathnames in @group, |
84 | * NULL otherwise. | 93 | * NULL otherwise. |
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c index 3312e5624f24..67975405140f 100644 --- a/security/tomoyo/load_policy.c +++ b/security/tomoyo/load_policy.c | |||
@@ -1,15 +1,32 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/load_policy.c | 2 | * security/tomoyo/load_policy.c |
3 | * | 3 | * |
4 | * Policy loader launcher for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | 8 | ||
11 | /* path to policy loader */ | 9 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
12 | static const char *tomoyo_loader = "/sbin/tomoyo-init"; | 10 | |
11 | /* | ||
12 | * Path to the policy loader. (default = CONFIG_SECURITY_TOMOYO_POLICY_LOADER) | ||
13 | */ | ||
14 | static const char *tomoyo_loader; | ||
15 | |||
16 | /** | ||
17 | * tomoyo_loader_setup - Set policy loader. | ||
18 | * | ||
19 | * @str: Program to use as a policy loader (e.g. /sbin/tomoyo-init ). | ||
20 | * | ||
21 | * Returns 0. | ||
22 | */ | ||
23 | static int __init tomoyo_loader_setup(char *str) | ||
24 | { | ||
25 | tomoyo_loader = str; | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | __setup("TOMOYO_loader=", tomoyo_loader_setup); | ||
13 | 30 | ||
14 | /** | 31 | /** |
15 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. | 32 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. |
@@ -18,24 +35,38 @@ static const char *tomoyo_loader = "/sbin/tomoyo-init"; | |||
18 | */ | 35 | */ |
19 | static bool tomoyo_policy_loader_exists(void) | 36 | static bool tomoyo_policy_loader_exists(void) |
20 | { | 37 | { |
21 | /* | ||
22 | * Don't activate MAC if the policy loader doesn't exist. | ||
23 | * If the initrd includes /sbin/init but real-root-dev has not | ||
24 | * mounted on / yet, activating MAC will block the system since | ||
25 | * policies are not loaded yet. | ||
26 | * Thus, let do_execve() call this function every time. | ||
27 | */ | ||
28 | struct path path; | 38 | struct path path; |
29 | 39 | if (!tomoyo_loader) | |
40 | tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER; | ||
30 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { | 41 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { |
31 | printk(KERN_INFO "Not activating Mandatory Access Control now " | 42 | printk(KERN_INFO "Not activating Mandatory Access Control " |
32 | "since %s doesn't exist.\n", tomoyo_loader); | 43 | "as %s does not exist.\n", tomoyo_loader); |
33 | return false; | 44 | return false; |
34 | } | 45 | } |
35 | path_put(&path); | 46 | path_put(&path); |
36 | return true; | 47 | return true; |
37 | } | 48 | } |
38 | 49 | ||
50 | /* | ||
51 | * Path to the trigger. (default = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER) | ||
52 | */ | ||
53 | static const char *tomoyo_trigger; | ||
54 | |||
55 | /** | ||
56 | * tomoyo_trigger_setup - Set trigger for activation. | ||
57 | * | ||
58 | * @str: Program to use as an activation trigger (e.g. /sbin/init ). | ||
59 | * | ||
60 | * Returns 0. | ||
61 | */ | ||
62 | static int __init tomoyo_trigger_setup(char *str) | ||
63 | { | ||
64 | tomoyo_trigger = str; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | __setup("TOMOYO_trigger=", tomoyo_trigger_setup); | ||
69 | |||
39 | /** | 70 | /** |
40 | * tomoyo_load_policy - Run external policy loader to load policy. | 71 | * tomoyo_load_policy - Run external policy loader to load policy. |
41 | * | 72 | * |
@@ -51,24 +82,19 @@ static bool tomoyo_policy_loader_exists(void) | |||
51 | */ | 82 | */ |
52 | void tomoyo_load_policy(const char *filename) | 83 | void tomoyo_load_policy(const char *filename) |
53 | { | 84 | { |
85 | static bool done; | ||
54 | char *argv[2]; | 86 | char *argv[2]; |
55 | char *envp[3]; | 87 | char *envp[3]; |
56 | 88 | ||
57 | if (tomoyo_policy_loaded) | 89 | if (tomoyo_policy_loaded || done) |
58 | return; | 90 | return; |
59 | /* | 91 | if (!tomoyo_trigger) |
60 | * Check filename is /sbin/init or /sbin/tomoyo-start. | 92 | tomoyo_trigger = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER; |
61 | * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't | 93 | if (strcmp(filename, tomoyo_trigger)) |
62 | * be passed. | ||
63 | * You can create /sbin/tomoyo-start by | ||
64 | * "ln -s /bin/true /sbin/tomoyo-start". | ||
65 | */ | ||
66 | if (strcmp(filename, "/sbin/init") && | ||
67 | strcmp(filename, "/sbin/tomoyo-start")) | ||
68 | return; | 94 | return; |
69 | if (!tomoyo_policy_loader_exists()) | 95 | if (!tomoyo_policy_loader_exists()) |
70 | return; | 96 | return; |
71 | 97 | done = true; | |
72 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", | 98 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", |
73 | tomoyo_loader); | 99 | tomoyo_loader); |
74 | argv[0] = (char *) tomoyo_loader; | 100 | argv[0] = (char *) tomoyo_loader; |
@@ -79,3 +105,5 @@ void tomoyo_load_policy(const char *filename) | |||
79 | call_usermodehelper(argv[0], argv, envp, 1); | 105 | call_usermodehelper(argv[0], argv, envp, 1); |
80 | tomoyo_check_profile(); | 106 | tomoyo_check_profile(); |
81 | } | 107 | } |
108 | |||
109 | #endif | ||
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 42a7b1ba8cbf..7a56051146c2 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/memory.c | 2 | * security/tomoyo/memory.c |
3 | * | 3 | * |
4 | * Memory management functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/hash.h> | 7 | #include <linux/hash.h> |
@@ -29,10 +27,12 @@ void tomoyo_warn_oom(const char *function) | |||
29 | panic("MAC Initialization failed.\n"); | 27 | panic("MAC Initialization failed.\n"); |
30 | } | 28 | } |
31 | 29 | ||
32 | /* Memory allocated for policy. */ | 30 | /* Lock for protecting tomoyo_memory_used. */ |
33 | static atomic_t tomoyo_policy_memory_size; | 31 | static DEFINE_SPINLOCK(tomoyo_policy_memory_lock); |
34 | /* Quota for holding policy. */ | 32 | /* Memoy currently used by policy/audit log/query. */ |
35 | static unsigned int tomoyo_quota_for_policy; | 33 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; |
34 | /* Memory quota for "policy"/"audit log"/"query". */ | ||
35 | unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; | ||
36 | 36 | ||
37 | /** | 37 | /** |
38 | * tomoyo_memory_ok - Check memory quota. | 38 | * tomoyo_memory_ok - Check memory quota. |
@@ -45,15 +45,20 @@ static unsigned int tomoyo_quota_for_policy; | |||
45 | */ | 45 | */ |
46 | bool tomoyo_memory_ok(void *ptr) | 46 | bool tomoyo_memory_ok(void *ptr) |
47 | { | 47 | { |
48 | size_t s = ptr ? ksize(ptr) : 0; | 48 | if (ptr) { |
49 | atomic_add(s, &tomoyo_policy_memory_size); | 49 | const size_t s = ksize(ptr); |
50 | if (ptr && (!tomoyo_quota_for_policy || | 50 | bool result; |
51 | atomic_read(&tomoyo_policy_memory_size) | 51 | spin_lock(&tomoyo_policy_memory_lock); |
52 | <= tomoyo_quota_for_policy)) { | 52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; |
53 | memset(ptr, 0, s); | 53 | result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || |
54 | return true; | 54 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= |
55 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]; | ||
56 | if (!result) | ||
57 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
58 | spin_unlock(&tomoyo_policy_memory_lock); | ||
59 | if (result) | ||
60 | return true; | ||
55 | } | 61 | } |
56 | atomic_sub(s, &tomoyo_policy_memory_size); | ||
57 | tomoyo_warn_oom(__func__); | 62 | tomoyo_warn_oom(__func__); |
58 | return false; | 63 | return false; |
59 | } | 64 | } |
@@ -86,22 +91,28 @@ void *tomoyo_commit_ok(void *data, const unsigned int size) | |||
86 | */ | 91 | */ |
87 | void tomoyo_memory_free(void *ptr) | 92 | void tomoyo_memory_free(void *ptr) |
88 | { | 93 | { |
89 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); | 94 | size_t s = ksize(ptr); |
95 | spin_lock(&tomoyo_policy_memory_lock); | ||
96 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
97 | spin_unlock(&tomoyo_policy_memory_lock); | ||
90 | kfree(ptr); | 98 | kfree(ptr); |
91 | } | 99 | } |
92 | 100 | ||
93 | /** | 101 | /** |
94 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". | 102 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". |
95 | * | 103 | * |
96 | * @group_name: The name of address group. | 104 | * @param: Pointer to "struct tomoyo_acl_param". |
97 | * @idx: Index number. | 105 | * @idx: Index number. |
98 | * | 106 | * |
99 | * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. | 107 | * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. |
100 | */ | 108 | */ |
101 | struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx) | 109 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, |
110 | const u8 idx) | ||
102 | { | 111 | { |
103 | struct tomoyo_group e = { }; | 112 | struct tomoyo_group e = { }; |
104 | struct tomoyo_group *group = NULL; | 113 | struct tomoyo_group *group = NULL; |
114 | struct list_head *list; | ||
115 | const char *group_name = tomoyo_read_token(param); | ||
105 | bool found = false; | 116 | bool found = false; |
106 | if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) | 117 | if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) |
107 | return NULL; | 118 | return NULL; |
@@ -110,10 +121,11 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx) | |||
110 | return NULL; | 121 | return NULL; |
111 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 122 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
112 | goto out; | 123 | goto out; |
113 | list_for_each_entry(group, &tomoyo_group_list[idx], list) { | 124 | list = ¶m->ns->group_list[idx]; |
125 | list_for_each_entry(group, list, head.list) { | ||
114 | if (e.group_name != group->group_name) | 126 | if (e.group_name != group->group_name) |
115 | continue; | 127 | continue; |
116 | atomic_inc(&group->users); | 128 | atomic_inc(&group->head.users); |
117 | found = true; | 129 | found = true; |
118 | break; | 130 | break; |
119 | } | 131 | } |
@@ -121,15 +133,14 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx) | |||
121 | struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); | 133 | struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); |
122 | if (entry) { | 134 | if (entry) { |
123 | INIT_LIST_HEAD(&entry->member_list); | 135 | INIT_LIST_HEAD(&entry->member_list); |
124 | atomic_set(&entry->users, 1); | 136 | atomic_set(&entry->head.users, 1); |
125 | list_add_tail_rcu(&entry->list, | 137 | list_add_tail_rcu(&entry->head.list, list); |
126 | &tomoyo_group_list[idx]); | ||
127 | group = entry; | 138 | group = entry; |
128 | found = true; | 139 | found = true; |
129 | } | 140 | } |
130 | } | 141 | } |
131 | mutex_unlock(&tomoyo_policy_lock); | 142 | mutex_unlock(&tomoyo_policy_lock); |
132 | out: | 143 | out: |
133 | tomoyo_put_name(e.group_name); | 144 | tomoyo_put_name(e.group_name); |
134 | return found ? group : NULL; | 145 | return found ? group : NULL; |
135 | } | 146 | } |
@@ -154,7 +165,6 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
154 | struct tomoyo_name *ptr; | 165 | struct tomoyo_name *ptr; |
155 | unsigned int hash; | 166 | unsigned int hash; |
156 | int len; | 167 | int len; |
157 | int allocated_len; | ||
158 | struct list_head *head; | 168 | struct list_head *head; |
159 | 169 | ||
160 | if (!name) | 170 | if (!name) |
@@ -164,120 +174,43 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
164 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 174 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
165 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 175 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
166 | return NULL; | 176 | return NULL; |
167 | list_for_each_entry(ptr, head, list) { | 177 | list_for_each_entry(ptr, head, head.list) { |
168 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 178 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
169 | continue; | 179 | continue; |
170 | atomic_inc(&ptr->users); | 180 | atomic_inc(&ptr->head.users); |
171 | goto out; | 181 | goto out; |
172 | } | 182 | } |
173 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); | 183 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); |
174 | allocated_len = ptr ? ksize(ptr) : 0; | 184 | if (tomoyo_memory_ok(ptr)) { |
175 | if (!ptr || (tomoyo_quota_for_policy && | 185 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
176 | atomic_read(&tomoyo_policy_memory_size) + allocated_len | 186 | memmove((char *) ptr->entry.name, name, len); |
177 | > tomoyo_quota_for_policy)) { | 187 | atomic_set(&ptr->head.users, 1); |
188 | tomoyo_fill_path_info(&ptr->entry); | ||
189 | list_add_tail(&ptr->head.list, head); | ||
190 | } else { | ||
178 | kfree(ptr); | 191 | kfree(ptr); |
179 | ptr = NULL; | 192 | ptr = NULL; |
180 | tomoyo_warn_oom(__func__); | ||
181 | goto out; | ||
182 | } | 193 | } |
183 | atomic_add(allocated_len, &tomoyo_policy_memory_size); | 194 | out: |
184 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); | ||
185 | memmove((char *) ptr->entry.name, name, len); | ||
186 | atomic_set(&ptr->users, 1); | ||
187 | tomoyo_fill_path_info(&ptr->entry); | ||
188 | list_add_tail(&ptr->list, head); | ||
189 | out: | ||
190 | mutex_unlock(&tomoyo_policy_lock); | 195 | mutex_unlock(&tomoyo_policy_lock); |
191 | return ptr ? &ptr->entry : NULL; | 196 | return ptr ? &ptr->entry : NULL; |
192 | } | 197 | } |
193 | 198 | ||
199 | /* Initial namespace.*/ | ||
200 | struct tomoyo_policy_namespace tomoyo_kernel_namespace; | ||
201 | |||
194 | /** | 202 | /** |
195 | * tomoyo_mm_init - Initialize mm related code. | 203 | * tomoyo_mm_init - Initialize mm related code. |
196 | */ | 204 | */ |
197 | void __init tomoyo_mm_init(void) | 205 | void __init tomoyo_mm_init(void) |
198 | { | 206 | { |
199 | int idx; | 207 | int idx; |
200 | |||
201 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | ||
202 | INIT_LIST_HEAD(&tomoyo_policy_list[idx]); | ||
203 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | ||
204 | INIT_LIST_HEAD(&tomoyo_group_list[idx]); | ||
205 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) | 208 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) |
206 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | 209 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); |
210 | tomoyo_kernel_namespace.name = "<kernel>"; | ||
211 | tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); | ||
212 | tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; | ||
207 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 213 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
208 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); | 214 | tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); |
209 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 215 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); |
210 | idx = tomoyo_read_lock(); | ||
211 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | ||
212 | panic("Can't register tomoyo_kernel_domain"); | ||
213 | { | ||
214 | /* Load built-in policy. */ | ||
215 | tomoyo_write_transition_control("/sbin/hotplug", false, | ||
216 | TOMOYO_TRANSITION_CONTROL_INITIALIZE); | ||
217 | tomoyo_write_transition_control("/sbin/modprobe", false, | ||
218 | TOMOYO_TRANSITION_CONTROL_INITIALIZE); | ||
219 | } | ||
220 | tomoyo_read_unlock(idx); | ||
221 | } | ||
222 | |||
223 | |||
224 | /* Memory allocated for query lists. */ | ||
225 | unsigned int tomoyo_query_memory_size; | ||
226 | /* Quota for holding query lists. */ | ||
227 | unsigned int tomoyo_quota_for_query; | ||
228 | |||
229 | /** | ||
230 | * tomoyo_read_memory_counter - Check for memory usage in bytes. | ||
231 | * | ||
232 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
233 | * | ||
234 | * Returns memory usage. | ||
235 | */ | ||
236 | void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | ||
237 | { | ||
238 | if (!head->r.eof) { | ||
239 | const unsigned int policy | ||
240 | = atomic_read(&tomoyo_policy_memory_size); | ||
241 | const unsigned int query = tomoyo_query_memory_size; | ||
242 | char buffer[64]; | ||
243 | |||
244 | memset(buffer, 0, sizeof(buffer)); | ||
245 | if (tomoyo_quota_for_policy) | ||
246 | snprintf(buffer, sizeof(buffer) - 1, | ||
247 | " (Quota: %10u)", | ||
248 | tomoyo_quota_for_policy); | ||
249 | else | ||
250 | buffer[0] = '\0'; | ||
251 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, | ||
252 | buffer); | ||
253 | if (tomoyo_quota_for_query) | ||
254 | snprintf(buffer, sizeof(buffer) - 1, | ||
255 | " (Quota: %10u)", | ||
256 | tomoyo_quota_for_query); | ||
257 | else | ||
258 | buffer[0] = '\0'; | ||
259 | tomoyo_io_printf(head, "Query lists: %10u%s\n", query, | ||
260 | buffer); | ||
261 | tomoyo_io_printf(head, "Total: %10u\n", policy + query); | ||
262 | head->r.eof = true; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * tomoyo_write_memory_quota - Set memory quota. | ||
268 | * | ||
269 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
270 | * | ||
271 | * Returns 0. | ||
272 | */ | ||
273 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | ||
274 | { | ||
275 | char *data = head->write_buf; | ||
276 | unsigned int size; | ||
277 | |||
278 | if (sscanf(data, "Policy: %u", &size) == 1) | ||
279 | tomoyo_quota_for_policy = size; | ||
280 | else if (sscanf(data, "Query lists: %u", &size) == 1) | ||
281 | tomoyo_quota_for_query = size; | ||
282 | return 0; | ||
283 | } | 216 | } |
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 9fc2e15841c9..bee09d062057 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c | |||
@@ -1,28 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/mount.c | 2 | * security/tomoyo/mount.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include "common.h" | 8 | #include "common.h" |
9 | 9 | ||
10 | /* Keywords for mount restrictions. */ | 10 | /* String table for special mount operations. */ |
11 | 11 | static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = { | |
12 | /* Allow to call 'mount --bind /source_dir /dest_dir' */ | 12 | [TOMOYO_MOUNT_BIND] = "--bind", |
13 | #define TOMOYO_MOUNT_BIND_KEYWORD "--bind" | 13 | [TOMOYO_MOUNT_MOVE] = "--move", |
14 | /* Allow to call 'mount --move /old_dir /new_dir ' */ | 14 | [TOMOYO_MOUNT_REMOUNT] = "--remount", |
15 | #define TOMOYO_MOUNT_MOVE_KEYWORD "--move" | 15 | [TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable", |
16 | /* Allow to call 'mount -o remount /dir ' */ | 16 | [TOMOYO_MOUNT_MAKE_PRIVATE] = "--make-private", |
17 | #define TOMOYO_MOUNT_REMOUNT_KEYWORD "--remount" | 17 | [TOMOYO_MOUNT_MAKE_SLAVE] = "--make-slave", |
18 | /* Allow to call 'mount --make-unbindable /dir' */ | 18 | [TOMOYO_MOUNT_MAKE_SHARED] = "--make-shared", |
19 | #define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable" | 19 | }; |
20 | /* Allow to call 'mount --make-private /dir' */ | ||
21 | #define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD "--make-private" | ||
22 | /* Allow to call 'mount --make-slave /dir' */ | ||
23 | #define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD "--make-slave" | ||
24 | /* Allow to call 'mount --make-shared /dir' */ | ||
25 | #define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared" | ||
26 | 20 | ||
27 | /** | 21 | /** |
28 | * tomoyo_audit_mount_log - Audit mount log. | 22 | * tomoyo_audit_mount_log - Audit mount log. |
@@ -33,50 +27,42 @@ | |||
33 | */ | 27 | */ |
34 | static int tomoyo_audit_mount_log(struct tomoyo_request_info *r) | 28 | static int tomoyo_audit_mount_log(struct tomoyo_request_info *r) |
35 | { | 29 | { |
36 | const char *dev = r->param.mount.dev->name; | 30 | return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n", |
37 | const char *dir = r->param.mount.dir->name; | 31 | r->param.mount.dev->name, |
38 | const char *type = r->param.mount.type->name; | 32 | r->param.mount.dir->name, |
39 | const unsigned long flags = r->param.mount.flags; | 33 | r->param.mount.type->name, |
40 | if (r->granted) | 34 | r->param.mount.flags); |
41 | return 0; | ||
42 | if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) | ||
43 | tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags); | ||
44 | else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) | ||
45 | || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) | ||
46 | tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir, | ||
47 | flags); | ||
48 | else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) || | ||
49 | !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) || | ||
50 | !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) || | ||
51 | !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) | ||
52 | tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags); | ||
53 | else | ||
54 | tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir, | ||
55 | flags); | ||
56 | return tomoyo_supervisor(r, | ||
57 | TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n", | ||
58 | tomoyo_pattern(r->param.mount.dev), | ||
59 | tomoyo_pattern(r->param.mount.dir), type, | ||
60 | flags); | ||
61 | } | 35 | } |
62 | 36 | ||
37 | /** | ||
38 | * tomoyo_check_mount_acl - Check permission for path path path number operation. | ||
39 | * | ||
40 | * @r: Pointer to "struct tomoyo_request_info". | ||
41 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
42 | * | ||
43 | * Returns true if granted, false otherwise. | ||
44 | */ | ||
63 | static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, | 45 | static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, |
64 | const struct tomoyo_acl_info *ptr) | 46 | const struct tomoyo_acl_info *ptr) |
65 | { | 47 | { |
66 | const struct tomoyo_mount_acl *acl = | 48 | const struct tomoyo_mount_acl *acl = |
67 | container_of(ptr, typeof(*acl), head); | 49 | container_of(ptr, typeof(*acl), head); |
68 | return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) && | 50 | return tomoyo_compare_number_union(r->param.mount.flags, |
69 | tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) && | 51 | &acl->flags) && |
70 | tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) && | 52 | tomoyo_compare_name_union(r->param.mount.type, |
53 | &acl->fs_type) && | ||
54 | tomoyo_compare_name_union(r->param.mount.dir, | ||
55 | &acl->dir_name) && | ||
71 | (!r->param.mount.need_dev || | 56 | (!r->param.mount.need_dev || |
72 | tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name)); | 57 | tomoyo_compare_name_union(r->param.mount.dev, |
58 | &acl->dev_name)); | ||
73 | } | 59 | } |
74 | 60 | ||
75 | /** | 61 | /** |
76 | * tomoyo_mount_acl - Check permission for mount() operation. | 62 | * tomoyo_mount_acl - Check permission for mount() operation. |
77 | * | 63 | * |
78 | * @r: Pointer to "struct tomoyo_request_info". | 64 | * @r: Pointer to "struct tomoyo_request_info". |
79 | * @dev_name: Name of device file. | 65 | * @dev_name: Name of device file. Maybe NULL. |
80 | * @dir: Pointer to "struct path". | 66 | * @dir: Pointer to "struct path". |
81 | * @type: Name of filesystem type. | 67 | * @type: Name of filesystem type. |
82 | * @flags: Mount options. | 68 | * @flags: Mount options. |
@@ -86,8 +72,10 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, | |||
86 | * Caller holds tomoyo_read_lock(). | 72 | * Caller holds tomoyo_read_lock(). |
87 | */ | 73 | */ |
88 | static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | 74 | static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, |
89 | struct path *dir, char *type, unsigned long flags) | 75 | struct path *dir, const char *type, |
76 | unsigned long flags) | ||
90 | { | 77 | { |
78 | struct tomoyo_obj_info obj = { }; | ||
91 | struct path path; | 79 | struct path path; |
92 | struct file_system_type *fstype = NULL; | 80 | struct file_system_type *fstype = NULL; |
93 | const char *requested_type = NULL; | 81 | const char *requested_type = NULL; |
@@ -98,6 +86,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | |||
98 | struct tomoyo_path_info rdir; | 86 | struct tomoyo_path_info rdir; |
99 | int need_dev = 0; | 87 | int need_dev = 0; |
100 | int error = -ENOMEM; | 88 | int error = -ENOMEM; |
89 | r->obj = &obj; | ||
101 | 90 | ||
102 | /* Get fstype. */ | 91 | /* Get fstype. */ |
103 | requested_type = tomoyo_encode(type); | 92 | requested_type = tomoyo_encode(type); |
@@ -107,6 +96,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | |||
107 | tomoyo_fill_path_info(&rtype); | 96 | tomoyo_fill_path_info(&rtype); |
108 | 97 | ||
109 | /* Get mount point. */ | 98 | /* Get mount point. */ |
99 | obj.path2 = *dir; | ||
110 | requested_dir_name = tomoyo_realpath_from_path(dir); | 100 | requested_dir_name = tomoyo_realpath_from_path(dir); |
111 | if (!requested_dir_name) { | 101 | if (!requested_dir_name) { |
112 | error = -ENOMEM; | 102 | error = -ENOMEM; |
@@ -116,15 +106,15 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | |||
116 | tomoyo_fill_path_info(&rdir); | 106 | tomoyo_fill_path_info(&rdir); |
117 | 107 | ||
118 | /* Compare fs name. */ | 108 | /* Compare fs name. */ |
119 | if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) { | 109 | if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) { |
120 | /* dev_name is ignored. */ | 110 | /* dev_name is ignored. */ |
121 | } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) || | 111 | } else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] || |
122 | !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) || | 112 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] || |
123 | !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) || | 113 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] || |
124 | !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) { | 114 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) { |
125 | /* dev_name is ignored. */ | 115 | /* dev_name is ignored. */ |
126 | } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) || | 116 | } else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] || |
127 | !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) { | 117 | type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) { |
128 | need_dev = -1; /* dev_name is a directory */ | 118 | need_dev = -1; /* dev_name is a directory */ |
129 | } else { | 119 | } else { |
130 | fstype = get_fs_type(type); | 120 | fstype = get_fs_type(type); |
@@ -142,8 +132,8 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | |||
142 | error = -ENOENT; | 132 | error = -ENOENT; |
143 | goto out; | 133 | goto out; |
144 | } | 134 | } |
135 | obj.path1 = path; | ||
145 | requested_dev_name = tomoyo_realpath_from_path(&path); | 136 | requested_dev_name = tomoyo_realpath_from_path(&path); |
146 | path_put(&path); | ||
147 | if (!requested_dev_name) { | 137 | if (!requested_dev_name) { |
148 | error = -ENOENT; | 138 | error = -ENOENT; |
149 | goto out; | 139 | goto out; |
@@ -176,22 +166,26 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | |||
176 | if (fstype) | 166 | if (fstype) |
177 | put_filesystem(fstype); | 167 | put_filesystem(fstype); |
178 | kfree(requested_type); | 168 | kfree(requested_type); |
169 | /* Drop refcount obtained by kern_path(). */ | ||
170 | if (obj.path1.dentry) | ||
171 | path_put(&obj.path1); | ||
179 | return error; | 172 | return error; |
180 | } | 173 | } |
181 | 174 | ||
182 | /** | 175 | /** |
183 | * tomoyo_mount_permission - Check permission for mount() operation. | 176 | * tomoyo_mount_permission - Check permission for mount() operation. |
184 | * | 177 | * |
185 | * @dev_name: Name of device file. | 178 | * @dev_name: Name of device file. Maybe NULL. |
186 | * @path: Pointer to "struct path". | 179 | * @path: Pointer to "struct path". |
187 | * @type: Name of filesystem type. May be NULL. | 180 | * @type: Name of filesystem type. Maybe NULL. |
188 | * @flags: Mount options. | 181 | * @flags: Mount options. |
189 | * @data_page: Optional data. May be NULL. | 182 | * @data_page: Optional data. Maybe NULL. |
190 | * | 183 | * |
191 | * Returns 0 on success, negative value otherwise. | 184 | * Returns 0 on success, negative value otherwise. |
192 | */ | 185 | */ |
193 | int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | 186 | int tomoyo_mount_permission(char *dev_name, struct path *path, |
194 | unsigned long flags, void *data_page) | 187 | const char *type, unsigned long flags, |
188 | void *data_page) | ||
195 | { | 189 | { |
196 | struct tomoyo_request_info r; | 190 | struct tomoyo_request_info r; |
197 | int error; | 191 | int error; |
@@ -203,31 +197,31 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | |||
203 | if ((flags & MS_MGC_MSK) == MS_MGC_VAL) | 197 | if ((flags & MS_MGC_MSK) == MS_MGC_VAL) |
204 | flags &= ~MS_MGC_MSK; | 198 | flags &= ~MS_MGC_MSK; |
205 | if (flags & MS_REMOUNT) { | 199 | if (flags & MS_REMOUNT) { |
206 | type = TOMOYO_MOUNT_REMOUNT_KEYWORD; | 200 | type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; |
207 | flags &= ~MS_REMOUNT; | 201 | flags &= ~MS_REMOUNT; |
208 | } | 202 | } |
209 | if (flags & MS_MOVE) { | 203 | if (flags & MS_MOVE) { |
210 | type = TOMOYO_MOUNT_MOVE_KEYWORD; | 204 | type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; |
211 | flags &= ~MS_MOVE; | 205 | flags &= ~MS_MOVE; |
212 | } | 206 | } |
213 | if (flags & MS_BIND) { | 207 | if (flags & MS_BIND) { |
214 | type = TOMOYO_MOUNT_BIND_KEYWORD; | 208 | type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; |
215 | flags &= ~MS_BIND; | 209 | flags &= ~MS_BIND; |
216 | } | 210 | } |
217 | if (flags & MS_UNBINDABLE) { | 211 | if (flags & MS_UNBINDABLE) { |
218 | type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD; | 212 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; |
219 | flags &= ~MS_UNBINDABLE; | 213 | flags &= ~MS_UNBINDABLE; |
220 | } | 214 | } |
221 | if (flags & MS_PRIVATE) { | 215 | if (flags & MS_PRIVATE) { |
222 | type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD; | 216 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; |
223 | flags &= ~MS_PRIVATE; | 217 | flags &= ~MS_PRIVATE; |
224 | } | 218 | } |
225 | if (flags & MS_SLAVE) { | 219 | if (flags & MS_SLAVE) { |
226 | type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD; | 220 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; |
227 | flags &= ~MS_SLAVE; | 221 | flags &= ~MS_SLAVE; |
228 | } | 222 | } |
229 | if (flags & MS_SHARED) { | 223 | if (flags & MS_SHARED) { |
230 | type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD; | 224 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; |
231 | flags &= ~MS_SHARED; | 225 | flags &= ~MS_SHARED; |
232 | } | 226 | } |
233 | if (!type) | 227 | if (!type) |
@@ -237,49 +231,3 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | |||
237 | tomoyo_read_unlock(idx); | 231 | tomoyo_read_unlock(idx); |
238 | return error; | 232 | return error; |
239 | } | 233 | } |
240 | |||
241 | static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, | ||
242 | const struct tomoyo_acl_info *b) | ||
243 | { | ||
244 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); | ||
245 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); | ||
246 | return tomoyo_same_acl_head(&p1->head, &p2->head) && | ||
247 | tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && | ||
248 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && | ||
249 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && | ||
250 | tomoyo_same_number_union(&p1->flags, &p2->flags); | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list. | ||
255 | * | ||
256 | * @data: String to parse. | ||
257 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
258 | * @is_delete: True if it is a delete request. | ||
259 | * | ||
260 | * Returns 0 on success, negative value otherwise. | ||
261 | * | ||
262 | * Caller holds tomoyo_read_lock(). | ||
263 | */ | ||
264 | int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain, | ||
265 | const bool is_delete) | ||
266 | { | ||
267 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; | ||
268 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
269 | char *w[4]; | ||
270 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0]) | ||
271 | return -EINVAL; | ||
272 | if (!tomoyo_parse_name_union(w[0], &e.dev_name) || | ||
273 | !tomoyo_parse_name_union(w[1], &e.dir_name) || | ||
274 | !tomoyo_parse_name_union(w[2], &e.fs_type) || | ||
275 | !tomoyo_parse_number_union(w[3], &e.flags)) | ||
276 | goto out; | ||
277 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | ||
278 | tomoyo_same_mount_acl, NULL); | ||
279 | out: | ||
280 | tomoyo_put_name_union(&e.dev_name); | ||
281 | tomoyo_put_name_union(&e.dir_name); | ||
282 | tomoyo_put_name_union(&e.fs_type); | ||
283 | tomoyo_put_number_union(&e.flags); | ||
284 | return error; | ||
285 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 8d95e91c9fc4..6c601bd300f3 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/realpath.c | 2 | * security/tomoyo/realpath.c |
3 | * | 3 | * |
4 | * Pathname calculation functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/types.h> | 7 | #include <linux/types.h> |
@@ -70,6 +68,161 @@ char *tomoyo_encode(const char *str) | |||
70 | } | 68 | } |
71 | 69 | ||
72 | /** | 70 | /** |
71 | * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. | ||
72 | * | ||
73 | * @path: Pointer to "struct path". | ||
74 | * @buffer: Pointer to buffer to return value in. | ||
75 | * @buflen: Sizeof @buffer. | ||
76 | * | ||
77 | * Returns the buffer on success, an error code otherwise. | ||
78 | * | ||
79 | * If dentry is a directory, trailing '/' is appended. | ||
80 | */ | ||
81 | static char *tomoyo_get_absolute_path(struct path *path, char * const buffer, | ||
82 | const int buflen) | ||
83 | { | ||
84 | char *pos = ERR_PTR(-ENOMEM); | ||
85 | if (buflen >= 256) { | ||
86 | struct path ns_root = { }; | ||
87 | /* go to whatever namespace root we are under */ | ||
88 | pos = __d_path(path, &ns_root, buffer, buflen - 1); | ||
89 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { | ||
90 | struct inode *inode = path->dentry->d_inode; | ||
91 | if (inode && S_ISDIR(inode->i_mode)) { | ||
92 | buffer[buflen - 2] = '/'; | ||
93 | buffer[buflen - 1] = '\0'; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | return pos; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * tomoyo_get_dentry_path - Get the path of a dentry. | ||
102 | * | ||
103 | * @dentry: Pointer to "struct dentry". | ||
104 | * @buffer: Pointer to buffer to return value in. | ||
105 | * @buflen: Sizeof @buffer. | ||
106 | * | ||
107 | * Returns the buffer on success, an error code otherwise. | ||
108 | * | ||
109 | * If dentry is a directory, trailing '/' is appended. | ||
110 | */ | ||
111 | static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer, | ||
112 | const int buflen) | ||
113 | { | ||
114 | char *pos = ERR_PTR(-ENOMEM); | ||
115 | if (buflen >= 256) { | ||
116 | pos = dentry_path_raw(dentry, buffer, buflen - 1); | ||
117 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { | ||
118 | struct inode *inode = dentry->d_inode; | ||
119 | if (inode && S_ISDIR(inode->i_mode)) { | ||
120 | buffer[buflen - 2] = '/'; | ||
121 | buffer[buflen - 1] = '\0'; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | return pos; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * tomoyo_get_local_path - Get the path of a dentry. | ||
130 | * | ||
131 | * @dentry: Pointer to "struct dentry". | ||
132 | * @buffer: Pointer to buffer to return value in. | ||
133 | * @buflen: Sizeof @buffer. | ||
134 | * | ||
135 | * Returns the buffer on success, an error code otherwise. | ||
136 | */ | ||
137 | static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, | ||
138 | const int buflen) | ||
139 | { | ||
140 | struct super_block *sb = dentry->d_sb; | ||
141 | char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen); | ||
142 | if (IS_ERR(pos)) | ||
143 | return pos; | ||
144 | /* Convert from $PID to self if $PID is current thread. */ | ||
145 | if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { | ||
146 | char *ep; | ||
147 | const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); | ||
148 | if (*ep == '/' && pid && pid == | ||
149 | task_tgid_nr_ns(current, sb->s_fs_info)) { | ||
150 | pos = ep - 5; | ||
151 | if (pos < buffer) | ||
152 | goto out; | ||
153 | memmove(pos, "/self", 5); | ||
154 | } | ||
155 | goto prepend_filesystem_name; | ||
156 | } | ||
157 | /* Use filesystem name for unnamed devices. */ | ||
158 | if (!MAJOR(sb->s_dev)) | ||
159 | goto prepend_filesystem_name; | ||
160 | { | ||
161 | struct inode *inode = sb->s_root->d_inode; | ||
162 | /* | ||
163 | * Use filesystem name if filesystem does not support rename() | ||
164 | * operation. | ||
165 | */ | ||
166 | if (inode->i_op && !inode->i_op->rename) | ||
167 | goto prepend_filesystem_name; | ||
168 | } | ||
169 | /* Prepend device name. */ | ||
170 | { | ||
171 | char name[64]; | ||
172 | int name_len; | ||
173 | const dev_t dev = sb->s_dev; | ||
174 | name[sizeof(name) - 1] = '\0'; | ||
175 | snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev), | ||
176 | MINOR(dev)); | ||
177 | name_len = strlen(name); | ||
178 | pos -= name_len; | ||
179 | if (pos < buffer) | ||
180 | goto out; | ||
181 | memmove(pos, name, name_len); | ||
182 | return pos; | ||
183 | } | ||
184 | /* Prepend filesystem name. */ | ||
185 | prepend_filesystem_name: | ||
186 | { | ||
187 | const char *name = sb->s_type->name; | ||
188 | const int name_len = strlen(name); | ||
189 | pos -= name_len + 1; | ||
190 | if (pos < buffer) | ||
191 | goto out; | ||
192 | memmove(pos, name, name_len); | ||
193 | pos[name_len] = ':'; | ||
194 | } | ||
195 | return pos; | ||
196 | out: | ||
197 | return ERR_PTR(-ENOMEM); | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * tomoyo_get_socket_name - Get the name of a socket. | ||
202 | * | ||
203 | * @path: Pointer to "struct path". | ||
204 | * @buffer: Pointer to buffer to return value in. | ||
205 | * @buflen: Sizeof @buffer. | ||
206 | * | ||
207 | * Returns the buffer. | ||
208 | */ | ||
209 | static char *tomoyo_get_socket_name(struct path *path, char * const buffer, | ||
210 | const int buflen) | ||
211 | { | ||
212 | struct inode *inode = path->dentry->d_inode; | ||
213 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; | ||
214 | struct sock *sk = sock ? sock->sk : NULL; | ||
215 | if (sk) { | ||
216 | snprintf(buffer, buflen, "socket:[family=%u:type=%u:" | ||
217 | "protocol=%u]", sk->sk_family, sk->sk_type, | ||
218 | sk->sk_protocol); | ||
219 | } else { | ||
220 | snprintf(buffer, buflen, "socket:[unknown]"); | ||
221 | } | ||
222 | return buffer; | ||
223 | } | ||
224 | |||
225 | /** | ||
73 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. | 226 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. |
74 | * | 227 | * |
75 | * @path: Pointer to "struct path". | 228 | * @path: Pointer to "struct path". |
@@ -90,55 +243,42 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
90 | char *name = NULL; | 243 | char *name = NULL; |
91 | unsigned int buf_len = PAGE_SIZE / 2; | 244 | unsigned int buf_len = PAGE_SIZE / 2; |
92 | struct dentry *dentry = path->dentry; | 245 | struct dentry *dentry = path->dentry; |
93 | bool is_dir; | 246 | struct super_block *sb; |
94 | if (!dentry) | 247 | if (!dentry) |
95 | return NULL; | 248 | return NULL; |
96 | is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode); | 249 | sb = dentry->d_sb; |
97 | while (1) { | 250 | while (1) { |
98 | struct path ns_root = { .mnt = NULL, .dentry = NULL }; | ||
99 | char *pos; | 251 | char *pos; |
252 | struct inode *inode; | ||
100 | buf_len <<= 1; | 253 | buf_len <<= 1; |
101 | kfree(buf); | 254 | kfree(buf); |
102 | buf = kmalloc(buf_len, GFP_NOFS); | 255 | buf = kmalloc(buf_len, GFP_NOFS); |
103 | if (!buf) | 256 | if (!buf) |
104 | break; | 257 | break; |
258 | /* To make sure that pos is '\0' terminated. */ | ||
259 | buf[buf_len - 1] = '\0'; | ||
105 | /* Get better name for socket. */ | 260 | /* Get better name for socket. */ |
106 | if (dentry->d_sb->s_magic == SOCKFS_MAGIC) { | 261 | if (sb->s_magic == SOCKFS_MAGIC) { |
107 | struct inode *inode = dentry->d_inode; | 262 | pos = tomoyo_get_socket_name(path, buf, buf_len - 1); |
108 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; | 263 | goto encode; |
109 | struct sock *sk = sock ? sock->sk : NULL; | ||
110 | if (sk) { | ||
111 | snprintf(buf, buf_len - 1, "socket:[family=%u:" | ||
112 | "type=%u:protocol=%u]", sk->sk_family, | ||
113 | sk->sk_type, sk->sk_protocol); | ||
114 | } else { | ||
115 | snprintf(buf, buf_len - 1, "socket:[unknown]"); | ||
116 | } | ||
117 | name = tomoyo_encode(buf); | ||
118 | break; | ||
119 | } | 264 | } |
120 | /* For "socket:[\$]" and "pipe:[\$]". */ | 265 | /* For "pipe:[\$]". */ |
121 | if (dentry->d_op && dentry->d_op->d_dname) { | 266 | if (dentry->d_op && dentry->d_op->d_dname) { |
122 | pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); | 267 | pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); |
123 | if (IS_ERR(pos)) | 268 | goto encode; |
124 | continue; | ||
125 | name = tomoyo_encode(pos); | ||
126 | break; | ||
127 | } | ||
128 | /* If we don't have a vfsmount, we can't calculate. */ | ||
129 | if (!path->mnt) | ||
130 | break; | ||
131 | /* go to whatever namespace root we are under */ | ||
132 | pos = __d_path(path, &ns_root, buf, buf_len); | ||
133 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | ||
134 | if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) && | ||
135 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { | ||
136 | pos -= 5; | ||
137 | if (pos >= buf) | ||
138 | memcpy(pos, "/proc", 5); | ||
139 | else | ||
140 | pos = ERR_PTR(-ENOMEM); | ||
141 | } | 269 | } |
270 | inode = sb->s_root->d_inode; | ||
271 | /* | ||
272 | * Get local name for filesystems without rename() operation | ||
273 | * or dentry without vfsmount. | ||
274 | */ | ||
275 | if (!path->mnt || (inode->i_op && !inode->i_op->rename)) | ||
276 | pos = tomoyo_get_local_path(path->dentry, buf, | ||
277 | buf_len - 1); | ||
278 | /* Get absolute name for the rest. */ | ||
279 | else | ||
280 | pos = tomoyo_get_absolute_path(path, buf, buf_len - 1); | ||
281 | encode: | ||
142 | if (IS_ERR(pos)) | 282 | if (IS_ERR(pos)) |
143 | continue; | 283 | continue; |
144 | name = tomoyo_encode(pos); | 284 | name = tomoyo_encode(pos); |
@@ -147,16 +287,6 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
147 | kfree(buf); | 287 | kfree(buf); |
148 | if (!name) | 288 | if (!name) |
149 | tomoyo_warn_oom(__func__); | 289 | tomoyo_warn_oom(__func__); |
150 | else if (is_dir && *name) { | ||
151 | /* Append trailing '/' if dentry is a directory. */ | ||
152 | char *pos = name + strlen(name) - 1; | ||
153 | if (*pos != '/') | ||
154 | /* | ||
155 | * This is OK because tomoyo_encode() reserves space | ||
156 | * for appending "/". | ||
157 | */ | ||
158 | *++pos = '/'; | ||
159 | } | ||
160 | return name; | 290 | return name; |
161 | } | 291 | } |
162 | 292 | ||
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index e43d5554b506..a49c3bfd4dd5 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/common.c | 2 | * security/tomoyo/securityfs_if.c |
3 | * | 3 | * |
4 | * Securityfs interface for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/security.h> | 7 | #include <linux/security.h> |
@@ -34,11 +32,11 @@ static int tomoyo_open(struct inode *inode, struct file *file) | |||
34 | */ | 32 | */ |
35 | static int tomoyo_release(struct inode *inode, struct file *file) | 33 | static int tomoyo_release(struct inode *inode, struct file *file) |
36 | { | 34 | { |
37 | return tomoyo_close_control(file); | 35 | return tomoyo_close_control(file->private_data); |
38 | } | 36 | } |
39 | 37 | ||
40 | /** | 38 | /** |
41 | * tomoyo_poll - poll() for /proc/ccs/ interface. | 39 | * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. |
42 | * | 40 | * |
43 | * @file: Pointer to "struct file". | 41 | * @file: Pointer to "struct file". |
44 | * @wait: Pointer to "poll_table". | 42 | * @wait: Pointer to "poll_table". |
@@ -63,7 +61,7 @@ static unsigned int tomoyo_poll(struct file *file, poll_table *wait) | |||
63 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, | 61 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, |
64 | loff_t *ppos) | 62 | loff_t *ppos) |
65 | { | 63 | { |
66 | return tomoyo_read_control(file, buf, count); | 64 | return tomoyo_read_control(file->private_data, buf, count); |
67 | } | 65 | } |
68 | 66 | ||
69 | /** | 67 | /** |
@@ -79,7 +77,7 @@ static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, | |||
79 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, | 77 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, |
80 | size_t count, loff_t *ppos) | 78 | size_t count, loff_t *ppos) |
81 | { | 79 | { |
82 | return tomoyo_write_control(file, buf, count); | 80 | return tomoyo_write_control(file->private_data, buf, count); |
83 | } | 81 | } |
84 | 82 | ||
85 | /* | 83 | /* |
@@ -135,14 +133,14 @@ static int __init tomoyo_initerface_init(void) | |||
135 | TOMOYO_DOMAINPOLICY); | 133 | TOMOYO_DOMAINPOLICY); |
136 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, | 134 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, |
137 | TOMOYO_EXCEPTIONPOLICY); | 135 | TOMOYO_EXCEPTIONPOLICY); |
136 | tomoyo_create_entry("audit", 0400, tomoyo_dir, | ||
137 | TOMOYO_AUDIT); | ||
138 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, | 138 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, |
139 | TOMOYO_SELFDOMAIN); | 139 | TOMOYO_SELFDOMAIN); |
140 | tomoyo_create_entry(".domain_status", 0600, tomoyo_dir, | ||
141 | TOMOYO_DOMAIN_STATUS); | ||
142 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, | 140 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, |
143 | TOMOYO_PROCESS_STATUS); | 141 | TOMOYO_PROCESS_STATUS); |
144 | tomoyo_create_entry("meminfo", 0600, tomoyo_dir, | 142 | tomoyo_create_entry("stat", 0644, tomoyo_dir, |
145 | TOMOYO_MEMINFO); | 143 | TOMOYO_STAT); |
146 | tomoyo_create_entry("profile", 0600, tomoyo_dir, | 144 | tomoyo_create_entry("profile", 0600, tomoyo_dir, |
147 | TOMOYO_PROFILE); | 145 | TOMOYO_PROFILE); |
148 | tomoyo_create_entry("manager", 0600, tomoyo_dir, | 146 | tomoyo_create_entry("manager", 0600, tomoyo_dir, |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 95d3f9572237..f776400a8f31 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -1,20 +1,35 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/tomoyo.c | 2 | * security/tomoyo/tomoyo.c |
3 | * | 3 | * |
4 | * LSM hooks for TOMOYO Linux. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/security.h> | 7 | #include <linux/security.h> |
10 | #include "common.h" | 8 | #include "common.h" |
11 | 9 | ||
10 | /** | ||
11 | * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank(). | ||
12 | * | ||
13 | * @new: Pointer to "struct cred". | ||
14 | * @gfp: Memory allocation flags. | ||
15 | * | ||
16 | * Returns 0. | ||
17 | */ | ||
12 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | 18 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) |
13 | { | 19 | { |
14 | new->security = NULL; | 20 | new->security = NULL; |
15 | return 0; | 21 | return 0; |
16 | } | 22 | } |
17 | 23 | ||
24 | /** | ||
25 | * tomoyo_cred_prepare - Target for security_prepare_creds(). | ||
26 | * | ||
27 | * @new: Pointer to "struct cred". | ||
28 | * @old: Pointer to "struct cred". | ||
29 | * @gfp: Memory allocation flags. | ||
30 | * | ||
31 | * Returns 0. | ||
32 | */ | ||
18 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 33 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
19 | gfp_t gfp) | 34 | gfp_t gfp) |
20 | { | 35 | { |
@@ -25,11 +40,22 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | |||
25 | return 0; | 40 | return 0; |
26 | } | 41 | } |
27 | 42 | ||
43 | /** | ||
44 | * tomoyo_cred_transfer - Target for security_transfer_creds(). | ||
45 | * | ||
46 | * @new: Pointer to "struct cred". | ||
47 | * @old: Pointer to "struct cred". | ||
48 | */ | ||
28 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | 49 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) |
29 | { | 50 | { |
30 | tomoyo_cred_prepare(new, old, 0); | 51 | tomoyo_cred_prepare(new, old, 0); |
31 | } | 52 | } |
32 | 53 | ||
54 | /** | ||
55 | * tomoyo_cred_free - Target for security_cred_free(). | ||
56 | * | ||
57 | * @cred: Pointer to "struct cred". | ||
58 | */ | ||
33 | static void tomoyo_cred_free(struct cred *cred) | 59 | static void tomoyo_cred_free(struct cred *cred) |
34 | { | 60 | { |
35 | struct tomoyo_domain_info *domain = cred->security; | 61 | struct tomoyo_domain_info *domain = cred->security; |
@@ -37,6 +63,13 @@ static void tomoyo_cred_free(struct cred *cred) | |||
37 | atomic_dec(&domain->users); | 63 | atomic_dec(&domain->users); |
38 | } | 64 | } |
39 | 65 | ||
66 | /** | ||
67 | * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). | ||
68 | * | ||
69 | * @bprm: Pointer to "struct linux_binprm". | ||
70 | * | ||
71 | * Returns 0 on success, negative value otherwise. | ||
72 | */ | ||
40 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 73 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
41 | { | 74 | { |
42 | int rc; | 75 | int rc; |
@@ -51,12 +84,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
51 | */ | 84 | */ |
52 | if (bprm->cred_prepared) | 85 | if (bprm->cred_prepared) |
53 | return 0; | 86 | return 0; |
87 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | ||
54 | /* | 88 | /* |
55 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested | 89 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested |
56 | * for the first time. | 90 | * for the first time. |
57 | */ | 91 | */ |
58 | if (!tomoyo_policy_loaded) | 92 | if (!tomoyo_policy_loaded) |
59 | tomoyo_load_policy(bprm->filename); | 93 | tomoyo_load_policy(bprm->filename); |
94 | #endif | ||
60 | /* | 95 | /* |
61 | * Release reference to "struct tomoyo_domain_info" stored inside | 96 | * Release reference to "struct tomoyo_domain_info" stored inside |
62 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" | 97 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" |
@@ -73,6 +108,13 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
73 | return 0; | 108 | return 0; |
74 | } | 109 | } |
75 | 110 | ||
111 | /** | ||
112 | * tomoyo_bprm_check_security - Target for security_bprm_check(). | ||
113 | * | ||
114 | * @bprm: Pointer to "struct linux_binprm". | ||
115 | * | ||
116 | * Returns 0 on success, negative value otherwise. | ||
117 | */ | ||
76 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | 118 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) |
77 | { | 119 | { |
78 | struct tomoyo_domain_info *domain = bprm->cred->security; | 120 | struct tomoyo_domain_info *domain = bprm->cred->security; |
@@ -90,20 +132,59 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
90 | /* | 132 | /* |
91 | * Read permission is checked against interpreters using next domain. | 133 | * Read permission is checked against interpreters using next domain. |
92 | */ | 134 | */ |
93 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY); | 135 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, |
136 | O_RDONLY); | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * tomoyo_inode_getattr - Target for security_inode_getattr(). | ||
141 | * | ||
142 | * @mnt: Pointer to "struct vfsmount". | ||
143 | * @dentry: Pointer to "struct dentry". | ||
144 | * | ||
145 | * Returns 0 on success, negative value otherwise. | ||
146 | */ | ||
147 | static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | ||
148 | { | ||
149 | struct path path = { mnt, dentry }; | ||
150 | return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL); | ||
94 | } | 151 | } |
95 | 152 | ||
153 | /** | ||
154 | * tomoyo_path_truncate - Target for security_path_truncate(). | ||
155 | * | ||
156 | * @path: Pointer to "struct path". | ||
157 | * | ||
158 | * Returns 0 on success, negative value otherwise. | ||
159 | */ | ||
96 | static int tomoyo_path_truncate(struct path *path) | 160 | static int tomoyo_path_truncate(struct path *path) |
97 | { | 161 | { |
98 | return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path); | 162 | return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); |
99 | } | 163 | } |
100 | 164 | ||
165 | /** | ||
166 | * tomoyo_path_unlink - Target for security_path_unlink(). | ||
167 | * | ||
168 | * @parent: Pointer to "struct path". | ||
169 | * @dentry: Pointer to "struct dentry". | ||
170 | * | ||
171 | * Returns 0 on success, negative value otherwise. | ||
172 | */ | ||
101 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) | 173 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) |
102 | { | 174 | { |
103 | struct path path = { parent->mnt, dentry }; | 175 | struct path path = { parent->mnt, dentry }; |
104 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path); | 176 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); |
105 | } | 177 | } |
106 | 178 | ||
179 | /** | ||
180 | * tomoyo_path_mkdir - Target for security_path_mkdir(). | ||
181 | * | ||
182 | * @parent: Pointer to "struct path". | ||
183 | * @dentry: Pointer to "struct dentry". | ||
184 | * @mode: DAC permission mode. | ||
185 | * | ||
186 | * Returns 0 on success, negative value otherwise. | ||
187 | */ | ||
107 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, | 188 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, |
108 | int mode) | 189 | int mode) |
109 | { | 190 | { |
@@ -112,19 +193,46 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, | |||
112 | mode & S_IALLUGO); | 193 | mode & S_IALLUGO); |
113 | } | 194 | } |
114 | 195 | ||
196 | /** | ||
197 | * tomoyo_path_rmdir - Target for security_path_rmdir(). | ||
198 | * | ||
199 | * @parent: Pointer to "struct path". | ||
200 | * @dentry: Pointer to "struct dentry". | ||
201 | * | ||
202 | * Returns 0 on success, negative value otherwise. | ||
203 | */ | ||
115 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) | 204 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) |
116 | { | 205 | { |
117 | struct path path = { parent->mnt, dentry }; | 206 | struct path path = { parent->mnt, dentry }; |
118 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path); | 207 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); |
119 | } | 208 | } |
120 | 209 | ||
210 | /** | ||
211 | * tomoyo_path_symlink - Target for security_path_symlink(). | ||
212 | * | ||
213 | * @parent: Pointer to "struct path". | ||
214 | * @dentry: Pointer to "struct dentry". | ||
215 | * @old_name: Symlink's content. | ||
216 | * | ||
217 | * Returns 0 on success, negative value otherwise. | ||
218 | */ | ||
121 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, | 219 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, |
122 | const char *old_name) | 220 | const char *old_name) |
123 | { | 221 | { |
124 | struct path path = { parent->mnt, dentry }; | 222 | struct path path = { parent->mnt, dentry }; |
125 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path); | 223 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); |
126 | } | 224 | } |
127 | 225 | ||
226 | /** | ||
227 | * tomoyo_path_mknod - Target for security_path_mknod(). | ||
228 | * | ||
229 | * @parent: Pointer to "struct path". | ||
230 | * @dentry: Pointer to "struct dentry". | ||
231 | * @mode: DAC permission mode. | ||
232 | * @dev: Device attributes. | ||
233 | * | ||
234 | * Returns 0 on success, negative value otherwise. | ||
235 | */ | ||
128 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, | 236 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, |
129 | int mode, unsigned int dev) | 237 | int mode, unsigned int dev) |
130 | { | 238 | { |
@@ -155,6 +263,15 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, | |||
155 | return tomoyo_path_number_perm(type, &path, perm); | 263 | return tomoyo_path_number_perm(type, &path, perm); |
156 | } | 264 | } |
157 | 265 | ||
266 | /** | ||
267 | * tomoyo_path_link - Target for security_path_link(). | ||
268 | * | ||
269 | * @old_dentry: Pointer to "struct dentry". | ||
270 | * @new_dir: Pointer to "struct path". | ||
271 | * @new_dentry: Pointer to "struct dentry". | ||
272 | * | ||
273 | * Returns 0 on success, negative value otherwise. | ||
274 | */ | ||
158 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | 275 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, |
159 | struct dentry *new_dentry) | 276 | struct dentry *new_dentry) |
160 | { | 277 | { |
@@ -163,6 +280,16 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | |||
163 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); | 280 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
164 | } | 281 | } |
165 | 282 | ||
283 | /** | ||
284 | * tomoyo_path_rename - Target for security_path_rename(). | ||
285 | * | ||
286 | * @old_parent: Pointer to "struct path". | ||
287 | * @old_dentry: Pointer to "struct dentry". | ||
288 | * @new_parent: Pointer to "struct path". | ||
289 | * @new_dentry: Pointer to "struct dentry". | ||
290 | * | ||
291 | * Returns 0 on success, negative value otherwise. | ||
292 | */ | ||
166 | static int tomoyo_path_rename(struct path *old_parent, | 293 | static int tomoyo_path_rename(struct path *old_parent, |
167 | struct dentry *old_dentry, | 294 | struct dentry *old_dentry, |
168 | struct path *new_parent, | 295 | struct path *new_parent, |
@@ -173,14 +300,32 @@ static int tomoyo_path_rename(struct path *old_parent, | |||
173 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); | 300 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
174 | } | 301 | } |
175 | 302 | ||
303 | /** | ||
304 | * tomoyo_file_fcntl - Target for security_file_fcntl(). | ||
305 | * | ||
306 | * @file: Pointer to "struct file". | ||
307 | * @cmd: Command for fcntl(). | ||
308 | * @arg: Argument for @cmd. | ||
309 | * | ||
310 | * Returns 0 on success, negative value otherwise. | ||
311 | */ | ||
176 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | 312 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, |
177 | unsigned long arg) | 313 | unsigned long arg) |
178 | { | 314 | { |
179 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) | 315 | if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))) |
180 | return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path); | 316 | return 0; |
181 | return 0; | 317 | return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path, |
318 | O_WRONLY | (arg & O_APPEND)); | ||
182 | } | 319 | } |
183 | 320 | ||
321 | /** | ||
322 | * tomoyo_dentry_open - Target for security_dentry_open(). | ||
323 | * | ||
324 | * @f: Pointer to "struct file". | ||
325 | * @cred: Pointer to "struct cred". | ||
326 | * | ||
327 | * Returns 0 on success, negative value otherwise. | ||
328 | */ | ||
184 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | 329 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) |
185 | { | 330 | { |
186 | int flags = f->f_flags; | 331 | int flags = f->f_flags; |
@@ -190,12 +335,30 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
190 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 335 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
191 | } | 336 | } |
192 | 337 | ||
338 | /** | ||
339 | * tomoyo_file_ioctl - Target for security_file_ioctl(). | ||
340 | * | ||
341 | * @file: Pointer to "struct file". | ||
342 | * @cmd: Command for ioctl(). | ||
343 | * @arg: Argument for @cmd. | ||
344 | * | ||
345 | * Returns 0 on success, negative value otherwise. | ||
346 | */ | ||
193 | static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, | 347 | static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, |
194 | unsigned long arg) | 348 | unsigned long arg) |
195 | { | 349 | { |
196 | return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd); | 350 | return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd); |
197 | } | 351 | } |
198 | 352 | ||
353 | /** | ||
354 | * tomoyo_path_chmod - Target for security_path_chmod(). | ||
355 | * | ||
356 | * @dentry: Pointer to "struct dentry". | ||
357 | * @mnt: Pointer to "struct vfsmount". | ||
358 | * @mode: DAC permission mode. | ||
359 | * | ||
360 | * Returns 0 on success, negative value otherwise. | ||
361 | */ | ||
199 | static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | 362 | static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, |
200 | mode_t mode) | 363 | mode_t mode) |
201 | { | 364 | { |
@@ -204,6 +367,15 @@ static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | |||
204 | mode & S_IALLUGO); | 367 | mode & S_IALLUGO); |
205 | } | 368 | } |
206 | 369 | ||
370 | /** | ||
371 | * tomoyo_path_chown - Target for security_path_chown(). | ||
372 | * | ||
373 | * @path: Pointer to "struct path". | ||
374 | * @uid: Owner ID. | ||
375 | * @gid: Group ID. | ||
376 | * | ||
377 | * Returns 0 on success, negative value otherwise. | ||
378 | */ | ||
207 | static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) | 379 | static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) |
208 | { | 380 | { |
209 | int error = 0; | 381 | int error = 0; |
@@ -214,23 +386,57 @@ static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) | |||
214 | return error; | 386 | return error; |
215 | } | 387 | } |
216 | 388 | ||
389 | /** | ||
390 | * tomoyo_path_chroot - Target for security_path_chroot(). | ||
391 | * | ||
392 | * @path: Pointer to "struct path". | ||
393 | * | ||
394 | * Returns 0 on success, negative value otherwise. | ||
395 | */ | ||
217 | static int tomoyo_path_chroot(struct path *path) | 396 | static int tomoyo_path_chroot(struct path *path) |
218 | { | 397 | { |
219 | return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path); | 398 | return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); |
220 | } | 399 | } |
221 | 400 | ||
401 | /** | ||
402 | * tomoyo_sb_mount - Target for security_sb_mount(). | ||
403 | * | ||
404 | * @dev_name: Name of device file. Maybe NULL. | ||
405 | * @path: Pointer to "struct path". | ||
406 | * @type: Name of filesystem type. Maybe NULL. | ||
407 | * @flags: Mount options. | ||
408 | * @data: Optional data. Maybe NULL. | ||
409 | * | ||
410 | * Returns 0 on success, negative value otherwise. | ||
411 | */ | ||
222 | static int tomoyo_sb_mount(char *dev_name, struct path *path, | 412 | static int tomoyo_sb_mount(char *dev_name, struct path *path, |
223 | char *type, unsigned long flags, void *data) | 413 | char *type, unsigned long flags, void *data) |
224 | { | 414 | { |
225 | return tomoyo_mount_permission(dev_name, path, type, flags, data); | 415 | return tomoyo_mount_permission(dev_name, path, type, flags, data); |
226 | } | 416 | } |
227 | 417 | ||
418 | /** | ||
419 | * tomoyo_sb_umount - Target for security_sb_umount(). | ||
420 | * | ||
421 | * @mnt: Pointer to "struct vfsmount". | ||
422 | * @flags: Unmount options. | ||
423 | * | ||
424 | * Returns 0 on success, negative value otherwise. | ||
425 | */ | ||
228 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) | 426 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) |
229 | { | 427 | { |
230 | struct path path = { mnt, mnt->mnt_root }; | 428 | struct path path = { mnt, mnt->mnt_root }; |
231 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path); | 429 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); |
232 | } | 430 | } |
233 | 431 | ||
432 | /** | ||
433 | * tomoyo_sb_pivotroot - Target for security_sb_pivotroot(). | ||
434 | * | ||
435 | * @old_path: Pointer to "struct path". | ||
436 | * @new_path: Pointer to "struct path". | ||
437 | * | ||
438 | * Returns 0 on success, negative value otherwise. | ||
439 | */ | ||
234 | static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) | 440 | static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) |
235 | { | 441 | { |
236 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); | 442 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); |
@@ -258,6 +464,7 @@ static struct security_operations tomoyo_security_ops = { | |||
258 | .path_mknod = tomoyo_path_mknod, | 464 | .path_mknod = tomoyo_path_mknod, |
259 | .path_link = tomoyo_path_link, | 465 | .path_link = tomoyo_path_link, |
260 | .path_rename = tomoyo_path_rename, | 466 | .path_rename = tomoyo_path_rename, |
467 | .inode_getattr = tomoyo_inode_getattr, | ||
261 | .file_ioctl = tomoyo_file_ioctl, | 468 | .file_ioctl = tomoyo_file_ioctl, |
262 | .path_chmod = tomoyo_path_chmod, | 469 | .path_chmod = tomoyo_path_chmod, |
263 | .path_chown = tomoyo_path_chown, | 470 | .path_chown = tomoyo_path_chown, |
@@ -270,6 +477,11 @@ static struct security_operations tomoyo_security_ops = { | |||
270 | /* Lock for GC. */ | 477 | /* Lock for GC. */ |
271 | struct srcu_struct tomoyo_ss; | 478 | struct srcu_struct tomoyo_ss; |
272 | 479 | ||
480 | /** | ||
481 | * tomoyo_init - Register TOMOYO Linux as a LSM module. | ||
482 | * | ||
483 | * Returns 0. | ||
484 | */ | ||
273 | static int __init tomoyo_init(void) | 485 | static int __init tomoyo_init(void) |
274 | { | 486 | { |
275 | struct cred *cred = (struct cred *) current_cred(); | 487 | struct cred *cred = (struct cred *) current_cred(); |
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 6d5393204d95..c36bd1107fc8 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/util.c | 2 | * security/tomoyo/util.c |
3 | * | 3 | * |
4 | * Utility functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
@@ -15,18 +13,130 @@ DEFINE_MUTEX(tomoyo_policy_lock); | |||
15 | /* Has /sbin/init started? */ | 13 | /* Has /sbin/init started? */ |
16 | bool tomoyo_policy_loaded; | 14 | bool tomoyo_policy_loaded; |
17 | 15 | ||
16 | /* | ||
17 | * Mapping table from "enum tomoyo_mac_index" to | ||
18 | * "enum tomoyo_mac_category_index". | ||
19 | */ | ||
20 | const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { | ||
21 | /* CONFIG::file group */ | ||
22 | [TOMOYO_MAC_FILE_EXECUTE] = TOMOYO_MAC_CATEGORY_FILE, | ||
23 | [TOMOYO_MAC_FILE_OPEN] = TOMOYO_MAC_CATEGORY_FILE, | ||
24 | [TOMOYO_MAC_FILE_CREATE] = TOMOYO_MAC_CATEGORY_FILE, | ||
25 | [TOMOYO_MAC_FILE_UNLINK] = TOMOYO_MAC_CATEGORY_FILE, | ||
26 | [TOMOYO_MAC_FILE_GETATTR] = TOMOYO_MAC_CATEGORY_FILE, | ||
27 | [TOMOYO_MAC_FILE_MKDIR] = TOMOYO_MAC_CATEGORY_FILE, | ||
28 | [TOMOYO_MAC_FILE_RMDIR] = TOMOYO_MAC_CATEGORY_FILE, | ||
29 | [TOMOYO_MAC_FILE_MKFIFO] = TOMOYO_MAC_CATEGORY_FILE, | ||
30 | [TOMOYO_MAC_FILE_MKSOCK] = TOMOYO_MAC_CATEGORY_FILE, | ||
31 | [TOMOYO_MAC_FILE_TRUNCATE] = TOMOYO_MAC_CATEGORY_FILE, | ||
32 | [TOMOYO_MAC_FILE_SYMLINK] = TOMOYO_MAC_CATEGORY_FILE, | ||
33 | [TOMOYO_MAC_FILE_MKBLOCK] = TOMOYO_MAC_CATEGORY_FILE, | ||
34 | [TOMOYO_MAC_FILE_MKCHAR] = TOMOYO_MAC_CATEGORY_FILE, | ||
35 | [TOMOYO_MAC_FILE_LINK] = TOMOYO_MAC_CATEGORY_FILE, | ||
36 | [TOMOYO_MAC_FILE_RENAME] = TOMOYO_MAC_CATEGORY_FILE, | ||
37 | [TOMOYO_MAC_FILE_CHMOD] = TOMOYO_MAC_CATEGORY_FILE, | ||
38 | [TOMOYO_MAC_FILE_CHOWN] = TOMOYO_MAC_CATEGORY_FILE, | ||
39 | [TOMOYO_MAC_FILE_CHGRP] = TOMOYO_MAC_CATEGORY_FILE, | ||
40 | [TOMOYO_MAC_FILE_IOCTL] = TOMOYO_MAC_CATEGORY_FILE, | ||
41 | [TOMOYO_MAC_FILE_CHROOT] = TOMOYO_MAC_CATEGORY_FILE, | ||
42 | [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, | ||
43 | [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, | ||
44 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss. | ||
49 | * | ||
50 | * @time: Seconds since 1970/01/01 00:00:00. | ||
51 | * @stamp: Pointer to "struct tomoyo_time". | ||
52 | * | ||
53 | * Returns nothing. | ||
54 | * | ||
55 | * This function does not handle Y2038 problem. | ||
56 | */ | ||
57 | void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp) | ||
58 | { | ||
59 | static const u16 tomoyo_eom[2][12] = { | ||
60 | { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | ||
61 | { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | ||
62 | }; | ||
63 | u16 y; | ||
64 | u8 m; | ||
65 | bool r; | ||
66 | stamp->sec = time % 60; | ||
67 | time /= 60; | ||
68 | stamp->min = time % 60; | ||
69 | time /= 60; | ||
70 | stamp->hour = time % 24; | ||
71 | time /= 24; | ||
72 | for (y = 1970; ; y++) { | ||
73 | const unsigned short days = (y & 3) ? 365 : 366; | ||
74 | if (time < days) | ||
75 | break; | ||
76 | time -= days; | ||
77 | } | ||
78 | r = (y & 3) == 0; | ||
79 | for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++) | ||
80 | ; | ||
81 | if (m) | ||
82 | time -= tomoyo_eom[r][m - 1]; | ||
83 | stamp->year = y; | ||
84 | stamp->month = ++m; | ||
85 | stamp->day = ++time; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * tomoyo_permstr - Find permission keywords. | ||
90 | * | ||
91 | * @string: String representation for permissions in foo/bar/buz format. | ||
92 | * @keyword: Keyword to find from @string/ | ||
93 | * | ||
94 | * Returns ture if @keyword was found in @string, false otherwise. | ||
95 | * | ||
96 | * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. | ||
97 | */ | ||
98 | bool tomoyo_permstr(const char *string, const char *keyword) | ||
99 | { | ||
100 | const char *cp = strstr(string, keyword); | ||
101 | if (cp) | ||
102 | return cp == string || *(cp - 1) == '/'; | ||
103 | return false; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * tomoyo_read_token - Read a word from a line. | ||
108 | * | ||
109 | * @param: Pointer to "struct tomoyo_acl_param". | ||
110 | * | ||
111 | * Returns a word on success, "" otherwise. | ||
112 | * | ||
113 | * To allow the caller to skip NULL check, this function returns "" rather than | ||
114 | * NULL if there is no more words to read. | ||
115 | */ | ||
116 | char *tomoyo_read_token(struct tomoyo_acl_param *param) | ||
117 | { | ||
118 | char *pos = param->data; | ||
119 | char *del = strchr(pos, ' '); | ||
120 | if (del) | ||
121 | *del++ = '\0'; | ||
122 | else | ||
123 | del = pos + strlen(pos); | ||
124 | param->data = del; | ||
125 | return pos; | ||
126 | } | ||
127 | |||
18 | /** | 128 | /** |
19 | * tomoyo_parse_ulong - Parse an "unsigned long" value. | 129 | * tomoyo_parse_ulong - Parse an "unsigned long" value. |
20 | * | 130 | * |
21 | * @result: Pointer to "unsigned long". | 131 | * @result: Pointer to "unsigned long". |
22 | * @str: Pointer to string to parse. | 132 | * @str: Pointer to string to parse. |
23 | * | 133 | * |
24 | * Returns value type on success, 0 otherwise. | 134 | * Returns one of values in "enum tomoyo_value_type". |
25 | * | 135 | * |
26 | * The @src is updated to point the first character after the value | 136 | * The @src is updated to point the first character after the value |
27 | * on success. | 137 | * on success. |
28 | */ | 138 | */ |
29 | static u8 tomoyo_parse_ulong(unsigned long *result, char **str) | 139 | u8 tomoyo_parse_ulong(unsigned long *result, char **str) |
30 | { | 140 | { |
31 | const char *cp = *str; | 141 | const char *cp = *str; |
32 | char *ep; | 142 | char *ep; |
@@ -43,7 +153,7 @@ static u8 tomoyo_parse_ulong(unsigned long *result, char **str) | |||
43 | } | 153 | } |
44 | *result = simple_strtoul(cp, &ep, base); | 154 | *result = simple_strtoul(cp, &ep, base); |
45 | if (cp == ep) | 155 | if (cp == ep) |
46 | return 0; | 156 | return TOMOYO_VALUE_TYPE_INVALID; |
47 | *str = ep; | 157 | *str = ep; |
48 | switch (base) { | 158 | switch (base) { |
49 | case 16: | 159 | case 16: |
@@ -81,63 +191,65 @@ void tomoyo_print_ulong(char *buffer, const int buffer_len, | |||
81 | /** | 191 | /** |
82 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | 192 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. |
83 | * | 193 | * |
84 | * @filename: Name or name group. | 194 | * @param: Pointer to "struct tomoyo_acl_param". |
85 | * @ptr: Pointer to "struct tomoyo_name_union". | 195 | * @ptr: Pointer to "struct tomoyo_name_union". |
86 | * | 196 | * |
87 | * Returns true on success, false otherwise. | 197 | * Returns true on success, false otherwise. |
88 | */ | 198 | */ |
89 | bool tomoyo_parse_name_union(const char *filename, | 199 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, |
90 | struct tomoyo_name_union *ptr) | 200 | struct tomoyo_name_union *ptr) |
91 | { | 201 | { |
92 | if (!tomoyo_correct_word(filename)) | 202 | char *filename; |
93 | return false; | 203 | if (param->data[0] == '@') { |
94 | if (filename[0] == '@') { | 204 | param->data++; |
95 | ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP); | 205 | ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); |
96 | ptr->is_group = true; | ||
97 | return ptr->group != NULL; | 206 | return ptr->group != NULL; |
98 | } | 207 | } |
208 | filename = tomoyo_read_token(param); | ||
209 | if (!tomoyo_correct_word(filename)) | ||
210 | return false; | ||
99 | ptr->filename = tomoyo_get_name(filename); | 211 | ptr->filename = tomoyo_get_name(filename); |
100 | ptr->is_group = false; | ||
101 | return ptr->filename != NULL; | 212 | return ptr->filename != NULL; |
102 | } | 213 | } |
103 | 214 | ||
104 | /** | 215 | /** |
105 | * tomoyo_parse_number_union - Parse a tomoyo_number_union. | 216 | * tomoyo_parse_number_union - Parse a tomoyo_number_union. |
106 | * | 217 | * |
107 | * @data: Number or number range or number group. | 218 | * @param: Pointer to "struct tomoyo_acl_param". |
108 | * @ptr: Pointer to "struct tomoyo_number_union". | 219 | * @ptr: Pointer to "struct tomoyo_number_union". |
109 | * | 220 | * |
110 | * Returns true on success, false otherwise. | 221 | * Returns true on success, false otherwise. |
111 | */ | 222 | */ |
112 | bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) | 223 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, |
224 | struct tomoyo_number_union *ptr) | ||
113 | { | 225 | { |
226 | char *data; | ||
114 | u8 type; | 227 | u8 type; |
115 | unsigned long v; | 228 | unsigned long v; |
116 | memset(num, 0, sizeof(*num)); | 229 | memset(ptr, 0, sizeof(*ptr)); |
117 | if (data[0] == '@') { | 230 | if (param->data[0] == '@') { |
118 | if (!tomoyo_correct_word(data)) | 231 | param->data++; |
119 | return false; | 232 | ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP); |
120 | num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP); | 233 | return ptr->group != NULL; |
121 | num->is_group = true; | ||
122 | return num->group != NULL; | ||
123 | } | 234 | } |
235 | data = tomoyo_read_token(param); | ||
124 | type = tomoyo_parse_ulong(&v, &data); | 236 | type = tomoyo_parse_ulong(&v, &data); |
125 | if (!type) | 237 | if (type == TOMOYO_VALUE_TYPE_INVALID) |
126 | return false; | 238 | return false; |
127 | num->values[0] = v; | 239 | ptr->values[0] = v; |
128 | num->min_type = type; | 240 | ptr->value_type[0] = type; |
129 | if (!*data) { | 241 | if (!*data) { |
130 | num->values[1] = v; | 242 | ptr->values[1] = v; |
131 | num->max_type = type; | 243 | ptr->value_type[1] = type; |
132 | return true; | 244 | return true; |
133 | } | 245 | } |
134 | if (*data++ != '-') | 246 | if (*data++ != '-') |
135 | return false; | 247 | return false; |
136 | type = tomoyo_parse_ulong(&v, &data); | 248 | type = tomoyo_parse_ulong(&v, &data); |
137 | if (!type || *data) | 249 | if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v) |
138 | return false; | 250 | return false; |
139 | num->values[1] = v; | 251 | ptr->values[1] = v; |
140 | num->max_type = type; | 252 | ptr->value_type[1] = type; |
141 | return true; | 253 | return true; |
142 | } | 254 | } |
143 | 255 | ||
@@ -185,6 +297,30 @@ static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) | |||
185 | } | 297 | } |
186 | 298 | ||
187 | /** | 299 | /** |
300 | * tomoyo_valid - Check whether the character is a valid char. | ||
301 | * | ||
302 | * @c: The character to check. | ||
303 | * | ||
304 | * Returns true if @c is a valid character, false otherwise. | ||
305 | */ | ||
306 | static inline bool tomoyo_valid(const unsigned char c) | ||
307 | { | ||
308 | return c > ' ' && c < 127; | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * tomoyo_invalid - Check whether the character is an invalid char. | ||
313 | * | ||
314 | * @c: The character to check. | ||
315 | * | ||
316 | * Returns true if @c is an invalid character, false otherwise. | ||
317 | */ | ||
318 | static inline bool tomoyo_invalid(const unsigned char c) | ||
319 | { | ||
320 | return c && (c <= ' ' || c >= 127); | ||
321 | } | ||
322 | |||
323 | /** | ||
188 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. | 324 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. |
189 | * | 325 | * |
190 | * @src: Pointer to pointer to the string. | 326 | * @src: Pointer to pointer to the string. |
@@ -238,36 +374,9 @@ void tomoyo_normalize_line(unsigned char *buffer) | |||
238 | } | 374 | } |
239 | 375 | ||
240 | /** | 376 | /** |
241 | * tomoyo_tokenize - Tokenize string. | ||
242 | * | ||
243 | * @buffer: The line to tokenize. | ||
244 | * @w: Pointer to "char *". | ||
245 | * @size: Sizeof @w . | ||
246 | * | ||
247 | * Returns true on success, false otherwise. | ||
248 | */ | ||
249 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size) | ||
250 | { | ||
251 | int count = size / sizeof(char *); | ||
252 | int i; | ||
253 | for (i = 0; i < count; i++) | ||
254 | w[i] = ""; | ||
255 | for (i = 0; i < count; i++) { | ||
256 | char *cp = strchr(buffer, ' '); | ||
257 | if (cp) | ||
258 | *cp = '\0'; | ||
259 | w[i] = buffer; | ||
260 | if (!cp) | ||
261 | break; | ||
262 | buffer = cp + 1; | ||
263 | } | ||
264 | return i < count || !*buffer; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * tomoyo_correct_word2 - Validate a string. | 377 | * tomoyo_correct_word2 - Validate a string. |
269 | * | 378 | * |
270 | * @string: The string to check. May be non-'\0'-terminated. | 379 | * @string: The string to check. Maybe non-'\0'-terminated. |
271 | * @len: Length of @string. | 380 | * @len: Length of @string. |
272 | * | 381 | * |
273 | * Check whether the given string follows the naming rules. | 382 | * Check whether the given string follows the naming rules. |
@@ -377,26 +486,21 @@ bool tomoyo_correct_path(const char *filename) | |||
377 | */ | 486 | */ |
378 | bool tomoyo_correct_domain(const unsigned char *domainname) | 487 | bool tomoyo_correct_domain(const unsigned char *domainname) |
379 | { | 488 | { |
380 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | 489 | if (!domainname || !tomoyo_domain_def(domainname)) |
381 | TOMOYO_ROOT_NAME_LEN)) | 490 | return false; |
382 | goto out; | 491 | domainname = strchr(domainname, ' '); |
383 | domainname += TOMOYO_ROOT_NAME_LEN; | 492 | if (!domainname++) |
384 | if (!*domainname) | ||
385 | return true; | 493 | return true; |
386 | if (*domainname++ != ' ') | ||
387 | goto out; | ||
388 | while (1) { | 494 | while (1) { |
389 | const unsigned char *cp = strchr(domainname, ' '); | 495 | const unsigned char *cp = strchr(domainname, ' '); |
390 | if (!cp) | 496 | if (!cp) |
391 | break; | 497 | break; |
392 | if (*domainname != '/' || | 498 | if (*domainname != '/' || |
393 | !tomoyo_correct_word2(domainname, cp - domainname)) | 499 | !tomoyo_correct_word2(domainname, cp - domainname)) |
394 | goto out; | 500 | return false; |
395 | domainname = cp + 1; | 501 | domainname = cp + 1; |
396 | } | 502 | } |
397 | return tomoyo_correct_path(domainname); | 503 | return tomoyo_correct_path(domainname); |
398 | out: | ||
399 | return false; | ||
400 | } | 504 | } |
401 | 505 | ||
402 | /** | 506 | /** |
@@ -408,7 +512,19 @@ bool tomoyo_correct_domain(const unsigned char *domainname) | |||
408 | */ | 512 | */ |
409 | bool tomoyo_domain_def(const unsigned char *buffer) | 513 | bool tomoyo_domain_def(const unsigned char *buffer) |
410 | { | 514 | { |
411 | return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); | 515 | const unsigned char *cp; |
516 | int len; | ||
517 | if (*buffer != '<') | ||
518 | return false; | ||
519 | cp = strchr(buffer, ' '); | ||
520 | if (!cp) | ||
521 | len = strlen(buffer); | ||
522 | else | ||
523 | len = cp - buffer; | ||
524 | if (buffer[len - 1] != '>' || | ||
525 | !tomoyo_correct_word2(buffer + 1, len - 2)) | ||
526 | return false; | ||
527 | return true; | ||
412 | } | 528 | } |
413 | 529 | ||
414 | /** | 530 | /** |
@@ -794,22 +910,24 @@ const char *tomoyo_get_exe(void) | |||
794 | /** | 910 | /** |
795 | * tomoyo_get_mode - Get MAC mode. | 911 | * tomoyo_get_mode - Get MAC mode. |
796 | * | 912 | * |
913 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
797 | * @profile: Profile number. | 914 | * @profile: Profile number. |
798 | * @index: Index number of functionality. | 915 | * @index: Index number of functionality. |
799 | * | 916 | * |
800 | * Returns mode. | 917 | * Returns mode. |
801 | */ | 918 | */ |
802 | int tomoyo_get_mode(const u8 profile, const u8 index) | 919 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, |
920 | const u8 index) | ||
803 | { | 921 | { |
804 | u8 mode; | 922 | u8 mode; |
805 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; | 923 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; |
806 | if (!tomoyo_policy_loaded) | 924 | if (!tomoyo_policy_loaded) |
807 | return TOMOYO_CONFIG_DISABLED; | 925 | return TOMOYO_CONFIG_DISABLED; |
808 | mode = tomoyo_profile(profile)->config[index]; | 926 | mode = tomoyo_profile(ns, profile)->config[index]; |
809 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 927 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
810 | mode = tomoyo_profile(profile)->config[category]; | 928 | mode = tomoyo_profile(ns, profile)->config[category]; |
811 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 929 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
812 | mode = tomoyo_profile(profile)->default_config; | 930 | mode = tomoyo_profile(ns, profile)->default_config; |
813 | return mode & 3; | 931 | return mode & 3; |
814 | } | 932 | } |
815 | 933 | ||
@@ -833,65 +951,11 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, | |||
833 | profile = domain->profile; | 951 | profile = domain->profile; |
834 | r->profile = profile; | 952 | r->profile = profile; |
835 | r->type = index; | 953 | r->type = index; |
836 | r->mode = tomoyo_get_mode(profile, index); | 954 | r->mode = tomoyo_get_mode(domain->ns, profile, index); |
837 | return r->mode; | 955 | return r->mode; |
838 | } | 956 | } |
839 | 957 | ||
840 | /** | 958 | /** |
841 | * tomoyo_last_word - Get last component of a line. | ||
842 | * | ||
843 | * @line: A line. | ||
844 | * | ||
845 | * Returns the last word of a line. | ||
846 | */ | ||
847 | const char *tomoyo_last_word(const char *name) | ||
848 | { | ||
849 | const char *cp = strrchr(name, ' '); | ||
850 | if (cp) | ||
851 | return cp + 1; | ||
852 | return name; | ||
853 | } | ||
854 | |||
855 | /** | ||
856 | * tomoyo_warn_log - Print warning or error message on console. | ||
857 | * | ||
858 | * @r: Pointer to "struct tomoyo_request_info". | ||
859 | * @fmt: The printf()'s format string, followed by parameters. | ||
860 | */ | ||
861 | void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
862 | { | ||
863 | va_list args; | ||
864 | char *buffer; | ||
865 | const struct tomoyo_domain_info * const domain = r->domain; | ||
866 | const struct tomoyo_profile *profile = tomoyo_profile(domain->profile); | ||
867 | switch (r->mode) { | ||
868 | case TOMOYO_CONFIG_ENFORCING: | ||
869 | if (!profile->enforcing->enforcing_verbose) | ||
870 | return; | ||
871 | break; | ||
872 | case TOMOYO_CONFIG_PERMISSIVE: | ||
873 | if (!profile->permissive->permissive_verbose) | ||
874 | return; | ||
875 | break; | ||
876 | case TOMOYO_CONFIG_LEARNING: | ||
877 | if (!profile->learning->learning_verbose) | ||
878 | return; | ||
879 | break; | ||
880 | } | ||
881 | buffer = kmalloc(4096, GFP_NOFS); | ||
882 | if (!buffer) | ||
883 | return; | ||
884 | va_start(args, fmt); | ||
885 | vsnprintf(buffer, 4095, fmt, args); | ||
886 | va_end(args); | ||
887 | buffer[4095] = '\0'; | ||
888 | printk(KERN_WARNING "%s: Access %s denied for %s\n", | ||
889 | r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer, | ||
890 | tomoyo_last_word(domain->domainname->name)); | ||
891 | kfree(buffer); | ||
892 | } | ||
893 | |||
894 | /** | ||
895 | * tomoyo_domain_quota_is_ok - Check for domain's quota. | 959 | * tomoyo_domain_quota_is_ok - Check for domain's quota. |
896 | * | 960 | * |
897 | * @r: Pointer to "struct tomoyo_request_info". | 961 | * @r: Pointer to "struct tomoyo_request_info". |
@@ -911,52 +975,43 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
911 | if (!domain) | 975 | if (!domain) |
912 | return true; | 976 | return true; |
913 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 977 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
978 | u16 perm; | ||
979 | u8 i; | ||
914 | if (ptr->is_deleted) | 980 | if (ptr->is_deleted) |
915 | continue; | 981 | continue; |
916 | switch (ptr->type) { | 982 | switch (ptr->type) { |
917 | u16 perm; | ||
918 | u8 i; | ||
919 | case TOMOYO_TYPE_PATH_ACL: | 983 | case TOMOYO_TYPE_PATH_ACL: |
920 | perm = container_of(ptr, struct tomoyo_path_acl, head) | 984 | perm = container_of(ptr, struct tomoyo_path_acl, head) |
921 | ->perm; | 985 | ->perm; |
922 | for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) | ||
923 | if (perm & (1 << i)) | ||
924 | count++; | ||
925 | if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
926 | count -= 2; | ||
927 | break; | 986 | break; |
928 | case TOMOYO_TYPE_PATH2_ACL: | 987 | case TOMOYO_TYPE_PATH2_ACL: |
929 | perm = container_of(ptr, struct tomoyo_path2_acl, head) | 988 | perm = container_of(ptr, struct tomoyo_path2_acl, head) |
930 | ->perm; | 989 | ->perm; |
931 | for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) | ||
932 | if (perm & (1 << i)) | ||
933 | count++; | ||
934 | break; | 990 | break; |
935 | case TOMOYO_TYPE_PATH_NUMBER_ACL: | 991 | case TOMOYO_TYPE_PATH_NUMBER_ACL: |
936 | perm = container_of(ptr, struct tomoyo_path_number_acl, | 992 | perm = container_of(ptr, struct tomoyo_path_number_acl, |
937 | head)->perm; | 993 | head)->perm; |
938 | for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++) | ||
939 | if (perm & (1 << i)) | ||
940 | count++; | ||
941 | break; | 994 | break; |
942 | case TOMOYO_TYPE_MKDEV_ACL: | 995 | case TOMOYO_TYPE_MKDEV_ACL: |
943 | perm = container_of(ptr, struct tomoyo_mkdev_acl, | 996 | perm = container_of(ptr, struct tomoyo_mkdev_acl, |
944 | head)->perm; | 997 | head)->perm; |
945 | for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++) | ||
946 | if (perm & (1 << i)) | ||
947 | count++; | ||
948 | break; | 998 | break; |
949 | default: | 999 | default: |
950 | count++; | 1000 | perm = 1; |
951 | } | 1001 | } |
1002 | for (i = 0; i < 16; i++) | ||
1003 | if (perm & (1 << i)) | ||
1004 | count++; | ||
952 | } | 1005 | } |
953 | if (count < tomoyo_profile(domain->profile)->learning-> | 1006 | if (count < tomoyo_profile(domain->ns, domain->profile)-> |
954 | learning_max_entry) | 1007 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) |
955 | return true; | 1008 | return true; |
956 | if (!domain->quota_warned) { | 1009 | if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) { |
957 | domain->quota_warned = true; | 1010 | domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; |
958 | printk(KERN_WARNING "TOMOYO-WARNING: " | 1011 | /* r->granted = false; */ |
959 | "Domain '%s' has so many ACLs to hold. " | 1012 | tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); |
1013 | printk(KERN_WARNING "WARNING: " | ||
1014 | "Domain '%s' has too many ACLs to hold. " | ||
960 | "Stopped learning mode.\n", domain->domainname->name); | 1015 | "Stopped learning mode.\n", domain->domainname->name); |
961 | } | 1016 | } |
962 | return false; | 1017 | return false; |