Commit c3fa109a5894077d1eaf8731ea741a15dd117b3c
Committed by
James Morris
1 parent
5bf1692f65
Exists in
master
and in
39 other branches
TOMOYO: Add description of lists and structures.
This patch adds some descriptions of lists and structures. This patch contains no code changes. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Showing 6 changed files with 504 additions and 34 deletions Inline Diff
security/tomoyo/common.c
1 | /* | 1 | /* |
2 | * security/tomoyo/common.c | 2 | * security/tomoyo/common.c |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Common functions for TOMOYO. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * | 7 | * |
8 | * Version: 2.2.0 2009/04/01 | 8 | * Version: 2.2.0 2009/04/01 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
13 | #include <linux/security.h> | 13 | #include <linux/security.h> |
14 | #include <linux/hardirq.h> | 14 | #include <linux/hardirq.h> |
15 | #include "realpath.h" | 15 | #include "realpath.h" |
16 | #include "common.h" | 16 | #include "common.h" |
17 | #include "tomoyo.h" | 17 | #include "tomoyo.h" |
18 | 18 | ||
19 | /* Has loading policy done? */ | 19 | /* Has loading policy done? */ |
20 | bool tomoyo_policy_loaded; | 20 | bool tomoyo_policy_loaded; |
21 | 21 | ||
22 | /* String table for functionality that takes 4 modes. */ | 22 | /* String table for functionality that takes 4 modes. */ |
23 | static const char *tomoyo_mode_4[4] = { | 23 | static const char *tomoyo_mode_4[4] = { |
24 | "disabled", "learning", "permissive", "enforcing" | 24 | "disabled", "learning", "permissive", "enforcing" |
25 | }; | 25 | }; |
26 | /* String table for functionality that takes 2 modes. */ | 26 | /* String table for functionality that takes 2 modes. */ |
27 | static const char *tomoyo_mode_2[4] = { | 27 | static const char *tomoyo_mode_2[4] = { |
28 | "disabled", "enabled", "enabled", "enabled" | 28 | "disabled", "enabled", "enabled", "enabled" |
29 | }; | 29 | }; |
30 | 30 | ||
31 | /* Table for profile. */ | 31 | /* |
32 | * tomoyo_control_array is a static data which contains | ||
33 | * | ||
34 | * (1) functionality name used by /sys/kernel/security/tomoyo/profile . | ||
35 | * (2) initial values for "struct tomoyo_profile". | ||
36 | * (3) max values for "struct tomoyo_profile". | ||
37 | */ | ||
32 | static struct { | 38 | static struct { |
33 | const char *keyword; | 39 | const char *keyword; |
34 | unsigned int current_value; | 40 | unsigned int current_value; |
35 | const unsigned int max_value; | 41 | const unsigned int max_value; |
36 | } tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = { | 42 | } tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = { |
37 | [TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 }, | 43 | [TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 }, |
38 | [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX }, | 44 | [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX }, |
39 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, | 45 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, |
40 | }; | 46 | }; |
41 | 47 | ||
42 | /* Profile table. Memory is allocated as needed. */ | 48 | /* |
49 | * tomoyo_profile is a structure which is used for holding the mode of access | ||
50 | * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing. | ||
51 | * An administrator can define up to 256 profiles. | ||
52 | * The ->profile of "struct tomoyo_domain_info" is used for remembering | ||
53 | * the profile's number (0 - 255) assigned to that domain. | ||
54 | */ | ||
43 | static struct tomoyo_profile { | 55 | static struct tomoyo_profile { |
44 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; | 56 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; |
45 | const struct tomoyo_path_info *comment; | 57 | const struct tomoyo_path_info *comment; |
46 | } *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; | 58 | } *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; |
47 | 59 | ||
48 | /* Permit policy management by non-root user? */ | 60 | /* Permit policy management by non-root user? */ |
49 | static bool tomoyo_manage_by_non_root; | 61 | static bool tomoyo_manage_by_non_root; |
50 | 62 | ||
51 | /* Utility functions. */ | 63 | /* Utility functions. */ |
52 | 64 | ||
53 | /* Open operation for /sys/kernel/security/tomoyo/ interface. */ | 65 | /* Open operation for /sys/kernel/security/tomoyo/ interface. */ |
54 | static int tomoyo_open_control(const u8 type, struct file *file); | 66 | static int tomoyo_open_control(const u8 type, struct file *file); |
55 | /* Close /sys/kernel/security/tomoyo/ interface. */ | 67 | /* Close /sys/kernel/security/tomoyo/ interface. */ |
56 | static int tomoyo_close_control(struct file *file); | 68 | static int tomoyo_close_control(struct file *file); |
57 | /* Read operation for /sys/kernel/security/tomoyo/ interface. */ | 69 | /* Read operation for /sys/kernel/security/tomoyo/ interface. */ |
58 | static int tomoyo_read_control(struct file *file, char __user *buffer, | 70 | static int tomoyo_read_control(struct file *file, char __user *buffer, |
59 | const int buffer_len); | 71 | const int buffer_len); |
60 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ | 72 | /* Write operation for /sys/kernel/security/tomoyo/ interface. */ |
61 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | 73 | static int tomoyo_write_control(struct file *file, const char __user *buffer, |
62 | const int buffer_len); | 74 | const int buffer_len); |
63 | 75 | ||
64 | /** | 76 | /** |
65 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. | 77 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. |
66 | * | 78 | * |
67 | * @str: Pointer to the string. | 79 | * @str: Pointer to the string. |
68 | * | 80 | * |
69 | * Returns true if @str is a \ooo style octal value, false otherwise. | 81 | * Returns true if @str is a \ooo style octal value, false otherwise. |
70 | * | 82 | * |
71 | * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. | 83 | * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. |
72 | * This function verifies that \ooo is in valid range. | 84 | * This function verifies that \ooo is in valid range. |
73 | */ | 85 | */ |
74 | static inline bool tomoyo_is_byte_range(const char *str) | 86 | static inline bool tomoyo_is_byte_range(const char *str) |
75 | { | 87 | { |
76 | return *str >= '0' && *str++ <= '3' && | 88 | return *str >= '0' && *str++ <= '3' && |
77 | *str >= '0' && *str++ <= '7' && | 89 | *str >= '0' && *str++ <= '7' && |
78 | *str >= '0' && *str <= '7'; | 90 | *str >= '0' && *str <= '7'; |
79 | } | 91 | } |
80 | 92 | ||
81 | /** | 93 | /** |
82 | * tomoyo_is_alphabet_char - Check whether the character is an alphabet. | 94 | * tomoyo_is_alphabet_char - Check whether the character is an alphabet. |
83 | * | 95 | * |
84 | * @c: The character to check. | 96 | * @c: The character to check. |
85 | * | 97 | * |
86 | * Returns true if @c is an alphabet character, false otherwise. | 98 | * Returns true if @c is an alphabet character, false otherwise. |
87 | */ | 99 | */ |
88 | static inline bool tomoyo_is_alphabet_char(const char c) | 100 | static inline bool tomoyo_is_alphabet_char(const char c) |
89 | { | 101 | { |
90 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); | 102 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); |
91 | } | 103 | } |
92 | 104 | ||
93 | /** | 105 | /** |
94 | * tomoyo_make_byte - Make byte value from three octal characters. | 106 | * tomoyo_make_byte - Make byte value from three octal characters. |
95 | * | 107 | * |
96 | * @c1: The first character. | 108 | * @c1: The first character. |
97 | * @c2: The second character. | 109 | * @c2: The second character. |
98 | * @c3: The third character. | 110 | * @c3: The third character. |
99 | * | 111 | * |
100 | * Returns byte value. | 112 | * Returns byte value. |
101 | */ | 113 | */ |
102 | static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) | 114 | static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) |
103 | { | 115 | { |
104 | return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); | 116 | return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); |
105 | } | 117 | } |
106 | 118 | ||
107 | /** | 119 | /** |
108 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. | 120 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. |
109 | * | 121 | * |
110 | * @src: Pointer to pointer to the string. | 122 | * @src: Pointer to pointer to the string. |
111 | * @find: Pointer to the keyword. | 123 | * @find: Pointer to the keyword. |
112 | * | 124 | * |
113 | * Returns true if @src starts with @find, false otherwise. | 125 | * Returns true if @src starts with @find, false otherwise. |
114 | * | 126 | * |
115 | * The @src is updated to point the first character after the @find | 127 | * The @src is updated to point the first character after the @find |
116 | * if @src starts with @find. | 128 | * if @src starts with @find. |
117 | */ | 129 | */ |
118 | static bool tomoyo_str_starts(char **src, const char *find) | 130 | static bool tomoyo_str_starts(char **src, const char *find) |
119 | { | 131 | { |
120 | const int len = strlen(find); | 132 | const int len = strlen(find); |
121 | char *tmp = *src; | 133 | char *tmp = *src; |
122 | 134 | ||
123 | if (strncmp(tmp, find, len)) | 135 | if (strncmp(tmp, find, len)) |
124 | return false; | 136 | return false; |
125 | tmp += len; | 137 | tmp += len; |
126 | *src = tmp; | 138 | *src = tmp; |
127 | return true; | 139 | return true; |
128 | } | 140 | } |
129 | 141 | ||
130 | /** | 142 | /** |
131 | * tomoyo_normalize_line - Format string. | 143 | * tomoyo_normalize_line - Format string. |
132 | * | 144 | * |
133 | * @buffer: The line to normalize. | 145 | * @buffer: The line to normalize. |
134 | * | 146 | * |
135 | * Leading and trailing whitespaces are removed. | 147 | * Leading and trailing whitespaces are removed. |
136 | * Multiple whitespaces are packed into single space. | 148 | * Multiple whitespaces are packed into single space. |
137 | * | 149 | * |
138 | * Returns nothing. | 150 | * Returns nothing. |
139 | */ | 151 | */ |
140 | static void tomoyo_normalize_line(unsigned char *buffer) | 152 | static void tomoyo_normalize_line(unsigned char *buffer) |
141 | { | 153 | { |
142 | unsigned char *sp = buffer; | 154 | unsigned char *sp = buffer; |
143 | unsigned char *dp = buffer; | 155 | unsigned char *dp = buffer; |
144 | bool first = true; | 156 | bool first = true; |
145 | 157 | ||
146 | while (tomoyo_is_invalid(*sp)) | 158 | while (tomoyo_is_invalid(*sp)) |
147 | sp++; | 159 | sp++; |
148 | while (*sp) { | 160 | while (*sp) { |
149 | if (!first) | 161 | if (!first) |
150 | *dp++ = ' '; | 162 | *dp++ = ' '; |
151 | first = false; | 163 | first = false; |
152 | while (tomoyo_is_valid(*sp)) | 164 | while (tomoyo_is_valid(*sp)) |
153 | *dp++ = *sp++; | 165 | *dp++ = *sp++; |
154 | while (tomoyo_is_invalid(*sp)) | 166 | while (tomoyo_is_invalid(*sp)) |
155 | sp++; | 167 | sp++; |
156 | } | 168 | } |
157 | *dp = '\0'; | 169 | *dp = '\0'; |
158 | } | 170 | } |
159 | 171 | ||
160 | /** | 172 | /** |
161 | * tomoyo_is_correct_path - Validate a pathname. | 173 | * tomoyo_is_correct_path - Validate a pathname. |
162 | * @filename: The pathname to check. | 174 | * @filename: The pathname to check. |
163 | * @start_type: Should the pathname start with '/'? | 175 | * @start_type: Should the pathname start with '/'? |
164 | * 1 = must / -1 = must not / 0 = don't care | 176 | * 1 = must / -1 = must not / 0 = don't care |
165 | * @pattern_type: Can the pathname contain a wildcard? | 177 | * @pattern_type: Can the pathname contain a wildcard? |
166 | * 1 = must / -1 = must not / 0 = don't care | 178 | * 1 = must / -1 = must not / 0 = don't care |
167 | * @end_type: Should the pathname end with '/'? | 179 | * @end_type: Should the pathname end with '/'? |
168 | * 1 = must / -1 = must not / 0 = don't care | 180 | * 1 = must / -1 = must not / 0 = don't care |
169 | * @function: The name of function calling me. | 181 | * @function: The name of function calling me. |
170 | * | 182 | * |
171 | * Check whether the given filename follows the naming rules. | 183 | * Check whether the given filename follows the naming rules. |
172 | * Returns true if @filename follows the naming rules, false otherwise. | 184 | * Returns true if @filename follows the naming rules, false otherwise. |
173 | */ | 185 | */ |
174 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | 186 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, |
175 | const s8 pattern_type, const s8 end_type, | 187 | const s8 pattern_type, const s8 end_type, |
176 | const char *function) | 188 | const char *function) |
177 | { | 189 | { |
178 | bool contains_pattern = false; | 190 | bool contains_pattern = false; |
179 | unsigned char c; | 191 | unsigned char c; |
180 | unsigned char d; | 192 | unsigned char d; |
181 | unsigned char e; | 193 | unsigned char e; |
182 | const char *original_filename = filename; | 194 | const char *original_filename = filename; |
183 | 195 | ||
184 | if (!filename) | 196 | if (!filename) |
185 | goto out; | 197 | goto out; |
186 | c = *filename; | 198 | c = *filename; |
187 | if (start_type == 1) { /* Must start with '/' */ | 199 | if (start_type == 1) { /* Must start with '/' */ |
188 | if (c != '/') | 200 | if (c != '/') |
189 | goto out; | 201 | goto out; |
190 | } else if (start_type == -1) { /* Must not start with '/' */ | 202 | } else if (start_type == -1) { /* Must not start with '/' */ |
191 | if (c == '/') | 203 | if (c == '/') |
192 | goto out; | 204 | goto out; |
193 | } | 205 | } |
194 | if (c) | 206 | if (c) |
195 | c = *(filename + strlen(filename) - 1); | 207 | c = *(filename + strlen(filename) - 1); |
196 | if (end_type == 1) { /* Must end with '/' */ | 208 | if (end_type == 1) { /* Must end with '/' */ |
197 | if (c != '/') | 209 | if (c != '/') |
198 | goto out; | 210 | goto out; |
199 | } else if (end_type == -1) { /* Must not end with '/' */ | 211 | } else if (end_type == -1) { /* Must not end with '/' */ |
200 | if (c == '/') | 212 | if (c == '/') |
201 | goto out; | 213 | goto out; |
202 | } | 214 | } |
203 | while ((c = *filename++) != '\0') { | 215 | while ((c = *filename++) != '\0') { |
204 | if (c == '\\') { | 216 | if (c == '\\') { |
205 | switch ((c = *filename++)) { | 217 | switch ((c = *filename++)) { |
206 | case '\\': /* "\\" */ | 218 | case '\\': /* "\\" */ |
207 | continue; | 219 | continue; |
208 | case '$': /* "\$" */ | 220 | case '$': /* "\$" */ |
209 | case '+': /* "\+" */ | 221 | case '+': /* "\+" */ |
210 | case '?': /* "\?" */ | 222 | case '?': /* "\?" */ |
211 | case '*': /* "\*" */ | 223 | case '*': /* "\*" */ |
212 | case '@': /* "\@" */ | 224 | case '@': /* "\@" */ |
213 | case 'x': /* "\x" */ | 225 | case 'x': /* "\x" */ |
214 | case 'X': /* "\X" */ | 226 | case 'X': /* "\X" */ |
215 | case 'a': /* "\a" */ | 227 | case 'a': /* "\a" */ |
216 | case 'A': /* "\A" */ | 228 | case 'A': /* "\A" */ |
217 | case '-': /* "\-" */ | 229 | case '-': /* "\-" */ |
218 | if (pattern_type == -1) | 230 | if (pattern_type == -1) |
219 | break; /* Must not contain pattern */ | 231 | break; /* Must not contain pattern */ |
220 | contains_pattern = true; | 232 | contains_pattern = true; |
221 | continue; | 233 | continue; |
222 | case '0': /* "\ooo" */ | 234 | case '0': /* "\ooo" */ |
223 | case '1': | 235 | case '1': |
224 | case '2': | 236 | case '2': |
225 | case '3': | 237 | case '3': |
226 | d = *filename++; | 238 | d = *filename++; |
227 | if (d < '0' || d > '7') | 239 | if (d < '0' || d > '7') |
228 | break; | 240 | break; |
229 | e = *filename++; | 241 | e = *filename++; |
230 | if (e < '0' || e > '7') | 242 | if (e < '0' || e > '7') |
231 | break; | 243 | break; |
232 | c = tomoyo_make_byte(c, d, e); | 244 | c = tomoyo_make_byte(c, d, e); |
233 | if (tomoyo_is_invalid(c)) | 245 | if (tomoyo_is_invalid(c)) |
234 | continue; /* pattern is not \000 */ | 246 | continue; /* pattern is not \000 */ |
235 | } | 247 | } |
236 | goto out; | 248 | goto out; |
237 | } else if (tomoyo_is_invalid(c)) { | 249 | } else if (tomoyo_is_invalid(c)) { |
238 | goto out; | 250 | goto out; |
239 | } | 251 | } |
240 | } | 252 | } |
241 | if (pattern_type == 1) { /* Must contain pattern */ | 253 | if (pattern_type == 1) { /* Must contain pattern */ |
242 | if (!contains_pattern) | 254 | if (!contains_pattern) |
243 | goto out; | 255 | goto out; |
244 | } | 256 | } |
245 | return true; | 257 | return true; |
246 | out: | 258 | out: |
247 | printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, | 259 | printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, |
248 | original_filename); | 260 | original_filename); |
249 | return false; | 261 | return false; |
250 | } | 262 | } |
251 | 263 | ||
252 | /** | 264 | /** |
253 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. | 265 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. |
254 | * @domainname: The domainname to check. | 266 | * @domainname: The domainname to check. |
255 | * @function: The name of function calling me. | 267 | * @function: The name of function calling me. |
256 | * | 268 | * |
257 | * Returns true if @domainname follows the naming rules, false otherwise. | 269 | * Returns true if @domainname follows the naming rules, false otherwise. |
258 | */ | 270 | */ |
259 | bool tomoyo_is_correct_domain(const unsigned char *domainname, | 271 | bool tomoyo_is_correct_domain(const unsigned char *domainname, |
260 | const char *function) | 272 | const char *function) |
261 | { | 273 | { |
262 | unsigned char c; | 274 | unsigned char c; |
263 | unsigned char d; | 275 | unsigned char d; |
264 | unsigned char e; | 276 | unsigned char e; |
265 | const char *org_domainname = domainname; | 277 | const char *org_domainname = domainname; |
266 | 278 | ||
267 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | 279 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, |
268 | TOMOYO_ROOT_NAME_LEN)) | 280 | TOMOYO_ROOT_NAME_LEN)) |
269 | goto out; | 281 | goto out; |
270 | domainname += TOMOYO_ROOT_NAME_LEN; | 282 | domainname += TOMOYO_ROOT_NAME_LEN; |
271 | if (!*domainname) | 283 | if (!*domainname) |
272 | return true; | 284 | return true; |
273 | do { | 285 | do { |
274 | if (*domainname++ != ' ') | 286 | if (*domainname++ != ' ') |
275 | goto out; | 287 | goto out; |
276 | if (*domainname++ != '/') | 288 | if (*domainname++ != '/') |
277 | goto out; | 289 | goto out; |
278 | while ((c = *domainname) != '\0' && c != ' ') { | 290 | while ((c = *domainname) != '\0' && c != ' ') { |
279 | domainname++; | 291 | domainname++; |
280 | if (c == '\\') { | 292 | if (c == '\\') { |
281 | c = *domainname++; | 293 | c = *domainname++; |
282 | switch ((c)) { | 294 | switch ((c)) { |
283 | case '\\': /* "\\" */ | 295 | case '\\': /* "\\" */ |
284 | continue; | 296 | continue; |
285 | case '0': /* "\ooo" */ | 297 | case '0': /* "\ooo" */ |
286 | case '1': | 298 | case '1': |
287 | case '2': | 299 | case '2': |
288 | case '3': | 300 | case '3': |
289 | d = *domainname++; | 301 | d = *domainname++; |
290 | if (d < '0' || d > '7') | 302 | if (d < '0' || d > '7') |
291 | break; | 303 | break; |
292 | e = *domainname++; | 304 | e = *domainname++; |
293 | if (e < '0' || e > '7') | 305 | if (e < '0' || e > '7') |
294 | break; | 306 | break; |
295 | c = tomoyo_make_byte(c, d, e); | 307 | c = tomoyo_make_byte(c, d, e); |
296 | if (tomoyo_is_invalid(c)) | 308 | if (tomoyo_is_invalid(c)) |
297 | /* pattern is not \000 */ | 309 | /* pattern is not \000 */ |
298 | continue; | 310 | continue; |
299 | } | 311 | } |
300 | goto out; | 312 | goto out; |
301 | } else if (tomoyo_is_invalid(c)) { | 313 | } else if (tomoyo_is_invalid(c)) { |
302 | goto out; | 314 | goto out; |
303 | } | 315 | } |
304 | } | 316 | } |
305 | } while (*domainname); | 317 | } while (*domainname); |
306 | return true; | 318 | return true; |
307 | out: | 319 | out: |
308 | printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, | 320 | printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, |
309 | org_domainname); | 321 | org_domainname); |
310 | return false; | 322 | return false; |
311 | } | 323 | } |
312 | 324 | ||
313 | /** | 325 | /** |
314 | * tomoyo_is_domain_def - Check whether the given token can be a domainname. | 326 | * tomoyo_is_domain_def - Check whether the given token can be a domainname. |
315 | * | 327 | * |
316 | * @buffer: The token to check. | 328 | * @buffer: The token to check. |
317 | * | 329 | * |
318 | * Returns true if @buffer possibly be a domainname, false otherwise. | 330 | * Returns true if @buffer possibly be a domainname, false otherwise. |
319 | */ | 331 | */ |
320 | bool tomoyo_is_domain_def(const unsigned char *buffer) | 332 | bool tomoyo_is_domain_def(const unsigned char *buffer) |
321 | { | 333 | { |
322 | return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); | 334 | return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); |
323 | } | 335 | } |
324 | 336 | ||
325 | /** | 337 | /** |
326 | * tomoyo_find_domain - Find a domain by the given name. | 338 | * tomoyo_find_domain - Find a domain by the given name. |
327 | * | 339 | * |
328 | * @domainname: The domainname to find. | 340 | * @domainname: The domainname to find. |
329 | * | 341 | * |
330 | * Caller must call down_read(&tomoyo_domain_list_lock); or | 342 | * Caller must call down_read(&tomoyo_domain_list_lock); or |
331 | * down_write(&tomoyo_domain_list_lock); . | 343 | * down_write(&tomoyo_domain_list_lock); . |
332 | * | 344 | * |
333 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. | 345 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. |
334 | */ | 346 | */ |
335 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | 347 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) |
336 | { | 348 | { |
337 | struct tomoyo_domain_info *domain; | 349 | struct tomoyo_domain_info *domain; |
338 | struct tomoyo_path_info name; | 350 | struct tomoyo_path_info name; |
339 | 351 | ||
340 | name.name = domainname; | 352 | name.name = domainname; |
341 | tomoyo_fill_path_info(&name); | 353 | tomoyo_fill_path_info(&name); |
342 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 354 | list_for_each_entry(domain, &tomoyo_domain_list, list) { |
343 | if (!domain->is_deleted && | 355 | if (!domain->is_deleted && |
344 | !tomoyo_pathcmp(&name, domain->domainname)) | 356 | !tomoyo_pathcmp(&name, domain->domainname)) |
345 | return domain; | 357 | return domain; |
346 | } | 358 | } |
347 | return NULL; | 359 | return NULL; |
348 | } | 360 | } |
349 | 361 | ||
350 | /** | 362 | /** |
351 | * tomoyo_path_depth - Evaluate the number of '/' in a string. | 363 | * tomoyo_path_depth - Evaluate the number of '/' in a string. |
352 | * | 364 | * |
353 | * @pathname: The string to evaluate. | 365 | * @pathname: The string to evaluate. |
354 | * | 366 | * |
355 | * Returns path depth of the string. | 367 | * Returns path depth of the string. |
356 | * | 368 | * |
357 | * I score 2 for each of the '/' in the @pathname | 369 | * I score 2 for each of the '/' in the @pathname |
358 | * and score 1 if the @pathname ends with '/'. | 370 | * and score 1 if the @pathname ends with '/'. |
359 | */ | 371 | */ |
360 | static int tomoyo_path_depth(const char *pathname) | 372 | static int tomoyo_path_depth(const char *pathname) |
361 | { | 373 | { |
362 | int i = 0; | 374 | int i = 0; |
363 | 375 | ||
364 | if (pathname) { | 376 | if (pathname) { |
365 | const char *ep = pathname + strlen(pathname); | 377 | const char *ep = pathname + strlen(pathname); |
366 | if (pathname < ep--) { | 378 | if (pathname < ep--) { |
367 | if (*ep != '/') | 379 | if (*ep != '/') |
368 | i++; | 380 | i++; |
369 | while (pathname <= ep) | 381 | while (pathname <= ep) |
370 | if (*ep-- == '/') | 382 | if (*ep-- == '/') |
371 | i += 2; | 383 | i += 2; |
372 | } | 384 | } |
373 | } | 385 | } |
374 | return i; | 386 | return i; |
375 | } | 387 | } |
376 | 388 | ||
377 | /** | 389 | /** |
378 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. | 390 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. |
379 | * | 391 | * |
380 | * @filename: The string to evaluate. | 392 | * @filename: The string to evaluate. |
381 | * | 393 | * |
382 | * Returns the initial length without a pattern in @filename. | 394 | * Returns the initial length without a pattern in @filename. |
383 | */ | 395 | */ |
384 | static int tomoyo_const_part_length(const char *filename) | 396 | static int tomoyo_const_part_length(const char *filename) |
385 | { | 397 | { |
386 | char c; | 398 | char c; |
387 | int len = 0; | 399 | int len = 0; |
388 | 400 | ||
389 | if (!filename) | 401 | if (!filename) |
390 | return 0; | 402 | return 0; |
391 | while ((c = *filename++) != '\0') { | 403 | while ((c = *filename++) != '\0') { |
392 | if (c != '\\') { | 404 | if (c != '\\') { |
393 | len++; | 405 | len++; |
394 | continue; | 406 | continue; |
395 | } | 407 | } |
396 | c = *filename++; | 408 | c = *filename++; |
397 | switch (c) { | 409 | switch (c) { |
398 | case '\\': /* "\\" */ | 410 | case '\\': /* "\\" */ |
399 | len += 2; | 411 | len += 2; |
400 | continue; | 412 | continue; |
401 | case '0': /* "\ooo" */ | 413 | case '0': /* "\ooo" */ |
402 | case '1': | 414 | case '1': |
403 | case '2': | 415 | case '2': |
404 | case '3': | 416 | case '3': |
405 | c = *filename++; | 417 | c = *filename++; |
406 | if (c < '0' || c > '7') | 418 | if (c < '0' || c > '7') |
407 | break; | 419 | break; |
408 | c = *filename++; | 420 | c = *filename++; |
409 | if (c < '0' || c > '7') | 421 | if (c < '0' || c > '7') |
410 | break; | 422 | break; |
411 | len += 4; | 423 | len += 4; |
412 | continue; | 424 | continue; |
413 | } | 425 | } |
414 | break; | 426 | break; |
415 | } | 427 | } |
416 | return len; | 428 | return len; |
417 | } | 429 | } |
418 | 430 | ||
419 | /** | 431 | /** |
420 | * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. | 432 | * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. |
421 | * | 433 | * |
422 | * @ptr: Pointer to "struct tomoyo_path_info" to fill in. | 434 | * @ptr: Pointer to "struct tomoyo_path_info" to fill in. |
423 | * | 435 | * |
424 | * The caller sets "struct tomoyo_path_info"->name. | 436 | * The caller sets "struct tomoyo_path_info"->name. |
425 | */ | 437 | */ |
426 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | 438 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) |
427 | { | 439 | { |
428 | const char *name = ptr->name; | 440 | const char *name = ptr->name; |
429 | const int len = strlen(name); | 441 | const int len = strlen(name); |
430 | 442 | ||
431 | ptr->const_len = tomoyo_const_part_length(name); | 443 | ptr->const_len = tomoyo_const_part_length(name); |
432 | ptr->is_dir = len && (name[len - 1] == '/'); | 444 | ptr->is_dir = len && (name[len - 1] == '/'); |
433 | ptr->is_patterned = (ptr->const_len < len); | 445 | ptr->is_patterned = (ptr->const_len < len); |
434 | ptr->hash = full_name_hash(name, len); | 446 | ptr->hash = full_name_hash(name, len); |
435 | ptr->depth = tomoyo_path_depth(name); | 447 | ptr->depth = tomoyo_path_depth(name); |
436 | } | 448 | } |
437 | 449 | ||
438 | /** | 450 | /** |
439 | * tomoyo_file_matches_to_pattern2 - Pattern matching without '/' character | 451 | * tomoyo_file_matches_to_pattern2 - Pattern matching without '/' character |
440 | * and "\-" pattern. | 452 | * and "\-" pattern. |
441 | * | 453 | * |
442 | * @filename: The start of string to check. | 454 | * @filename: The start of string to check. |
443 | * @filename_end: The end of string to check. | 455 | * @filename_end: The end of string to check. |
444 | * @pattern: The start of pattern to compare. | 456 | * @pattern: The start of pattern to compare. |
445 | * @pattern_end: The end of pattern to compare. | 457 | * @pattern_end: The end of pattern to compare. |
446 | * | 458 | * |
447 | * Returns true if @filename matches @pattern, false otherwise. | 459 | * Returns true if @filename matches @pattern, false otherwise. |
448 | */ | 460 | */ |
449 | static bool tomoyo_file_matches_to_pattern2(const char *filename, | 461 | static bool tomoyo_file_matches_to_pattern2(const char *filename, |
450 | const char *filename_end, | 462 | const char *filename_end, |
451 | const char *pattern, | 463 | const char *pattern, |
452 | const char *pattern_end) | 464 | const char *pattern_end) |
453 | { | 465 | { |
454 | while (filename < filename_end && pattern < pattern_end) { | 466 | while (filename < filename_end && pattern < pattern_end) { |
455 | char c; | 467 | char c; |
456 | if (*pattern != '\\') { | 468 | if (*pattern != '\\') { |
457 | if (*filename++ != *pattern++) | 469 | if (*filename++ != *pattern++) |
458 | return false; | 470 | return false; |
459 | continue; | 471 | continue; |
460 | } | 472 | } |
461 | c = *filename; | 473 | c = *filename; |
462 | pattern++; | 474 | pattern++; |
463 | switch (*pattern) { | 475 | switch (*pattern) { |
464 | int i; | 476 | int i; |
465 | int j; | 477 | int j; |
466 | case '?': | 478 | case '?': |
467 | if (c == '/') { | 479 | if (c == '/') { |
468 | return false; | 480 | return false; |
469 | } else if (c == '\\') { | 481 | } else if (c == '\\') { |
470 | if (filename[1] == '\\') | 482 | if (filename[1] == '\\') |
471 | filename++; | 483 | filename++; |
472 | else if (tomoyo_is_byte_range(filename + 1)) | 484 | else if (tomoyo_is_byte_range(filename + 1)) |
473 | filename += 3; | 485 | filename += 3; |
474 | else | 486 | else |
475 | return false; | 487 | return false; |
476 | } | 488 | } |
477 | break; | 489 | break; |
478 | case '\\': | 490 | case '\\': |
479 | if (c != '\\') | 491 | if (c != '\\') |
480 | return false; | 492 | return false; |
481 | if (*++filename != '\\') | 493 | if (*++filename != '\\') |
482 | return false; | 494 | return false; |
483 | break; | 495 | break; |
484 | case '+': | 496 | case '+': |
485 | if (!isdigit(c)) | 497 | if (!isdigit(c)) |
486 | return false; | 498 | return false; |
487 | break; | 499 | break; |
488 | case 'x': | 500 | case 'x': |
489 | if (!isxdigit(c)) | 501 | if (!isxdigit(c)) |
490 | return false; | 502 | return false; |
491 | break; | 503 | break; |
492 | case 'a': | 504 | case 'a': |
493 | if (!tomoyo_is_alphabet_char(c)) | 505 | if (!tomoyo_is_alphabet_char(c)) |
494 | return false; | 506 | return false; |
495 | break; | 507 | break; |
496 | case '0': | 508 | case '0': |
497 | case '1': | 509 | case '1': |
498 | case '2': | 510 | case '2': |
499 | case '3': | 511 | case '3': |
500 | if (c == '\\' && tomoyo_is_byte_range(filename + 1) | 512 | if (c == '\\' && tomoyo_is_byte_range(filename + 1) |
501 | && strncmp(filename + 1, pattern, 3) == 0) { | 513 | && strncmp(filename + 1, pattern, 3) == 0) { |
502 | filename += 3; | 514 | filename += 3; |
503 | pattern += 2; | 515 | pattern += 2; |
504 | break; | 516 | break; |
505 | } | 517 | } |
506 | return false; /* Not matched. */ | 518 | return false; /* Not matched. */ |
507 | case '*': | 519 | case '*': |
508 | case '@': | 520 | case '@': |
509 | for (i = 0; i <= filename_end - filename; i++) { | 521 | for (i = 0; i <= filename_end - filename; i++) { |
510 | if (tomoyo_file_matches_to_pattern2( | 522 | if (tomoyo_file_matches_to_pattern2( |
511 | filename + i, filename_end, | 523 | filename + i, filename_end, |
512 | pattern + 1, pattern_end)) | 524 | pattern + 1, pattern_end)) |
513 | return true; | 525 | return true; |
514 | c = filename[i]; | 526 | c = filename[i]; |
515 | if (c == '.' && *pattern == '@') | 527 | if (c == '.' && *pattern == '@') |
516 | break; | 528 | break; |
517 | if (c != '\\') | 529 | if (c != '\\') |
518 | continue; | 530 | continue; |
519 | if (filename[i + 1] == '\\') | 531 | if (filename[i + 1] == '\\') |
520 | i++; | 532 | i++; |
521 | else if (tomoyo_is_byte_range(filename + i + 1)) | 533 | else if (tomoyo_is_byte_range(filename + i + 1)) |
522 | i += 3; | 534 | i += 3; |
523 | else | 535 | else |
524 | break; /* Bad pattern. */ | 536 | break; /* Bad pattern. */ |
525 | } | 537 | } |
526 | return false; /* Not matched. */ | 538 | return false; /* Not matched. */ |
527 | default: | 539 | default: |
528 | j = 0; | 540 | j = 0; |
529 | c = *pattern; | 541 | c = *pattern; |
530 | if (c == '$') { | 542 | if (c == '$') { |
531 | while (isdigit(filename[j])) | 543 | while (isdigit(filename[j])) |
532 | j++; | 544 | j++; |
533 | } else if (c == 'X') { | 545 | } else if (c == 'X') { |
534 | while (isxdigit(filename[j])) | 546 | while (isxdigit(filename[j])) |
535 | j++; | 547 | j++; |
536 | } else if (c == 'A') { | 548 | } else if (c == 'A') { |
537 | while (tomoyo_is_alphabet_char(filename[j])) | 549 | while (tomoyo_is_alphabet_char(filename[j])) |
538 | j++; | 550 | j++; |
539 | } | 551 | } |
540 | for (i = 1; i <= j; i++) { | 552 | for (i = 1; i <= j; i++) { |
541 | if (tomoyo_file_matches_to_pattern2( | 553 | if (tomoyo_file_matches_to_pattern2( |
542 | filename + i, filename_end, | 554 | filename + i, filename_end, |
543 | pattern + 1, pattern_end)) | 555 | pattern + 1, pattern_end)) |
544 | return true; | 556 | return true; |
545 | } | 557 | } |
546 | return false; /* Not matched or bad pattern. */ | 558 | return false; /* Not matched or bad pattern. */ |
547 | } | 559 | } |
548 | filename++; | 560 | filename++; |
549 | pattern++; | 561 | pattern++; |
550 | } | 562 | } |
551 | while (*pattern == '\\' && | 563 | while (*pattern == '\\' && |
552 | (*(pattern + 1) == '*' || *(pattern + 1) == '@')) | 564 | (*(pattern + 1) == '*' || *(pattern + 1) == '@')) |
553 | pattern += 2; | 565 | pattern += 2; |
554 | return filename == filename_end && pattern == pattern_end; | 566 | return filename == filename_end && pattern == pattern_end; |
555 | } | 567 | } |
556 | 568 | ||
557 | /** | 569 | /** |
558 | * tomoyo_file_matches_to_pattern - Pattern matching without without '/' character. | 570 | * tomoyo_file_matches_to_pattern - Pattern matching without without '/' character. |
559 | * | 571 | * |
560 | * @filename: The start of string to check. | 572 | * @filename: The start of string to check. |
561 | * @filename_end: The end of string to check. | 573 | * @filename_end: The end of string to check. |
562 | * @pattern: The start of pattern to compare. | 574 | * @pattern: The start of pattern to compare. |
563 | * @pattern_end: The end of pattern to compare. | 575 | * @pattern_end: The end of pattern to compare. |
564 | * | 576 | * |
565 | * Returns true if @filename matches @pattern, false otherwise. | 577 | * Returns true if @filename matches @pattern, false otherwise. |
566 | */ | 578 | */ |
567 | static bool tomoyo_file_matches_to_pattern(const char *filename, | 579 | static bool tomoyo_file_matches_to_pattern(const char *filename, |
568 | const char *filename_end, | 580 | const char *filename_end, |
569 | const char *pattern, | 581 | const char *pattern, |
570 | const char *pattern_end) | 582 | const char *pattern_end) |
571 | { | 583 | { |
572 | const char *pattern_start = pattern; | 584 | const char *pattern_start = pattern; |
573 | bool first = true; | 585 | bool first = true; |
574 | bool result; | 586 | bool result; |
575 | 587 | ||
576 | while (pattern < pattern_end - 1) { | 588 | while (pattern < pattern_end - 1) { |
577 | /* Split at "\-" pattern. */ | 589 | /* Split at "\-" pattern. */ |
578 | if (*pattern++ != '\\' || *pattern++ != '-') | 590 | if (*pattern++ != '\\' || *pattern++ != '-') |
579 | continue; | 591 | continue; |
580 | result = tomoyo_file_matches_to_pattern2(filename, | 592 | result = tomoyo_file_matches_to_pattern2(filename, |
581 | filename_end, | 593 | filename_end, |
582 | pattern_start, | 594 | pattern_start, |
583 | pattern - 2); | 595 | pattern - 2); |
584 | if (first) | 596 | if (first) |
585 | result = !result; | 597 | result = !result; |
586 | if (result) | 598 | if (result) |
587 | return false; | 599 | return false; |
588 | first = false; | 600 | first = false; |
589 | pattern_start = pattern; | 601 | pattern_start = pattern; |
590 | } | 602 | } |
591 | result = tomoyo_file_matches_to_pattern2(filename, filename_end, | 603 | result = tomoyo_file_matches_to_pattern2(filename, filename_end, |
592 | pattern_start, pattern_end); | 604 | pattern_start, pattern_end); |
593 | return first ? result : !result; | 605 | return first ? result : !result; |
594 | } | 606 | } |
595 | 607 | ||
596 | /** | 608 | /** |
597 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. | 609 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. |
598 | * @filename: The filename to check. | 610 | * @filename: The filename to check. |
599 | * @pattern: The pattern to compare. | 611 | * @pattern: The pattern to compare. |
600 | * | 612 | * |
601 | * Returns true if matches, false otherwise. | 613 | * Returns true if matches, false otherwise. |
602 | * | 614 | * |
603 | * The following patterns are available. | 615 | * The following patterns are available. |
604 | * \\ \ itself. | 616 | * \\ \ itself. |
605 | * \ooo Octal representation of a byte. | 617 | * \ooo Octal representation of a byte. |
606 | * \* More than or equals to 0 character other than '/'. | 618 | * \* More than or equals to 0 character other than '/'. |
607 | * \@ More than or equals to 0 character other than '/' or '.'. | 619 | * \@ More than or equals to 0 character other than '/' or '.'. |
608 | * \? 1 byte character other than '/'. | 620 | * \? 1 byte character other than '/'. |
609 | * \$ More than or equals to 1 decimal digit. | 621 | * \$ More than or equals to 1 decimal digit. |
610 | * \+ 1 decimal digit. | 622 | * \+ 1 decimal digit. |
611 | * \X More than or equals to 1 hexadecimal digit. | 623 | * \X More than or equals to 1 hexadecimal digit. |
612 | * \x 1 hexadecimal digit. | 624 | * \x 1 hexadecimal digit. |
613 | * \A More than or equals to 1 alphabet character. | 625 | * \A More than or equals to 1 alphabet character. |
614 | * \a 1 alphabet character. | 626 | * \a 1 alphabet character. |
615 | * \- Subtraction operator. | 627 | * \- Subtraction operator. |
616 | */ | 628 | */ |
617 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | 629 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, |
618 | const struct tomoyo_path_info *pattern) | 630 | const struct tomoyo_path_info *pattern) |
619 | { | 631 | { |
620 | /* | 632 | /* |
621 | if (!filename || !pattern) | 633 | if (!filename || !pattern) |
622 | return false; | 634 | return false; |
623 | */ | 635 | */ |
624 | const char *f = filename->name; | 636 | const char *f = filename->name; |
625 | const char *p = pattern->name; | 637 | const char *p = pattern->name; |
626 | const int len = pattern->const_len; | 638 | const int len = pattern->const_len; |
627 | 639 | ||
628 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ | 640 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ |
629 | if (!pattern->is_patterned) | 641 | if (!pattern->is_patterned) |
630 | return !tomoyo_pathcmp(filename, pattern); | 642 | return !tomoyo_pathcmp(filename, pattern); |
631 | /* Dont compare if the number of '/' differs. */ | 643 | /* Dont compare if the number of '/' differs. */ |
632 | if (filename->depth != pattern->depth) | 644 | if (filename->depth != pattern->depth) |
633 | return false; | 645 | return false; |
634 | /* Compare the initial length without patterns. */ | 646 | /* Compare the initial length without patterns. */ |
635 | if (strncmp(f, p, len)) | 647 | if (strncmp(f, p, len)) |
636 | return false; | 648 | return false; |
637 | f += len; | 649 | f += len; |
638 | p += len; | 650 | p += len; |
639 | /* Main loop. Compare each directory component. */ | 651 | /* Main loop. Compare each directory component. */ |
640 | while (*f && *p) { | 652 | while (*f && *p) { |
641 | const char *f_delimiter = strchr(f, '/'); | 653 | const char *f_delimiter = strchr(f, '/'); |
642 | const char *p_delimiter = strchr(p, '/'); | 654 | const char *p_delimiter = strchr(p, '/'); |
643 | if (!f_delimiter) | 655 | if (!f_delimiter) |
644 | f_delimiter = f + strlen(f); | 656 | f_delimiter = f + strlen(f); |
645 | if (!p_delimiter) | 657 | if (!p_delimiter) |
646 | p_delimiter = p + strlen(p); | 658 | p_delimiter = p + strlen(p); |
647 | if (!tomoyo_file_matches_to_pattern(f, f_delimiter, | 659 | if (!tomoyo_file_matches_to_pattern(f, f_delimiter, |
648 | p, p_delimiter)) | 660 | p, p_delimiter)) |
649 | return false; | 661 | return false; |
650 | f = f_delimiter; | 662 | f = f_delimiter; |
651 | if (*f) | 663 | if (*f) |
652 | f++; | 664 | f++; |
653 | p = p_delimiter; | 665 | p = p_delimiter; |
654 | if (*p) | 666 | if (*p) |
655 | p++; | 667 | p++; |
656 | } | 668 | } |
657 | /* Ignore trailing "\*" and "\@" in @pattern. */ | 669 | /* Ignore trailing "\*" and "\@" in @pattern. */ |
658 | while (*p == '\\' && | 670 | while (*p == '\\' && |
659 | (*(p + 1) == '*' || *(p + 1) == '@')) | 671 | (*(p + 1) == '*' || *(p + 1) == '@')) |
660 | p += 2; | 672 | p += 2; |
661 | return !*f && !*p; | 673 | return !*f && !*p; |
662 | } | 674 | } |
663 | 675 | ||
664 | /** | 676 | /** |
665 | * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. | 677 | * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. |
666 | * | 678 | * |
667 | * @head: Pointer to "struct tomoyo_io_buffer". | 679 | * @head: Pointer to "struct tomoyo_io_buffer". |
668 | * @fmt: The printf()'s format string, followed by parameters. | 680 | * @fmt: The printf()'s format string, followed by parameters. |
669 | * | 681 | * |
670 | * Returns true if output was written, false otherwise. | 682 | * Returns true if output was written, false otherwise. |
671 | * | 683 | * |
672 | * The snprintf() will truncate, but tomoyo_io_printf() won't. | 684 | * The snprintf() will truncate, but tomoyo_io_printf() won't. |
673 | */ | 685 | */ |
674 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 686 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
675 | { | 687 | { |
676 | va_list args; | 688 | va_list args; |
677 | int len; | 689 | int len; |
678 | int pos = head->read_avail; | 690 | int pos = head->read_avail; |
679 | int size = head->readbuf_size - pos; | 691 | int size = head->readbuf_size - pos; |
680 | 692 | ||
681 | if (size <= 0) | 693 | if (size <= 0) |
682 | return false; | 694 | return false; |
683 | va_start(args, fmt); | 695 | va_start(args, fmt); |
684 | len = vsnprintf(head->read_buf + pos, size, fmt, args); | 696 | len = vsnprintf(head->read_buf + pos, size, fmt, args); |
685 | va_end(args); | 697 | va_end(args); |
686 | if (pos + len >= head->readbuf_size) | 698 | if (pos + len >= head->readbuf_size) |
687 | return false; | 699 | return false; |
688 | head->read_avail += len; | 700 | head->read_avail += len; |
689 | return true; | 701 | return true; |
690 | } | 702 | } |
691 | 703 | ||
692 | /** | 704 | /** |
693 | * tomoyo_get_exe - Get tomoyo_realpath() of current process. | 705 | * tomoyo_get_exe - Get tomoyo_realpath() of current process. |
694 | * | 706 | * |
695 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. | 707 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. |
696 | * | 708 | * |
697 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() | 709 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() |
698 | * if this function didn't return NULL. | 710 | * if this function didn't return NULL. |
699 | */ | 711 | */ |
700 | static const char *tomoyo_get_exe(void) | 712 | static const char *tomoyo_get_exe(void) |
701 | { | 713 | { |
702 | struct mm_struct *mm = current->mm; | 714 | struct mm_struct *mm = current->mm; |
703 | struct vm_area_struct *vma; | 715 | struct vm_area_struct *vma; |
704 | const char *cp = NULL; | 716 | const char *cp = NULL; |
705 | 717 | ||
706 | if (!mm) | 718 | if (!mm) |
707 | return NULL; | 719 | return NULL; |
708 | down_read(&mm->mmap_sem); | 720 | down_read(&mm->mmap_sem); |
709 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | 721 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
710 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { | 722 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { |
711 | cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); | 723 | cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); |
712 | break; | 724 | break; |
713 | } | 725 | } |
714 | } | 726 | } |
715 | up_read(&mm->mmap_sem); | 727 | up_read(&mm->mmap_sem); |
716 | return cp; | 728 | return cp; |
717 | } | 729 | } |
718 | 730 | ||
719 | /** | 731 | /** |
720 | * tomoyo_get_msg - Get warning message. | 732 | * tomoyo_get_msg - Get warning message. |
721 | * | 733 | * |
722 | * @is_enforce: Is it enforcing mode? | 734 | * @is_enforce: Is it enforcing mode? |
723 | * | 735 | * |
724 | * Returns "ERROR" or "WARNING". | 736 | * Returns "ERROR" or "WARNING". |
725 | */ | 737 | */ |
726 | const char *tomoyo_get_msg(const bool is_enforce) | 738 | const char *tomoyo_get_msg(const bool is_enforce) |
727 | { | 739 | { |
728 | if (is_enforce) | 740 | if (is_enforce) |
729 | return "ERROR"; | 741 | return "ERROR"; |
730 | else | 742 | else |
731 | return "WARNING"; | 743 | return "WARNING"; |
732 | } | 744 | } |
733 | 745 | ||
734 | /** | 746 | /** |
735 | * tomoyo_check_flags - Check mode for specified functionality. | 747 | * tomoyo_check_flags - Check mode for specified functionality. |
736 | * | 748 | * |
737 | * @domain: Pointer to "struct tomoyo_domain_info". | 749 | * @domain: Pointer to "struct tomoyo_domain_info". |
738 | * @index: The functionality to check mode. | 750 | * @index: The functionality to check mode. |
739 | * | 751 | * |
740 | * TOMOYO checks only process context. | 752 | * TOMOYO checks only process context. |
741 | * This code disables TOMOYO's enforcement in case the function is called from | 753 | * This code disables TOMOYO's enforcement in case the function is called from |
742 | * interrupt context. | 754 | * interrupt context. |
743 | */ | 755 | */ |
744 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | 756 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, |
745 | const u8 index) | 757 | const u8 index) |
746 | { | 758 | { |
747 | const u8 profile = domain->profile; | 759 | const u8 profile = domain->profile; |
748 | 760 | ||
749 | if (WARN_ON(in_interrupt())) | 761 | if (WARN_ON(in_interrupt())) |
750 | return 0; | 762 | return 0; |
751 | return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX | 763 | return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX |
752 | #if TOMOYO_MAX_PROFILES != 256 | 764 | #if TOMOYO_MAX_PROFILES != 256 |
753 | && profile < TOMOYO_MAX_PROFILES | 765 | && profile < TOMOYO_MAX_PROFILES |
754 | #endif | 766 | #endif |
755 | && tomoyo_profile_ptr[profile] ? | 767 | && tomoyo_profile_ptr[profile] ? |
756 | tomoyo_profile_ptr[profile]->value[index] : 0; | 768 | tomoyo_profile_ptr[profile]->value[index] : 0; |
757 | } | 769 | } |
758 | 770 | ||
759 | /** | 771 | /** |
760 | * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode. | 772 | * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode. |
761 | * | 773 | * |
762 | * @domain: Pointer to "struct tomoyo_domain_info". | 774 | * @domain: Pointer to "struct tomoyo_domain_info". |
763 | * | 775 | * |
764 | * Returns true if domain policy violation warning should be printed to | 776 | * Returns true if domain policy violation warning should be printed to |
765 | * console. | 777 | * console. |
766 | */ | 778 | */ |
767 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) | 779 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) |
768 | { | 780 | { |
769 | return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0; | 781 | return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0; |
770 | } | 782 | } |
771 | 783 | ||
772 | /** | 784 | /** |
773 | * tomoyo_domain_quota_is_ok - Check for domain's quota. | 785 | * tomoyo_domain_quota_is_ok - Check for domain's quota. |
774 | * | 786 | * |
775 | * @domain: Pointer to "struct tomoyo_domain_info". | 787 | * @domain: Pointer to "struct tomoyo_domain_info". |
776 | * | 788 | * |
777 | * Returns true if the domain is not exceeded quota, false otherwise. | 789 | * Returns true if the domain is not exceeded quota, false otherwise. |
778 | */ | 790 | */ |
779 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | 791 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) |
780 | { | 792 | { |
781 | unsigned int count = 0; | 793 | unsigned int count = 0; |
782 | struct tomoyo_acl_info *ptr; | 794 | struct tomoyo_acl_info *ptr; |
783 | 795 | ||
784 | if (!domain) | 796 | if (!domain) |
785 | return true; | 797 | return true; |
786 | down_read(&tomoyo_domain_acl_info_list_lock); | 798 | down_read(&tomoyo_domain_acl_info_list_lock); |
787 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 799 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
788 | if (ptr->type & TOMOYO_ACL_DELETED) | 800 | if (ptr->type & TOMOYO_ACL_DELETED) |
789 | continue; | 801 | continue; |
790 | switch (tomoyo_acl_type2(ptr)) { | 802 | switch (tomoyo_acl_type2(ptr)) { |
791 | struct tomoyo_single_path_acl_record *acl1; | 803 | struct tomoyo_single_path_acl_record *acl1; |
792 | struct tomoyo_double_path_acl_record *acl2; | 804 | struct tomoyo_double_path_acl_record *acl2; |
793 | u16 perm; | 805 | u16 perm; |
794 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | 806 | case TOMOYO_TYPE_SINGLE_PATH_ACL: |
795 | acl1 = container_of(ptr, | 807 | acl1 = container_of(ptr, |
796 | struct tomoyo_single_path_acl_record, | 808 | struct tomoyo_single_path_acl_record, |
797 | head); | 809 | head); |
798 | perm = acl1->perm; | 810 | perm = acl1->perm; |
799 | if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL)) | 811 | if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL)) |
800 | count++; | 812 | count++; |
801 | if (perm & | 813 | if (perm & |
802 | ((1 << TOMOYO_TYPE_READ_ACL) | | 814 | ((1 << TOMOYO_TYPE_READ_ACL) | |
803 | (1 << TOMOYO_TYPE_WRITE_ACL))) | 815 | (1 << TOMOYO_TYPE_WRITE_ACL))) |
804 | count++; | 816 | count++; |
805 | if (perm & (1 << TOMOYO_TYPE_CREATE_ACL)) | 817 | if (perm & (1 << TOMOYO_TYPE_CREATE_ACL)) |
806 | count++; | 818 | count++; |
807 | if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL)) | 819 | if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL)) |
808 | count++; | 820 | count++; |
809 | if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL)) | 821 | if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL)) |
810 | count++; | 822 | count++; |
811 | if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL)) | 823 | if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL)) |
812 | count++; | 824 | count++; |
813 | if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL)) | 825 | if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL)) |
814 | count++; | 826 | count++; |
815 | if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL)) | 827 | if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL)) |
816 | count++; | 828 | count++; |
817 | if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL)) | 829 | if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL)) |
818 | count++; | 830 | count++; |
819 | if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL)) | 831 | if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL)) |
820 | count++; | 832 | count++; |
821 | if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL)) | 833 | if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL)) |
822 | count++; | 834 | count++; |
823 | if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL)) | 835 | if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL)) |
824 | count++; | 836 | count++; |
825 | if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL)) | 837 | if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL)) |
826 | count++; | 838 | count++; |
827 | break; | 839 | break; |
828 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | 840 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: |
829 | acl2 = container_of(ptr, | 841 | acl2 = container_of(ptr, |
830 | struct tomoyo_double_path_acl_record, | 842 | struct tomoyo_double_path_acl_record, |
831 | head); | 843 | head); |
832 | perm = acl2->perm; | 844 | perm = acl2->perm; |
833 | if (perm & (1 << TOMOYO_TYPE_LINK_ACL)) | 845 | if (perm & (1 << TOMOYO_TYPE_LINK_ACL)) |
834 | count++; | 846 | count++; |
835 | if (perm & (1 << TOMOYO_TYPE_RENAME_ACL)) | 847 | if (perm & (1 << TOMOYO_TYPE_RENAME_ACL)) |
836 | count++; | 848 | count++; |
837 | break; | 849 | break; |
838 | } | 850 | } |
839 | } | 851 | } |
840 | up_read(&tomoyo_domain_acl_info_list_lock); | 852 | up_read(&tomoyo_domain_acl_info_list_lock); |
841 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) | 853 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) |
842 | return true; | 854 | return true; |
843 | if (!domain->quota_warned) { | 855 | if (!domain->quota_warned) { |
844 | domain->quota_warned = true; | 856 | domain->quota_warned = true; |
845 | printk(KERN_WARNING "TOMOYO-WARNING: " | 857 | printk(KERN_WARNING "TOMOYO-WARNING: " |
846 | "Domain '%s' has so many ACLs to hold. " | 858 | "Domain '%s' has so many ACLs to hold. " |
847 | "Stopped learning mode.\n", domain->domainname->name); | 859 | "Stopped learning mode.\n", domain->domainname->name); |
848 | } | 860 | } |
849 | return false; | 861 | return false; |
850 | } | 862 | } |
851 | 863 | ||
852 | /** | 864 | /** |
853 | * tomoyo_find_or_assign_new_profile - Create a new profile. | 865 | * tomoyo_find_or_assign_new_profile - Create a new profile. |
854 | * | 866 | * |
855 | * @profile: Profile number to create. | 867 | * @profile: Profile number to create. |
856 | * | 868 | * |
857 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. | 869 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. |
858 | */ | 870 | */ |
859 | static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | 871 | static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned |
860 | int profile) | 872 | int profile) |
861 | { | 873 | { |
862 | static DEFINE_MUTEX(lock); | 874 | static DEFINE_MUTEX(lock); |
863 | struct tomoyo_profile *ptr = NULL; | 875 | struct tomoyo_profile *ptr = NULL; |
864 | int i; | 876 | int i; |
865 | 877 | ||
866 | if (profile >= TOMOYO_MAX_PROFILES) | 878 | if (profile >= TOMOYO_MAX_PROFILES) |
867 | return NULL; | 879 | return NULL; |
868 | mutex_lock(&lock); | 880 | mutex_lock(&lock); |
869 | ptr = tomoyo_profile_ptr[profile]; | 881 | ptr = tomoyo_profile_ptr[profile]; |
870 | if (ptr) | 882 | if (ptr) |
871 | goto ok; | 883 | goto ok; |
872 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | 884 | ptr = tomoyo_alloc_element(sizeof(*ptr)); |
873 | if (!ptr) | 885 | if (!ptr) |
874 | goto ok; | 886 | goto ok; |
875 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) | 887 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) |
876 | ptr->value[i] = tomoyo_control_array[i].current_value; | 888 | ptr->value[i] = tomoyo_control_array[i].current_value; |
877 | mb(); /* Avoid out-of-order execution. */ | 889 | mb(); /* Avoid out-of-order execution. */ |
878 | tomoyo_profile_ptr[profile] = ptr; | 890 | tomoyo_profile_ptr[profile] = ptr; |
879 | ok: | 891 | ok: |
880 | mutex_unlock(&lock); | 892 | mutex_unlock(&lock); |
881 | return ptr; | 893 | return ptr; |
882 | } | 894 | } |
883 | 895 | ||
884 | /** | 896 | /** |
885 | * tomoyo_write_profile - Write to profile table. | 897 | * tomoyo_write_profile - Write to profile table. |
886 | * | 898 | * |
887 | * @head: Pointer to "struct tomoyo_io_buffer". | 899 | * @head: Pointer to "struct tomoyo_io_buffer". |
888 | * | 900 | * |
889 | * Returns 0 on success, negative value otherwise. | 901 | * Returns 0 on success, negative value otherwise. |
890 | */ | 902 | */ |
891 | static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | 903 | static int tomoyo_write_profile(struct tomoyo_io_buffer *head) |
892 | { | 904 | { |
893 | char *data = head->write_buf; | 905 | char *data = head->write_buf; |
894 | unsigned int i; | 906 | unsigned int i; |
895 | unsigned int value; | 907 | unsigned int value; |
896 | char *cp; | 908 | char *cp; |
897 | struct tomoyo_profile *profile; | 909 | struct tomoyo_profile *profile; |
898 | unsigned long num; | 910 | unsigned long num; |
899 | 911 | ||
900 | cp = strchr(data, '-'); | 912 | cp = strchr(data, '-'); |
901 | if (cp) | 913 | if (cp) |
902 | *cp = '\0'; | 914 | *cp = '\0'; |
903 | if (strict_strtoul(data, 10, &num)) | 915 | if (strict_strtoul(data, 10, &num)) |
904 | return -EINVAL; | 916 | return -EINVAL; |
905 | if (cp) | 917 | if (cp) |
906 | data = cp + 1; | 918 | data = cp + 1; |
907 | profile = tomoyo_find_or_assign_new_profile(num); | 919 | profile = tomoyo_find_or_assign_new_profile(num); |
908 | if (!profile) | 920 | if (!profile) |
909 | return -EINVAL; | 921 | return -EINVAL; |
910 | cp = strchr(data, '='); | 922 | cp = strchr(data, '='); |
911 | if (!cp) | 923 | if (!cp) |
912 | return -EINVAL; | 924 | return -EINVAL; |
913 | *cp = '\0'; | 925 | *cp = '\0'; |
914 | if (!strcmp(data, "COMMENT")) { | 926 | if (!strcmp(data, "COMMENT")) { |
915 | profile->comment = tomoyo_save_name(cp + 1); | 927 | profile->comment = tomoyo_save_name(cp + 1); |
916 | return 0; | 928 | return 0; |
917 | } | 929 | } |
918 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { | 930 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { |
919 | if (strcmp(data, tomoyo_control_array[i].keyword)) | 931 | if (strcmp(data, tomoyo_control_array[i].keyword)) |
920 | continue; | 932 | continue; |
921 | if (sscanf(cp + 1, "%u", &value) != 1) { | 933 | if (sscanf(cp + 1, "%u", &value) != 1) { |
922 | int j; | 934 | int j; |
923 | const char **modes; | 935 | const char **modes; |
924 | switch (i) { | 936 | switch (i) { |
925 | case TOMOYO_VERBOSE: | 937 | case TOMOYO_VERBOSE: |
926 | modes = tomoyo_mode_2; | 938 | modes = tomoyo_mode_2; |
927 | break; | 939 | break; |
928 | default: | 940 | default: |
929 | modes = tomoyo_mode_4; | 941 | modes = tomoyo_mode_4; |
930 | break; | 942 | break; |
931 | } | 943 | } |
932 | for (j = 0; j < 4; j++) { | 944 | for (j = 0; j < 4; j++) { |
933 | if (strcmp(cp + 1, modes[j])) | 945 | if (strcmp(cp + 1, modes[j])) |
934 | continue; | 946 | continue; |
935 | value = j; | 947 | value = j; |
936 | break; | 948 | break; |
937 | } | 949 | } |
938 | if (j == 4) | 950 | if (j == 4) |
939 | return -EINVAL; | 951 | return -EINVAL; |
940 | } else if (value > tomoyo_control_array[i].max_value) { | 952 | } else if (value > tomoyo_control_array[i].max_value) { |
941 | value = tomoyo_control_array[i].max_value; | 953 | value = tomoyo_control_array[i].max_value; |
942 | } | 954 | } |
943 | profile->value[i] = value; | 955 | profile->value[i] = value; |
944 | return 0; | 956 | return 0; |
945 | } | 957 | } |
946 | return -EINVAL; | 958 | return -EINVAL; |
947 | } | 959 | } |
948 | 960 | ||
949 | /** | 961 | /** |
950 | * tomoyo_read_profile - Read from profile table. | 962 | * tomoyo_read_profile - Read from profile table. |
951 | * | 963 | * |
952 | * @head: Pointer to "struct tomoyo_io_buffer". | 964 | * @head: Pointer to "struct tomoyo_io_buffer". |
953 | * | 965 | * |
954 | * Returns 0. | 966 | * Returns 0. |
955 | */ | 967 | */ |
956 | static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | 968 | static int tomoyo_read_profile(struct tomoyo_io_buffer *head) |
957 | { | 969 | { |
958 | static const int total = TOMOYO_MAX_CONTROL_INDEX + 1; | 970 | static const int total = TOMOYO_MAX_CONTROL_INDEX + 1; |
959 | int step; | 971 | int step; |
960 | 972 | ||
961 | if (head->read_eof) | 973 | if (head->read_eof) |
962 | return 0; | 974 | return 0; |
963 | for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total; | 975 | for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total; |
964 | step++) { | 976 | step++) { |
965 | const u8 index = step / total; | 977 | const u8 index = step / total; |
966 | u8 type = step % total; | 978 | u8 type = step % total; |
967 | const struct tomoyo_profile *profile | 979 | const struct tomoyo_profile *profile |
968 | = tomoyo_profile_ptr[index]; | 980 | = tomoyo_profile_ptr[index]; |
969 | head->read_step = step; | 981 | head->read_step = step; |
970 | if (!profile) | 982 | if (!profile) |
971 | continue; | 983 | continue; |
972 | if (!type) { /* Print profile' comment tag. */ | 984 | if (!type) { /* Print profile' comment tag. */ |
973 | if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n", | 985 | if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n", |
974 | index, profile->comment ? | 986 | index, profile->comment ? |
975 | profile->comment->name : "")) | 987 | profile->comment->name : "")) |
976 | break; | 988 | break; |
977 | continue; | 989 | continue; |
978 | } | 990 | } |
979 | type--; | 991 | type--; |
980 | if (type < TOMOYO_MAX_CONTROL_INDEX) { | 992 | if (type < TOMOYO_MAX_CONTROL_INDEX) { |
981 | const unsigned int value = profile->value[type]; | 993 | const unsigned int value = profile->value[type]; |
982 | const char **modes = NULL; | 994 | const char **modes = NULL; |
983 | const char *keyword | 995 | const char *keyword |
984 | = tomoyo_control_array[type].keyword; | 996 | = tomoyo_control_array[type].keyword; |
985 | switch (tomoyo_control_array[type].max_value) { | 997 | switch (tomoyo_control_array[type].max_value) { |
986 | case 3: | 998 | case 3: |
987 | modes = tomoyo_mode_4; | 999 | modes = tomoyo_mode_4; |
988 | break; | 1000 | break; |
989 | case 1: | 1001 | case 1: |
990 | modes = tomoyo_mode_2; | 1002 | modes = tomoyo_mode_2; |
991 | break; | 1003 | break; |
992 | } | 1004 | } |
993 | if (modes) { | 1005 | if (modes) { |
994 | if (!tomoyo_io_printf(head, "%u-%s=%s\n", index, | 1006 | if (!tomoyo_io_printf(head, "%u-%s=%s\n", index, |
995 | keyword, modes[value])) | 1007 | keyword, modes[value])) |
996 | break; | 1008 | break; |
997 | } else { | 1009 | } else { |
998 | if (!tomoyo_io_printf(head, "%u-%s=%u\n", index, | 1010 | if (!tomoyo_io_printf(head, "%u-%s=%u\n", index, |
999 | keyword, value)) | 1011 | keyword, value)) |
1000 | break; | 1012 | break; |
1001 | } | 1013 | } |
1002 | } | 1014 | } |
1003 | } | 1015 | } |
1004 | if (step == TOMOYO_MAX_PROFILES * total) | 1016 | if (step == TOMOYO_MAX_PROFILES * total) |
1005 | head->read_eof = true; | 1017 | head->read_eof = true; |
1006 | return 0; | 1018 | return 0; |
1007 | } | 1019 | } |
1008 | 1020 | ||
1009 | /* Structure for policy manager. */ | 1021 | /* |
1022 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
1023 | * domainnames or programs which are permitted to modify configuration via | ||
1024 | * /sys/kernel/security/tomoyo/ interface. | ||
1025 | * It has following fields. | ||
1026 | * | ||
1027 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
1028 | * (2) "manager" is a domainname or a program's pathname. | ||
1029 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
1030 | * otherwise. | ||
1031 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
1032 | * otherwise. | ||
1033 | */ | ||
1010 | struct tomoyo_policy_manager_entry { | 1034 | struct tomoyo_policy_manager_entry { |
1011 | struct list_head list; | 1035 | struct list_head list; |
1012 | /* A path to program or a domainname. */ | 1036 | /* A path to program or a domainname. */ |
1013 | const struct tomoyo_path_info *manager; | 1037 | const struct tomoyo_path_info *manager; |
1014 | bool is_domain; /* True if manager is a domainname. */ | 1038 | bool is_domain; /* True if manager is a domainname. */ |
1015 | bool is_deleted; /* True if this entry is deleted. */ | 1039 | bool is_deleted; /* True if this entry is deleted. */ |
1016 | }; | 1040 | }; |
1017 | 1041 | ||
1018 | /* The list for "struct tomoyo_policy_manager_entry". */ | 1042 | /* |
1043 | * tomoyo_policy_manager_list is used for holding list of domainnames or | ||
1044 | * programs which are permitted to modify configuration via | ||
1045 | * /sys/kernel/security/tomoyo/ interface. | ||
1046 | * | ||
1047 | * An entry is added by | ||
1048 | * | ||
1049 | * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1050 | * /sys/kernel/security/tomoyo/manager | ||
1051 | * (if you want to specify by a domainname) | ||
1052 | * | ||
1053 | * or | ||
1054 | * | ||
1055 | * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager | ||
1056 | * (if you want to specify by a program's location) | ||
1057 | * | ||
1058 | * and is deleted by | ||
1059 | * | ||
1060 | * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1061 | * /sys/kernel/security/tomoyo/manager | ||
1062 | * | ||
1063 | * or | ||
1064 | * | ||
1065 | * # echo 'delete /usr/lib/ccs/editpolicy' > \ | ||
1066 | * /sys/kernel/security/tomoyo/manager | ||
1067 | * | ||
1068 | * and all entries are retrieved by | ||
1069 | * | ||
1070 | * # cat /sys/kernel/security/tomoyo/manager | ||
1071 | */ | ||
1019 | static LIST_HEAD(tomoyo_policy_manager_list); | 1072 | static LIST_HEAD(tomoyo_policy_manager_list); |
1020 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | 1073 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); |
1021 | 1074 | ||
1022 | /** | 1075 | /** |
1023 | * tomoyo_update_manager_entry - Add a manager entry. | 1076 | * tomoyo_update_manager_entry - Add a manager entry. |
1024 | * | 1077 | * |
1025 | * @manager: The path to manager or the domainnamme. | 1078 | * @manager: The path to manager or the domainnamme. |
1026 | * @is_delete: True if it is a delete request. | 1079 | * @is_delete: True if it is a delete request. |
1027 | * | 1080 | * |
1028 | * Returns 0 on success, negative value otherwise. | 1081 | * Returns 0 on success, negative value otherwise. |
1029 | */ | 1082 | */ |
1030 | static int tomoyo_update_manager_entry(const char *manager, | 1083 | static int tomoyo_update_manager_entry(const char *manager, |
1031 | const bool is_delete) | 1084 | const bool is_delete) |
1032 | { | 1085 | { |
1033 | struct tomoyo_policy_manager_entry *new_entry; | 1086 | struct tomoyo_policy_manager_entry *new_entry; |
1034 | struct tomoyo_policy_manager_entry *ptr; | 1087 | struct tomoyo_policy_manager_entry *ptr; |
1035 | const struct tomoyo_path_info *saved_manager; | 1088 | const struct tomoyo_path_info *saved_manager; |
1036 | int error = -ENOMEM; | 1089 | int error = -ENOMEM; |
1037 | bool is_domain = false; | 1090 | bool is_domain = false; |
1038 | 1091 | ||
1039 | if (tomoyo_is_domain_def(manager)) { | 1092 | if (tomoyo_is_domain_def(manager)) { |
1040 | if (!tomoyo_is_correct_domain(manager, __func__)) | 1093 | if (!tomoyo_is_correct_domain(manager, __func__)) |
1041 | return -EINVAL; | 1094 | return -EINVAL; |
1042 | is_domain = true; | 1095 | is_domain = true; |
1043 | } else { | 1096 | } else { |
1044 | if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__)) | 1097 | if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__)) |
1045 | return -EINVAL; | 1098 | return -EINVAL; |
1046 | } | 1099 | } |
1047 | saved_manager = tomoyo_save_name(manager); | 1100 | saved_manager = tomoyo_save_name(manager); |
1048 | if (!saved_manager) | 1101 | if (!saved_manager) |
1049 | return -ENOMEM; | 1102 | return -ENOMEM; |
1050 | down_write(&tomoyo_policy_manager_list_lock); | 1103 | down_write(&tomoyo_policy_manager_list_lock); |
1051 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1104 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { |
1052 | if (ptr->manager != saved_manager) | 1105 | if (ptr->manager != saved_manager) |
1053 | continue; | 1106 | continue; |
1054 | ptr->is_deleted = is_delete; | 1107 | ptr->is_deleted = is_delete; |
1055 | error = 0; | 1108 | error = 0; |
1056 | goto out; | 1109 | goto out; |
1057 | } | 1110 | } |
1058 | if (is_delete) { | 1111 | if (is_delete) { |
1059 | error = -ENOENT; | 1112 | error = -ENOENT; |
1060 | goto out; | 1113 | goto out; |
1061 | } | 1114 | } |
1062 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 1115 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
1063 | if (!new_entry) | 1116 | if (!new_entry) |
1064 | goto out; | 1117 | goto out; |
1065 | new_entry->manager = saved_manager; | 1118 | new_entry->manager = saved_manager; |
1066 | new_entry->is_domain = is_domain; | 1119 | new_entry->is_domain = is_domain; |
1067 | list_add_tail(&new_entry->list, &tomoyo_policy_manager_list); | 1120 | list_add_tail(&new_entry->list, &tomoyo_policy_manager_list); |
1068 | error = 0; | 1121 | error = 0; |
1069 | out: | 1122 | out: |
1070 | up_write(&tomoyo_policy_manager_list_lock); | 1123 | up_write(&tomoyo_policy_manager_list_lock); |
1071 | return error; | 1124 | return error; |
1072 | } | 1125 | } |
1073 | 1126 | ||
1074 | /** | 1127 | /** |
1075 | * tomoyo_write_manager_policy - Write manager policy. | 1128 | * tomoyo_write_manager_policy - Write manager policy. |
1076 | * | 1129 | * |
1077 | * @head: Pointer to "struct tomoyo_io_buffer". | 1130 | * @head: Pointer to "struct tomoyo_io_buffer". |
1078 | * | 1131 | * |
1079 | * Returns 0 on success, negative value otherwise. | 1132 | * Returns 0 on success, negative value otherwise. |
1080 | */ | 1133 | */ |
1081 | static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) | 1134 | static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) |
1082 | { | 1135 | { |
1083 | char *data = head->write_buf; | 1136 | char *data = head->write_buf; |
1084 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | 1137 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); |
1085 | 1138 | ||
1086 | if (!strcmp(data, "manage_by_non_root")) { | 1139 | if (!strcmp(data, "manage_by_non_root")) { |
1087 | tomoyo_manage_by_non_root = !is_delete; | 1140 | tomoyo_manage_by_non_root = !is_delete; |
1088 | return 0; | 1141 | return 0; |
1089 | } | 1142 | } |
1090 | return tomoyo_update_manager_entry(data, is_delete); | 1143 | return tomoyo_update_manager_entry(data, is_delete); |
1091 | } | 1144 | } |
1092 | 1145 | ||
1093 | /** | 1146 | /** |
1094 | * tomoyo_read_manager_policy - Read manager policy. | 1147 | * tomoyo_read_manager_policy - Read manager policy. |
1095 | * | 1148 | * |
1096 | * @head: Pointer to "struct tomoyo_io_buffer". | 1149 | * @head: Pointer to "struct tomoyo_io_buffer". |
1097 | * | 1150 | * |
1098 | * Returns 0. | 1151 | * Returns 0. |
1099 | */ | 1152 | */ |
1100 | static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | 1153 | static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) |
1101 | { | 1154 | { |
1102 | struct list_head *pos; | 1155 | struct list_head *pos; |
1103 | bool done = true; | 1156 | bool done = true; |
1104 | 1157 | ||
1105 | if (head->read_eof) | 1158 | if (head->read_eof) |
1106 | return 0; | 1159 | return 0; |
1107 | down_read(&tomoyo_policy_manager_list_lock); | 1160 | down_read(&tomoyo_policy_manager_list_lock); |
1108 | list_for_each_cookie(pos, head->read_var2, | 1161 | list_for_each_cookie(pos, head->read_var2, |
1109 | &tomoyo_policy_manager_list) { | 1162 | &tomoyo_policy_manager_list) { |
1110 | struct tomoyo_policy_manager_entry *ptr; | 1163 | struct tomoyo_policy_manager_entry *ptr; |
1111 | ptr = list_entry(pos, struct tomoyo_policy_manager_entry, | 1164 | ptr = list_entry(pos, struct tomoyo_policy_manager_entry, |
1112 | list); | 1165 | list); |
1113 | if (ptr->is_deleted) | 1166 | if (ptr->is_deleted) |
1114 | continue; | 1167 | continue; |
1115 | done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); | 1168 | done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); |
1116 | if (!done) | 1169 | if (!done) |
1117 | break; | 1170 | break; |
1118 | } | 1171 | } |
1119 | up_read(&tomoyo_policy_manager_list_lock); | 1172 | up_read(&tomoyo_policy_manager_list_lock); |
1120 | head->read_eof = done; | 1173 | head->read_eof = done; |
1121 | return 0; | 1174 | return 0; |
1122 | } | 1175 | } |
1123 | 1176 | ||
1124 | /** | 1177 | /** |
1125 | * tomoyo_is_policy_manager - Check whether the current process is a policy manager. | 1178 | * tomoyo_is_policy_manager - Check whether the current process is a policy manager. |
1126 | * | 1179 | * |
1127 | * Returns true if the current process is permitted to modify policy | 1180 | * Returns true if the current process is permitted to modify policy |
1128 | * via /sys/kernel/security/tomoyo/ interface. | 1181 | * via /sys/kernel/security/tomoyo/ interface. |
1129 | */ | 1182 | */ |
1130 | static bool tomoyo_is_policy_manager(void) | 1183 | static bool tomoyo_is_policy_manager(void) |
1131 | { | 1184 | { |
1132 | struct tomoyo_policy_manager_entry *ptr; | 1185 | struct tomoyo_policy_manager_entry *ptr; |
1133 | const char *exe; | 1186 | const char *exe; |
1134 | const struct task_struct *task = current; | 1187 | const struct task_struct *task = current; |
1135 | const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; | 1188 | const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; |
1136 | bool found = false; | 1189 | bool found = false; |
1137 | 1190 | ||
1138 | if (!tomoyo_policy_loaded) | 1191 | if (!tomoyo_policy_loaded) |
1139 | return true; | 1192 | return true; |
1140 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 1193 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
1141 | return false; | 1194 | return false; |
1142 | down_read(&tomoyo_policy_manager_list_lock); | 1195 | down_read(&tomoyo_policy_manager_list_lock); |
1143 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1196 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { |
1144 | if (!ptr->is_deleted && ptr->is_domain | 1197 | if (!ptr->is_deleted && ptr->is_domain |
1145 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 1198 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
1146 | found = true; | 1199 | found = true; |
1147 | break; | 1200 | break; |
1148 | } | 1201 | } |
1149 | } | 1202 | } |
1150 | up_read(&tomoyo_policy_manager_list_lock); | 1203 | up_read(&tomoyo_policy_manager_list_lock); |
1151 | if (found) | 1204 | if (found) |
1152 | return true; | 1205 | return true; |
1153 | exe = tomoyo_get_exe(); | 1206 | exe = tomoyo_get_exe(); |
1154 | if (!exe) | 1207 | if (!exe) |
1155 | return false; | 1208 | return false; |
1156 | down_read(&tomoyo_policy_manager_list_lock); | 1209 | down_read(&tomoyo_policy_manager_list_lock); |
1157 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1210 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { |
1158 | if (!ptr->is_deleted && !ptr->is_domain | 1211 | if (!ptr->is_deleted && !ptr->is_domain |
1159 | && !strcmp(exe, ptr->manager->name)) { | 1212 | && !strcmp(exe, ptr->manager->name)) { |
1160 | found = true; | 1213 | found = true; |
1161 | break; | 1214 | break; |
1162 | } | 1215 | } |
1163 | } | 1216 | } |
1164 | up_read(&tomoyo_policy_manager_list_lock); | 1217 | up_read(&tomoyo_policy_manager_list_lock); |
1165 | if (!found) { /* Reduce error messages. */ | 1218 | if (!found) { /* Reduce error messages. */ |
1166 | static pid_t last_pid; | 1219 | static pid_t last_pid; |
1167 | const pid_t pid = current->pid; | 1220 | const pid_t pid = current->pid; |
1168 | if (last_pid != pid) { | 1221 | if (last_pid != pid) { |
1169 | printk(KERN_WARNING "%s ( %s ) is not permitted to " | 1222 | printk(KERN_WARNING "%s ( %s ) is not permitted to " |
1170 | "update policies.\n", domainname->name, exe); | 1223 | "update policies.\n", domainname->name, exe); |
1171 | last_pid = pid; | 1224 | last_pid = pid; |
1172 | } | 1225 | } |
1173 | } | 1226 | } |
1174 | tomoyo_free(exe); | 1227 | tomoyo_free(exe); |
1175 | return found; | 1228 | return found; |
1176 | } | 1229 | } |
1177 | 1230 | ||
1178 | /** | 1231 | /** |
1179 | * tomoyo_is_select_one - Parse select command. | 1232 | * tomoyo_is_select_one - Parse select command. |
1180 | * | 1233 | * |
1181 | * @head: Pointer to "struct tomoyo_io_buffer". | 1234 | * @head: Pointer to "struct tomoyo_io_buffer". |
1182 | * @data: String to parse. | 1235 | * @data: String to parse. |
1183 | * | 1236 | * |
1184 | * Returns true on success, false otherwise. | 1237 | * Returns true on success, false otherwise. |
1185 | */ | 1238 | */ |
1186 | static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | 1239 | static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, |
1187 | const char *data) | 1240 | const char *data) |
1188 | { | 1241 | { |
1189 | unsigned int pid; | 1242 | unsigned int pid; |
1190 | struct tomoyo_domain_info *domain = NULL; | 1243 | struct tomoyo_domain_info *domain = NULL; |
1191 | 1244 | ||
1192 | if (sscanf(data, "pid=%u", &pid) == 1) { | 1245 | if (sscanf(data, "pid=%u", &pid) == 1) { |
1193 | struct task_struct *p; | 1246 | struct task_struct *p; |
1194 | read_lock(&tasklist_lock); | 1247 | read_lock(&tasklist_lock); |
1195 | p = find_task_by_vpid(pid); | 1248 | p = find_task_by_vpid(pid); |
1196 | if (p) | 1249 | if (p) |
1197 | domain = tomoyo_real_domain(p); | 1250 | domain = tomoyo_real_domain(p); |
1198 | read_unlock(&tasklist_lock); | 1251 | read_unlock(&tasklist_lock); |
1199 | } else if (!strncmp(data, "domain=", 7)) { | 1252 | } else if (!strncmp(data, "domain=", 7)) { |
1200 | if (tomoyo_is_domain_def(data + 7)) { | 1253 | if (tomoyo_is_domain_def(data + 7)) { |
1201 | down_read(&tomoyo_domain_list_lock); | 1254 | down_read(&tomoyo_domain_list_lock); |
1202 | domain = tomoyo_find_domain(data + 7); | 1255 | domain = tomoyo_find_domain(data + 7); |
1203 | up_read(&tomoyo_domain_list_lock); | 1256 | up_read(&tomoyo_domain_list_lock); |
1204 | } | 1257 | } |
1205 | } else | 1258 | } else |
1206 | return false; | 1259 | return false; |
1207 | head->write_var1 = domain; | 1260 | head->write_var1 = domain; |
1208 | /* Accessing read_buf is safe because head->io_sem is held. */ | 1261 | /* Accessing read_buf is safe because head->io_sem is held. */ |
1209 | if (!head->read_buf) | 1262 | if (!head->read_buf) |
1210 | return true; /* Do nothing if open(O_WRONLY). */ | 1263 | return true; /* Do nothing if open(O_WRONLY). */ |
1211 | head->read_avail = 0; | 1264 | head->read_avail = 0; |
1212 | tomoyo_io_printf(head, "# select %s\n", data); | 1265 | tomoyo_io_printf(head, "# select %s\n", data); |
1213 | head->read_single_domain = true; | 1266 | head->read_single_domain = true; |
1214 | head->read_eof = !domain; | 1267 | head->read_eof = !domain; |
1215 | if (domain) { | 1268 | if (domain) { |
1216 | struct tomoyo_domain_info *d; | 1269 | struct tomoyo_domain_info *d; |
1217 | head->read_var1 = NULL; | 1270 | head->read_var1 = NULL; |
1218 | down_read(&tomoyo_domain_list_lock); | 1271 | down_read(&tomoyo_domain_list_lock); |
1219 | list_for_each_entry(d, &tomoyo_domain_list, list) { | 1272 | list_for_each_entry(d, &tomoyo_domain_list, list) { |
1220 | if (d == domain) | 1273 | if (d == domain) |
1221 | break; | 1274 | break; |
1222 | head->read_var1 = &d->list; | 1275 | head->read_var1 = &d->list; |
1223 | } | 1276 | } |
1224 | up_read(&tomoyo_domain_list_lock); | 1277 | up_read(&tomoyo_domain_list_lock); |
1225 | head->read_var2 = NULL; | 1278 | head->read_var2 = NULL; |
1226 | head->read_bit = 0; | 1279 | head->read_bit = 0; |
1227 | head->read_step = 0; | 1280 | head->read_step = 0; |
1228 | if (domain->is_deleted) | 1281 | if (domain->is_deleted) |
1229 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); | 1282 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); |
1230 | } | 1283 | } |
1231 | return true; | 1284 | return true; |
1232 | } | 1285 | } |
1233 | 1286 | ||
1234 | /** | 1287 | /** |
1235 | * tomoyo_write_domain_policy - Write domain policy. | 1288 | * tomoyo_write_domain_policy - Write domain policy. |
1236 | * | 1289 | * |
1237 | * @head: Pointer to "struct tomoyo_io_buffer". | 1290 | * @head: Pointer to "struct tomoyo_io_buffer". |
1238 | * | 1291 | * |
1239 | * Returns 0 on success, negative value otherwise. | 1292 | * Returns 0 on success, negative value otherwise. |
1240 | */ | 1293 | */ |
1241 | static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | 1294 | static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) |
1242 | { | 1295 | { |
1243 | char *data = head->write_buf; | 1296 | char *data = head->write_buf; |
1244 | struct tomoyo_domain_info *domain = head->write_var1; | 1297 | struct tomoyo_domain_info *domain = head->write_var1; |
1245 | bool is_delete = false; | 1298 | bool is_delete = false; |
1246 | bool is_select = false; | 1299 | bool is_select = false; |
1247 | unsigned int profile; | 1300 | unsigned int profile; |
1248 | 1301 | ||
1249 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE)) | 1302 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE)) |
1250 | is_delete = true; | 1303 | is_delete = true; |
1251 | else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT)) | 1304 | else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT)) |
1252 | is_select = true; | 1305 | is_select = true; |
1253 | if (is_select && tomoyo_is_select_one(head, data)) | 1306 | if (is_select && tomoyo_is_select_one(head, data)) |
1254 | return 0; | 1307 | return 0; |
1255 | /* Don't allow updating policies by non manager programs. */ | 1308 | /* Don't allow updating policies by non manager programs. */ |
1256 | if (!tomoyo_is_policy_manager()) | 1309 | if (!tomoyo_is_policy_manager()) |
1257 | return -EPERM; | 1310 | return -EPERM; |
1258 | if (tomoyo_is_domain_def(data)) { | 1311 | if (tomoyo_is_domain_def(data)) { |
1259 | domain = NULL; | 1312 | domain = NULL; |
1260 | if (is_delete) | 1313 | if (is_delete) |
1261 | tomoyo_delete_domain(data); | 1314 | tomoyo_delete_domain(data); |
1262 | else if (is_select) { | 1315 | else if (is_select) { |
1263 | down_read(&tomoyo_domain_list_lock); | 1316 | down_read(&tomoyo_domain_list_lock); |
1264 | domain = tomoyo_find_domain(data); | 1317 | domain = tomoyo_find_domain(data); |
1265 | up_read(&tomoyo_domain_list_lock); | 1318 | up_read(&tomoyo_domain_list_lock); |
1266 | } else | 1319 | } else |
1267 | domain = tomoyo_find_or_assign_new_domain(data, 0); | 1320 | domain = tomoyo_find_or_assign_new_domain(data, 0); |
1268 | head->write_var1 = domain; | 1321 | head->write_var1 = domain; |
1269 | return 0; | 1322 | return 0; |
1270 | } | 1323 | } |
1271 | if (!domain) | 1324 | if (!domain) |
1272 | return -EINVAL; | 1325 | return -EINVAL; |
1273 | 1326 | ||
1274 | if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1 | 1327 | if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1 |
1275 | && profile < TOMOYO_MAX_PROFILES) { | 1328 | && profile < TOMOYO_MAX_PROFILES) { |
1276 | if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) | 1329 | if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) |
1277 | domain->profile = (u8) profile; | 1330 | domain->profile = (u8) profile; |
1278 | return 0; | 1331 | return 0; |
1279 | } | 1332 | } |
1280 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { | 1333 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { |
1281 | tomoyo_set_domain_flag(domain, is_delete, | 1334 | tomoyo_set_domain_flag(domain, is_delete, |
1282 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ); | 1335 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ); |
1283 | return 0; | 1336 | return 0; |
1284 | } | 1337 | } |
1285 | return tomoyo_write_file_policy(data, domain, is_delete); | 1338 | return tomoyo_write_file_policy(data, domain, is_delete); |
1286 | } | 1339 | } |
1287 | 1340 | ||
1288 | /** | 1341 | /** |
1289 | * tomoyo_print_single_path_acl - Print a single path ACL entry. | 1342 | * tomoyo_print_single_path_acl - Print a single path ACL entry. |
1290 | * | 1343 | * |
1291 | * @head: Pointer to "struct tomoyo_io_buffer". | 1344 | * @head: Pointer to "struct tomoyo_io_buffer". |
1292 | * @ptr: Pointer to "struct tomoyo_single_path_acl_record". | 1345 | * @ptr: Pointer to "struct tomoyo_single_path_acl_record". |
1293 | * | 1346 | * |
1294 | * Returns true on success, false otherwise. | 1347 | * Returns true on success, false otherwise. |
1295 | */ | 1348 | */ |
1296 | static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, | 1349 | static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, |
1297 | struct tomoyo_single_path_acl_record * | 1350 | struct tomoyo_single_path_acl_record * |
1298 | ptr) | 1351 | ptr) |
1299 | { | 1352 | { |
1300 | int pos; | 1353 | int pos; |
1301 | u8 bit; | 1354 | u8 bit; |
1302 | const char *atmark = ""; | 1355 | const char *atmark = ""; |
1303 | const char *filename; | 1356 | const char *filename; |
1304 | const u16 perm = ptr->perm; | 1357 | const u16 perm = ptr->perm; |
1305 | 1358 | ||
1306 | filename = ptr->filename->name; | 1359 | filename = ptr->filename->name; |
1307 | for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION; | 1360 | for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION; |
1308 | bit++) { | 1361 | bit++) { |
1309 | const char *msg; | 1362 | const char *msg; |
1310 | if (!(perm & (1 << bit))) | 1363 | if (!(perm & (1 << bit))) |
1311 | continue; | 1364 | continue; |
1312 | /* Print "read/write" instead of "read" and "write". */ | 1365 | /* Print "read/write" instead of "read" and "write". */ |
1313 | if ((bit == TOMOYO_TYPE_READ_ACL || | 1366 | if ((bit == TOMOYO_TYPE_READ_ACL || |
1314 | bit == TOMOYO_TYPE_WRITE_ACL) | 1367 | bit == TOMOYO_TYPE_WRITE_ACL) |
1315 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | 1368 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) |
1316 | continue; | 1369 | continue; |
1317 | msg = tomoyo_sp2keyword(bit); | 1370 | msg = tomoyo_sp2keyword(bit); |
1318 | pos = head->read_avail; | 1371 | pos = head->read_avail; |
1319 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, | 1372 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, |
1320 | atmark, filename)) | 1373 | atmark, filename)) |
1321 | goto out; | 1374 | goto out; |
1322 | } | 1375 | } |
1323 | head->read_bit = 0; | 1376 | head->read_bit = 0; |
1324 | return true; | 1377 | return true; |
1325 | out: | 1378 | out: |
1326 | head->read_bit = bit; | 1379 | head->read_bit = bit; |
1327 | head->read_avail = pos; | 1380 | head->read_avail = pos; |
1328 | return false; | 1381 | return false; |
1329 | } | 1382 | } |
1330 | 1383 | ||
1331 | /** | 1384 | /** |
1332 | * tomoyo_print_double_path_acl - Print a double path ACL entry. | 1385 | * tomoyo_print_double_path_acl - Print a double path ACL entry. |
1333 | * | 1386 | * |
1334 | * @head: Pointer to "struct tomoyo_io_buffer". | 1387 | * @head: Pointer to "struct tomoyo_io_buffer". |
1335 | * @ptr: Pointer to "struct tomoyo_double_path_acl_record". | 1388 | * @ptr: Pointer to "struct tomoyo_double_path_acl_record". |
1336 | * | 1389 | * |
1337 | * Returns true on success, false otherwise. | 1390 | * Returns true on success, false otherwise. |
1338 | */ | 1391 | */ |
1339 | static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | 1392 | static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, |
1340 | struct tomoyo_double_path_acl_record * | 1393 | struct tomoyo_double_path_acl_record * |
1341 | ptr) | 1394 | ptr) |
1342 | { | 1395 | { |
1343 | int pos; | 1396 | int pos; |
1344 | const char *atmark1 = ""; | 1397 | const char *atmark1 = ""; |
1345 | const char *atmark2 = ""; | 1398 | const char *atmark2 = ""; |
1346 | const char *filename1; | 1399 | const char *filename1; |
1347 | const char *filename2; | 1400 | const char *filename2; |
1348 | const u8 perm = ptr->perm; | 1401 | const u8 perm = ptr->perm; |
1349 | u8 bit; | 1402 | u8 bit; |
1350 | 1403 | ||
1351 | filename1 = ptr->filename1->name; | 1404 | filename1 = ptr->filename1->name; |
1352 | filename2 = ptr->filename2->name; | 1405 | filename2 = ptr->filename2->name; |
1353 | for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION; | 1406 | for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION; |
1354 | bit++) { | 1407 | bit++) { |
1355 | const char *msg; | 1408 | const char *msg; |
1356 | if (!(perm & (1 << bit))) | 1409 | if (!(perm & (1 << bit))) |
1357 | continue; | 1410 | continue; |
1358 | msg = tomoyo_dp2keyword(bit); | 1411 | msg = tomoyo_dp2keyword(bit); |
1359 | pos = head->read_avail; | 1412 | pos = head->read_avail; |
1360 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, | 1413 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, |
1361 | atmark1, filename1, atmark2, filename2)) | 1414 | atmark1, filename1, atmark2, filename2)) |
1362 | goto out; | 1415 | goto out; |
1363 | } | 1416 | } |
1364 | head->read_bit = 0; | 1417 | head->read_bit = 0; |
1365 | return true; | 1418 | return true; |
1366 | out: | 1419 | out: |
1367 | head->read_bit = bit; | 1420 | head->read_bit = bit; |
1368 | head->read_avail = pos; | 1421 | head->read_avail = pos; |
1369 | return false; | 1422 | return false; |
1370 | } | 1423 | } |
1371 | 1424 | ||
1372 | /** | 1425 | /** |
1373 | * tomoyo_print_entry - Print an ACL entry. | 1426 | * tomoyo_print_entry - Print an ACL entry. |
1374 | * | 1427 | * |
1375 | * @head: Pointer to "struct tomoyo_io_buffer". | 1428 | * @head: Pointer to "struct tomoyo_io_buffer". |
1376 | * @ptr: Pointer to an ACL entry. | 1429 | * @ptr: Pointer to an ACL entry. |
1377 | * | 1430 | * |
1378 | * Returns true on success, false otherwise. | 1431 | * Returns true on success, false otherwise. |
1379 | */ | 1432 | */ |
1380 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | 1433 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, |
1381 | struct tomoyo_acl_info *ptr) | 1434 | struct tomoyo_acl_info *ptr) |
1382 | { | 1435 | { |
1383 | const u8 acl_type = tomoyo_acl_type2(ptr); | 1436 | const u8 acl_type = tomoyo_acl_type2(ptr); |
1384 | 1437 | ||
1385 | if (acl_type & TOMOYO_ACL_DELETED) | 1438 | if (acl_type & TOMOYO_ACL_DELETED) |
1386 | return true; | 1439 | return true; |
1387 | if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) { | 1440 | if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) { |
1388 | struct tomoyo_single_path_acl_record *acl | 1441 | struct tomoyo_single_path_acl_record *acl |
1389 | = container_of(ptr, | 1442 | = container_of(ptr, |
1390 | struct tomoyo_single_path_acl_record, | 1443 | struct tomoyo_single_path_acl_record, |
1391 | head); | 1444 | head); |
1392 | return tomoyo_print_single_path_acl(head, acl); | 1445 | return tomoyo_print_single_path_acl(head, acl); |
1393 | } | 1446 | } |
1394 | if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) { | 1447 | if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) { |
1395 | struct tomoyo_double_path_acl_record *acl | 1448 | struct tomoyo_double_path_acl_record *acl |
1396 | = container_of(ptr, | 1449 | = container_of(ptr, |
1397 | struct tomoyo_double_path_acl_record, | 1450 | struct tomoyo_double_path_acl_record, |
1398 | head); | 1451 | head); |
1399 | return tomoyo_print_double_path_acl(head, acl); | 1452 | return tomoyo_print_double_path_acl(head, acl); |
1400 | } | 1453 | } |
1401 | BUG(); /* This must not happen. */ | 1454 | BUG(); /* This must not happen. */ |
1402 | return false; | 1455 | return false; |
1403 | } | 1456 | } |
1404 | 1457 | ||
1405 | /** | 1458 | /** |
1406 | * tomoyo_read_domain_policy - Read domain policy. | 1459 | * tomoyo_read_domain_policy - Read domain policy. |
1407 | * | 1460 | * |
1408 | * @head: Pointer to "struct tomoyo_io_buffer". | 1461 | * @head: Pointer to "struct tomoyo_io_buffer". |
1409 | * | 1462 | * |
1410 | * Returns 0. | 1463 | * Returns 0. |
1411 | */ | 1464 | */ |
1412 | static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | 1465 | static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) |
1413 | { | 1466 | { |
1414 | struct list_head *dpos; | 1467 | struct list_head *dpos; |
1415 | struct list_head *apos; | 1468 | struct list_head *apos; |
1416 | bool done = true; | 1469 | bool done = true; |
1417 | 1470 | ||
1418 | if (head->read_eof) | 1471 | if (head->read_eof) |
1419 | return 0; | 1472 | return 0; |
1420 | if (head->read_step == 0) | 1473 | if (head->read_step == 0) |
1421 | head->read_step = 1; | 1474 | head->read_step = 1; |
1422 | down_read(&tomoyo_domain_list_lock); | 1475 | down_read(&tomoyo_domain_list_lock); |
1423 | list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { | 1476 | list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { |
1424 | struct tomoyo_domain_info *domain; | 1477 | struct tomoyo_domain_info *domain; |
1425 | const char *quota_exceeded = ""; | 1478 | const char *quota_exceeded = ""; |
1426 | const char *transition_failed = ""; | 1479 | const char *transition_failed = ""; |
1427 | const char *ignore_global_allow_read = ""; | 1480 | const char *ignore_global_allow_read = ""; |
1428 | domain = list_entry(dpos, struct tomoyo_domain_info, list); | 1481 | domain = list_entry(dpos, struct tomoyo_domain_info, list); |
1429 | if (head->read_step != 1) | 1482 | if (head->read_step != 1) |
1430 | goto acl_loop; | 1483 | goto acl_loop; |
1431 | if (domain->is_deleted && !head->read_single_domain) | 1484 | if (domain->is_deleted && !head->read_single_domain) |
1432 | continue; | 1485 | continue; |
1433 | /* Print domainname and flags. */ | 1486 | /* Print domainname and flags. */ |
1434 | if (domain->quota_warned) | 1487 | if (domain->quota_warned) |
1435 | quota_exceeded = "quota_exceeded\n"; | 1488 | quota_exceeded = "quota_exceeded\n"; |
1436 | if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED) | 1489 | if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED) |
1437 | transition_failed = "transition_failed\n"; | 1490 | transition_failed = "transition_failed\n"; |
1438 | if (domain->flags & | 1491 | if (domain->flags & |
1439 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) | 1492 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) |
1440 | ignore_global_allow_read | 1493 | ignore_global_allow_read |
1441 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; | 1494 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
1442 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE | 1495 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE |
1443 | "%u\n%s%s%s\n", | 1496 | "%u\n%s%s%s\n", |
1444 | domain->domainname->name, | 1497 | domain->domainname->name, |
1445 | domain->profile, quota_exceeded, | 1498 | domain->profile, quota_exceeded, |
1446 | transition_failed, | 1499 | transition_failed, |
1447 | ignore_global_allow_read); | 1500 | ignore_global_allow_read); |
1448 | if (!done) | 1501 | if (!done) |
1449 | break; | 1502 | break; |
1450 | head->read_step = 2; | 1503 | head->read_step = 2; |
1451 | acl_loop: | 1504 | acl_loop: |
1452 | if (head->read_step == 3) | 1505 | if (head->read_step == 3) |
1453 | goto tail_mark; | 1506 | goto tail_mark; |
1454 | /* Print ACL entries in the domain. */ | 1507 | /* Print ACL entries in the domain. */ |
1455 | down_read(&tomoyo_domain_acl_info_list_lock); | 1508 | down_read(&tomoyo_domain_acl_info_list_lock); |
1456 | list_for_each_cookie(apos, head->read_var2, | 1509 | list_for_each_cookie(apos, head->read_var2, |
1457 | &domain->acl_info_list) { | 1510 | &domain->acl_info_list) { |
1458 | struct tomoyo_acl_info *ptr | 1511 | struct tomoyo_acl_info *ptr |
1459 | = list_entry(apos, struct tomoyo_acl_info, | 1512 | = list_entry(apos, struct tomoyo_acl_info, |
1460 | list); | 1513 | list); |
1461 | done = tomoyo_print_entry(head, ptr); | 1514 | done = tomoyo_print_entry(head, ptr); |
1462 | if (!done) | 1515 | if (!done) |
1463 | break; | 1516 | break; |
1464 | } | 1517 | } |
1465 | up_read(&tomoyo_domain_acl_info_list_lock); | 1518 | up_read(&tomoyo_domain_acl_info_list_lock); |
1466 | if (!done) | 1519 | if (!done) |
1467 | break; | 1520 | break; |
1468 | head->read_step = 3; | 1521 | head->read_step = 3; |
1469 | tail_mark: | 1522 | tail_mark: |
1470 | done = tomoyo_io_printf(head, "\n"); | 1523 | done = tomoyo_io_printf(head, "\n"); |
1471 | if (!done) | 1524 | if (!done) |
1472 | break; | 1525 | break; |
1473 | head->read_step = 1; | 1526 | head->read_step = 1; |
1474 | if (head->read_single_domain) | 1527 | if (head->read_single_domain) |
1475 | break; | 1528 | break; |
1476 | } | 1529 | } |
1477 | up_read(&tomoyo_domain_list_lock); | 1530 | up_read(&tomoyo_domain_list_lock); |
1478 | head->read_eof = done; | 1531 | head->read_eof = done; |
1479 | return 0; | 1532 | return 0; |
1480 | } | 1533 | } |
1481 | 1534 | ||
1482 | /** | 1535 | /** |
1483 | * tomoyo_write_domain_profile - Assign profile for specified domain. | 1536 | * tomoyo_write_domain_profile - Assign profile for specified domain. |
1484 | * | 1537 | * |
1485 | * @head: Pointer to "struct tomoyo_io_buffer". | 1538 | * @head: Pointer to "struct tomoyo_io_buffer". |
1486 | * | 1539 | * |
1487 | * Returns 0 on success, -EINVAL otherwise. | 1540 | * Returns 0 on success, -EINVAL otherwise. |
1488 | * | 1541 | * |
1489 | * This is equivalent to doing | 1542 | * This is equivalent to doing |
1490 | * | 1543 | * |
1491 | * ( echo "select " $domainname; echo "use_profile " $profile ) | | 1544 | * ( echo "select " $domainname; echo "use_profile " $profile ) | |
1492 | * /usr/lib/ccs/loadpolicy -d | 1545 | * /usr/lib/ccs/loadpolicy -d |
1493 | */ | 1546 | */ |
1494 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | 1547 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) |
1495 | { | 1548 | { |
1496 | char *data = head->write_buf; | 1549 | char *data = head->write_buf; |
1497 | char *cp = strchr(data, ' '); | 1550 | char *cp = strchr(data, ' '); |
1498 | struct tomoyo_domain_info *domain; | 1551 | struct tomoyo_domain_info *domain; |
1499 | unsigned long profile; | 1552 | unsigned long profile; |
1500 | 1553 | ||
1501 | if (!cp) | 1554 | if (!cp) |
1502 | return -EINVAL; | 1555 | return -EINVAL; |
1503 | *cp = '\0'; | 1556 | *cp = '\0'; |
1504 | down_read(&tomoyo_domain_list_lock); | 1557 | down_read(&tomoyo_domain_list_lock); |
1505 | domain = tomoyo_find_domain(cp + 1); | 1558 | domain = tomoyo_find_domain(cp + 1); |
1506 | up_read(&tomoyo_domain_list_lock); | 1559 | up_read(&tomoyo_domain_list_lock); |
1507 | if (strict_strtoul(data, 10, &profile)) | 1560 | if (strict_strtoul(data, 10, &profile)) |
1508 | return -EINVAL; | 1561 | return -EINVAL; |
1509 | if (domain && profile < TOMOYO_MAX_PROFILES | 1562 | if (domain && profile < TOMOYO_MAX_PROFILES |
1510 | && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) | 1563 | && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) |
1511 | domain->profile = (u8) profile; | 1564 | domain->profile = (u8) profile; |
1512 | return 0; | 1565 | return 0; |
1513 | } | 1566 | } |
1514 | 1567 | ||
1515 | /** | 1568 | /** |
1516 | * tomoyo_read_domain_profile - Read only domainname and profile. | 1569 | * tomoyo_read_domain_profile - Read only domainname and profile. |
1517 | * | 1570 | * |
1518 | * @head: Pointer to "struct tomoyo_io_buffer". | 1571 | * @head: Pointer to "struct tomoyo_io_buffer". |
1519 | * | 1572 | * |
1520 | * Returns list of profile number and domainname pairs. | 1573 | * Returns list of profile number and domainname pairs. |
1521 | * | 1574 | * |
1522 | * This is equivalent to doing | 1575 | * This is equivalent to doing |
1523 | * | 1576 | * |
1524 | * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | | 1577 | * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | |
1525 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) | 1578 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) |
1526 | * domainname = $0; } else if ( $1 == "use_profile" ) { | 1579 | * domainname = $0; } else if ( $1 == "use_profile" ) { |
1527 | * print $2 " " domainname; domainname = ""; } } ; ' | 1580 | * print $2 " " domainname; domainname = ""; } } ; ' |
1528 | */ | 1581 | */ |
1529 | static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | 1582 | static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) |
1530 | { | 1583 | { |
1531 | struct list_head *pos; | 1584 | struct list_head *pos; |
1532 | bool done = true; | 1585 | bool done = true; |
1533 | 1586 | ||
1534 | if (head->read_eof) | 1587 | if (head->read_eof) |
1535 | return 0; | 1588 | return 0; |
1536 | down_read(&tomoyo_domain_list_lock); | 1589 | down_read(&tomoyo_domain_list_lock); |
1537 | list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { | 1590 | list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { |
1538 | struct tomoyo_domain_info *domain; | 1591 | struct tomoyo_domain_info *domain; |
1539 | domain = list_entry(pos, struct tomoyo_domain_info, list); | 1592 | domain = list_entry(pos, struct tomoyo_domain_info, list); |
1540 | if (domain->is_deleted) | 1593 | if (domain->is_deleted) |
1541 | continue; | 1594 | continue; |
1542 | done = tomoyo_io_printf(head, "%u %s\n", domain->profile, | 1595 | done = tomoyo_io_printf(head, "%u %s\n", domain->profile, |
1543 | domain->domainname->name); | 1596 | domain->domainname->name); |
1544 | if (!done) | 1597 | if (!done) |
1545 | break; | 1598 | break; |
1546 | } | 1599 | } |
1547 | up_read(&tomoyo_domain_list_lock); | 1600 | up_read(&tomoyo_domain_list_lock); |
1548 | head->read_eof = done; | 1601 | head->read_eof = done; |
1549 | return 0; | 1602 | return 0; |
1550 | } | 1603 | } |
1551 | 1604 | ||
1552 | /** | 1605 | /** |
1553 | * tomoyo_write_pid: Specify PID to obtain domainname. | 1606 | * tomoyo_write_pid: Specify PID to obtain domainname. |
1554 | * | 1607 | * |
1555 | * @head: Pointer to "struct tomoyo_io_buffer". | 1608 | * @head: Pointer to "struct tomoyo_io_buffer". |
1556 | * | 1609 | * |
1557 | * Returns 0. | 1610 | * Returns 0. |
1558 | */ | 1611 | */ |
1559 | static int tomoyo_write_pid(struct tomoyo_io_buffer *head) | 1612 | static int tomoyo_write_pid(struct tomoyo_io_buffer *head) |
1560 | { | 1613 | { |
1561 | unsigned long pid; | 1614 | unsigned long pid; |
1562 | /* No error check. */ | 1615 | /* No error check. */ |
1563 | strict_strtoul(head->write_buf, 10, &pid); | 1616 | strict_strtoul(head->write_buf, 10, &pid); |
1564 | head->read_step = (int) pid; | 1617 | head->read_step = (int) pid; |
1565 | head->read_eof = false; | 1618 | head->read_eof = false; |
1566 | return 0; | 1619 | return 0; |
1567 | } | 1620 | } |
1568 | 1621 | ||
1569 | /** | 1622 | /** |
1570 | * tomoyo_read_pid - Get domainname of the specified PID. | 1623 | * tomoyo_read_pid - Get domainname of the specified PID. |
1571 | * | 1624 | * |
1572 | * @head: Pointer to "struct tomoyo_io_buffer". | 1625 | * @head: Pointer to "struct tomoyo_io_buffer". |
1573 | * | 1626 | * |
1574 | * Returns the domainname which the specified PID is in on success, | 1627 | * Returns the domainname which the specified PID is in on success, |
1575 | * empty string otherwise. | 1628 | * empty string otherwise. |
1576 | * The PID is specified by tomoyo_write_pid() so that the user can obtain | 1629 | * The PID is specified by tomoyo_write_pid() so that the user can obtain |
1577 | * using read()/write() interface rather than sysctl() interface. | 1630 | * using read()/write() interface rather than sysctl() interface. |
1578 | */ | 1631 | */ |
1579 | static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | 1632 | static int tomoyo_read_pid(struct tomoyo_io_buffer *head) |
1580 | { | 1633 | { |
1581 | if (head->read_avail == 0 && !head->read_eof) { | 1634 | if (head->read_avail == 0 && !head->read_eof) { |
1582 | const int pid = head->read_step; | 1635 | const int pid = head->read_step; |
1583 | struct task_struct *p; | 1636 | struct task_struct *p; |
1584 | struct tomoyo_domain_info *domain = NULL; | 1637 | struct tomoyo_domain_info *domain = NULL; |
1585 | read_lock(&tasklist_lock); | 1638 | read_lock(&tasklist_lock); |
1586 | p = find_task_by_vpid(pid); | 1639 | p = find_task_by_vpid(pid); |
1587 | if (p) | 1640 | if (p) |
1588 | domain = tomoyo_real_domain(p); | 1641 | domain = tomoyo_real_domain(p); |
1589 | read_unlock(&tasklist_lock); | 1642 | read_unlock(&tasklist_lock); |
1590 | if (domain) | 1643 | if (domain) |
1591 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, | 1644 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, |
1592 | domain->domainname->name); | 1645 | domain->domainname->name); |
1593 | head->read_eof = true; | 1646 | head->read_eof = true; |
1594 | } | 1647 | } |
1595 | return 0; | 1648 | return 0; |
1596 | } | 1649 | } |
1597 | 1650 | ||
1598 | /** | 1651 | /** |
1599 | * tomoyo_write_exception_policy - Write exception policy. | 1652 | * tomoyo_write_exception_policy - Write exception policy. |
1600 | * | 1653 | * |
1601 | * @head: Pointer to "struct tomoyo_io_buffer". | 1654 | * @head: Pointer to "struct tomoyo_io_buffer". |
1602 | * | 1655 | * |
1603 | * Returns 0 on success, negative value otherwise. | 1656 | * Returns 0 on success, negative value otherwise. |
1604 | */ | 1657 | */ |
1605 | static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | 1658 | static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) |
1606 | { | 1659 | { |
1607 | char *data = head->write_buf; | 1660 | char *data = head->write_buf; |
1608 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | 1661 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); |
1609 | 1662 | ||
1610 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN)) | 1663 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN)) |
1611 | return tomoyo_write_domain_keeper_policy(data, false, | 1664 | return tomoyo_write_domain_keeper_policy(data, false, |
1612 | is_delete); | 1665 | is_delete); |
1613 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN)) | 1666 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN)) |
1614 | return tomoyo_write_domain_keeper_policy(data, true, is_delete); | 1667 | return tomoyo_write_domain_keeper_policy(data, true, is_delete); |
1615 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN)) | 1668 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN)) |
1616 | return tomoyo_write_domain_initializer_policy(data, false, | 1669 | return tomoyo_write_domain_initializer_policy(data, false, |
1617 | is_delete); | 1670 | is_delete); |
1618 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) | 1671 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) |
1619 | return tomoyo_write_domain_initializer_policy(data, true, | 1672 | return tomoyo_write_domain_initializer_policy(data, true, |
1620 | is_delete); | 1673 | is_delete); |
1621 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS)) | 1674 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS)) |
1622 | return tomoyo_write_alias_policy(data, is_delete); | 1675 | return tomoyo_write_alias_policy(data, is_delete); |
1623 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) | 1676 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) |
1624 | return tomoyo_write_globally_readable_policy(data, is_delete); | 1677 | return tomoyo_write_globally_readable_policy(data, is_delete); |
1625 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN)) | 1678 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN)) |
1626 | return tomoyo_write_pattern_policy(data, is_delete); | 1679 | return tomoyo_write_pattern_policy(data, is_delete); |
1627 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) | 1680 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) |
1628 | return tomoyo_write_no_rewrite_policy(data, is_delete); | 1681 | return tomoyo_write_no_rewrite_policy(data, is_delete); |
1629 | return -EINVAL; | 1682 | return -EINVAL; |
1630 | } | 1683 | } |
1631 | 1684 | ||
1632 | /** | 1685 | /** |
1633 | * tomoyo_read_exception_policy - Read exception policy. | 1686 | * tomoyo_read_exception_policy - Read exception policy. |
1634 | * | 1687 | * |
1635 | * @head: Pointer to "struct tomoyo_io_buffer". | 1688 | * @head: Pointer to "struct tomoyo_io_buffer". |
1636 | * | 1689 | * |
1637 | * Returns 0 on success, -EINVAL otherwise. | 1690 | * Returns 0 on success, -EINVAL otherwise. |
1638 | */ | 1691 | */ |
1639 | static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | 1692 | static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) |
1640 | { | 1693 | { |
1641 | if (!head->read_eof) { | 1694 | if (!head->read_eof) { |
1642 | switch (head->read_step) { | 1695 | switch (head->read_step) { |
1643 | case 0: | 1696 | case 0: |
1644 | head->read_var2 = NULL; | 1697 | head->read_var2 = NULL; |
1645 | head->read_step = 1; | 1698 | head->read_step = 1; |
1646 | case 1: | 1699 | case 1: |
1647 | if (!tomoyo_read_domain_keeper_policy(head)) | 1700 | if (!tomoyo_read_domain_keeper_policy(head)) |
1648 | break; | 1701 | break; |
1649 | head->read_var2 = NULL; | 1702 | head->read_var2 = NULL; |
1650 | head->read_step = 2; | 1703 | head->read_step = 2; |
1651 | case 2: | 1704 | case 2: |
1652 | if (!tomoyo_read_globally_readable_policy(head)) | 1705 | if (!tomoyo_read_globally_readable_policy(head)) |
1653 | break; | 1706 | break; |
1654 | head->read_var2 = NULL; | 1707 | head->read_var2 = NULL; |
1655 | head->read_step = 3; | 1708 | head->read_step = 3; |
1656 | case 3: | 1709 | case 3: |
1657 | head->read_var2 = NULL; | 1710 | head->read_var2 = NULL; |
1658 | head->read_step = 4; | 1711 | head->read_step = 4; |
1659 | case 4: | 1712 | case 4: |
1660 | if (!tomoyo_read_domain_initializer_policy(head)) | 1713 | if (!tomoyo_read_domain_initializer_policy(head)) |
1661 | break; | 1714 | break; |
1662 | head->read_var2 = NULL; | 1715 | head->read_var2 = NULL; |
1663 | head->read_step = 5; | 1716 | head->read_step = 5; |
1664 | case 5: | 1717 | case 5: |
1665 | if (!tomoyo_read_alias_policy(head)) | 1718 | if (!tomoyo_read_alias_policy(head)) |
1666 | break; | 1719 | break; |
1667 | head->read_var2 = NULL; | 1720 | head->read_var2 = NULL; |
1668 | head->read_step = 6; | 1721 | head->read_step = 6; |
1669 | case 6: | 1722 | case 6: |
1670 | head->read_var2 = NULL; | 1723 | head->read_var2 = NULL; |
1671 | head->read_step = 7; | 1724 | head->read_step = 7; |
1672 | case 7: | 1725 | case 7: |
1673 | if (!tomoyo_read_file_pattern(head)) | 1726 | if (!tomoyo_read_file_pattern(head)) |
1674 | break; | 1727 | break; |
1675 | head->read_var2 = NULL; | 1728 | head->read_var2 = NULL; |
1676 | head->read_step = 8; | 1729 | head->read_step = 8; |
1677 | case 8: | 1730 | case 8: |
1678 | if (!tomoyo_read_no_rewrite_policy(head)) | 1731 | if (!tomoyo_read_no_rewrite_policy(head)) |
1679 | break; | 1732 | break; |
1680 | head->read_var2 = NULL; | 1733 | head->read_var2 = NULL; |
1681 | head->read_step = 9; | 1734 | head->read_step = 9; |
1682 | case 9: | 1735 | case 9: |
1683 | head->read_eof = true; | 1736 | head->read_eof = true; |
1684 | break; | 1737 | break; |
1685 | default: | 1738 | default: |
1686 | return -EINVAL; | 1739 | return -EINVAL; |
1687 | } | 1740 | } |
1688 | } | 1741 | } |
1689 | return 0; | 1742 | return 0; |
1690 | } | 1743 | } |
1691 | 1744 | ||
1692 | /* path to policy loader */ | 1745 | /* path to policy loader */ |
1693 | static const char *tomoyo_loader = "/sbin/tomoyo-init"; | 1746 | static const char *tomoyo_loader = "/sbin/tomoyo-init"; |
1694 | 1747 | ||
1695 | /** | 1748 | /** |
1696 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. | 1749 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. |
1697 | * | 1750 | * |
1698 | * Returns true if /sbin/tomoyo-init exists, false otherwise. | 1751 | * Returns true if /sbin/tomoyo-init exists, false otherwise. |
1699 | */ | 1752 | */ |
1700 | static bool tomoyo_policy_loader_exists(void) | 1753 | static bool tomoyo_policy_loader_exists(void) |
1701 | { | 1754 | { |
1702 | /* | 1755 | /* |
1703 | * Don't activate MAC if the policy loader doesn't exist. | 1756 | * Don't activate MAC if the policy loader doesn't exist. |
1704 | * If the initrd includes /sbin/init but real-root-dev has not | 1757 | * If the initrd includes /sbin/init but real-root-dev has not |
1705 | * mounted on / yet, activating MAC will block the system since | 1758 | * mounted on / yet, activating MAC will block the system since |
1706 | * policies are not loaded yet. | 1759 | * policies are not loaded yet. |
1707 | * Thus, let do_execve() call this function everytime. | 1760 | * Thus, let do_execve() call this function everytime. |
1708 | */ | 1761 | */ |
1709 | struct path path; | 1762 | struct path path; |
1710 | 1763 | ||
1711 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { | 1764 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { |
1712 | printk(KERN_INFO "Not activating Mandatory Access Control now " | 1765 | printk(KERN_INFO "Not activating Mandatory Access Control now " |
1713 | "since %s doesn't exist.\n", tomoyo_loader); | 1766 | "since %s doesn't exist.\n", tomoyo_loader); |
1714 | return false; | 1767 | return false; |
1715 | } | 1768 | } |
1716 | path_put(&path); | 1769 | path_put(&path); |
1717 | return true; | 1770 | return true; |
1718 | } | 1771 | } |
1719 | 1772 | ||
1720 | /** | 1773 | /** |
1721 | * tomoyo_load_policy - Run external policy loader to load policy. | 1774 | * tomoyo_load_policy - Run external policy loader to load policy. |
1722 | * | 1775 | * |
1723 | * @filename: The program about to start. | 1776 | * @filename: The program about to start. |
1724 | * | 1777 | * |
1725 | * This function checks whether @filename is /sbin/init , and if so | 1778 | * This function checks whether @filename is /sbin/init , and if so |
1726 | * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init | 1779 | * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init |
1727 | * and then continues invocation of /sbin/init. | 1780 | * and then continues invocation of /sbin/init. |
1728 | * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and | 1781 | * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and |
1729 | * writes to /sys/kernel/security/tomoyo/ interfaces. | 1782 | * writes to /sys/kernel/security/tomoyo/ interfaces. |
1730 | * | 1783 | * |
1731 | * Returns nothing. | 1784 | * Returns nothing. |
1732 | */ | 1785 | */ |
1733 | void tomoyo_load_policy(const char *filename) | 1786 | void tomoyo_load_policy(const char *filename) |
1734 | { | 1787 | { |
1735 | char *argv[2]; | 1788 | char *argv[2]; |
1736 | char *envp[3]; | 1789 | char *envp[3]; |
1737 | 1790 | ||
1738 | if (tomoyo_policy_loaded) | 1791 | if (tomoyo_policy_loaded) |
1739 | return; | 1792 | return; |
1740 | /* | 1793 | /* |
1741 | * Check filename is /sbin/init or /sbin/tomoyo-start. | 1794 | * Check filename is /sbin/init or /sbin/tomoyo-start. |
1742 | * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't | 1795 | * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't |
1743 | * be passed. | 1796 | * be passed. |
1744 | * You can create /sbin/tomoyo-start by | 1797 | * You can create /sbin/tomoyo-start by |
1745 | * "ln -s /bin/true /sbin/tomoyo-start". | 1798 | * "ln -s /bin/true /sbin/tomoyo-start". |
1746 | */ | 1799 | */ |
1747 | if (strcmp(filename, "/sbin/init") && | 1800 | if (strcmp(filename, "/sbin/init") && |
1748 | strcmp(filename, "/sbin/tomoyo-start")) | 1801 | strcmp(filename, "/sbin/tomoyo-start")) |
1749 | return; | 1802 | return; |
1750 | if (!tomoyo_policy_loader_exists()) | 1803 | if (!tomoyo_policy_loader_exists()) |
1751 | return; | 1804 | return; |
1752 | 1805 | ||
1753 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", | 1806 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", |
1754 | tomoyo_loader); | 1807 | tomoyo_loader); |
1755 | argv[0] = (char *) tomoyo_loader; | 1808 | argv[0] = (char *) tomoyo_loader; |
1756 | argv[1] = NULL; | 1809 | argv[1] = NULL; |
1757 | envp[0] = "HOME=/"; | 1810 | envp[0] = "HOME=/"; |
1758 | envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | 1811 | envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; |
1759 | envp[2] = NULL; | 1812 | envp[2] = NULL; |
1760 | call_usermodehelper(argv[0], argv, envp, 1); | 1813 | call_usermodehelper(argv[0], argv, envp, 1); |
1761 | 1814 | ||
1762 | printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n"); | 1815 | printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n"); |
1763 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 1816 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
1764 | tomoyo_policy_loaded = true; | 1817 | tomoyo_policy_loaded = true; |
1765 | { /* Check all profiles currently assigned to domains are defined. */ | 1818 | { /* Check all profiles currently assigned to domains are defined. */ |
1766 | struct tomoyo_domain_info *domain; | 1819 | struct tomoyo_domain_info *domain; |
1767 | down_read(&tomoyo_domain_list_lock); | 1820 | down_read(&tomoyo_domain_list_lock); |
1768 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 1821 | list_for_each_entry(domain, &tomoyo_domain_list, list) { |
1769 | const u8 profile = domain->profile; | 1822 | const u8 profile = domain->profile; |
1770 | if (tomoyo_profile_ptr[profile]) | 1823 | if (tomoyo_profile_ptr[profile]) |
1771 | continue; | 1824 | continue; |
1772 | panic("Profile %u (used by '%s') not defined.\n", | 1825 | panic("Profile %u (used by '%s') not defined.\n", |
1773 | profile, domain->domainname->name); | 1826 | profile, domain->domainname->name); |
1774 | } | 1827 | } |
1775 | up_read(&tomoyo_domain_list_lock); | 1828 | up_read(&tomoyo_domain_list_lock); |
1776 | } | 1829 | } |
1777 | } | 1830 | } |
1778 | 1831 | ||
1779 | /** | 1832 | /** |
1780 | * tomoyo_read_version: Get version. | 1833 | * tomoyo_read_version: Get version. |
1781 | * | 1834 | * |
1782 | * @head: Pointer to "struct tomoyo_io_buffer". | 1835 | * @head: Pointer to "struct tomoyo_io_buffer". |
1783 | * | 1836 | * |
1784 | * Returns version information. | 1837 | * Returns version information. |
1785 | */ | 1838 | */ |
1786 | static int tomoyo_read_version(struct tomoyo_io_buffer *head) | 1839 | static int tomoyo_read_version(struct tomoyo_io_buffer *head) |
1787 | { | 1840 | { |
1788 | if (!head->read_eof) { | 1841 | if (!head->read_eof) { |
1789 | tomoyo_io_printf(head, "2.2.0"); | 1842 | tomoyo_io_printf(head, "2.2.0"); |
1790 | head->read_eof = true; | 1843 | head->read_eof = true; |
1791 | } | 1844 | } |
1792 | return 0; | 1845 | return 0; |
1793 | } | 1846 | } |
1794 | 1847 | ||
1795 | /** | 1848 | /** |
1796 | * tomoyo_read_self_domain - Get the current process's domainname. | 1849 | * tomoyo_read_self_domain - Get the current process's domainname. |
1797 | * | 1850 | * |
1798 | * @head: Pointer to "struct tomoyo_io_buffer". | 1851 | * @head: Pointer to "struct tomoyo_io_buffer". |
1799 | * | 1852 | * |
1800 | * Returns the current process's domainname. | 1853 | * Returns the current process's domainname. |
1801 | */ | 1854 | */ |
1802 | static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | 1855 | static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) |
1803 | { | 1856 | { |
1804 | if (!head->read_eof) { | 1857 | if (!head->read_eof) { |
1805 | /* | 1858 | /* |
1806 | * tomoyo_domain()->domainname != NULL | 1859 | * tomoyo_domain()->domainname != NULL |
1807 | * because every process belongs to a domain and | 1860 | * because every process belongs to a domain and |
1808 | * the domain's name cannot be NULL. | 1861 | * the domain's name cannot be NULL. |
1809 | */ | 1862 | */ |
1810 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); | 1863 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); |
1811 | head->read_eof = true; | 1864 | head->read_eof = true; |
1812 | } | 1865 | } |
1813 | return 0; | 1866 | return 0; |
1814 | } | 1867 | } |
1815 | 1868 | ||
1816 | /** | 1869 | /** |
1817 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. | 1870 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. |
1818 | * | 1871 | * |
1819 | * @type: Type of interface. | 1872 | * @type: Type of interface. |
1820 | * @file: Pointer to "struct file". | 1873 | * @file: Pointer to "struct file". |
1821 | * | 1874 | * |
1822 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. | 1875 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. |
1823 | */ | 1876 | */ |
1824 | static int tomoyo_open_control(const u8 type, struct file *file) | 1877 | static int tomoyo_open_control(const u8 type, struct file *file) |
1825 | { | 1878 | { |
1826 | struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head)); | 1879 | struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head)); |
1827 | 1880 | ||
1828 | if (!head) | 1881 | if (!head) |
1829 | return -ENOMEM; | 1882 | return -ENOMEM; |
1830 | mutex_init(&head->io_sem); | 1883 | mutex_init(&head->io_sem); |
1831 | switch (type) { | 1884 | switch (type) { |
1832 | case TOMOYO_DOMAINPOLICY: | 1885 | case TOMOYO_DOMAINPOLICY: |
1833 | /* /sys/kernel/security/tomoyo/domain_policy */ | 1886 | /* /sys/kernel/security/tomoyo/domain_policy */ |
1834 | head->write = tomoyo_write_domain_policy; | 1887 | head->write = tomoyo_write_domain_policy; |
1835 | head->read = tomoyo_read_domain_policy; | 1888 | head->read = tomoyo_read_domain_policy; |
1836 | break; | 1889 | break; |
1837 | case TOMOYO_EXCEPTIONPOLICY: | 1890 | case TOMOYO_EXCEPTIONPOLICY: |
1838 | /* /sys/kernel/security/tomoyo/exception_policy */ | 1891 | /* /sys/kernel/security/tomoyo/exception_policy */ |
1839 | head->write = tomoyo_write_exception_policy; | 1892 | head->write = tomoyo_write_exception_policy; |
1840 | head->read = tomoyo_read_exception_policy; | 1893 | head->read = tomoyo_read_exception_policy; |
1841 | break; | 1894 | break; |
1842 | case TOMOYO_SELFDOMAIN: | 1895 | case TOMOYO_SELFDOMAIN: |
1843 | /* /sys/kernel/security/tomoyo/self_domain */ | 1896 | /* /sys/kernel/security/tomoyo/self_domain */ |
1844 | head->read = tomoyo_read_self_domain; | 1897 | head->read = tomoyo_read_self_domain; |
1845 | break; | 1898 | break; |
1846 | case TOMOYO_DOMAIN_STATUS: | 1899 | case TOMOYO_DOMAIN_STATUS: |
1847 | /* /sys/kernel/security/tomoyo/.domain_status */ | 1900 | /* /sys/kernel/security/tomoyo/.domain_status */ |
1848 | head->write = tomoyo_write_domain_profile; | 1901 | head->write = tomoyo_write_domain_profile; |
1849 | head->read = tomoyo_read_domain_profile; | 1902 | head->read = tomoyo_read_domain_profile; |
1850 | break; | 1903 | break; |
1851 | case TOMOYO_PROCESS_STATUS: | 1904 | case TOMOYO_PROCESS_STATUS: |
1852 | /* /sys/kernel/security/tomoyo/.process_status */ | 1905 | /* /sys/kernel/security/tomoyo/.process_status */ |
1853 | head->write = tomoyo_write_pid; | 1906 | head->write = tomoyo_write_pid; |
1854 | head->read = tomoyo_read_pid; | 1907 | head->read = tomoyo_read_pid; |
1855 | break; | 1908 | break; |
1856 | case TOMOYO_VERSION: | 1909 | case TOMOYO_VERSION: |
1857 | /* /sys/kernel/security/tomoyo/version */ | 1910 | /* /sys/kernel/security/tomoyo/version */ |
1858 | head->read = tomoyo_read_version; | 1911 | head->read = tomoyo_read_version; |
1859 | head->readbuf_size = 128; | 1912 | head->readbuf_size = 128; |
1860 | break; | 1913 | break; |
1861 | case TOMOYO_MEMINFO: | 1914 | case TOMOYO_MEMINFO: |
1862 | /* /sys/kernel/security/tomoyo/meminfo */ | 1915 | /* /sys/kernel/security/tomoyo/meminfo */ |
1863 | head->write = tomoyo_write_memory_quota; | 1916 | head->write = tomoyo_write_memory_quota; |
1864 | head->read = tomoyo_read_memory_counter; | 1917 | head->read = tomoyo_read_memory_counter; |
1865 | head->readbuf_size = 512; | 1918 | head->readbuf_size = 512; |
1866 | break; | 1919 | break; |
1867 | case TOMOYO_PROFILE: | 1920 | case TOMOYO_PROFILE: |
1868 | /* /sys/kernel/security/tomoyo/profile */ | 1921 | /* /sys/kernel/security/tomoyo/profile */ |
1869 | head->write = tomoyo_write_profile; | 1922 | head->write = tomoyo_write_profile; |
1870 | head->read = tomoyo_read_profile; | 1923 | head->read = tomoyo_read_profile; |
1871 | break; | 1924 | break; |
1872 | case TOMOYO_MANAGER: | 1925 | case TOMOYO_MANAGER: |
1873 | /* /sys/kernel/security/tomoyo/manager */ | 1926 | /* /sys/kernel/security/tomoyo/manager */ |
1874 | head->write = tomoyo_write_manager_policy; | 1927 | head->write = tomoyo_write_manager_policy; |
1875 | head->read = tomoyo_read_manager_policy; | 1928 | head->read = tomoyo_read_manager_policy; |
1876 | break; | 1929 | break; |
1877 | } | 1930 | } |
1878 | if (!(file->f_mode & FMODE_READ)) { | 1931 | if (!(file->f_mode & FMODE_READ)) { |
1879 | /* | 1932 | /* |
1880 | * No need to allocate read_buf since it is not opened | 1933 | * No need to allocate read_buf since it is not opened |
1881 | * for reading. | 1934 | * for reading. |
1882 | */ | 1935 | */ |
1883 | head->read = NULL; | 1936 | head->read = NULL; |
1884 | } else { | 1937 | } else { |
1885 | if (!head->readbuf_size) | 1938 | if (!head->readbuf_size) |
1886 | head->readbuf_size = 4096 * 2; | 1939 | head->readbuf_size = 4096 * 2; |
1887 | head->read_buf = tomoyo_alloc(head->readbuf_size); | 1940 | head->read_buf = tomoyo_alloc(head->readbuf_size); |
1888 | if (!head->read_buf) { | 1941 | if (!head->read_buf) { |
1889 | tomoyo_free(head); | 1942 | tomoyo_free(head); |
1890 | return -ENOMEM; | 1943 | return -ENOMEM; |
1891 | } | 1944 | } |
1892 | } | 1945 | } |
1893 | if (!(file->f_mode & FMODE_WRITE)) { | 1946 | if (!(file->f_mode & FMODE_WRITE)) { |
1894 | /* | 1947 | /* |
1895 | * No need to allocate write_buf since it is not opened | 1948 | * No need to allocate write_buf since it is not opened |
1896 | * for writing. | 1949 | * for writing. |
1897 | */ | 1950 | */ |
1898 | head->write = NULL; | 1951 | head->write = NULL; |
1899 | } else if (head->write) { | 1952 | } else if (head->write) { |
1900 | head->writebuf_size = 4096 * 2; | 1953 | head->writebuf_size = 4096 * 2; |
1901 | head->write_buf = tomoyo_alloc(head->writebuf_size); | 1954 | head->write_buf = tomoyo_alloc(head->writebuf_size); |
1902 | if (!head->write_buf) { | 1955 | if (!head->write_buf) { |
1903 | tomoyo_free(head->read_buf); | 1956 | tomoyo_free(head->read_buf); |
1904 | tomoyo_free(head); | 1957 | tomoyo_free(head); |
1905 | return -ENOMEM; | 1958 | return -ENOMEM; |
1906 | } | 1959 | } |
1907 | } | 1960 | } |
1908 | file->private_data = head; | 1961 | file->private_data = head; |
1909 | /* | 1962 | /* |
1910 | * Call the handler now if the file is | 1963 | * Call the handler now if the file is |
1911 | * /sys/kernel/security/tomoyo/self_domain | 1964 | * /sys/kernel/security/tomoyo/self_domain |
1912 | * so that the user can use | 1965 | * so that the user can use |
1913 | * cat < /sys/kernel/security/tomoyo/self_domain" | 1966 | * cat < /sys/kernel/security/tomoyo/self_domain" |
1914 | * to know the current process's domainname. | 1967 | * to know the current process's domainname. |
1915 | */ | 1968 | */ |
1916 | if (type == TOMOYO_SELFDOMAIN) | 1969 | if (type == TOMOYO_SELFDOMAIN) |
1917 | tomoyo_read_control(file, NULL, 0); | 1970 | tomoyo_read_control(file, NULL, 0); |
1918 | return 0; | 1971 | return 0; |
1919 | } | 1972 | } |
1920 | 1973 | ||
1921 | /** | 1974 | /** |
1922 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. | 1975 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. |
1923 | * | 1976 | * |
1924 | * @file: Pointer to "struct file". | 1977 | * @file: Pointer to "struct file". |
1925 | * @buffer: Poiner to buffer to write to. | 1978 | * @buffer: Poiner to buffer to write to. |
1926 | * @buffer_len: Size of @buffer. | 1979 | * @buffer_len: Size of @buffer. |
1927 | * | 1980 | * |
1928 | * Returns bytes read on success, negative value otherwise. | 1981 | * Returns bytes read on success, negative value otherwise. |
1929 | */ | 1982 | */ |
1930 | static int tomoyo_read_control(struct file *file, char __user *buffer, | 1983 | static int tomoyo_read_control(struct file *file, char __user *buffer, |
1931 | const int buffer_len) | 1984 | const int buffer_len) |
1932 | { | 1985 | { |
1933 | int len = 0; | 1986 | int len = 0; |
1934 | struct tomoyo_io_buffer *head = file->private_data; | 1987 | struct tomoyo_io_buffer *head = file->private_data; |
1935 | char *cp; | 1988 | char *cp; |
1936 | 1989 | ||
1937 | if (!head->read) | 1990 | if (!head->read) |
1938 | return -ENOSYS; | 1991 | return -ENOSYS; |
1939 | if (mutex_lock_interruptible(&head->io_sem)) | 1992 | if (mutex_lock_interruptible(&head->io_sem)) |
1940 | return -EINTR; | 1993 | return -EINTR; |
1941 | /* Call the policy handler. */ | 1994 | /* Call the policy handler. */ |
1942 | len = head->read(head); | 1995 | len = head->read(head); |
1943 | if (len < 0) | 1996 | if (len < 0) |
1944 | goto out; | 1997 | goto out; |
1945 | /* Write to buffer. */ | 1998 | /* Write to buffer. */ |
1946 | len = head->read_avail; | 1999 | len = head->read_avail; |
1947 | if (len > buffer_len) | 2000 | if (len > buffer_len) |
1948 | len = buffer_len; | 2001 | len = buffer_len; |
1949 | if (!len) | 2002 | if (!len) |
1950 | goto out; | 2003 | goto out; |
1951 | /* head->read_buf changes by some functions. */ | 2004 | /* head->read_buf changes by some functions. */ |
1952 | cp = head->read_buf; | 2005 | cp = head->read_buf; |
1953 | if (copy_to_user(buffer, cp, len)) { | 2006 | if (copy_to_user(buffer, cp, len)) { |
1954 | len = -EFAULT; | 2007 | len = -EFAULT; |
1955 | goto out; | 2008 | goto out; |
1956 | } | 2009 | } |
1957 | head->read_avail -= len; | 2010 | head->read_avail -= len; |
1958 | memmove(cp, cp + len, head->read_avail); | 2011 | memmove(cp, cp + len, head->read_avail); |
1959 | out: | 2012 | out: |
1960 | mutex_unlock(&head->io_sem); | 2013 | mutex_unlock(&head->io_sem); |
1961 | return len; | 2014 | return len; |
1962 | } | 2015 | } |
1963 | 2016 | ||
1964 | /** | 2017 | /** |
1965 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. | 2018 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. |
1966 | * | 2019 | * |
1967 | * @file: Pointer to "struct file". | 2020 | * @file: Pointer to "struct file". |
1968 | * @buffer: Pointer to buffer to read from. | 2021 | * @buffer: Pointer to buffer to read from. |
1969 | * @buffer_len: Size of @buffer. | 2022 | * @buffer_len: Size of @buffer. |
1970 | * | 2023 | * |
1971 | * Returns @buffer_len on success, negative value otherwise. | 2024 | * Returns @buffer_len on success, negative value otherwise. |
1972 | */ | 2025 | */ |
1973 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | 2026 | static int tomoyo_write_control(struct file *file, const char __user *buffer, |
1974 | const int buffer_len) | 2027 | const int buffer_len) |
1975 | { | 2028 | { |
1976 | struct tomoyo_io_buffer *head = file->private_data; | 2029 | struct tomoyo_io_buffer *head = file->private_data; |
1977 | int error = buffer_len; | 2030 | int error = buffer_len; |
1978 | int avail_len = buffer_len; | 2031 | int avail_len = buffer_len; |
1979 | char *cp0 = head->write_buf; | 2032 | char *cp0 = head->write_buf; |
1980 | 2033 | ||
1981 | if (!head->write) | 2034 | if (!head->write) |
1982 | return -ENOSYS; | 2035 | return -ENOSYS; |
1983 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) | 2036 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
1984 | return -EFAULT; | 2037 | return -EFAULT; |
1985 | /* Don't allow updating policies by non manager programs. */ | 2038 | /* Don't allow updating policies by non manager programs. */ |
1986 | if (head->write != tomoyo_write_pid && | 2039 | if (head->write != tomoyo_write_pid && |
1987 | head->write != tomoyo_write_domain_policy && | 2040 | head->write != tomoyo_write_domain_policy && |
1988 | !tomoyo_is_policy_manager()) | 2041 | !tomoyo_is_policy_manager()) |
1989 | return -EPERM; | 2042 | return -EPERM; |
1990 | if (mutex_lock_interruptible(&head->io_sem)) | 2043 | if (mutex_lock_interruptible(&head->io_sem)) |
1991 | return -EINTR; | 2044 | return -EINTR; |
1992 | /* Read a line and dispatch it to the policy handler. */ | 2045 | /* Read a line and dispatch it to the policy handler. */ |
1993 | while (avail_len > 0) { | 2046 | while (avail_len > 0) { |
1994 | char c; | 2047 | char c; |
1995 | if (head->write_avail >= head->writebuf_size - 1) { | 2048 | if (head->write_avail >= head->writebuf_size - 1) { |
1996 | error = -ENOMEM; | 2049 | error = -ENOMEM; |
1997 | break; | 2050 | break; |
1998 | } else if (get_user(c, buffer)) { | 2051 | } else if (get_user(c, buffer)) { |
1999 | error = -EFAULT; | 2052 | error = -EFAULT; |
2000 | break; | 2053 | break; |
2001 | } | 2054 | } |
2002 | buffer++; | 2055 | buffer++; |
2003 | avail_len--; | 2056 | avail_len--; |
2004 | cp0[head->write_avail++] = c; | 2057 | cp0[head->write_avail++] = c; |
2005 | if (c != '\n') | 2058 | if (c != '\n') |
2006 | continue; | 2059 | continue; |
2007 | cp0[head->write_avail - 1] = '\0'; | 2060 | cp0[head->write_avail - 1] = '\0'; |
2008 | head->write_avail = 0; | 2061 | head->write_avail = 0; |
2009 | tomoyo_normalize_line(cp0); | 2062 | tomoyo_normalize_line(cp0); |
2010 | head->write(head); | 2063 | head->write(head); |
2011 | } | 2064 | } |
2012 | mutex_unlock(&head->io_sem); | 2065 | mutex_unlock(&head->io_sem); |
2013 | return error; | 2066 | return error; |
2014 | } | 2067 | } |
2015 | 2068 | ||
2016 | /** | 2069 | /** |
2017 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. | 2070 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. |
2018 | * | 2071 | * |
2019 | * @file: Pointer to "struct file". | 2072 | * @file: Pointer to "struct file". |
2020 | * | 2073 | * |
2021 | * Releases memory and returns 0. | 2074 | * Releases memory and returns 0. |
2022 | */ | 2075 | */ |
2023 | static int tomoyo_close_control(struct file *file) | 2076 | static int tomoyo_close_control(struct file *file) |
2024 | { | 2077 | { |
2025 | struct tomoyo_io_buffer *head = file->private_data; | 2078 | struct tomoyo_io_buffer *head = file->private_data; |
2026 | 2079 | ||
2027 | /* Release memory used for policy I/O. */ | 2080 | /* Release memory used for policy I/O. */ |
2028 | tomoyo_free(head->read_buf); | 2081 | tomoyo_free(head->read_buf); |
2029 | head->read_buf = NULL; | 2082 | head->read_buf = NULL; |
2030 | tomoyo_free(head->write_buf); | 2083 | tomoyo_free(head->write_buf); |
2031 | head->write_buf = NULL; | 2084 | head->write_buf = NULL; |
2032 | tomoyo_free(head); | 2085 | tomoyo_free(head); |
2033 | head = NULL; | 2086 | head = NULL; |
2034 | file->private_data = NULL; | 2087 | file->private_data = NULL; |
2035 | return 0; | 2088 | return 0; |
2036 | } | 2089 | } |
2037 | 2090 | ||
2038 | /** | 2091 | /** |
2039 | * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry. | 2092 | * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry. |
2040 | * | 2093 | * |
2041 | * @acl_type: Type of ACL entry. | 2094 | * @acl_type: Type of ACL entry. |
2042 | * | 2095 | * |
2043 | * Returns pointer to the ACL entry on success, NULL otherwise. | 2096 | * Returns pointer to the ACL entry on success, NULL otherwise. |
2044 | */ | 2097 | */ |
2045 | void *tomoyo_alloc_acl_element(const u8 acl_type) | 2098 | void *tomoyo_alloc_acl_element(const u8 acl_type) |
2046 | { | 2099 | { |
2047 | int len; | 2100 | int len; |
2048 | struct tomoyo_acl_info *ptr; | 2101 | struct tomoyo_acl_info *ptr; |
2049 | 2102 | ||
2050 | switch (acl_type) { | 2103 | switch (acl_type) { |
2051 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | 2104 | case TOMOYO_TYPE_SINGLE_PATH_ACL: |
2052 | len = sizeof(struct tomoyo_single_path_acl_record); | 2105 | len = sizeof(struct tomoyo_single_path_acl_record); |
2053 | break; | 2106 | break; |
2054 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | 2107 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: |
2055 | len = sizeof(struct tomoyo_double_path_acl_record); | 2108 | len = sizeof(struct tomoyo_double_path_acl_record); |
2056 | break; | 2109 | break; |
2057 | default: | 2110 | default: |
2058 | return NULL; | 2111 | return NULL; |
2059 | } | 2112 | } |
2060 | ptr = tomoyo_alloc_element(len); | 2113 | ptr = tomoyo_alloc_element(len); |
2061 | if (!ptr) | 2114 | if (!ptr) |
2062 | return NULL; | 2115 | return NULL; |
2063 | ptr->type = acl_type; | 2116 | ptr->type = acl_type; |
2064 | return ptr; | 2117 | return ptr; |
2065 | } | 2118 | } |
2066 | 2119 | ||
2067 | /** | 2120 | /** |
2068 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | 2121 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. |
2069 | * | 2122 | * |
2070 | * @inode: Pointer to "struct inode". | 2123 | * @inode: Pointer to "struct inode". |
2071 | * @file: Pointer to "struct file". | 2124 | * @file: Pointer to "struct file". |
2072 | * | 2125 | * |
2073 | * Returns 0 on success, negative value otherwise. | 2126 | * Returns 0 on success, negative value otherwise. |
2074 | */ | 2127 | */ |
2075 | static int tomoyo_open(struct inode *inode, struct file *file) | 2128 | static int tomoyo_open(struct inode *inode, struct file *file) |
2076 | { | 2129 | { |
2077 | const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) | 2130 | const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) |
2078 | - ((u8 *) NULL); | 2131 | - ((u8 *) NULL); |
2079 | return tomoyo_open_control(key, file); | 2132 | return tomoyo_open_control(key, file); |
2080 | } | 2133 | } |
2081 | 2134 | ||
2082 | /** | 2135 | /** |
2083 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. | 2136 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. |
2084 | * | 2137 | * |
2085 | * @inode: Pointer to "struct inode". | 2138 | * @inode: Pointer to "struct inode". |
2086 | * @file: Pointer to "struct file". | 2139 | * @file: Pointer to "struct file". |
2087 | * | 2140 | * |
2088 | * Returns 0 on success, negative value otherwise. | 2141 | * Returns 0 on success, negative value otherwise. |
2089 | */ | 2142 | */ |
2090 | static int tomoyo_release(struct inode *inode, struct file *file) | 2143 | static int tomoyo_release(struct inode *inode, struct file *file) |
2091 | { | 2144 | { |
2092 | return tomoyo_close_control(file); | 2145 | return tomoyo_close_control(file); |
2093 | } | 2146 | } |
2094 | 2147 | ||
2095 | /** | 2148 | /** |
2096 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. | 2149 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. |
2097 | * | 2150 | * |
2098 | * @file: Pointer to "struct file". | 2151 | * @file: Pointer to "struct file". |
2099 | * @buf: Pointer to buffer. | 2152 | * @buf: Pointer to buffer. |
2100 | * @count: Size of @buf. | 2153 | * @count: Size of @buf. |
2101 | * @ppos: Unused. | 2154 | * @ppos: Unused. |
2102 | * | 2155 | * |
2103 | * Returns bytes read on success, negative value otherwise. | 2156 | * Returns bytes read on success, negative value otherwise. |
2104 | */ | 2157 | */ |
2105 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, | 2158 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, |
2106 | loff_t *ppos) | 2159 | loff_t *ppos) |
2107 | { | 2160 | { |
2108 | return tomoyo_read_control(file, buf, count); | 2161 | return tomoyo_read_control(file, buf, count); |
2109 | } | 2162 | } |
2110 | 2163 | ||
2111 | /** | 2164 | /** |
2112 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. | 2165 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. |
2113 | * | 2166 | * |
2114 | * @file: Pointer to "struct file". | 2167 | * @file: Pointer to "struct file". |
2115 | * @buf: Pointer to buffer. | 2168 | * @buf: Pointer to buffer. |
2116 | * @count: Size of @buf. | 2169 | * @count: Size of @buf. |
2117 | * @ppos: Unused. | 2170 | * @ppos: Unused. |
2118 | * | 2171 | * |
2119 | * Returns @count on success, negative value otherwise. | 2172 | * Returns @count on success, negative value otherwise. |
2120 | */ | 2173 | */ |
2121 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, | 2174 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, |
2122 | size_t count, loff_t *ppos) | 2175 | size_t count, loff_t *ppos) |
2123 | { | 2176 | { |
2124 | return tomoyo_write_control(file, buf, count); | 2177 | return tomoyo_write_control(file, buf, count); |
2125 | } | 2178 | } |
2126 | 2179 | ||
2127 | /* Operations for /sys/kernel/security/tomoyo/ interface. */ | 2180 | /* |
2181 | * tomoyo_operations is a "struct file_operations" which is used for handling | ||
2182 | * /sys/kernel/security/tomoyo/ interface. | ||
2183 | * | ||
2184 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | ||
2185 | * See tomoyo_io_buffer for internals. | ||
2186 | */ | ||
2128 | static const struct file_operations tomoyo_operations = { | 2187 | static const struct file_operations tomoyo_operations = { |
2129 | .open = tomoyo_open, | 2188 | .open = tomoyo_open, |
2130 | .release = tomoyo_release, | 2189 | .release = tomoyo_release, |
2131 | .read = tomoyo_read, | 2190 | .read = tomoyo_read, |
2132 | .write = tomoyo_write, | 2191 | .write = tomoyo_write, |
2133 | }; | 2192 | }; |
2134 | 2193 | ||
2135 | /** | 2194 | /** |
2136 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. | 2195 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. |
2137 | * | 2196 | * |
2138 | * @name: The name of the interface file. | 2197 | * @name: The name of the interface file. |
2139 | * @mode: The permission of the interface file. | 2198 | * @mode: The permission of the interface file. |
2140 | * @parent: The parent directory. | 2199 | * @parent: The parent directory. |
2141 | * @key: Type of interface. | 2200 | * @key: Type of interface. |
2142 | * | 2201 | * |
2143 | * Returns nothing. | 2202 | * Returns nothing. |
2144 | */ | 2203 | */ |
2145 | static void __init tomoyo_create_entry(const char *name, const mode_t mode, | 2204 | static void __init tomoyo_create_entry(const char *name, const mode_t mode, |
2146 | struct dentry *parent, const u8 key) | 2205 | struct dentry *parent, const u8 key) |
2147 | { | 2206 | { |
2148 | securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, | 2207 | securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, |
2149 | &tomoyo_operations); | 2208 | &tomoyo_operations); |
2150 | } | 2209 | } |
2151 | 2210 | ||
2152 | /** | 2211 | /** |
2153 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. | 2212 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. |
2154 | * | 2213 | * |
2155 | * Returns 0. | 2214 | * Returns 0. |
2156 | */ | 2215 | */ |
2157 | static int __init tomoyo_initerface_init(void) | 2216 | static int __init tomoyo_initerface_init(void) |
2158 | { | 2217 | { |
2159 | struct dentry *tomoyo_dir; | 2218 | struct dentry *tomoyo_dir; |
2160 | 2219 | ||
2161 | /* Don't create securityfs entries unless registered. */ | 2220 | /* Don't create securityfs entries unless registered. */ |
2162 | if (current_cred()->security != &tomoyo_kernel_domain) | 2221 | if (current_cred()->security != &tomoyo_kernel_domain) |
2163 | return 0; | 2222 | return 0; |
2164 | 2223 | ||
2165 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); | 2224 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); |
2166 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, | 2225 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, |
2167 | TOMOYO_DOMAINPOLICY); | 2226 | TOMOYO_DOMAINPOLICY); |
2168 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, | 2227 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, |
2169 | TOMOYO_EXCEPTIONPOLICY); | 2228 | TOMOYO_EXCEPTIONPOLICY); |
2170 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, | 2229 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, |
2171 | TOMOYO_SELFDOMAIN); | 2230 | TOMOYO_SELFDOMAIN); |
2172 | tomoyo_create_entry(".domain_status", 0600, tomoyo_dir, | 2231 | tomoyo_create_entry(".domain_status", 0600, tomoyo_dir, |
2173 | TOMOYO_DOMAIN_STATUS); | 2232 | TOMOYO_DOMAIN_STATUS); |
2174 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, | 2233 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, |
2175 | TOMOYO_PROCESS_STATUS); | 2234 | TOMOYO_PROCESS_STATUS); |
2176 | tomoyo_create_entry("meminfo", 0600, tomoyo_dir, | 2235 | tomoyo_create_entry("meminfo", 0600, tomoyo_dir, |
2177 | TOMOYO_MEMINFO); | 2236 | TOMOYO_MEMINFO); |
2178 | tomoyo_create_entry("profile", 0600, tomoyo_dir, | 2237 | tomoyo_create_entry("profile", 0600, tomoyo_dir, |
2179 | TOMOYO_PROFILE); | 2238 | TOMOYO_PROFILE); |
2180 | tomoyo_create_entry("manager", 0600, tomoyo_dir, | 2239 | tomoyo_create_entry("manager", 0600, tomoyo_dir, |
2181 | TOMOYO_MANAGER); | 2240 | TOMOYO_MANAGER); |
2182 | tomoyo_create_entry("version", 0400, tomoyo_dir, | 2241 | tomoyo_create_entry("version", 0400, tomoyo_dir, |
2183 | TOMOYO_VERSION); | 2242 | TOMOYO_VERSION); |
2184 | return 0; | 2243 | return 0; |
2185 | } | 2244 | } |
2186 | 2245 | ||
2187 | fs_initcall(tomoyo_initerface_init); | 2246 | fs_initcall(tomoyo_initerface_init); |
2188 | 2247 |
security/tomoyo/common.h
1 | /* | 1 | /* |
2 | * security/tomoyo/common.h | 2 | * security/tomoyo/common.h |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Common functions for TOMOYO. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * | 7 | * |
8 | * Version: 2.2.0 2009/04/01 | 8 | * Version: 2.2.0 2009/04/01 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef _SECURITY_TOMOYO_COMMON_H | 12 | #ifndef _SECURITY_TOMOYO_COMMON_H |
13 | #define _SECURITY_TOMOYO_COMMON_H | 13 | #define _SECURITY_TOMOYO_COMMON_H |
14 | 14 | ||
15 | #include <linux/ctype.h> | 15 | #include <linux/ctype.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/file.h> | 18 | #include <linux/file.h> |
19 | #include <linux/kmod.h> | 19 | #include <linux/kmod.h> |
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/namei.h> | 22 | #include <linux/namei.h> |
23 | #include <linux/mount.h> | 23 | #include <linux/mount.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | 25 | ||
26 | struct dentry; | 26 | struct dentry; |
27 | struct vfsmount; | 27 | struct vfsmount; |
28 | 28 | ||
29 | /* Temporary buffer for holding pathnames. */ | 29 | /* |
30 | * tomoyo_page_buffer is a structure which is used for holding a pathname | ||
31 | * obtained from "struct dentry" and "struct vfsmount" pair. | ||
32 | * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small | ||
33 | * (because TOMOYO escapes non ASCII printable characters using \ooo format), | ||
34 | * we will make the buffer larger. | ||
35 | */ | ||
30 | struct tomoyo_page_buffer { | 36 | struct tomoyo_page_buffer { |
31 | char buffer[4096]; | 37 | char buffer[4096]; |
32 | }; | 38 | }; |
33 | 39 | ||
34 | /* Structure for holding a token. */ | 40 | /* |
41 | * tomoyo_path_info is a structure which is used for holding a string data | ||
42 | * used by TOMOYO. | ||
43 | * This structure has several fields for supporting pattern matching. | ||
44 | * | ||
45 | * (1) "name" is the '\0' terminated string data. | ||
46 | * (2) "hash" is full_name_hash(name, strlen(name)). | ||
47 | * This allows tomoyo_pathcmp() to compare by hash before actually compare | ||
48 | * using strcmp(). | ||
49 | * (3) "const_len" is the length of the initial segment of "name" which | ||
50 | * consists entirely of non wildcard characters. In other words, the length | ||
51 | * which we can compare two strings using strncmp(). | ||
52 | * (4) "is_dir" is a bool which is true if "name" ends with "/", | ||
53 | * false otherwise. | ||
54 | * TOMOYO distinguishes directory and non-directory. A directory ends with | ||
55 | * "/" and non-directory does not end with "/". | ||
56 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard | ||
57 | * characters, false otherwise. This allows TOMOYO to use "hash" and | ||
58 | * strcmp() for string comparison if "is_patterned" is false. | ||
59 | * (6) "depth" is calculated using the number of "/" characters in "name". | ||
60 | * This allows TOMOYO to avoid comparing two pathnames which never match | ||
61 | * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). | ||
62 | */ | ||
35 | struct tomoyo_path_info { | 63 | struct tomoyo_path_info { |
36 | const char *name; | 64 | const char *name; |
37 | u32 hash; /* = full_name_hash(name, strlen(name)) */ | 65 | u32 hash; /* = full_name_hash(name, strlen(name)) */ |
38 | u16 const_len; /* = tomoyo_const_part_length(name) */ | 66 | u16 const_len; /* = tomoyo_const_part_length(name) */ |
39 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ | 67 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ |
40 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ | 68 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ |
41 | u16 depth; /* = tomoyo_path_depth(name) */ | 69 | u16 depth; /* = tomoyo_path_depth(name) */ |
42 | }; | 70 | }; |
43 | 71 | ||
44 | /* | 72 | /* |
45 | * This is the max length of a token. | 73 | * This is the max length of a token. |
46 | * | 74 | * |
47 | * A token consists of only ASCII printable characters. | 75 | * A token consists of only ASCII printable characters. |
48 | * Non printable characters in a token is represented in \ooo style | 76 | * Non printable characters in a token is represented in \ooo style |
49 | * octal string. Thus, \ itself is represented as \\. | 77 | * octal string. Thus, \ itself is represented as \\. |
50 | */ | 78 | */ |
51 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | 79 | #define TOMOYO_MAX_PATHNAME_LEN 4000 |
52 | 80 | ||
53 | /* Structure for holding requested pathname. */ | 81 | /* |
82 | * tomoyo_path_info_with_data is a structure which is used for holding a | ||
83 | * pathname obtained from "struct dentry" and "struct vfsmount" pair. | ||
84 | * | ||
85 | * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info" | ||
86 | * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of | ||
87 | * buffer for the pathname only. | ||
88 | * | ||
89 | * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release | ||
90 | * both "struct tomoyo_path_info" and buffer for the pathname by single kfree() | ||
91 | * so that we don't need to return two pointers to the caller. If the caller | ||
92 | * puts "struct tomoyo_path_info" on stack memory, we will be able to remove | ||
93 | * "struct tomoyo_path_info_with_data". | ||
94 | */ | ||
54 | struct tomoyo_path_info_with_data { | 95 | struct tomoyo_path_info_with_data { |
55 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 96 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ |
56 | struct tomoyo_path_info head; | 97 | struct tomoyo_path_info head; |
57 | char barrier1[16]; /* Safeguard for overrun. */ | 98 | char barrier1[16]; /* Safeguard for overrun. */ |
58 | char body[TOMOYO_MAX_PATHNAME_LEN]; | 99 | char body[TOMOYO_MAX_PATHNAME_LEN]; |
59 | char barrier2[16]; /* Safeguard for overrun. */ | 100 | char barrier2[16]; /* Safeguard for overrun. */ |
60 | }; | 101 | }; |
61 | 102 | ||
62 | /* | 103 | /* |
63 | * Common header for holding ACL entries. | 104 | * tomoyo_acl_info is a structure which is used for holding |
64 | * | 105 | * |
106 | * (1) "list" which is linked to the ->acl_info_list of | ||
107 | * "struct tomoyo_domain_info" | ||
108 | * (2) "type" which tells | ||
109 | * (a) type & 0x7F : type of the entry (either | ||
110 | * "struct tomoyo_single_path_acl_record" or | ||
111 | * "struct tomoyo_double_path_acl_record") | ||
112 | * (b) type & 0x80 : whether the entry is marked as "deleted". | ||
113 | * | ||
65 | * Packing "struct tomoyo_acl_info" allows | 114 | * Packing "struct tomoyo_acl_info" allows |
66 | * "struct tomoyo_single_path_acl_record" to embed "u16" and | 115 | * "struct tomoyo_single_path_acl_record" to embed "u16" and |
67 | * "struct tomoyo_double_path_acl_record" to embed "u8" | 116 | * "struct tomoyo_double_path_acl_record" to embed "u8" |
68 | * without enlarging their structure size. | 117 | * without enlarging their structure size. |
69 | */ | 118 | */ |
70 | struct tomoyo_acl_info { | 119 | struct tomoyo_acl_info { |
71 | struct list_head list; | 120 | struct list_head list; |
72 | /* | 121 | /* |
73 | * Type of this ACL entry. | 122 | * Type of this ACL entry. |
74 | * | 123 | * |
75 | * MSB is is_deleted flag. | 124 | * MSB is is_deleted flag. |
76 | */ | 125 | */ |
77 | u8 type; | 126 | u8 type; |
78 | } __packed; | 127 | } __packed; |
79 | 128 | ||
80 | /* This ACL entry is deleted. */ | 129 | /* This ACL entry is deleted. */ |
81 | #define TOMOYO_ACL_DELETED 0x80 | 130 | #define TOMOYO_ACL_DELETED 0x80 |
82 | 131 | ||
83 | /* Structure for domain information. */ | 132 | /* |
133 | * tomoyo_domain_info is a structure which is used for holding permissions | ||
134 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
135 | * It has following fields. | ||
136 | * | ||
137 | * (1) "list" which is linked to tomoyo_domain_list . | ||
138 | * (2) "acl_info_list" which is linked to "struct tomoyo_acl_info". | ||
139 | * (3) "domainname" which holds the name of the domain. | ||
140 | * (4) "profile" which remembers profile number assigned to this domain. | ||
141 | * (5) "is_deleted" is a bool which is true if this domain is marked as | ||
142 | * "deleted", false otherwise. | ||
143 | * (6) "quota_warned" is a bool which is used for suppressing warning message | ||
144 | * when learning mode learned too much entries. | ||
145 | * (7) "flags" which remembers this domain's attributes. | ||
146 | * | ||
147 | * A domain's lifecycle is an analogy of files on / directory. | ||
148 | * Multiple domains with the same domainname cannot be created (as with | ||
149 | * creating files with the same filename fails with -EEXIST). | ||
150 | * If a process reached a domain, that process can reside in that domain after | ||
151 | * that domain is marked as "deleted" (as with a process can access an already | ||
152 | * open()ed file after that file was unlink()ed). | ||
153 | */ | ||
84 | struct tomoyo_domain_info { | 154 | struct tomoyo_domain_info { |
85 | struct list_head list; | 155 | struct list_head list; |
86 | struct list_head acl_info_list; | 156 | struct list_head acl_info_list; |
87 | /* Name of this domain. Never NULL. */ | 157 | /* Name of this domain. Never NULL. */ |
88 | const struct tomoyo_path_info *domainname; | 158 | const struct tomoyo_path_info *domainname; |
89 | u8 profile; /* Profile number to use. */ | 159 | u8 profile; /* Profile number to use. */ |
90 | bool is_deleted; /* Delete flag. */ | 160 | bool is_deleted; /* Delete flag. */ |
91 | bool quota_warned; /* Quota warnning flag. */ | 161 | bool quota_warned; /* Quota warnning flag. */ |
92 | /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */ | 162 | /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */ |
93 | u8 flags; | 163 | u8 flags; |
94 | }; | 164 | }; |
95 | 165 | ||
96 | /* Profile number is an integer between 0 and 255. */ | 166 | /* Profile number is an integer between 0 and 255. */ |
97 | #define TOMOYO_MAX_PROFILES 256 | 167 | #define TOMOYO_MAX_PROFILES 256 |
98 | 168 | ||
99 | /* Ignore "allow_read" directive in exception policy. */ | 169 | /* Ignore "allow_read" directive in exception policy. */ |
100 | #define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1 | 170 | #define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1 |
101 | /* | 171 | /* |
102 | * This domain was unable to create a new domain at tomoyo_find_next_domain() | 172 | * This domain was unable to create a new domain at tomoyo_find_next_domain() |
103 | * because the name of the domain to be created was too long or | 173 | * because the name of the domain to be created was too long or |
104 | * it could not allocate memory. | 174 | * it could not allocate memory. |
105 | * More than one process continued execve() without domain transition. | 175 | * More than one process continued execve() without domain transition. |
106 | */ | 176 | */ |
107 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 | 177 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 |
108 | 178 | ||
109 | /* | 179 | /* |
110 | * Structure for "allow_read/write", "allow_execute", "allow_read", | 180 | * tomoyo_single_path_acl_record is a structure which is used for holding an |
111 | * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | 181 | * entry with one pathname operation (e.g. open(), mkdir()). |
112 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", | 182 | * It has following fields. |
113 | * "allow_truncate", "allow_symlink" and "allow_rewrite" directive. | 183 | * |
184 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
185 | * (2) "perm" which is a bitmask of permitted operations. | ||
186 | * (3) "filename" is the pathname. | ||
187 | * | ||
188 | * Directives held by this structure are "allow_read/write", "allow_execute", | ||
189 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | ||
190 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", | ||
191 | * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". | ||
114 | */ | 192 | */ |
115 | struct tomoyo_single_path_acl_record { | 193 | struct tomoyo_single_path_acl_record { |
116 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ | 194 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ |
117 | u16 perm; | 195 | u16 perm; |
118 | /* Pointer to single pathname. */ | 196 | /* Pointer to single pathname. */ |
119 | const struct tomoyo_path_info *filename; | 197 | const struct tomoyo_path_info *filename; |
120 | }; | 198 | }; |
121 | 199 | ||
122 | /* Structure for "allow_rename" and "allow_link" directive. */ | 200 | /* |
201 | * tomoyo_double_path_acl_record is a structure which is used for holding an | ||
202 | * entry with two pathnames operation (i.e. link() and rename()). | ||
203 | * It has following fields. | ||
204 | * | ||
205 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
206 | * (2) "perm" which is a bitmask of permitted operations. | ||
207 | * (3) "filename1" is the source/old pathname. | ||
208 | * (4) "filename2" is the destination/new pathname. | ||
209 | * | ||
210 | * Directives held by this structure are "allow_rename" and "allow_link". | ||
211 | */ | ||
123 | struct tomoyo_double_path_acl_record { | 212 | struct tomoyo_double_path_acl_record { |
124 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ | 213 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ |
125 | u8 perm; | 214 | u8 perm; |
126 | /* Pointer to single pathname. */ | 215 | /* Pointer to single pathname. */ |
127 | const struct tomoyo_path_info *filename1; | 216 | const struct tomoyo_path_info *filename1; |
128 | /* Pointer to single pathname. */ | 217 | /* Pointer to single pathname. */ |
129 | const struct tomoyo_path_info *filename2; | 218 | const struct tomoyo_path_info *filename2; |
130 | }; | 219 | }; |
131 | 220 | ||
132 | /* Keywords for ACLs. */ | 221 | /* Keywords for ACLs. */ |
133 | #define TOMOYO_KEYWORD_ALIAS "alias " | 222 | #define TOMOYO_KEYWORD_ALIAS "alias " |
134 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | 223 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " |
135 | #define TOMOYO_KEYWORD_DELETE "delete " | 224 | #define TOMOYO_KEYWORD_DELETE "delete " |
136 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | 225 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " |
137 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " | 226 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " |
138 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " | 227 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " |
139 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | 228 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " |
140 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | 229 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " |
141 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | 230 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " |
142 | #define TOMOYO_KEYWORD_SELECT "select " | 231 | #define TOMOYO_KEYWORD_SELECT "select " |
143 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | 232 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " |
144 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | 233 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" |
145 | /* A domain definition starts with <kernel>. */ | 234 | /* A domain definition starts with <kernel>. */ |
146 | #define TOMOYO_ROOT_NAME "<kernel>" | 235 | #define TOMOYO_ROOT_NAME "<kernel>" |
147 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | 236 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) |
148 | 237 | ||
149 | /* Index numbers for Access Controls. */ | 238 | /* Index numbers for Access Controls. */ |
150 | #define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ | 239 | #define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ |
151 | #define TOMOYO_MAX_ACCEPT_ENTRY 1 | 240 | #define TOMOYO_MAX_ACCEPT_ENTRY 1 |
152 | #define TOMOYO_VERBOSE 2 | 241 | #define TOMOYO_VERBOSE 2 |
153 | #define TOMOYO_MAX_CONTROL_INDEX 3 | 242 | #define TOMOYO_MAX_CONTROL_INDEX 3 |
154 | 243 | ||
155 | /* Structure for reading/writing policy via securityfs interfaces. */ | 244 | /* |
245 | * tomoyo_io_buffer is a structure which is used for reading and modifying | ||
246 | * configuration via /sys/kernel/security/tomoyo/ interface. | ||
247 | * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as | ||
248 | * cursors. | ||
249 | * | ||
250 | * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of | ||
251 | * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info" | ||
252 | * entry has a list of "struct tomoyo_acl_info", we need two cursors when | ||
253 | * reading (one is for traversing tomoyo_domain_list and the other is for | ||
254 | * traversing "struct tomoyo_acl_info"->acl_info_list ). | ||
255 | * | ||
256 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
257 | * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the | ||
258 | * domain with the domainname specified by the rest of that line (NULL is set | ||
259 | * if seek failed). | ||
260 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
261 | * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that | ||
262 | * line (->write_var1 is set to NULL if a domain was deleted). | ||
263 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
264 | * neither "select " nor "delete ", an entry or a domain specified by that line | ||
265 | * is appended. | ||
266 | */ | ||
156 | struct tomoyo_io_buffer { | 267 | struct tomoyo_io_buffer { |
157 | int (*read) (struct tomoyo_io_buffer *); | 268 | int (*read) (struct tomoyo_io_buffer *); |
158 | int (*write) (struct tomoyo_io_buffer *); | 269 | int (*write) (struct tomoyo_io_buffer *); |
159 | /* Exclusive lock for this structure. */ | 270 | /* Exclusive lock for this structure. */ |
160 | struct mutex io_sem; | 271 | struct mutex io_sem; |
161 | /* The position currently reading from. */ | 272 | /* The position currently reading from. */ |
162 | struct list_head *read_var1; | 273 | struct list_head *read_var1; |
163 | /* Extra variables for reading. */ | 274 | /* Extra variables for reading. */ |
164 | struct list_head *read_var2; | 275 | struct list_head *read_var2; |
165 | /* The position currently writing to. */ | 276 | /* The position currently writing to. */ |
166 | struct tomoyo_domain_info *write_var1; | 277 | struct tomoyo_domain_info *write_var1; |
167 | /* The step for reading. */ | 278 | /* The step for reading. */ |
168 | int read_step; | 279 | int read_step; |
169 | /* Buffer for reading. */ | 280 | /* Buffer for reading. */ |
170 | char *read_buf; | 281 | char *read_buf; |
171 | /* EOF flag for reading. */ | 282 | /* EOF flag for reading. */ |
172 | bool read_eof; | 283 | bool read_eof; |
173 | /* Read domain ACL of specified PID? */ | 284 | /* Read domain ACL of specified PID? */ |
174 | bool read_single_domain; | 285 | bool read_single_domain; |
175 | /* Extra variable for reading. */ | 286 | /* Extra variable for reading. */ |
176 | u8 read_bit; | 287 | u8 read_bit; |
177 | /* Bytes available for reading. */ | 288 | /* Bytes available for reading. */ |
178 | int read_avail; | 289 | int read_avail; |
179 | /* Size of read buffer. */ | 290 | /* Size of read buffer. */ |
180 | int readbuf_size; | 291 | int readbuf_size; |
181 | /* Buffer for writing. */ | 292 | /* Buffer for writing. */ |
182 | char *write_buf; | 293 | char *write_buf; |
183 | /* Bytes available for writing. */ | 294 | /* Bytes available for writing. */ |
184 | int write_avail; | 295 | int write_avail; |
185 | /* Size of write buffer. */ | 296 | /* Size of write buffer. */ |
186 | int writebuf_size; | 297 | int writebuf_size; |
187 | }; | 298 | }; |
188 | 299 | ||
189 | /* Check whether the domain has too many ACL entries to hold. */ | 300 | /* Check whether the domain has too many ACL entries to hold. */ |
190 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); | 301 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); |
191 | /* Transactional sprintf() for policy dump. */ | 302 | /* Transactional sprintf() for policy dump. */ |
192 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 303 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
193 | __attribute__ ((format(printf, 2, 3))); | 304 | __attribute__ ((format(printf, 2, 3))); |
194 | /* Check whether the domainname is correct. */ | 305 | /* Check whether the domainname is correct. */ |
195 | bool tomoyo_is_correct_domain(const unsigned char *domainname, | 306 | bool tomoyo_is_correct_domain(const unsigned char *domainname, |
196 | const char *function); | 307 | const char *function); |
197 | /* Check whether the token is correct. */ | 308 | /* Check whether the token is correct. */ |
198 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | 309 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, |
199 | const s8 pattern_type, const s8 end_type, | 310 | const s8 pattern_type, const s8 end_type, |
200 | const char *function); | 311 | const char *function); |
201 | /* Check whether the token can be a domainname. */ | 312 | /* Check whether the token can be a domainname. */ |
202 | bool tomoyo_is_domain_def(const unsigned char *buffer); | 313 | bool tomoyo_is_domain_def(const unsigned char *buffer); |
203 | /* Check whether the given filename matches the given pattern. */ | 314 | /* Check whether the given filename matches the given pattern. */ |
204 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | 315 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, |
205 | const struct tomoyo_path_info *pattern); | 316 | const struct tomoyo_path_info *pattern); |
206 | /* Read "alias" entry in exception policy. */ | 317 | /* Read "alias" entry in exception policy. */ |
207 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head); | 318 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head); |
208 | /* | 319 | /* |
209 | * Read "initialize_domain" and "no_initialize_domain" entry | 320 | * Read "initialize_domain" and "no_initialize_domain" entry |
210 | * in exception policy. | 321 | * in exception policy. |
211 | */ | 322 | */ |
212 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head); | 323 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head); |
213 | /* Read "keep_domain" and "no_keep_domain" entry in exception policy. */ | 324 | /* Read "keep_domain" and "no_keep_domain" entry in exception policy. */ |
214 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head); | 325 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head); |
215 | /* Read "file_pattern" entry in exception policy. */ | 326 | /* Read "file_pattern" entry in exception policy. */ |
216 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head); | 327 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head); |
217 | /* Read "allow_read" entry in exception policy. */ | 328 | /* Read "allow_read" entry in exception policy. */ |
218 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head); | 329 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head); |
219 | /* Read "deny_rewrite" entry in exception policy. */ | 330 | /* Read "deny_rewrite" entry in exception policy. */ |
220 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); | 331 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); |
221 | /* Write domain policy violation warning message to console? */ | 332 | /* Write domain policy violation warning message to console? */ |
222 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); | 333 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); |
223 | /* Convert double path operation to operation name. */ | 334 | /* Convert double path operation to operation name. */ |
224 | const char *tomoyo_dp2keyword(const u8 operation); | 335 | const char *tomoyo_dp2keyword(const u8 operation); |
225 | /* Get the last component of the given domainname. */ | 336 | /* Get the last component of the given domainname. */ |
226 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | 337 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); |
227 | /* Get warning message. */ | 338 | /* Get warning message. */ |
228 | const char *tomoyo_get_msg(const bool is_enforce); | 339 | const char *tomoyo_get_msg(const bool is_enforce); |
229 | /* Convert single path operation to operation name. */ | 340 | /* Convert single path operation to operation name. */ |
230 | const char *tomoyo_sp2keyword(const u8 operation); | 341 | const char *tomoyo_sp2keyword(const u8 operation); |
231 | /* Delete a domain. */ | 342 | /* Delete a domain. */ |
232 | int tomoyo_delete_domain(char *data); | 343 | int tomoyo_delete_domain(char *data); |
233 | /* Create "alias" entry in exception policy. */ | 344 | /* Create "alias" entry in exception policy. */ |
234 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 345 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
235 | /* | 346 | /* |
236 | * Create "initialize_domain" and "no_initialize_domain" entry | 347 | * Create "initialize_domain" and "no_initialize_domain" entry |
237 | * in exception policy. | 348 | * in exception policy. |
238 | */ | 349 | */ |
239 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 350 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, |
240 | const bool is_delete); | 351 | const bool is_delete); |
241 | /* Create "keep_domain" and "no_keep_domain" entry in exception policy. */ | 352 | /* Create "keep_domain" and "no_keep_domain" entry in exception policy. */ |
242 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | 353 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, |
243 | const bool is_delete); | 354 | const bool is_delete); |
244 | /* | 355 | /* |
245 | * Create "allow_read/write", "allow_execute", "allow_read", "allow_write", | 356 | * Create "allow_read/write", "allow_execute", "allow_read", "allow_write", |
246 | * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | 357 | * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", |
247 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", | 358 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", |
248 | * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and | 359 | * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and |
249 | * "allow_link" entry in domain policy. | 360 | * "allow_link" entry in domain policy. |
250 | */ | 361 | */ |
251 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | 362 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, |
252 | const bool is_delete); | 363 | const bool is_delete); |
253 | /* Create "allow_read" entry in exception policy. */ | 364 | /* Create "allow_read" entry in exception policy. */ |
254 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); | 365 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); |
255 | /* Create "deny_rewrite" entry in exception policy. */ | 366 | /* Create "deny_rewrite" entry in exception policy. */ |
256 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); | 367 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); |
257 | /* Create "file_pattern" entry in exception policy. */ | 368 | /* Create "file_pattern" entry in exception policy. */ |
258 | int tomoyo_write_pattern_policy(char *data, const bool is_delete); | 369 | int tomoyo_write_pattern_policy(char *data, const bool is_delete); |
259 | /* Find a domain by the given name. */ | 370 | /* Find a domain by the given name. */ |
260 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | 371 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); |
261 | /* Find or create a domain by the given name. */ | 372 | /* Find or create a domain by the given name. */ |
262 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 373 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
263 | domainname, | 374 | domainname, |
264 | const u8 profile); | 375 | const u8 profile); |
265 | /* Check mode for specified functionality. */ | 376 | /* Check mode for specified functionality. */ |
266 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | 377 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, |
267 | const u8 index); | 378 | const u8 index); |
268 | /* Allocate memory for structures. */ | 379 | /* Allocate memory for structures. */ |
269 | void *tomoyo_alloc_acl_element(const u8 acl_type); | 380 | void *tomoyo_alloc_acl_element(const u8 acl_type); |
270 | /* Fill in "struct tomoyo_path_info" members. */ | 381 | /* Fill in "struct tomoyo_path_info" members. */ |
271 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | 382 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); |
272 | /* Run policy loader when /sbin/init starts. */ | 383 | /* Run policy loader when /sbin/init starts. */ |
273 | void tomoyo_load_policy(const char *filename); | 384 | void tomoyo_load_policy(const char *filename); |
274 | /* Change "struct tomoyo_domain_info"->flags. */ | 385 | /* Change "struct tomoyo_domain_info"->flags. */ |
275 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | 386 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, |
276 | const bool is_delete, const u8 flags); | 387 | const bool is_delete, const u8 flags); |
277 | 388 | ||
278 | /* strcmp() for "struct tomoyo_path_info" structure. */ | 389 | /* strcmp() for "struct tomoyo_path_info" structure. */ |
279 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, | 390 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, |
280 | const struct tomoyo_path_info *b) | 391 | const struct tomoyo_path_info *b) |
281 | { | 392 | { |
282 | return a->hash != b->hash || strcmp(a->name, b->name); | 393 | return a->hash != b->hash || strcmp(a->name, b->name); |
283 | } | 394 | } |
284 | 395 | ||
285 | /* Get type of an ACL entry. */ | 396 | /* Get type of an ACL entry. */ |
286 | static inline u8 tomoyo_acl_type1(struct tomoyo_acl_info *ptr) | 397 | static inline u8 tomoyo_acl_type1(struct tomoyo_acl_info *ptr) |
287 | { | 398 | { |
288 | return ptr->type & ~TOMOYO_ACL_DELETED; | 399 | return ptr->type & ~TOMOYO_ACL_DELETED; |
289 | } | 400 | } |
290 | 401 | ||
291 | /* Get type of an ACL entry. */ | 402 | /* Get type of an ACL entry. */ |
292 | static inline u8 tomoyo_acl_type2(struct tomoyo_acl_info *ptr) | 403 | static inline u8 tomoyo_acl_type2(struct tomoyo_acl_info *ptr) |
293 | { | 404 | { |
294 | return ptr->type; | 405 | return ptr->type; |
295 | } | 406 | } |
296 | 407 | ||
297 | /** | 408 | /** |
298 | * tomoyo_is_valid - Check whether the character is a valid char. | 409 | * tomoyo_is_valid - Check whether the character is a valid char. |
299 | * | 410 | * |
300 | * @c: The character to check. | 411 | * @c: The character to check. |
301 | * | 412 | * |
302 | * Returns true if @c is a valid character, false otherwise. | 413 | * Returns true if @c is a valid character, false otherwise. |
303 | */ | 414 | */ |
304 | static inline bool tomoyo_is_valid(const unsigned char c) | 415 | static inline bool tomoyo_is_valid(const unsigned char c) |
305 | { | 416 | { |
306 | return c > ' ' && c < 127; | 417 | return c > ' ' && c < 127; |
307 | } | 418 | } |
308 | 419 | ||
309 | /** | 420 | /** |
310 | * tomoyo_is_invalid - Check whether the character is an invalid char. | 421 | * tomoyo_is_invalid - Check whether the character is an invalid char. |
311 | * | 422 | * |
312 | * @c: The character to check. | 423 | * @c: The character to check. |
313 | * | 424 | * |
314 | * Returns true if @c is an invalid character, false otherwise. | 425 | * Returns true if @c is an invalid character, false otherwise. |
315 | */ | 426 | */ |
316 | static inline bool tomoyo_is_invalid(const unsigned char c) | 427 | static inline bool tomoyo_is_invalid(const unsigned char c) |
317 | { | 428 | { |
318 | return c && (c <= ' ' || c >= 127); | 429 | return c && (c <= ' ' || c >= 127); |
319 | } | 430 | } |
320 | 431 | ||
321 | /* The list for "struct tomoyo_domain_info". */ | 432 | /* The list for "struct tomoyo_domain_info". */ |
322 | extern struct list_head tomoyo_domain_list; | 433 | extern struct list_head tomoyo_domain_list; |
323 | extern struct rw_semaphore tomoyo_domain_list_lock; | 434 | extern struct rw_semaphore tomoyo_domain_list_lock; |
324 | 435 | ||
325 | /* Lock for domain->acl_info_list. */ | 436 | /* Lock for domain->acl_info_list. */ |
326 | extern struct rw_semaphore tomoyo_domain_acl_info_list_lock; | 437 | extern struct rw_semaphore tomoyo_domain_acl_info_list_lock; |
327 | 438 | ||
328 | /* Has /sbin/init started? */ | 439 | /* Has /sbin/init started? */ |
329 | extern bool tomoyo_policy_loaded; | 440 | extern bool tomoyo_policy_loaded; |
330 | 441 | ||
331 | /* The kernel's domain. */ | 442 | /* The kernel's domain. */ |
332 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | 443 | extern struct tomoyo_domain_info tomoyo_kernel_domain; |
333 | 444 | ||
334 | /** | 445 | /** |
335 | * list_for_each_cookie - iterate over a list with cookie. | 446 | * list_for_each_cookie - iterate over a list with cookie. |
336 | * @pos: the &struct list_head to use as a loop cursor. | 447 | * @pos: the &struct list_head to use as a loop cursor. |
337 | * @cookie: the &struct list_head to use as a cookie. | 448 | * @cookie: the &struct list_head to use as a cookie. |
338 | * @head: the head for your list. | 449 | * @head: the head for your list. |
339 | * | 450 | * |
340 | * Same with list_for_each() except that this primitive uses @cookie | 451 | * Same with list_for_each() except that this primitive uses @cookie |
341 | * so that we can continue iteration. | 452 | * so that we can continue iteration. |
342 | * @cookie must be NULL when iteration starts, and @cookie will become | 453 | * @cookie must be NULL when iteration starts, and @cookie will become |
343 | * NULL when iteration finishes. | 454 | * NULL when iteration finishes. |
344 | */ | 455 | */ |
345 | #define list_for_each_cookie(pos, cookie, head) \ | 456 | #define list_for_each_cookie(pos, cookie, head) \ |
346 | for (({ if (!cookie) \ | 457 | for (({ if (!cookie) \ |
347 | cookie = head; }), \ | 458 | cookie = head; }), \ |
348 | pos = (cookie)->next; \ | 459 | pos = (cookie)->next; \ |
349 | prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ | 460 | prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ |
350 | (cookie) = pos, pos = pos->next) | 461 | (cookie) = pos, pos = pos->next) |
351 | 462 | ||
352 | #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ | 463 | #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ |
353 | 464 |
security/tomoyo/domain.c
1 | /* | 1 | /* |
2 | * security/tomoyo/domain.c | 2 | * security/tomoyo/domain.c |
3 | * | 3 | * |
4 | * Implementation of the Domain-Based Mandatory Access Control. | 4 | * Implementation of the Domain-Based Mandatory Access Control. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * | 7 | * |
8 | * Version: 2.2.0 2009/04/01 | 8 | * Version: 2.2.0 2009/04/01 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | 13 | #include "tomoyo.h" |
14 | #include "realpath.h" | 14 | #include "realpath.h" |
15 | #include <linux/binfmts.h> | 15 | #include <linux/binfmts.h> |
16 | 16 | ||
17 | /* Variables definitions.*/ | 17 | /* Variables definitions.*/ |
18 | 18 | ||
19 | /* The initial domain. */ | 19 | /* The initial domain. */ |
20 | struct tomoyo_domain_info tomoyo_kernel_domain; | 20 | struct tomoyo_domain_info tomoyo_kernel_domain; |
21 | 21 | ||
22 | /* The list for "struct tomoyo_domain_info". */ | 22 | /* |
23 | * tomoyo_domain_list is used for holding list of domains. | ||
24 | * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding | ||
25 | * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
26 | * | ||
27 | * An entry is added by | ||
28 | * | ||
29 | * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \ | ||
30 | * /sys/kernel/security/tomoyo/domain_policy | ||
31 | * | ||
32 | * and is deleted by | ||
33 | * | ||
34 | * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \ | ||
35 | * /sys/kernel/security/tomoyo/domain_policy | ||
36 | * | ||
37 | * and all entries are retrieved by | ||
38 | * | ||
39 | * # cat /sys/kernel/security/tomoyo/domain_policy | ||
40 | * | ||
41 | * A domain is added by | ||
42 | * | ||
43 | * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
44 | * | ||
45 | * and is deleted by | ||
46 | * | ||
47 | * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
48 | * | ||
49 | * and all domains are retrieved by | ||
50 | * | ||
51 | * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | ||
52 | * | ||
53 | * Normally, a domainname is monotonically getting longer because a domainname | ||
54 | * which the process will belong to if an execve() operation succeeds is | ||
55 | * defined as a concatenation of "current domainname" + "pathname passed to | ||
56 | * execve()". | ||
57 | * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for | ||
58 | * exceptions. | ||
59 | */ | ||
23 | LIST_HEAD(tomoyo_domain_list); | 60 | LIST_HEAD(tomoyo_domain_list); |
24 | DECLARE_RWSEM(tomoyo_domain_list_lock); | 61 | DECLARE_RWSEM(tomoyo_domain_list_lock); |
25 | 62 | ||
26 | /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */ | 63 | /* |
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
27 | struct tomoyo_domain_initializer_entry { | 79 | struct tomoyo_domain_initializer_entry { |
28 | struct list_head list; | 80 | struct list_head list; |
29 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | 81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ |
30 | const struct tomoyo_path_info *program; | 82 | const struct tomoyo_path_info *program; |
31 | bool is_deleted; | 83 | bool is_deleted; |
32 | bool is_not; /* True if this entry is "no_initialize_domain". */ | 84 | bool is_not; /* True if this entry is "no_initialize_domain". */ |
33 | /* True if the domainname is tomoyo_get_last_name(). */ | 85 | /* True if the domainname is tomoyo_get_last_name(). */ |
34 | bool is_last_name; | 86 | bool is_last_name; |
35 | }; | 87 | }; |
36 | 88 | ||
37 | /* Structure for "keep_domain" and "no_keep_domain" keyword. */ | 89 | /* |
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
38 | struct tomoyo_domain_keeper_entry { | 106 | struct tomoyo_domain_keeper_entry { |
39 | struct list_head list; | 107 | struct list_head list; |
40 | const struct tomoyo_path_info *domainname; | 108 | const struct tomoyo_path_info *domainname; |
41 | const struct tomoyo_path_info *program; /* This may be NULL */ | 109 | const struct tomoyo_path_info *program; /* This may be NULL */ |
42 | bool is_deleted; | 110 | bool is_deleted; |
43 | bool is_not; /* True if this entry is "no_keep_domain". */ | 111 | bool is_not; /* True if this entry is "no_keep_domain". */ |
44 | /* True if the domainname is tomoyo_get_last_name(). */ | 112 | /* True if the domainname is tomoyo_get_last_name(). */ |
45 | bool is_last_name; | 113 | bool is_last_name; |
46 | }; | 114 | }; |
47 | 115 | ||
48 | /* Structure for "alias" keyword. */ | 116 | /* |
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
49 | struct tomoyo_alias_entry { | 126 | struct tomoyo_alias_entry { |
50 | struct list_head list; | 127 | struct list_head list; |
51 | const struct tomoyo_path_info *original_name; | 128 | const struct tomoyo_path_info *original_name; |
52 | const struct tomoyo_path_info *aliased_name; | 129 | const struct tomoyo_path_info *aliased_name; |
53 | bool is_deleted; | 130 | bool is_deleted; |
54 | }; | 131 | }; |
55 | 132 | ||
56 | /** | 133 | /** |
57 | * tomoyo_set_domain_flag - Set or clear domain's attribute flags. | 134 | * tomoyo_set_domain_flag - Set or clear domain's attribute flags. |
58 | * | 135 | * |
59 | * @domain: Pointer to "struct tomoyo_domain_info". | 136 | * @domain: Pointer to "struct tomoyo_domain_info". |
60 | * @is_delete: True if it is a delete request. | 137 | * @is_delete: True if it is a delete request. |
61 | * @flags: Flags to set or clear. | 138 | * @flags: Flags to set or clear. |
62 | * | 139 | * |
63 | * Returns nothing. | 140 | * Returns nothing. |
64 | */ | 141 | */ |
65 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | 142 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, |
66 | const bool is_delete, const u8 flags) | 143 | const bool is_delete, const u8 flags) |
67 | { | 144 | { |
68 | /* We need to serialize because this is bitfield operation. */ | 145 | /* We need to serialize because this is bitfield operation. */ |
69 | static DEFINE_SPINLOCK(lock); | 146 | static DEFINE_SPINLOCK(lock); |
70 | spin_lock(&lock); | 147 | spin_lock(&lock); |
71 | if (!is_delete) | 148 | if (!is_delete) |
72 | domain->flags |= flags; | 149 | domain->flags |= flags; |
73 | else | 150 | else |
74 | domain->flags &= ~flags; | 151 | domain->flags &= ~flags; |
75 | spin_unlock(&lock); | 152 | spin_unlock(&lock); |
76 | } | 153 | } |
77 | 154 | ||
78 | /** | 155 | /** |
79 | * tomoyo_get_last_name - Get last component of a domainname. | 156 | * tomoyo_get_last_name - Get last component of a domainname. |
80 | * | 157 | * |
81 | * @domain: Pointer to "struct tomoyo_domain_info". | 158 | * @domain: Pointer to "struct tomoyo_domain_info". |
82 | * | 159 | * |
83 | * Returns the last component of the domainname. | 160 | * Returns the last component of the domainname. |
84 | */ | 161 | */ |
85 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | 162 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) |
86 | { | 163 | { |
87 | const char *cp0 = domain->domainname->name; | 164 | const char *cp0 = domain->domainname->name; |
88 | const char *cp1 = strrchr(cp0, ' '); | 165 | const char *cp1 = strrchr(cp0, ' '); |
89 | 166 | ||
90 | if (cp1) | 167 | if (cp1) |
91 | return cp1 + 1; | 168 | return cp1 + 1; |
92 | return cp0; | 169 | return cp0; |
93 | } | 170 | } |
94 | 171 | ||
95 | /* The list for "struct tomoyo_domain_initializer_entry". */ | 172 | /* |
173 | * tomoyo_domain_initializer_list is used for holding list of programs which | ||
174 | * triggers reinitialization of domainname. Normally, a domainname is | ||
175 | * monotonically getting longer. But sometimes, we restart daemon programs. | ||
176 | * It would be convenient for us that "a daemon started upon system boot" and | ||
177 | * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO | ||
178 | * provides a way to shorten domainnames. | ||
179 | * | ||
180 | * An entry is added by | ||
181 | * | ||
182 | * # echo 'initialize_domain /usr/sbin/httpd' > \ | ||
183 | * /sys/kernel/security/tomoyo/exception_policy | ||
184 | * | ||
185 | * and is deleted by | ||
186 | * | ||
187 | * # echo 'delete initialize_domain /usr/sbin/httpd' > \ | ||
188 | * /sys/kernel/security/tomoyo/exception_policy | ||
189 | * | ||
190 | * and all entries are retrieved by | ||
191 | * | ||
192 | * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy | ||
193 | * | ||
194 | * In the example above, /usr/sbin/httpd will belong to | ||
195 | * "<kernel> /usr/sbin/httpd" domain. | ||
196 | * | ||
197 | * You may specify a domainname using "from" keyword. | ||
198 | * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
199 | * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd" | ||
200 | * domain to belong to "<kernel> /usr/sbin/httpd" domain. | ||
201 | * | ||
202 | * You may add "no_" prefix to "initialize_domain". | ||
203 | * "initialize_domain /usr/sbin/httpd" and | ||
204 | * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
205 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | ||
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | ||
207 | */ | ||
96 | static LIST_HEAD(tomoyo_domain_initializer_list); | 208 | static LIST_HEAD(tomoyo_domain_initializer_list); |
97 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | 209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); |
98 | 210 | ||
99 | /** | 211 | /** |
100 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 212 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. |
101 | * | 213 | * |
102 | * @domainname: The name of domain. May be NULL. | 214 | * @domainname: The name of domain. May be NULL. |
103 | * @program: The name of program. | 215 | * @program: The name of program. |
104 | * @is_not: True if it is "no_initialize_domain" entry. | 216 | * @is_not: True if it is "no_initialize_domain" entry. |
105 | * @is_delete: True if it is a delete request. | 217 | * @is_delete: True if it is a delete request. |
106 | * | 218 | * |
107 | * Returns 0 on success, negative value otherwise. | 219 | * Returns 0 on success, negative value otherwise. |
108 | */ | 220 | */ |
109 | static int tomoyo_update_domain_initializer_entry(const char *domainname, | 221 | static int tomoyo_update_domain_initializer_entry(const char *domainname, |
110 | const char *program, | 222 | const char *program, |
111 | const bool is_not, | 223 | const bool is_not, |
112 | const bool is_delete) | 224 | const bool is_delete) |
113 | { | 225 | { |
114 | struct tomoyo_domain_initializer_entry *new_entry; | 226 | struct tomoyo_domain_initializer_entry *new_entry; |
115 | struct tomoyo_domain_initializer_entry *ptr; | 227 | struct tomoyo_domain_initializer_entry *ptr; |
116 | const struct tomoyo_path_info *saved_program; | 228 | const struct tomoyo_path_info *saved_program; |
117 | const struct tomoyo_path_info *saved_domainname = NULL; | 229 | const struct tomoyo_path_info *saved_domainname = NULL; |
118 | int error = -ENOMEM; | 230 | int error = -ENOMEM; |
119 | bool is_last_name = false; | 231 | bool is_last_name = false; |
120 | 232 | ||
121 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 233 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) |
122 | return -EINVAL; /* No patterns allowed. */ | 234 | return -EINVAL; /* No patterns allowed. */ |
123 | if (domainname) { | 235 | if (domainname) { |
124 | if (!tomoyo_is_domain_def(domainname) && | 236 | if (!tomoyo_is_domain_def(domainname) && |
125 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 237 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) |
126 | is_last_name = true; | 238 | is_last_name = true; |
127 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 239 | else if (!tomoyo_is_correct_domain(domainname, __func__)) |
128 | return -EINVAL; | 240 | return -EINVAL; |
129 | saved_domainname = tomoyo_save_name(domainname); | 241 | saved_domainname = tomoyo_save_name(domainname); |
130 | if (!saved_domainname) | 242 | if (!saved_domainname) |
131 | return -ENOMEM; | 243 | return -ENOMEM; |
132 | } | 244 | } |
133 | saved_program = tomoyo_save_name(program); | 245 | saved_program = tomoyo_save_name(program); |
134 | if (!saved_program) | 246 | if (!saved_program) |
135 | return -ENOMEM; | 247 | return -ENOMEM; |
136 | down_write(&tomoyo_domain_initializer_list_lock); | 248 | down_write(&tomoyo_domain_initializer_list_lock); |
137 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 249 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { |
138 | if (ptr->is_not != is_not || | 250 | if (ptr->is_not != is_not || |
139 | ptr->domainname != saved_domainname || | 251 | ptr->domainname != saved_domainname || |
140 | ptr->program != saved_program) | 252 | ptr->program != saved_program) |
141 | continue; | 253 | continue; |
142 | ptr->is_deleted = is_delete; | 254 | ptr->is_deleted = is_delete; |
143 | error = 0; | 255 | error = 0; |
144 | goto out; | 256 | goto out; |
145 | } | 257 | } |
146 | if (is_delete) { | 258 | if (is_delete) { |
147 | error = -ENOENT; | 259 | error = -ENOENT; |
148 | goto out; | 260 | goto out; |
149 | } | 261 | } |
150 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 262 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
151 | if (!new_entry) | 263 | if (!new_entry) |
152 | goto out; | 264 | goto out; |
153 | new_entry->domainname = saved_domainname; | 265 | new_entry->domainname = saved_domainname; |
154 | new_entry->program = saved_program; | 266 | new_entry->program = saved_program; |
155 | new_entry->is_not = is_not; | 267 | new_entry->is_not = is_not; |
156 | new_entry->is_last_name = is_last_name; | 268 | new_entry->is_last_name = is_last_name; |
157 | list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); | 269 | list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); |
158 | error = 0; | 270 | error = 0; |
159 | out: | 271 | out: |
160 | up_write(&tomoyo_domain_initializer_list_lock); | 272 | up_write(&tomoyo_domain_initializer_list_lock); |
161 | return error; | 273 | return error; |
162 | } | 274 | } |
163 | 275 | ||
164 | /** | 276 | /** |
165 | * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list. | 277 | * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list. |
166 | * | 278 | * |
167 | * @head: Pointer to "struct tomoyo_io_buffer". | 279 | * @head: Pointer to "struct tomoyo_io_buffer". |
168 | * | 280 | * |
169 | * Returns true on success, false otherwise. | 281 | * Returns true on success, false otherwise. |
170 | */ | 282 | */ |
171 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | 283 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) |
172 | { | 284 | { |
173 | struct list_head *pos; | 285 | struct list_head *pos; |
174 | bool done = true; | 286 | bool done = true; |
175 | 287 | ||
176 | down_read(&tomoyo_domain_initializer_list_lock); | 288 | down_read(&tomoyo_domain_initializer_list_lock); |
177 | list_for_each_cookie(pos, head->read_var2, | 289 | list_for_each_cookie(pos, head->read_var2, |
178 | &tomoyo_domain_initializer_list) { | 290 | &tomoyo_domain_initializer_list) { |
179 | const char *no; | 291 | const char *no; |
180 | const char *from = ""; | 292 | const char *from = ""; |
181 | const char *domain = ""; | 293 | const char *domain = ""; |
182 | struct tomoyo_domain_initializer_entry *ptr; | 294 | struct tomoyo_domain_initializer_entry *ptr; |
183 | ptr = list_entry(pos, struct tomoyo_domain_initializer_entry, | 295 | ptr = list_entry(pos, struct tomoyo_domain_initializer_entry, |
184 | list); | 296 | list); |
185 | if (ptr->is_deleted) | 297 | if (ptr->is_deleted) |
186 | continue; | 298 | continue; |
187 | no = ptr->is_not ? "no_" : ""; | 299 | no = ptr->is_not ? "no_" : ""; |
188 | if (ptr->domainname) { | 300 | if (ptr->domainname) { |
189 | from = " from "; | 301 | from = " from "; |
190 | domain = ptr->domainname->name; | 302 | domain = ptr->domainname->name; |
191 | } | 303 | } |
192 | done = tomoyo_io_printf(head, | 304 | done = tomoyo_io_printf(head, |
193 | "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN | 305 | "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN |
194 | "%s%s%s\n", no, ptr->program->name, | 306 | "%s%s%s\n", no, ptr->program->name, |
195 | from, domain); | 307 | from, domain); |
196 | if (!done) | 308 | if (!done) |
197 | break; | 309 | break; |
198 | } | 310 | } |
199 | up_read(&tomoyo_domain_initializer_list_lock); | 311 | up_read(&tomoyo_domain_initializer_list_lock); |
200 | return done; | 312 | return done; |
201 | } | 313 | } |
202 | 314 | ||
203 | /** | 315 | /** |
204 | * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list. | 316 | * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list. |
205 | * | 317 | * |
206 | * @data: String to parse. | 318 | * @data: String to parse. |
207 | * @is_not: True if it is "no_initialize_domain" entry. | 319 | * @is_not: True if it is "no_initialize_domain" entry. |
208 | * @is_delete: True if it is a delete request. | 320 | * @is_delete: True if it is a delete request. |
209 | * | 321 | * |
210 | * Returns 0 on success, negative value otherwise. | 322 | * Returns 0 on success, negative value otherwise. |
211 | */ | 323 | */ |
212 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 324 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, |
213 | const bool is_delete) | 325 | const bool is_delete) |
214 | { | 326 | { |
215 | char *cp = strstr(data, " from "); | 327 | char *cp = strstr(data, " from "); |
216 | 328 | ||
217 | if (cp) { | 329 | if (cp) { |
218 | *cp = '\0'; | 330 | *cp = '\0'; |
219 | return tomoyo_update_domain_initializer_entry(cp + 6, data, | 331 | return tomoyo_update_domain_initializer_entry(cp + 6, data, |
220 | is_not, | 332 | is_not, |
221 | is_delete); | 333 | is_delete); |
222 | } | 334 | } |
223 | return tomoyo_update_domain_initializer_entry(NULL, data, is_not, | 335 | return tomoyo_update_domain_initializer_entry(NULL, data, is_not, |
224 | is_delete); | 336 | is_delete); |
225 | } | 337 | } |
226 | 338 | ||
227 | /** | 339 | /** |
228 | * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization. | 340 | * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization. |
229 | * | 341 | * |
230 | * @domainname: The name of domain. | 342 | * @domainname: The name of domain. |
231 | * @program: The name of program. | 343 | * @program: The name of program. |
232 | * @last_name: The last component of @domainname. | 344 | * @last_name: The last component of @domainname. |
233 | * | 345 | * |
234 | * Returns true if executing @program reinitializes domain transition, | 346 | * Returns true if executing @program reinitializes domain transition, |
235 | * false otherwise. | 347 | * false otherwise. |
236 | */ | 348 | */ |
237 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | 349 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * |
238 | domainname, | 350 | domainname, |
239 | const struct tomoyo_path_info *program, | 351 | const struct tomoyo_path_info *program, |
240 | const struct tomoyo_path_info * | 352 | const struct tomoyo_path_info * |
241 | last_name) | 353 | last_name) |
242 | { | 354 | { |
243 | struct tomoyo_domain_initializer_entry *ptr; | 355 | struct tomoyo_domain_initializer_entry *ptr; |
244 | bool flag = false; | 356 | bool flag = false; |
245 | 357 | ||
246 | down_read(&tomoyo_domain_initializer_list_lock); | 358 | down_read(&tomoyo_domain_initializer_list_lock); |
247 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 359 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { |
248 | if (ptr->is_deleted) | 360 | if (ptr->is_deleted) |
249 | continue; | 361 | continue; |
250 | if (ptr->domainname) { | 362 | if (ptr->domainname) { |
251 | if (!ptr->is_last_name) { | 363 | if (!ptr->is_last_name) { |
252 | if (ptr->domainname != domainname) | 364 | if (ptr->domainname != domainname) |
253 | continue; | 365 | continue; |
254 | } else { | 366 | } else { |
255 | if (tomoyo_pathcmp(ptr->domainname, last_name)) | 367 | if (tomoyo_pathcmp(ptr->domainname, last_name)) |
256 | continue; | 368 | continue; |
257 | } | 369 | } |
258 | } | 370 | } |
259 | if (tomoyo_pathcmp(ptr->program, program)) | 371 | if (tomoyo_pathcmp(ptr->program, program)) |
260 | continue; | 372 | continue; |
261 | if (ptr->is_not) { | 373 | if (ptr->is_not) { |
262 | flag = false; | 374 | flag = false; |
263 | break; | 375 | break; |
264 | } | 376 | } |
265 | flag = true; | 377 | flag = true; |
266 | } | 378 | } |
267 | up_read(&tomoyo_domain_initializer_list_lock); | 379 | up_read(&tomoyo_domain_initializer_list_lock); |
268 | return flag; | 380 | return flag; |
269 | } | 381 | } |
270 | 382 | ||
271 | /* The list for "struct tomoyo_domain_keeper_entry". */ | 383 | /* |
384 | * tomoyo_domain_keeper_list is used for holding list of domainnames which | ||
385 | * suppresses domain transition. Normally, a domainname is monotonically | ||
386 | * getting longer. But sometimes, we want to suppress domain transition. | ||
387 | * It would be convenient for us that programs executed from a login session | ||
388 | * belong to the same domain. Thus, TOMOYO provides a way to suppress domain | ||
389 | * transition. | ||
390 | * | ||
391 | * An entry is added by | ||
392 | * | ||
393 | * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
394 | * /sys/kernel/security/tomoyo/exception_policy | ||
395 | * | ||
396 | * and is deleted by | ||
397 | * | ||
398 | * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
399 | * /sys/kernel/security/tomoyo/exception_policy | ||
400 | * | ||
401 | * and all entries are retrieved by | ||
402 | * | ||
403 | * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy | ||
404 | * | ||
405 | * In the example above, any process which belongs to | ||
406 | * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain, | ||
407 | * unless explicitly specified by "initialize_domain" or "no_keep_domain". | ||
408 | * | ||
409 | * You may specify a program using "from" keyword. | ||
410 | * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash" | ||
411 | * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash" | ||
412 | * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain. | ||
413 | * | ||
414 | * You may add "no_" prefix to "keep_domain". | ||
415 | * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and | ||
416 | * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will | ||
417 | * cause "/usr/bin/passwd" to belong to | ||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | ||
419 | * explicitly specified by "initialize_domain". | ||
420 | */ | ||
272 | static LIST_HEAD(tomoyo_domain_keeper_list); | 421 | static LIST_HEAD(tomoyo_domain_keeper_list); |
273 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | 422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); |
274 | 423 | ||
275 | /** | 424 | /** |
276 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | 425 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. |
277 | * | 426 | * |
278 | * @domainname: The name of domain. | 427 | * @domainname: The name of domain. |
279 | * @program: The name of program. May be NULL. | 428 | * @program: The name of program. May be NULL. |
280 | * @is_not: True if it is "no_keep_domain" entry. | 429 | * @is_not: True if it is "no_keep_domain" entry. |
281 | * @is_delete: True if it is a delete request. | 430 | * @is_delete: True if it is a delete request. |
282 | * | 431 | * |
283 | * Returns 0 on success, negative value otherwise. | 432 | * Returns 0 on success, negative value otherwise. |
284 | */ | 433 | */ |
285 | static int tomoyo_update_domain_keeper_entry(const char *domainname, | 434 | static int tomoyo_update_domain_keeper_entry(const char *domainname, |
286 | const char *program, | 435 | const char *program, |
287 | const bool is_not, | 436 | const bool is_not, |
288 | const bool is_delete) | 437 | const bool is_delete) |
289 | { | 438 | { |
290 | struct tomoyo_domain_keeper_entry *new_entry; | 439 | struct tomoyo_domain_keeper_entry *new_entry; |
291 | struct tomoyo_domain_keeper_entry *ptr; | 440 | struct tomoyo_domain_keeper_entry *ptr; |
292 | const struct tomoyo_path_info *saved_domainname; | 441 | const struct tomoyo_path_info *saved_domainname; |
293 | const struct tomoyo_path_info *saved_program = NULL; | 442 | const struct tomoyo_path_info *saved_program = NULL; |
294 | int error = -ENOMEM; | 443 | int error = -ENOMEM; |
295 | bool is_last_name = false; | 444 | bool is_last_name = false; |
296 | 445 | ||
297 | if (!tomoyo_is_domain_def(domainname) && | 446 | if (!tomoyo_is_domain_def(domainname) && |
298 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 447 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) |
299 | is_last_name = true; | 448 | is_last_name = true; |
300 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 449 | else if (!tomoyo_is_correct_domain(domainname, __func__)) |
301 | return -EINVAL; | 450 | return -EINVAL; |
302 | if (program) { | 451 | if (program) { |
303 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 452 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) |
304 | return -EINVAL; | 453 | return -EINVAL; |
305 | saved_program = tomoyo_save_name(program); | 454 | saved_program = tomoyo_save_name(program); |
306 | if (!saved_program) | 455 | if (!saved_program) |
307 | return -ENOMEM; | 456 | return -ENOMEM; |
308 | } | 457 | } |
309 | saved_domainname = tomoyo_save_name(domainname); | 458 | saved_domainname = tomoyo_save_name(domainname); |
310 | if (!saved_domainname) | 459 | if (!saved_domainname) |
311 | return -ENOMEM; | 460 | return -ENOMEM; |
312 | down_write(&tomoyo_domain_keeper_list_lock); | 461 | down_write(&tomoyo_domain_keeper_list_lock); |
313 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 462 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { |
314 | if (ptr->is_not != is_not || | 463 | if (ptr->is_not != is_not || |
315 | ptr->domainname != saved_domainname || | 464 | ptr->domainname != saved_domainname || |
316 | ptr->program != saved_program) | 465 | ptr->program != saved_program) |
317 | continue; | 466 | continue; |
318 | ptr->is_deleted = is_delete; | 467 | ptr->is_deleted = is_delete; |
319 | error = 0; | 468 | error = 0; |
320 | goto out; | 469 | goto out; |
321 | } | 470 | } |
322 | if (is_delete) { | 471 | if (is_delete) { |
323 | error = -ENOENT; | 472 | error = -ENOENT; |
324 | goto out; | 473 | goto out; |
325 | } | 474 | } |
326 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 475 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
327 | if (!new_entry) | 476 | if (!new_entry) |
328 | goto out; | 477 | goto out; |
329 | new_entry->domainname = saved_domainname; | 478 | new_entry->domainname = saved_domainname; |
330 | new_entry->program = saved_program; | 479 | new_entry->program = saved_program; |
331 | new_entry->is_not = is_not; | 480 | new_entry->is_not = is_not; |
332 | new_entry->is_last_name = is_last_name; | 481 | new_entry->is_last_name = is_last_name; |
333 | list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); | 482 | list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); |
334 | error = 0; | 483 | error = 0; |
335 | out: | 484 | out: |
336 | up_write(&tomoyo_domain_keeper_list_lock); | 485 | up_write(&tomoyo_domain_keeper_list_lock); |
337 | return error; | 486 | return error; |
338 | } | 487 | } |
339 | 488 | ||
340 | /** | 489 | /** |
341 | * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list. | 490 | * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list. |
342 | * | 491 | * |
343 | * @data: String to parse. | 492 | * @data: String to parse. |
344 | * @is_not: True if it is "no_keep_domain" entry. | 493 | * @is_not: True if it is "no_keep_domain" entry. |
345 | * @is_delete: True if it is a delete request. | 494 | * @is_delete: True if it is a delete request. |
346 | * | 495 | * |
347 | */ | 496 | */ |
348 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | 497 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, |
349 | const bool is_delete) | 498 | const bool is_delete) |
350 | { | 499 | { |
351 | char *cp = strstr(data, " from "); | 500 | char *cp = strstr(data, " from "); |
352 | 501 | ||
353 | if (cp) { | 502 | if (cp) { |
354 | *cp = '\0'; | 503 | *cp = '\0'; |
355 | return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not, | 504 | return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not, |
356 | is_delete); | 505 | is_delete); |
357 | } | 506 | } |
358 | return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete); | 507 | return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete); |
359 | } | 508 | } |
360 | 509 | ||
361 | /** | 510 | /** |
362 | * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list. | 511 | * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list. |
363 | * | 512 | * |
364 | * @head: Pointer to "struct tomoyo_io_buffer". | 513 | * @head: Pointer to "struct tomoyo_io_buffer". |
365 | * | 514 | * |
366 | * Returns true on success, false otherwise. | 515 | * Returns true on success, false otherwise. |
367 | */ | 516 | */ |
368 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | 517 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) |
369 | { | 518 | { |
370 | struct list_head *pos; | 519 | struct list_head *pos; |
371 | bool done = true; | 520 | bool done = true; |
372 | 521 | ||
373 | down_read(&tomoyo_domain_keeper_list_lock); | 522 | down_read(&tomoyo_domain_keeper_list_lock); |
374 | list_for_each_cookie(pos, head->read_var2, | 523 | list_for_each_cookie(pos, head->read_var2, |
375 | &tomoyo_domain_keeper_list) { | 524 | &tomoyo_domain_keeper_list) { |
376 | struct tomoyo_domain_keeper_entry *ptr; | 525 | struct tomoyo_domain_keeper_entry *ptr; |
377 | const char *no; | 526 | const char *no; |
378 | const char *from = ""; | 527 | const char *from = ""; |
379 | const char *program = ""; | 528 | const char *program = ""; |
380 | 529 | ||
381 | ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list); | 530 | ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list); |
382 | if (ptr->is_deleted) | 531 | if (ptr->is_deleted) |
383 | continue; | 532 | continue; |
384 | no = ptr->is_not ? "no_" : ""; | 533 | no = ptr->is_not ? "no_" : ""; |
385 | if (ptr->program) { | 534 | if (ptr->program) { |
386 | from = " from "; | 535 | from = " from "; |
387 | program = ptr->program->name; | 536 | program = ptr->program->name; |
388 | } | 537 | } |
389 | done = tomoyo_io_printf(head, | 538 | done = tomoyo_io_printf(head, |
390 | "%s" TOMOYO_KEYWORD_KEEP_DOMAIN | 539 | "%s" TOMOYO_KEYWORD_KEEP_DOMAIN |
391 | "%s%s%s\n", no, program, from, | 540 | "%s%s%s\n", no, program, from, |
392 | ptr->domainname->name); | 541 | ptr->domainname->name); |
393 | if (!done) | 542 | if (!done) |
394 | break; | 543 | break; |
395 | } | 544 | } |
396 | up_read(&tomoyo_domain_keeper_list_lock); | 545 | up_read(&tomoyo_domain_keeper_list_lock); |
397 | return done; | 546 | return done; |
398 | } | 547 | } |
399 | 548 | ||
400 | /** | 549 | /** |
401 | * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression. | 550 | * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression. |
402 | * | 551 | * |
403 | * @domainname: The name of domain. | 552 | * @domainname: The name of domain. |
404 | * @program: The name of program. | 553 | * @program: The name of program. |
405 | * @last_name: The last component of @domainname. | 554 | * @last_name: The last component of @domainname. |
406 | * | 555 | * |
407 | * Returns true if executing @program supresses domain transition, | 556 | * Returns true if executing @program supresses domain transition, |
408 | * false otherwise. | 557 | * false otherwise. |
409 | */ | 558 | */ |
410 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | 559 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, |
411 | const struct tomoyo_path_info *program, | 560 | const struct tomoyo_path_info *program, |
412 | const struct tomoyo_path_info *last_name) | 561 | const struct tomoyo_path_info *last_name) |
413 | { | 562 | { |
414 | struct tomoyo_domain_keeper_entry *ptr; | 563 | struct tomoyo_domain_keeper_entry *ptr; |
415 | bool flag = false; | 564 | bool flag = false; |
416 | 565 | ||
417 | down_read(&tomoyo_domain_keeper_list_lock); | 566 | down_read(&tomoyo_domain_keeper_list_lock); |
418 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 567 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { |
419 | if (ptr->is_deleted) | 568 | if (ptr->is_deleted) |
420 | continue; | 569 | continue; |
421 | if (!ptr->is_last_name) { | 570 | if (!ptr->is_last_name) { |
422 | if (ptr->domainname != domainname) | 571 | if (ptr->domainname != domainname) |
423 | continue; | 572 | continue; |
424 | } else { | 573 | } else { |
425 | if (tomoyo_pathcmp(ptr->domainname, last_name)) | 574 | if (tomoyo_pathcmp(ptr->domainname, last_name)) |
426 | continue; | 575 | continue; |
427 | } | 576 | } |
428 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) | 577 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) |
429 | continue; | 578 | continue; |
430 | if (ptr->is_not) { | 579 | if (ptr->is_not) { |
431 | flag = false; | 580 | flag = false; |
432 | break; | 581 | break; |
433 | } | 582 | } |
434 | flag = true; | 583 | flag = true; |
435 | } | 584 | } |
436 | up_read(&tomoyo_domain_keeper_list_lock); | 585 | up_read(&tomoyo_domain_keeper_list_lock); |
437 | return flag; | 586 | return flag; |
438 | } | 587 | } |
439 | 588 | ||
440 | /* The list for "struct tomoyo_alias_entry". */ | 589 | /* |
590 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are | ||
591 | * allowed to be passed to an execve() request. Normally, the domainname which | ||
592 | * the current process will belong to after execve() succeeds is calculated | ||
593 | * using dereferenced pathnames. But some programs behave differently depending | ||
594 | * on the name passed to argv[0]. For busybox, calculating domainname using | ||
595 | * dereferenced pathnames will cause all programs in the busybox to belong to | ||
596 | * the same domain. Thus, TOMOYO provides a way to allow use of symlink's | ||
597 | * pathname for checking execve()'s permission and calculating domainname which | ||
598 | * the current process will belong to after execve() succeeds. | ||
599 | * | ||
600 | * An entry is added by | ||
601 | * | ||
602 | * # echo 'alias /bin/busybox /bin/cat' > \ | ||
603 | * /sys/kernel/security/tomoyo/exception_policy | ||
604 | * | ||
605 | * and is deleted by | ||
606 | * | ||
607 | * # echo 'delete alias /bin/busybox /bin/cat' > \ | ||
608 | * /sys/kernel/security/tomoyo/exception_policy | ||
609 | * | ||
610 | * and all entries are retrieved by | ||
611 | * | ||
612 | * # grep ^alias /sys/kernel/security/tomoyo/exception_policy | ||
613 | * | ||
614 | * In the example above, if /bin/cat is a symlink to /bin/busybox and execution | ||
615 | * of /bin/cat is requested, permission is checked for /bin/cat rather than | ||
616 | * /bin/busybox and domainname which the current process will belong to after | ||
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | ||
618 | */ | ||
441 | static LIST_HEAD(tomoyo_alias_list); | 619 | static LIST_HEAD(tomoyo_alias_list); |
442 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | 620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); |
443 | 621 | ||
444 | /** | 622 | /** |
445 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. | 623 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. |
446 | * | 624 | * |
447 | * @original_name: The original program's real name. | 625 | * @original_name: The original program's real name. |
448 | * @aliased_name: The symbolic program's symbolic link's name. | 626 | * @aliased_name: The symbolic program's symbolic link's name. |
449 | * @is_delete: True if it is a delete request. | 627 | * @is_delete: True if it is a delete request. |
450 | * | 628 | * |
451 | * Returns 0 on success, negative value otherwise. | 629 | * Returns 0 on success, negative value otherwise. |
452 | */ | 630 | */ |
453 | static int tomoyo_update_alias_entry(const char *original_name, | 631 | static int tomoyo_update_alias_entry(const char *original_name, |
454 | const char *aliased_name, | 632 | const char *aliased_name, |
455 | const bool is_delete) | 633 | const bool is_delete) |
456 | { | 634 | { |
457 | struct tomoyo_alias_entry *new_entry; | 635 | struct tomoyo_alias_entry *new_entry; |
458 | struct tomoyo_alias_entry *ptr; | 636 | struct tomoyo_alias_entry *ptr; |
459 | const struct tomoyo_path_info *saved_original_name; | 637 | const struct tomoyo_path_info *saved_original_name; |
460 | const struct tomoyo_path_info *saved_aliased_name; | 638 | const struct tomoyo_path_info *saved_aliased_name; |
461 | int error = -ENOMEM; | 639 | int error = -ENOMEM; |
462 | 640 | ||
463 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || | 641 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || |
464 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) | 642 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) |
465 | return -EINVAL; /* No patterns allowed. */ | 643 | return -EINVAL; /* No patterns allowed. */ |
466 | saved_original_name = tomoyo_save_name(original_name); | 644 | saved_original_name = tomoyo_save_name(original_name); |
467 | saved_aliased_name = tomoyo_save_name(aliased_name); | 645 | saved_aliased_name = tomoyo_save_name(aliased_name); |
468 | if (!saved_original_name || !saved_aliased_name) | 646 | if (!saved_original_name || !saved_aliased_name) |
469 | return -ENOMEM; | 647 | return -ENOMEM; |
470 | down_write(&tomoyo_alias_list_lock); | 648 | down_write(&tomoyo_alias_list_lock); |
471 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 649 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { |
472 | if (ptr->original_name != saved_original_name || | 650 | if (ptr->original_name != saved_original_name || |
473 | ptr->aliased_name != saved_aliased_name) | 651 | ptr->aliased_name != saved_aliased_name) |
474 | continue; | 652 | continue; |
475 | ptr->is_deleted = is_delete; | 653 | ptr->is_deleted = is_delete; |
476 | error = 0; | 654 | error = 0; |
477 | goto out; | 655 | goto out; |
478 | } | 656 | } |
479 | if (is_delete) { | 657 | if (is_delete) { |
480 | error = -ENOENT; | 658 | error = -ENOENT; |
481 | goto out; | 659 | goto out; |
482 | } | 660 | } |
483 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 661 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
484 | if (!new_entry) | 662 | if (!new_entry) |
485 | goto out; | 663 | goto out; |
486 | new_entry->original_name = saved_original_name; | 664 | new_entry->original_name = saved_original_name; |
487 | new_entry->aliased_name = saved_aliased_name; | 665 | new_entry->aliased_name = saved_aliased_name; |
488 | list_add_tail(&new_entry->list, &tomoyo_alias_list); | 666 | list_add_tail(&new_entry->list, &tomoyo_alias_list); |
489 | error = 0; | 667 | error = 0; |
490 | out: | 668 | out: |
491 | up_write(&tomoyo_alias_list_lock); | 669 | up_write(&tomoyo_alias_list_lock); |
492 | return error; | 670 | return error; |
493 | } | 671 | } |
494 | 672 | ||
495 | /** | 673 | /** |
496 | * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list. | 674 | * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list. |
497 | * | 675 | * |
498 | * @head: Pointer to "struct tomoyo_io_buffer". | 676 | * @head: Pointer to "struct tomoyo_io_buffer". |
499 | * | 677 | * |
500 | * Returns true on success, false otherwise. | 678 | * Returns true on success, false otherwise. |
501 | */ | 679 | */ |
502 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | 680 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) |
503 | { | 681 | { |
504 | struct list_head *pos; | 682 | struct list_head *pos; |
505 | bool done = true; | 683 | bool done = true; |
506 | 684 | ||
507 | down_read(&tomoyo_alias_list_lock); | 685 | down_read(&tomoyo_alias_list_lock); |
508 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { | 686 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { |
509 | struct tomoyo_alias_entry *ptr; | 687 | struct tomoyo_alias_entry *ptr; |
510 | 688 | ||
511 | ptr = list_entry(pos, struct tomoyo_alias_entry, list); | 689 | ptr = list_entry(pos, struct tomoyo_alias_entry, list); |
512 | if (ptr->is_deleted) | 690 | if (ptr->is_deleted) |
513 | continue; | 691 | continue; |
514 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", | 692 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", |
515 | ptr->original_name->name, | 693 | ptr->original_name->name, |
516 | ptr->aliased_name->name); | 694 | ptr->aliased_name->name); |
517 | if (!done) | 695 | if (!done) |
518 | break; | 696 | break; |
519 | } | 697 | } |
520 | up_read(&tomoyo_alias_list_lock); | 698 | up_read(&tomoyo_alias_list_lock); |
521 | return done; | 699 | return done; |
522 | } | 700 | } |
523 | 701 | ||
524 | /** | 702 | /** |
525 | * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list. | 703 | * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list. |
526 | * | 704 | * |
527 | * @data: String to parse. | 705 | * @data: String to parse. |
528 | * @is_delete: True if it is a delete request. | 706 | * @is_delete: True if it is a delete request. |
529 | * | 707 | * |
530 | * Returns 0 on success, negative value otherwise. | 708 | * Returns 0 on success, negative value otherwise. |
531 | */ | 709 | */ |
532 | int tomoyo_write_alias_policy(char *data, const bool is_delete) | 710 | int tomoyo_write_alias_policy(char *data, const bool is_delete) |
533 | { | 711 | { |
534 | char *cp = strchr(data, ' '); | 712 | char *cp = strchr(data, ' '); |
535 | 713 | ||
536 | if (!cp) | 714 | if (!cp) |
537 | return -EINVAL; | 715 | return -EINVAL; |
538 | *cp++ = '\0'; | 716 | *cp++ = '\0'; |
539 | return tomoyo_update_alias_entry(data, cp, is_delete); | 717 | return tomoyo_update_alias_entry(data, cp, is_delete); |
540 | } | 718 | } |
541 | 719 | ||
542 | /* Domain create/delete handler. */ | 720 | /* Domain create/delete handler. */ |
543 | 721 | ||
544 | /** | 722 | /** |
545 | * tomoyo_delete_domain - Delete a domain. | 723 | * tomoyo_delete_domain - Delete a domain. |
546 | * | 724 | * |
547 | * @domainname: The name of domain. | 725 | * @domainname: The name of domain. |
548 | * | 726 | * |
549 | * Returns 0. | 727 | * Returns 0. |
550 | */ | 728 | */ |
551 | int tomoyo_delete_domain(char *domainname) | 729 | int tomoyo_delete_domain(char *domainname) |
552 | { | 730 | { |
553 | struct tomoyo_domain_info *domain; | 731 | struct tomoyo_domain_info *domain; |
554 | struct tomoyo_path_info name; | 732 | struct tomoyo_path_info name; |
555 | 733 | ||
556 | name.name = domainname; | 734 | name.name = domainname; |
557 | tomoyo_fill_path_info(&name); | 735 | tomoyo_fill_path_info(&name); |
558 | down_write(&tomoyo_domain_list_lock); | 736 | down_write(&tomoyo_domain_list_lock); |
559 | /* Is there an active domain? */ | 737 | /* Is there an active domain? */ |
560 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 738 | list_for_each_entry(domain, &tomoyo_domain_list, list) { |
561 | /* Never delete tomoyo_kernel_domain */ | 739 | /* Never delete tomoyo_kernel_domain */ |
562 | if (domain == &tomoyo_kernel_domain) | 740 | if (domain == &tomoyo_kernel_domain) |
563 | continue; | 741 | continue; |
564 | if (domain->is_deleted || | 742 | if (domain->is_deleted || |
565 | tomoyo_pathcmp(domain->domainname, &name)) | 743 | tomoyo_pathcmp(domain->domainname, &name)) |
566 | continue; | 744 | continue; |
567 | domain->is_deleted = true; | 745 | domain->is_deleted = true; |
568 | break; | 746 | break; |
569 | } | 747 | } |
570 | up_write(&tomoyo_domain_list_lock); | 748 | up_write(&tomoyo_domain_list_lock); |
571 | return 0; | 749 | return 0; |
572 | } | 750 | } |
573 | 751 | ||
574 | /** | 752 | /** |
575 | * tomoyo_find_or_assign_new_domain - Create a domain. | 753 | * tomoyo_find_or_assign_new_domain - Create a domain. |
576 | * | 754 | * |
577 | * @domainname: The name of domain. | 755 | * @domainname: The name of domain. |
578 | * @profile: Profile number to assign if the domain was newly created. | 756 | * @profile: Profile number to assign if the domain was newly created. |
579 | * | 757 | * |
580 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 758 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. |
581 | */ | 759 | */ |
582 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 760 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
583 | domainname, | 761 | domainname, |
584 | const u8 profile) | 762 | const u8 profile) |
585 | { | 763 | { |
586 | struct tomoyo_domain_info *domain = NULL; | 764 | struct tomoyo_domain_info *domain = NULL; |
587 | const struct tomoyo_path_info *saved_domainname; | 765 | const struct tomoyo_path_info *saved_domainname; |
588 | 766 | ||
589 | down_write(&tomoyo_domain_list_lock); | 767 | down_write(&tomoyo_domain_list_lock); |
590 | domain = tomoyo_find_domain(domainname); | 768 | domain = tomoyo_find_domain(domainname); |
591 | if (domain) | 769 | if (domain) |
592 | goto out; | 770 | goto out; |
593 | if (!tomoyo_is_correct_domain(domainname, __func__)) | 771 | if (!tomoyo_is_correct_domain(domainname, __func__)) |
594 | goto out; | 772 | goto out; |
595 | saved_domainname = tomoyo_save_name(domainname); | 773 | saved_domainname = tomoyo_save_name(domainname); |
596 | if (!saved_domainname) | 774 | if (!saved_domainname) |
597 | goto out; | 775 | goto out; |
598 | /* Can I reuse memory of deleted domain? */ | 776 | /* Can I reuse memory of deleted domain? */ |
599 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 777 | list_for_each_entry(domain, &tomoyo_domain_list, list) { |
600 | struct task_struct *p; | 778 | struct task_struct *p; |
601 | struct tomoyo_acl_info *ptr; | 779 | struct tomoyo_acl_info *ptr; |
602 | bool flag; | 780 | bool flag; |
603 | if (!domain->is_deleted || | 781 | if (!domain->is_deleted || |
604 | domain->domainname != saved_domainname) | 782 | domain->domainname != saved_domainname) |
605 | continue; | 783 | continue; |
606 | flag = false; | 784 | flag = false; |
607 | read_lock(&tasklist_lock); | 785 | read_lock(&tasklist_lock); |
608 | for_each_process(p) { | 786 | for_each_process(p) { |
609 | if (tomoyo_real_domain(p) != domain) | 787 | if (tomoyo_real_domain(p) != domain) |
610 | continue; | 788 | continue; |
611 | flag = true; | 789 | flag = true; |
612 | break; | 790 | break; |
613 | } | 791 | } |
614 | read_unlock(&tasklist_lock); | 792 | read_unlock(&tasklist_lock); |
615 | if (flag) | 793 | if (flag) |
616 | continue; | 794 | continue; |
617 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 795 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
618 | ptr->type |= TOMOYO_ACL_DELETED; | 796 | ptr->type |= TOMOYO_ACL_DELETED; |
619 | } | 797 | } |
620 | tomoyo_set_domain_flag(domain, true, domain->flags); | 798 | tomoyo_set_domain_flag(domain, true, domain->flags); |
621 | domain->profile = profile; | 799 | domain->profile = profile; |
622 | domain->quota_warned = false; | 800 | domain->quota_warned = false; |
623 | mb(); /* Avoid out-of-order execution. */ | 801 | mb(); /* Avoid out-of-order execution. */ |
624 | domain->is_deleted = false; | 802 | domain->is_deleted = false; |
625 | goto out; | 803 | goto out; |
626 | } | 804 | } |
627 | /* No memory reusable. Create using new memory. */ | 805 | /* No memory reusable. Create using new memory. */ |
628 | domain = tomoyo_alloc_element(sizeof(*domain)); | 806 | domain = tomoyo_alloc_element(sizeof(*domain)); |
629 | if (domain) { | 807 | if (domain) { |
630 | INIT_LIST_HEAD(&domain->acl_info_list); | 808 | INIT_LIST_HEAD(&domain->acl_info_list); |
631 | domain->domainname = saved_domainname; | 809 | domain->domainname = saved_domainname; |
632 | domain->profile = profile; | 810 | domain->profile = profile; |
633 | list_add_tail(&domain->list, &tomoyo_domain_list); | 811 | list_add_tail(&domain->list, &tomoyo_domain_list); |
634 | } | 812 | } |
635 | out: | 813 | out: |
636 | up_write(&tomoyo_domain_list_lock); | 814 | up_write(&tomoyo_domain_list_lock); |
637 | return domain; | 815 | return domain; |
638 | } | 816 | } |
639 | 817 | ||
640 | /** | 818 | /** |
641 | * tomoyo_find_next_domain - Find a domain. | 819 | * tomoyo_find_next_domain - Find a domain. |
642 | * | 820 | * |
643 | * @bprm: Pointer to "struct linux_binprm". | 821 | * @bprm: Pointer to "struct linux_binprm". |
644 | * @next_domain: Pointer to pointer to "struct tomoyo_domain_info". | 822 | * @next_domain: Pointer to pointer to "struct tomoyo_domain_info". |
645 | * | 823 | * |
646 | * Returns 0 on success, negative value otherwise. | 824 | * Returns 0 on success, negative value otherwise. |
647 | */ | 825 | */ |
648 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 826 | int tomoyo_find_next_domain(struct linux_binprm *bprm, |
649 | struct tomoyo_domain_info **next_domain) | 827 | struct tomoyo_domain_info **next_domain) |
650 | { | 828 | { |
651 | /* | 829 | /* |
652 | * This function assumes that the size of buffer returned by | 830 | * This function assumes that the size of buffer returned by |
653 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | 831 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. |
654 | */ | 832 | */ |
655 | struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp)); | 833 | struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp)); |
656 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 834 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
657 | struct tomoyo_domain_info *domain = NULL; | 835 | struct tomoyo_domain_info *domain = NULL; |
658 | const char *old_domain_name = old_domain->domainname->name; | 836 | const char *old_domain_name = old_domain->domainname->name; |
659 | const char *original_name = bprm->filename; | 837 | const char *original_name = bprm->filename; |
660 | char *new_domain_name = NULL; | 838 | char *new_domain_name = NULL; |
661 | char *real_program_name = NULL; | 839 | char *real_program_name = NULL; |
662 | char *symlink_program_name = NULL; | 840 | char *symlink_program_name = NULL; |
663 | const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); | 841 | const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); |
664 | const bool is_enforce = (mode == 3); | 842 | const bool is_enforce = (mode == 3); |
665 | int retval = -ENOMEM; | 843 | int retval = -ENOMEM; |
666 | struct tomoyo_path_info r; /* real name */ | 844 | struct tomoyo_path_info r; /* real name */ |
667 | struct tomoyo_path_info s; /* symlink name */ | 845 | struct tomoyo_path_info s; /* symlink name */ |
668 | struct tomoyo_path_info l; /* last name */ | 846 | struct tomoyo_path_info l; /* last name */ |
669 | static bool initialized; | 847 | static bool initialized; |
670 | 848 | ||
671 | if (!tmp) | 849 | if (!tmp) |
672 | goto out; | 850 | goto out; |
673 | 851 | ||
674 | if (!initialized) { | 852 | if (!initialized) { |
675 | /* | 853 | /* |
676 | * Built-in initializers. This is needed because policies are | 854 | * Built-in initializers. This is needed because policies are |
677 | * not loaded until starting /sbin/init. | 855 | * not loaded until starting /sbin/init. |
678 | */ | 856 | */ |
679 | tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug", | 857 | tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug", |
680 | false, false); | 858 | false, false); |
681 | tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe", | 859 | tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe", |
682 | false, false); | 860 | false, false); |
683 | initialized = true; | 861 | initialized = true; |
684 | } | 862 | } |
685 | 863 | ||
686 | /* Get tomoyo_realpath of program. */ | 864 | /* Get tomoyo_realpath of program. */ |
687 | retval = -ENOENT; | 865 | retval = -ENOENT; |
688 | /* I hope tomoyo_realpath() won't fail with -ENOMEM. */ | 866 | /* I hope tomoyo_realpath() won't fail with -ENOMEM. */ |
689 | real_program_name = tomoyo_realpath(original_name); | 867 | real_program_name = tomoyo_realpath(original_name); |
690 | if (!real_program_name) | 868 | if (!real_program_name) |
691 | goto out; | 869 | goto out; |
692 | /* Get tomoyo_realpath of symbolic link. */ | 870 | /* Get tomoyo_realpath of symbolic link. */ |
693 | symlink_program_name = tomoyo_realpath_nofollow(original_name); | 871 | symlink_program_name = tomoyo_realpath_nofollow(original_name); |
694 | if (!symlink_program_name) | 872 | if (!symlink_program_name) |
695 | goto out; | 873 | goto out; |
696 | 874 | ||
697 | r.name = real_program_name; | 875 | r.name = real_program_name; |
698 | tomoyo_fill_path_info(&r); | 876 | tomoyo_fill_path_info(&r); |
699 | s.name = symlink_program_name; | 877 | s.name = symlink_program_name; |
700 | tomoyo_fill_path_info(&s); | 878 | tomoyo_fill_path_info(&s); |
701 | l.name = tomoyo_get_last_name(old_domain); | 879 | l.name = tomoyo_get_last_name(old_domain); |
702 | tomoyo_fill_path_info(&l); | 880 | tomoyo_fill_path_info(&l); |
703 | 881 | ||
704 | /* Check 'alias' directive. */ | 882 | /* Check 'alias' directive. */ |
705 | if (tomoyo_pathcmp(&r, &s)) { | 883 | if (tomoyo_pathcmp(&r, &s)) { |
706 | struct tomoyo_alias_entry *ptr; | 884 | struct tomoyo_alias_entry *ptr; |
707 | /* Is this program allowed to be called via symbolic links? */ | 885 | /* Is this program allowed to be called via symbolic links? */ |
708 | down_read(&tomoyo_alias_list_lock); | 886 | down_read(&tomoyo_alias_list_lock); |
709 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 887 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { |
710 | if (ptr->is_deleted || | 888 | if (ptr->is_deleted || |
711 | tomoyo_pathcmp(&r, ptr->original_name) || | 889 | tomoyo_pathcmp(&r, ptr->original_name) || |
712 | tomoyo_pathcmp(&s, ptr->aliased_name)) | 890 | tomoyo_pathcmp(&s, ptr->aliased_name)) |
713 | continue; | 891 | continue; |
714 | memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); | 892 | memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); |
715 | strncpy(real_program_name, ptr->aliased_name->name, | 893 | strncpy(real_program_name, ptr->aliased_name->name, |
716 | TOMOYO_MAX_PATHNAME_LEN - 1); | 894 | TOMOYO_MAX_PATHNAME_LEN - 1); |
717 | tomoyo_fill_path_info(&r); | 895 | tomoyo_fill_path_info(&r); |
718 | break; | 896 | break; |
719 | } | 897 | } |
720 | up_read(&tomoyo_alias_list_lock); | 898 | up_read(&tomoyo_alias_list_lock); |
721 | } | 899 | } |
722 | 900 | ||
723 | /* Check execute permission. */ | 901 | /* Check execute permission. */ |
724 | retval = tomoyo_check_exec_perm(old_domain, &r); | 902 | retval = tomoyo_check_exec_perm(old_domain, &r); |
725 | if (retval < 0) | 903 | if (retval < 0) |
726 | goto out; | 904 | goto out; |
727 | 905 | ||
728 | new_domain_name = tmp->buffer; | 906 | new_domain_name = tmp->buffer; |
729 | if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) { | 907 | if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) { |
730 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 908 | /* Transit to the child of tomoyo_kernel_domain domain. */ |
731 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, | 909 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, |
732 | TOMOYO_ROOT_NAME " " "%s", real_program_name); | 910 | TOMOYO_ROOT_NAME " " "%s", real_program_name); |
733 | } else if (old_domain == &tomoyo_kernel_domain && | 911 | } else if (old_domain == &tomoyo_kernel_domain && |
734 | !tomoyo_policy_loaded) { | 912 | !tomoyo_policy_loaded) { |
735 | /* | 913 | /* |
736 | * Needn't to transit from kernel domain before starting | 914 | * Needn't to transit from kernel domain before starting |
737 | * /sbin/init. But transit from kernel domain if executing | 915 | * /sbin/init. But transit from kernel domain if executing |
738 | * initializers because they might start before /sbin/init. | 916 | * initializers because they might start before /sbin/init. |
739 | */ | 917 | */ |
740 | domain = old_domain; | 918 | domain = old_domain; |
741 | } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) { | 919 | } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) { |
742 | /* Keep current domain. */ | 920 | /* Keep current domain. */ |
743 | domain = old_domain; | 921 | domain = old_domain; |
744 | } else { | 922 | } else { |
745 | /* Normal domain transition. */ | 923 | /* Normal domain transition. */ |
746 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, | 924 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, |
747 | "%s %s", old_domain_name, real_program_name); | 925 | "%s %s", old_domain_name, real_program_name); |
748 | } | 926 | } |
749 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) | 927 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) |
750 | goto done; | 928 | goto done; |
751 | down_read(&tomoyo_domain_list_lock); | 929 | down_read(&tomoyo_domain_list_lock); |
752 | domain = tomoyo_find_domain(new_domain_name); | 930 | domain = tomoyo_find_domain(new_domain_name); |
753 | up_read(&tomoyo_domain_list_lock); | 931 | up_read(&tomoyo_domain_list_lock); |
754 | if (domain) | 932 | if (domain) |
755 | goto done; | 933 | goto done; |
756 | if (is_enforce) | 934 | if (is_enforce) |
757 | goto done; | 935 | goto done; |
758 | domain = tomoyo_find_or_assign_new_domain(new_domain_name, | 936 | domain = tomoyo_find_or_assign_new_domain(new_domain_name, |
759 | old_domain->profile); | 937 | old_domain->profile); |
760 | done: | 938 | done: |
761 | if (domain) | 939 | if (domain) |
762 | goto out; | 940 | goto out; |
763 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", | 941 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", |
764 | new_domain_name); | 942 | new_domain_name); |
765 | if (is_enforce) | 943 | if (is_enforce) |
766 | retval = -EPERM; | 944 | retval = -EPERM; |
767 | else | 945 | else |
768 | tomoyo_set_domain_flag(old_domain, false, | 946 | tomoyo_set_domain_flag(old_domain, false, |
769 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | 947 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); |
770 | out: | 948 | out: |
771 | tomoyo_free(real_program_name); | 949 | tomoyo_free(real_program_name); |
772 | tomoyo_free(symlink_program_name); | 950 | tomoyo_free(symlink_program_name); |
773 | *next_domain = domain ? domain : old_domain; | 951 | *next_domain = domain ? domain : old_domain; |
774 | tomoyo_free(tmp); | 952 | tomoyo_free(tmp); |
775 | return retval; | 953 | return retval; |
776 | } | 954 | } |
777 | 955 |
security/tomoyo/file.c
1 | /* | 1 | /* |
2 | * security/tomoyo/file.c | 2 | * security/tomoyo/file.c |
3 | * | 3 | * |
4 | * Implementation of the Domain-Based Mandatory Access Control. | 4 | * Implementation of the Domain-Based Mandatory Access Control. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * | 7 | * |
8 | * Version: 2.2.0 2009/04/01 | 8 | * Version: 2.2.0 2009/04/01 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | 13 | #include "tomoyo.h" |
14 | #include "realpath.h" | 14 | #include "realpath.h" |
15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) | 15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) |
16 | 16 | ||
17 | /* Structure for "allow_read" keyword. */ | 17 | /* |
18 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
19 | * "allow_read" entries. | ||
20 | * It has following fields. | ||
21 | * | ||
22 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
23 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
24 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
25 | * otherwise. | ||
26 | */ | ||
18 | struct tomoyo_globally_readable_file_entry { | 27 | struct tomoyo_globally_readable_file_entry { |
19 | struct list_head list; | 28 | struct list_head list; |
20 | const struct tomoyo_path_info *filename; | 29 | const struct tomoyo_path_info *filename; |
21 | bool is_deleted; | 30 | bool is_deleted; |
22 | }; | 31 | }; |
23 | 32 | ||
24 | /* Structure for "file_pattern" keyword. */ | 33 | /* |
34 | * tomoyo_pattern_entry is a structure which is used for holding | ||
35 | * "tomoyo_pattern_list" entries. | ||
36 | * It has following fields. | ||
37 | * | ||
38 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
39 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
40 | * to pathname patterns during learning mode. | ||
41 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
42 | * otherwise. | ||
43 | */ | ||
25 | struct tomoyo_pattern_entry { | 44 | struct tomoyo_pattern_entry { |
26 | struct list_head list; | 45 | struct list_head list; |
27 | const struct tomoyo_path_info *pattern; | 46 | const struct tomoyo_path_info *pattern; |
28 | bool is_deleted; | 47 | bool is_deleted; |
29 | }; | 48 | }; |
30 | 49 | ||
31 | /* Structure for "deny_rewrite" keyword. */ | 50 | /* |
51 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
52 | * "deny_rewrite" entries. | ||
53 | * It has following fields. | ||
54 | * | ||
55 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
56 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
57 | * already existing content. | ||
58 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
59 | * otherwise. | ||
60 | */ | ||
32 | struct tomoyo_no_rewrite_entry { | 61 | struct tomoyo_no_rewrite_entry { |
33 | struct list_head list; | 62 | struct list_head list; |
34 | const struct tomoyo_path_info *pattern; | 63 | const struct tomoyo_path_info *pattern; |
35 | bool is_deleted; | 64 | bool is_deleted; |
36 | }; | 65 | }; |
37 | 66 | ||
38 | /* Keyword array for single path operations. */ | 67 | /* Keyword array for single path operations. */ |
39 | static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { | 68 | static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { |
40 | [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", | 69 | [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", |
41 | [TOMOYO_TYPE_EXECUTE_ACL] = "execute", | 70 | [TOMOYO_TYPE_EXECUTE_ACL] = "execute", |
42 | [TOMOYO_TYPE_READ_ACL] = "read", | 71 | [TOMOYO_TYPE_READ_ACL] = "read", |
43 | [TOMOYO_TYPE_WRITE_ACL] = "write", | 72 | [TOMOYO_TYPE_WRITE_ACL] = "write", |
44 | [TOMOYO_TYPE_CREATE_ACL] = "create", | 73 | [TOMOYO_TYPE_CREATE_ACL] = "create", |
45 | [TOMOYO_TYPE_UNLINK_ACL] = "unlink", | 74 | [TOMOYO_TYPE_UNLINK_ACL] = "unlink", |
46 | [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", | 75 | [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", |
47 | [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", | 76 | [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", |
48 | [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", | 77 | [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", |
49 | [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", | 78 | [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", |
50 | [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", | 79 | [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", |
51 | [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", | 80 | [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", |
52 | [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", | 81 | [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", |
53 | [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", | 82 | [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", |
54 | [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", | 83 | [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", |
55 | }; | 84 | }; |
56 | 85 | ||
57 | /* Keyword array for double path operations. */ | 86 | /* Keyword array for double path operations. */ |
58 | static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { | 87 | static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { |
59 | [TOMOYO_TYPE_LINK_ACL] = "link", | 88 | [TOMOYO_TYPE_LINK_ACL] = "link", |
60 | [TOMOYO_TYPE_RENAME_ACL] = "rename", | 89 | [TOMOYO_TYPE_RENAME_ACL] = "rename", |
61 | }; | 90 | }; |
62 | 91 | ||
63 | /** | 92 | /** |
64 | * tomoyo_sp2keyword - Get the name of single path operation. | 93 | * tomoyo_sp2keyword - Get the name of single path operation. |
65 | * | 94 | * |
66 | * @operation: Type of operation. | 95 | * @operation: Type of operation. |
67 | * | 96 | * |
68 | * Returns the name of single path operation. | 97 | * Returns the name of single path operation. |
69 | */ | 98 | */ |
70 | const char *tomoyo_sp2keyword(const u8 operation) | 99 | const char *tomoyo_sp2keyword(const u8 operation) |
71 | { | 100 | { |
72 | return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) | 101 | return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) |
73 | ? tomoyo_sp_keyword[operation] : NULL; | 102 | ? tomoyo_sp_keyword[operation] : NULL; |
74 | } | 103 | } |
75 | 104 | ||
76 | /** | 105 | /** |
77 | * tomoyo_dp2keyword - Get the name of double path operation. | 106 | * tomoyo_dp2keyword - Get the name of double path operation. |
78 | * | 107 | * |
79 | * @operation: Type of operation. | 108 | * @operation: Type of operation. |
80 | * | 109 | * |
81 | * Returns the name of double path operation. | 110 | * Returns the name of double path operation. |
82 | */ | 111 | */ |
83 | const char *tomoyo_dp2keyword(const u8 operation) | 112 | const char *tomoyo_dp2keyword(const u8 operation) |
84 | { | 113 | { |
85 | return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) | 114 | return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) |
86 | ? tomoyo_dp_keyword[operation] : NULL; | 115 | ? tomoyo_dp_keyword[operation] : NULL; |
87 | } | 116 | } |
88 | 117 | ||
89 | /** | 118 | /** |
90 | * tomoyo_strendswith - Check whether the token ends with the given token. | 119 | * tomoyo_strendswith - Check whether the token ends with the given token. |
91 | * | 120 | * |
92 | * @name: The token to check. | 121 | * @name: The token to check. |
93 | * @tail: The token to find. | 122 | * @tail: The token to find. |
94 | * | 123 | * |
95 | * Returns true if @name ends with @tail, false otherwise. | 124 | * Returns true if @name ends with @tail, false otherwise. |
96 | */ | 125 | */ |
97 | static bool tomoyo_strendswith(const char *name, const char *tail) | 126 | static bool tomoyo_strendswith(const char *name, const char *tail) |
98 | { | 127 | { |
99 | int len; | 128 | int len; |
100 | 129 | ||
101 | if (!name || !tail) | 130 | if (!name || !tail) |
102 | return false; | 131 | return false; |
103 | len = strlen(name) - strlen(tail); | 132 | len = strlen(name) - strlen(tail); |
104 | return len >= 0 && !strcmp(name + len, tail); | 133 | return len >= 0 && !strcmp(name + len, tail); |
105 | } | 134 | } |
106 | 135 | ||
107 | /** | 136 | /** |
108 | * tomoyo_get_path - Get realpath. | 137 | * tomoyo_get_path - Get realpath. |
109 | * | 138 | * |
110 | * @path: Pointer to "struct path". | 139 | * @path: Pointer to "struct path". |
111 | * | 140 | * |
112 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 141 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
113 | */ | 142 | */ |
114 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | 143 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) |
115 | { | 144 | { |
116 | int error; | 145 | int error; |
117 | struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); | 146 | struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); |
118 | 147 | ||
119 | if (!buf) | 148 | if (!buf) |
120 | return NULL; | 149 | return NULL; |
121 | /* Reserve one byte for appending "/". */ | 150 | /* Reserve one byte for appending "/". */ |
122 | error = tomoyo_realpath_from_path2(path, buf->body, | 151 | error = tomoyo_realpath_from_path2(path, buf->body, |
123 | sizeof(buf->body) - 2); | 152 | sizeof(buf->body) - 2); |
124 | if (!error) { | 153 | if (!error) { |
125 | buf->head.name = buf->body; | 154 | buf->head.name = buf->body; |
126 | tomoyo_fill_path_info(&buf->head); | 155 | tomoyo_fill_path_info(&buf->head); |
127 | return &buf->head; | 156 | return &buf->head; |
128 | } | 157 | } |
129 | tomoyo_free(buf); | 158 | tomoyo_free(buf); |
130 | return NULL; | 159 | return NULL; |
131 | } | 160 | } |
132 | 161 | ||
133 | /* Lock for domain->acl_info_list. */ | 162 | /* Lock for domain->acl_info_list. */ |
134 | DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); | 163 | DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); |
135 | 164 | ||
136 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 165 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, |
137 | const char *filename2, | 166 | const char *filename2, |
138 | struct tomoyo_domain_info * | 167 | struct tomoyo_domain_info * |
139 | const domain, const bool is_delete); | 168 | const domain, const bool is_delete); |
140 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | 169 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, |
141 | struct tomoyo_domain_info * | 170 | struct tomoyo_domain_info * |
142 | const domain, const bool is_delete); | 171 | const domain, const bool is_delete); |
143 | 172 | ||
144 | /* The list for "struct tomoyo_globally_readable_file_entry". */ | 173 | /* |
174 | * tomoyo_globally_readable_list is used for holding list of pathnames which | ||
175 | * are by default allowed to be open()ed for reading by any process. | ||
176 | * | ||
177 | * An entry is added by | ||
178 | * | ||
179 | * # echo 'allow_read /lib/libc-2.5.so' > \ | ||
180 | * /sys/kernel/security/tomoyo/exception_policy | ||
181 | * | ||
182 | * and is deleted by | ||
183 | * | ||
184 | * # echo 'delete allow_read /lib/libc-2.5.so' > \ | ||
185 | * /sys/kernel/security/tomoyo/exception_policy | ||
186 | * | ||
187 | * and all entries are retrieved by | ||
188 | * | ||
189 | * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy | ||
190 | * | ||
191 | * In the example above, any process is allowed to | ||
192 | * open("/lib/libc-2.5.so", O_RDONLY). | ||
193 | * One exception is, if the domain which current process belongs to is marked | ||
194 | * as "ignore_global_allow_read", current process can't do so unless explicitly | ||
195 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | ||
196 | * belongs to. | ||
197 | */ | ||
145 | static LIST_HEAD(tomoyo_globally_readable_list); | 198 | static LIST_HEAD(tomoyo_globally_readable_list); |
146 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | 199 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); |
147 | 200 | ||
148 | /** | 201 | /** |
149 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. | 202 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. |
150 | * | 203 | * |
151 | * @filename: Filename unconditionally permitted to open() for reading. | 204 | * @filename: Filename unconditionally permitted to open() for reading. |
152 | * @is_delete: True if it is a delete request. | 205 | * @is_delete: True if it is a delete request. |
153 | * | 206 | * |
154 | * Returns 0 on success, negative value otherwise. | 207 | * Returns 0 on success, negative value otherwise. |
155 | */ | 208 | */ |
156 | static int tomoyo_update_globally_readable_entry(const char *filename, | 209 | static int tomoyo_update_globally_readable_entry(const char *filename, |
157 | const bool is_delete) | 210 | const bool is_delete) |
158 | { | 211 | { |
159 | struct tomoyo_globally_readable_file_entry *new_entry; | 212 | struct tomoyo_globally_readable_file_entry *new_entry; |
160 | struct tomoyo_globally_readable_file_entry *ptr; | 213 | struct tomoyo_globally_readable_file_entry *ptr; |
161 | const struct tomoyo_path_info *saved_filename; | 214 | const struct tomoyo_path_info *saved_filename; |
162 | int error = -ENOMEM; | 215 | int error = -ENOMEM; |
163 | 216 | ||
164 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) | 217 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) |
165 | return -EINVAL; | 218 | return -EINVAL; |
166 | saved_filename = tomoyo_save_name(filename); | 219 | saved_filename = tomoyo_save_name(filename); |
167 | if (!saved_filename) | 220 | if (!saved_filename) |
168 | return -ENOMEM; | 221 | return -ENOMEM; |
169 | down_write(&tomoyo_globally_readable_list_lock); | 222 | down_write(&tomoyo_globally_readable_list_lock); |
170 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 223 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { |
171 | if (ptr->filename != saved_filename) | 224 | if (ptr->filename != saved_filename) |
172 | continue; | 225 | continue; |
173 | ptr->is_deleted = is_delete; | 226 | ptr->is_deleted = is_delete; |
174 | error = 0; | 227 | error = 0; |
175 | goto out; | 228 | goto out; |
176 | } | 229 | } |
177 | if (is_delete) { | 230 | if (is_delete) { |
178 | error = -ENOENT; | 231 | error = -ENOENT; |
179 | goto out; | 232 | goto out; |
180 | } | 233 | } |
181 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 234 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
182 | if (!new_entry) | 235 | if (!new_entry) |
183 | goto out; | 236 | goto out; |
184 | new_entry->filename = saved_filename; | 237 | new_entry->filename = saved_filename; |
185 | list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); | 238 | list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); |
186 | error = 0; | 239 | error = 0; |
187 | out: | 240 | out: |
188 | up_write(&tomoyo_globally_readable_list_lock); | 241 | up_write(&tomoyo_globally_readable_list_lock); |
189 | return error; | 242 | return error; |
190 | } | 243 | } |
191 | 244 | ||
192 | /** | 245 | /** |
193 | * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. | 246 | * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. |
194 | * | 247 | * |
195 | * @filename: The filename to check. | 248 | * @filename: The filename to check. |
196 | * | 249 | * |
197 | * Returns true if any domain can open @filename for reading, false otherwise. | 250 | * Returns true if any domain can open @filename for reading, false otherwise. |
198 | */ | 251 | */ |
199 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | 252 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * |
200 | filename) | 253 | filename) |
201 | { | 254 | { |
202 | struct tomoyo_globally_readable_file_entry *ptr; | 255 | struct tomoyo_globally_readable_file_entry *ptr; |
203 | bool found = false; | 256 | bool found = false; |
204 | down_read(&tomoyo_globally_readable_list_lock); | 257 | down_read(&tomoyo_globally_readable_list_lock); |
205 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 258 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { |
206 | if (!ptr->is_deleted && | 259 | if (!ptr->is_deleted && |
207 | tomoyo_path_matches_pattern(filename, ptr->filename)) { | 260 | tomoyo_path_matches_pattern(filename, ptr->filename)) { |
208 | found = true; | 261 | found = true; |
209 | break; | 262 | break; |
210 | } | 263 | } |
211 | } | 264 | } |
212 | up_read(&tomoyo_globally_readable_list_lock); | 265 | up_read(&tomoyo_globally_readable_list_lock); |
213 | return found; | 266 | return found; |
214 | } | 267 | } |
215 | 268 | ||
216 | /** | 269 | /** |
217 | * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. | 270 | * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. |
218 | * | 271 | * |
219 | * @data: String to parse. | 272 | * @data: String to parse. |
220 | * @is_delete: True if it is a delete request. | 273 | * @is_delete: True if it is a delete request. |
221 | * | 274 | * |
222 | * Returns 0 on success, negative value otherwise. | 275 | * Returns 0 on success, negative value otherwise. |
223 | */ | 276 | */ |
224 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | 277 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) |
225 | { | 278 | { |
226 | return tomoyo_update_globally_readable_entry(data, is_delete); | 279 | return tomoyo_update_globally_readable_entry(data, is_delete); |
227 | } | 280 | } |
228 | 281 | ||
229 | /** | 282 | /** |
230 | * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. | 283 | * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. |
231 | * | 284 | * |
232 | * @head: Pointer to "struct tomoyo_io_buffer". | 285 | * @head: Pointer to "struct tomoyo_io_buffer". |
233 | * | 286 | * |
234 | * Returns true on success, false otherwise. | 287 | * Returns true on success, false otherwise. |
235 | */ | 288 | */ |
236 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | 289 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) |
237 | { | 290 | { |
238 | struct list_head *pos; | 291 | struct list_head *pos; |
239 | bool done = true; | 292 | bool done = true; |
240 | 293 | ||
241 | down_read(&tomoyo_globally_readable_list_lock); | 294 | down_read(&tomoyo_globally_readable_list_lock); |
242 | list_for_each_cookie(pos, head->read_var2, | 295 | list_for_each_cookie(pos, head->read_var2, |
243 | &tomoyo_globally_readable_list) { | 296 | &tomoyo_globally_readable_list) { |
244 | struct tomoyo_globally_readable_file_entry *ptr; | 297 | struct tomoyo_globally_readable_file_entry *ptr; |
245 | ptr = list_entry(pos, | 298 | ptr = list_entry(pos, |
246 | struct tomoyo_globally_readable_file_entry, | 299 | struct tomoyo_globally_readable_file_entry, |
247 | list); | 300 | list); |
248 | if (ptr->is_deleted) | 301 | if (ptr->is_deleted) |
249 | continue; | 302 | continue; |
250 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", | 303 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", |
251 | ptr->filename->name); | 304 | ptr->filename->name); |
252 | if (!done) | 305 | if (!done) |
253 | break; | 306 | break; |
254 | } | 307 | } |
255 | up_read(&tomoyo_globally_readable_list_lock); | 308 | up_read(&tomoyo_globally_readable_list_lock); |
256 | return done; | 309 | return done; |
257 | } | 310 | } |
258 | 311 | ||
259 | /* The list for "struct tomoyo_pattern_entry". */ | 312 | /* tomoyo_pattern_list is used for holding list of pathnames which are used for |
313 | * converting pathnames to pathname patterns during learning mode. | ||
314 | * | ||
315 | * An entry is added by | ||
316 | * | ||
317 | * # echo 'file_pattern /proc/\$/mounts' > \ | ||
318 | * /sys/kernel/security/tomoyo/exception_policy | ||
319 | * | ||
320 | * and is deleted by | ||
321 | * | ||
322 | * # echo 'delete file_pattern /proc/\$/mounts' > \ | ||
323 | * /sys/kernel/security/tomoyo/exception_policy | ||
324 | * | ||
325 | * and all entries are retrieved by | ||
326 | * | ||
327 | * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy | ||
328 | * | ||
329 | * In the example above, if a process which belongs to a domain which is in | ||
330 | * learning mode requested open("/proc/1/mounts", O_RDONLY), | ||
331 | * "allow_read /proc/\$/mounts" is automatically added to the domain which that | ||
332 | * process belongs to. | ||
333 | * | ||
334 | * It is not a desirable behavior that we have to use /proc/\$/ instead of | ||
335 | * /proc/self/ when current process needs to access only current process's | ||
336 | * information. As of now, LSM version of TOMOYO is using __d_path() for | ||
337 | * calculating pathname. Non LSM version of TOMOYO is using its own function | ||
338 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | ||
339 | * current process from accessing other process's information. | ||
340 | */ | ||
260 | static LIST_HEAD(tomoyo_pattern_list); | 341 | static LIST_HEAD(tomoyo_pattern_list); |
261 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | 342 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); |
262 | 343 | ||
263 | /** | 344 | /** |
264 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. | 345 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. |
265 | * | 346 | * |
266 | * @pattern: Pathname pattern. | 347 | * @pattern: Pathname pattern. |
267 | * @is_delete: True if it is a delete request. | 348 | * @is_delete: True if it is a delete request. |
268 | * | 349 | * |
269 | * Returns 0 on success, negative value otherwise. | 350 | * Returns 0 on success, negative value otherwise. |
270 | */ | 351 | */ |
271 | static int tomoyo_update_file_pattern_entry(const char *pattern, | 352 | static int tomoyo_update_file_pattern_entry(const char *pattern, |
272 | const bool is_delete) | 353 | const bool is_delete) |
273 | { | 354 | { |
274 | struct tomoyo_pattern_entry *new_entry; | 355 | struct tomoyo_pattern_entry *new_entry; |
275 | struct tomoyo_pattern_entry *ptr; | 356 | struct tomoyo_pattern_entry *ptr; |
276 | const struct tomoyo_path_info *saved_pattern; | 357 | const struct tomoyo_path_info *saved_pattern; |
277 | int error = -ENOMEM; | 358 | int error = -ENOMEM; |
278 | 359 | ||
279 | if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) | 360 | if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) |
280 | return -EINVAL; | 361 | return -EINVAL; |
281 | saved_pattern = tomoyo_save_name(pattern); | 362 | saved_pattern = tomoyo_save_name(pattern); |
282 | if (!saved_pattern) | 363 | if (!saved_pattern) |
283 | return -ENOMEM; | 364 | return -ENOMEM; |
284 | down_write(&tomoyo_pattern_list_lock); | 365 | down_write(&tomoyo_pattern_list_lock); |
285 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 366 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { |
286 | if (saved_pattern != ptr->pattern) | 367 | if (saved_pattern != ptr->pattern) |
287 | continue; | 368 | continue; |
288 | ptr->is_deleted = is_delete; | 369 | ptr->is_deleted = is_delete; |
289 | error = 0; | 370 | error = 0; |
290 | goto out; | 371 | goto out; |
291 | } | 372 | } |
292 | if (is_delete) { | 373 | if (is_delete) { |
293 | error = -ENOENT; | 374 | error = -ENOENT; |
294 | goto out; | 375 | goto out; |
295 | } | 376 | } |
296 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 377 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
297 | if (!new_entry) | 378 | if (!new_entry) |
298 | goto out; | 379 | goto out; |
299 | new_entry->pattern = saved_pattern; | 380 | new_entry->pattern = saved_pattern; |
300 | list_add_tail(&new_entry->list, &tomoyo_pattern_list); | 381 | list_add_tail(&new_entry->list, &tomoyo_pattern_list); |
301 | error = 0; | 382 | error = 0; |
302 | out: | 383 | out: |
303 | up_write(&tomoyo_pattern_list_lock); | 384 | up_write(&tomoyo_pattern_list_lock); |
304 | return error; | 385 | return error; |
305 | } | 386 | } |
306 | 387 | ||
307 | /** | 388 | /** |
308 | * tomoyo_get_file_pattern - Get patterned pathname. | 389 | * tomoyo_get_file_pattern - Get patterned pathname. |
309 | * | 390 | * |
310 | * @filename: The filename to find patterned pathname. | 391 | * @filename: The filename to find patterned pathname. |
311 | * | 392 | * |
312 | * Returns pointer to pathname pattern if matched, @filename otherwise. | 393 | * Returns pointer to pathname pattern if matched, @filename otherwise. |
313 | */ | 394 | */ |
314 | static const struct tomoyo_path_info * | 395 | static const struct tomoyo_path_info * |
315 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | 396 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) |
316 | { | 397 | { |
317 | struct tomoyo_pattern_entry *ptr; | 398 | struct tomoyo_pattern_entry *ptr; |
318 | const struct tomoyo_path_info *pattern = NULL; | 399 | const struct tomoyo_path_info *pattern = NULL; |
319 | 400 | ||
320 | down_read(&tomoyo_pattern_list_lock); | 401 | down_read(&tomoyo_pattern_list_lock); |
321 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 402 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { |
322 | if (ptr->is_deleted) | 403 | if (ptr->is_deleted) |
323 | continue; | 404 | continue; |
324 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 405 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
325 | continue; | 406 | continue; |
326 | pattern = ptr->pattern; | 407 | pattern = ptr->pattern; |
327 | if (tomoyo_strendswith(pattern->name, "/\\*")) { | 408 | if (tomoyo_strendswith(pattern->name, "/\\*")) { |
328 | /* Do nothing. Try to find the better match. */ | 409 | /* Do nothing. Try to find the better match. */ |
329 | } else { | 410 | } else { |
330 | /* This would be the better match. Use this. */ | 411 | /* This would be the better match. Use this. */ |
331 | break; | 412 | break; |
332 | } | 413 | } |
333 | } | 414 | } |
334 | up_read(&tomoyo_pattern_list_lock); | 415 | up_read(&tomoyo_pattern_list_lock); |
335 | if (pattern) | 416 | if (pattern) |
336 | filename = pattern; | 417 | filename = pattern; |
337 | return filename; | 418 | return filename; |
338 | } | 419 | } |
339 | 420 | ||
340 | /** | 421 | /** |
341 | * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. | 422 | * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. |
342 | * | 423 | * |
343 | * @data: String to parse. | 424 | * @data: String to parse. |
344 | * @is_delete: True if it is a delete request. | 425 | * @is_delete: True if it is a delete request. |
345 | * | 426 | * |
346 | * Returns 0 on success, negative value otherwise. | 427 | * Returns 0 on success, negative value otherwise. |
347 | */ | 428 | */ |
348 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) | 429 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) |
349 | { | 430 | { |
350 | return tomoyo_update_file_pattern_entry(data, is_delete); | 431 | return tomoyo_update_file_pattern_entry(data, is_delete); |
351 | } | 432 | } |
352 | 433 | ||
353 | /** | 434 | /** |
354 | * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. | 435 | * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. |
355 | * | 436 | * |
356 | * @head: Pointer to "struct tomoyo_io_buffer". | 437 | * @head: Pointer to "struct tomoyo_io_buffer". |
357 | * | 438 | * |
358 | * Returns true on success, false otherwise. | 439 | * Returns true on success, false otherwise. |
359 | */ | 440 | */ |
360 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | 441 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) |
361 | { | 442 | { |
362 | struct list_head *pos; | 443 | struct list_head *pos; |
363 | bool done = true; | 444 | bool done = true; |
364 | 445 | ||
365 | down_read(&tomoyo_pattern_list_lock); | 446 | down_read(&tomoyo_pattern_list_lock); |
366 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { | 447 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { |
367 | struct tomoyo_pattern_entry *ptr; | 448 | struct tomoyo_pattern_entry *ptr; |
368 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); | 449 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); |
369 | if (ptr->is_deleted) | 450 | if (ptr->is_deleted) |
370 | continue; | 451 | continue; |
371 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN | 452 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN |
372 | "%s\n", ptr->pattern->name); | 453 | "%s\n", ptr->pattern->name); |
373 | if (!done) | 454 | if (!done) |
374 | break; | 455 | break; |
375 | } | 456 | } |
376 | up_read(&tomoyo_pattern_list_lock); | 457 | up_read(&tomoyo_pattern_list_lock); |
377 | return done; | 458 | return done; |
378 | } | 459 | } |
379 | 460 | ||
380 | /* The list for "struct tomoyo_no_rewrite_entry". */ | 461 | /* |
462 | * tomoyo_no_rewrite_list is used for holding list of pathnames which are by | ||
463 | * default forbidden to modify already written content of a file. | ||
464 | * | ||
465 | * An entry is added by | ||
466 | * | ||
467 | * # echo 'deny_rewrite /var/log/messages' > \ | ||
468 | * /sys/kernel/security/tomoyo/exception_policy | ||
469 | * | ||
470 | * and is deleted by | ||
471 | * | ||
472 | * # echo 'delete deny_rewrite /var/log/messages' > \ | ||
473 | * /sys/kernel/security/tomoyo/exception_policy | ||
474 | * | ||
475 | * and all entries are retrieved by | ||
476 | * | ||
477 | * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy | ||
478 | * | ||
479 | * In the example above, if a process requested to rewrite /var/log/messages , | ||
480 | * the process can't rewrite unless the domain which that process belongs to | ||
481 | * has "allow_rewrite /var/log/messages" entry. | ||
482 | * | ||
483 | * It is not a desirable behavior that we have to add "\040(deleted)" suffix | ||
484 | * when we want to allow rewriting already unlink()ed file. As of now, | ||
485 | * LSM version of TOMOYO is using __d_path() for calculating pathname. | ||
486 | * Non LSM version of TOMOYO is using its own function which doesn't append | ||
487 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | ||
488 | * need to worry whether the file is already unlink()ed or not. | ||
489 | */ | ||
381 | static LIST_HEAD(tomoyo_no_rewrite_list); | 490 | static LIST_HEAD(tomoyo_no_rewrite_list); |
382 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | 491 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); |
383 | 492 | ||
384 | /** | 493 | /** |
385 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. | 494 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. |
386 | * | 495 | * |
387 | * @pattern: Pathname pattern that are not rewritable by default. | 496 | * @pattern: Pathname pattern that are not rewritable by default. |
388 | * @is_delete: True if it is a delete request. | 497 | * @is_delete: True if it is a delete request. |
389 | * | 498 | * |
390 | * Returns 0 on success, negative value otherwise. | 499 | * Returns 0 on success, negative value otherwise. |
391 | */ | 500 | */ |
392 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | 501 | static int tomoyo_update_no_rewrite_entry(const char *pattern, |
393 | const bool is_delete) | 502 | const bool is_delete) |
394 | { | 503 | { |
395 | struct tomoyo_no_rewrite_entry *new_entry, *ptr; | 504 | struct tomoyo_no_rewrite_entry *new_entry, *ptr; |
396 | const struct tomoyo_path_info *saved_pattern; | 505 | const struct tomoyo_path_info *saved_pattern; |
397 | int error = -ENOMEM; | 506 | int error = -ENOMEM; |
398 | 507 | ||
399 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) | 508 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) |
400 | return -EINVAL; | 509 | return -EINVAL; |
401 | saved_pattern = tomoyo_save_name(pattern); | 510 | saved_pattern = tomoyo_save_name(pattern); |
402 | if (!saved_pattern) | 511 | if (!saved_pattern) |
403 | return -ENOMEM; | 512 | return -ENOMEM; |
404 | down_write(&tomoyo_no_rewrite_list_lock); | 513 | down_write(&tomoyo_no_rewrite_list_lock); |
405 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 514 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { |
406 | if (ptr->pattern != saved_pattern) | 515 | if (ptr->pattern != saved_pattern) |
407 | continue; | 516 | continue; |
408 | ptr->is_deleted = is_delete; | 517 | ptr->is_deleted = is_delete; |
409 | error = 0; | 518 | error = 0; |
410 | goto out; | 519 | goto out; |
411 | } | 520 | } |
412 | if (is_delete) { | 521 | if (is_delete) { |
413 | error = -ENOENT; | 522 | error = -ENOENT; |
414 | goto out; | 523 | goto out; |
415 | } | 524 | } |
416 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 525 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); |
417 | if (!new_entry) | 526 | if (!new_entry) |
418 | goto out; | 527 | goto out; |
419 | new_entry->pattern = saved_pattern; | 528 | new_entry->pattern = saved_pattern; |
420 | list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); | 529 | list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); |
421 | error = 0; | 530 | error = 0; |
422 | out: | 531 | out: |
423 | up_write(&tomoyo_no_rewrite_list_lock); | 532 | up_write(&tomoyo_no_rewrite_list_lock); |
424 | return error; | 533 | return error; |
425 | } | 534 | } |
426 | 535 | ||
427 | /** | 536 | /** |
428 | * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. | 537 | * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. |
429 | * | 538 | * |
430 | * @filename: Filename to check. | 539 | * @filename: Filename to check. |
431 | * | 540 | * |
432 | * Returns true if @filename is specified by "deny_rewrite" directive, | 541 | * Returns true if @filename is specified by "deny_rewrite" directive, |
433 | * false otherwise. | 542 | * false otherwise. |
434 | */ | 543 | */ |
435 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | 544 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) |
436 | { | 545 | { |
437 | struct tomoyo_no_rewrite_entry *ptr; | 546 | struct tomoyo_no_rewrite_entry *ptr; |
438 | bool found = false; | 547 | bool found = false; |
439 | 548 | ||
440 | down_read(&tomoyo_no_rewrite_list_lock); | 549 | down_read(&tomoyo_no_rewrite_list_lock); |
441 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 550 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { |
442 | if (ptr->is_deleted) | 551 | if (ptr->is_deleted) |
443 | continue; | 552 | continue; |
444 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 553 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
445 | continue; | 554 | continue; |
446 | found = true; | 555 | found = true; |
447 | break; | 556 | break; |
448 | } | 557 | } |
449 | up_read(&tomoyo_no_rewrite_list_lock); | 558 | up_read(&tomoyo_no_rewrite_list_lock); |
450 | return found; | 559 | return found; |
451 | } | 560 | } |
452 | 561 | ||
453 | /** | 562 | /** |
454 | * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. | 563 | * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. |
455 | * | 564 | * |
456 | * @data: String to parse. | 565 | * @data: String to parse. |
457 | * @is_delete: True if it is a delete request. | 566 | * @is_delete: True if it is a delete request. |
458 | * | 567 | * |
459 | * Returns 0 on success, negative value otherwise. | 568 | * Returns 0 on success, negative value otherwise. |
460 | */ | 569 | */ |
461 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | 570 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) |
462 | { | 571 | { |
463 | return tomoyo_update_no_rewrite_entry(data, is_delete); | 572 | return tomoyo_update_no_rewrite_entry(data, is_delete); |
464 | } | 573 | } |
465 | 574 | ||
466 | /** | 575 | /** |
467 | * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. | 576 | * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. |
468 | * | 577 | * |
469 | * @head: Pointer to "struct tomoyo_io_buffer". | 578 | * @head: Pointer to "struct tomoyo_io_buffer". |
470 | * | 579 | * |
471 | * Returns true on success, false otherwise. | 580 | * Returns true on success, false otherwise. |
472 | */ | 581 | */ |
473 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | 582 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) |
474 | { | 583 | { |
475 | struct list_head *pos; | 584 | struct list_head *pos; |
476 | bool done = true; | 585 | bool done = true; |
477 | 586 | ||
478 | down_read(&tomoyo_no_rewrite_list_lock); | 587 | down_read(&tomoyo_no_rewrite_list_lock); |
479 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { | 588 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { |
480 | struct tomoyo_no_rewrite_entry *ptr; | 589 | struct tomoyo_no_rewrite_entry *ptr; |
481 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); | 590 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); |
482 | if (ptr->is_deleted) | 591 | if (ptr->is_deleted) |
483 | continue; | 592 | continue; |
484 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE | 593 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE |
485 | "%s\n", ptr->pattern->name); | 594 | "%s\n", ptr->pattern->name); |
486 | if (!done) | 595 | if (!done) |
487 | break; | 596 | break; |
488 | } | 597 | } |
489 | up_read(&tomoyo_no_rewrite_list_lock); | 598 | up_read(&tomoyo_no_rewrite_list_lock); |
490 | return done; | 599 | return done; |
491 | } | 600 | } |
492 | 601 | ||
493 | /** | 602 | /** |
494 | * tomoyo_update_file_acl - Update file's read/write/execute ACL. | 603 | * tomoyo_update_file_acl - Update file's read/write/execute ACL. |
495 | * | 604 | * |
496 | * @filename: Filename. | 605 | * @filename: Filename. |
497 | * @perm: Permission (between 1 to 7). | 606 | * @perm: Permission (between 1 to 7). |
498 | * @domain: Pointer to "struct tomoyo_domain_info". | 607 | * @domain: Pointer to "struct tomoyo_domain_info". |
499 | * @is_delete: True if it is a delete request. | 608 | * @is_delete: True if it is a delete request. |
500 | * | 609 | * |
501 | * Returns 0 on success, negative value otherwise. | 610 | * Returns 0 on success, negative value otherwise. |
502 | * | 611 | * |
503 | * This is legacy support interface for older policy syntax. | 612 | * This is legacy support interface for older policy syntax. |
504 | * Current policy syntax uses "allow_read/write" instead of "6", | 613 | * Current policy syntax uses "allow_read/write" instead of "6", |
505 | * "allow_read" instead of "4", "allow_write" instead of "2", | 614 | * "allow_read" instead of "4", "allow_write" instead of "2", |
506 | * "allow_execute" instead of "1". | 615 | * "allow_execute" instead of "1". |
507 | */ | 616 | */ |
508 | static int tomoyo_update_file_acl(const char *filename, u8 perm, | 617 | static int tomoyo_update_file_acl(const char *filename, u8 perm, |
509 | struct tomoyo_domain_info * const domain, | 618 | struct tomoyo_domain_info * const domain, |
510 | const bool is_delete) | 619 | const bool is_delete) |
511 | { | 620 | { |
512 | if (perm > 7 || !perm) { | 621 | if (perm > 7 || !perm) { |
513 | printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", | 622 | printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", |
514 | __func__, perm, filename); | 623 | __func__, perm, filename); |
515 | return -EINVAL; | 624 | return -EINVAL; |
516 | } | 625 | } |
517 | if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) | 626 | if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) |
518 | /* | 627 | /* |
519 | * Only 'allow_mkdir' and 'allow_rmdir' are valid for | 628 | * Only 'allow_mkdir' and 'allow_rmdir' are valid for |
520 | * directory permissions. | 629 | * directory permissions. |
521 | */ | 630 | */ |
522 | return 0; | 631 | return 0; |
523 | if (perm & 4) | 632 | if (perm & 4) |
524 | tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, | 633 | tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, |
525 | domain, is_delete); | 634 | domain, is_delete); |
526 | if (perm & 2) | 635 | if (perm & 2) |
527 | tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, | 636 | tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, |
528 | domain, is_delete); | 637 | domain, is_delete); |
529 | if (perm & 1) | 638 | if (perm & 1) |
530 | tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, | 639 | tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, |
531 | filename, domain, is_delete); | 640 | filename, domain, is_delete); |
532 | return 0; | 641 | return 0; |
533 | } | 642 | } |
534 | 643 | ||
535 | /** | 644 | /** |
536 | * tomoyo_check_single_path_acl2 - Check permission for single path operation. | 645 | * tomoyo_check_single_path_acl2 - Check permission for single path operation. |
537 | * | 646 | * |
538 | * @domain: Pointer to "struct tomoyo_domain_info". | 647 | * @domain: Pointer to "struct tomoyo_domain_info". |
539 | * @filename: Filename to check. | 648 | * @filename: Filename to check. |
540 | * @perm: Permission. | 649 | * @perm: Permission. |
541 | * @may_use_pattern: True if patterned ACL is permitted. | 650 | * @may_use_pattern: True if patterned ACL is permitted. |
542 | * | 651 | * |
543 | * Returns 0 on success, -EPERM otherwise. | 652 | * Returns 0 on success, -EPERM otherwise. |
544 | */ | 653 | */ |
545 | static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | 654 | static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * |
546 | domain, | 655 | domain, |
547 | const struct tomoyo_path_info * | 656 | const struct tomoyo_path_info * |
548 | filename, | 657 | filename, |
549 | const u16 perm, | 658 | const u16 perm, |
550 | const bool may_use_pattern) | 659 | const bool may_use_pattern) |
551 | { | 660 | { |
552 | struct tomoyo_acl_info *ptr; | 661 | struct tomoyo_acl_info *ptr; |
553 | int error = -EPERM; | 662 | int error = -EPERM; |
554 | 663 | ||
555 | down_read(&tomoyo_domain_acl_info_list_lock); | 664 | down_read(&tomoyo_domain_acl_info_list_lock); |
556 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 665 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
557 | struct tomoyo_single_path_acl_record *acl; | 666 | struct tomoyo_single_path_acl_record *acl; |
558 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | 667 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) |
559 | continue; | 668 | continue; |
560 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | 669 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, |
561 | head); | 670 | head); |
562 | if (!(acl->perm & perm)) | 671 | if (!(acl->perm & perm)) |
563 | continue; | 672 | continue; |
564 | if (may_use_pattern || !acl->filename->is_patterned) { | 673 | if (may_use_pattern || !acl->filename->is_patterned) { |
565 | if (!tomoyo_path_matches_pattern(filename, | 674 | if (!tomoyo_path_matches_pattern(filename, |
566 | acl->filename)) | 675 | acl->filename)) |
567 | continue; | 676 | continue; |
568 | } else { | 677 | } else { |
569 | continue; | 678 | continue; |
570 | } | 679 | } |
571 | error = 0; | 680 | error = 0; |
572 | break; | 681 | break; |
573 | } | 682 | } |
574 | up_read(&tomoyo_domain_acl_info_list_lock); | 683 | up_read(&tomoyo_domain_acl_info_list_lock); |
575 | return error; | 684 | return error; |
576 | } | 685 | } |
577 | 686 | ||
578 | /** | 687 | /** |
579 | * tomoyo_check_file_acl - Check permission for opening files. | 688 | * tomoyo_check_file_acl - Check permission for opening files. |
580 | * | 689 | * |
581 | * @domain: Pointer to "struct tomoyo_domain_info". | 690 | * @domain: Pointer to "struct tomoyo_domain_info". |
582 | * @filename: Filename to check. | 691 | * @filename: Filename to check. |
583 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). | 692 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). |
584 | * | 693 | * |
585 | * Returns 0 on success, -EPERM otherwise. | 694 | * Returns 0 on success, -EPERM otherwise. |
586 | */ | 695 | */ |
587 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | 696 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, |
588 | const struct tomoyo_path_info *filename, | 697 | const struct tomoyo_path_info *filename, |
589 | const u8 operation) | 698 | const u8 operation) |
590 | { | 699 | { |
591 | u16 perm = 0; | 700 | u16 perm = 0; |
592 | 701 | ||
593 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 702 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
594 | return 0; | 703 | return 0; |
595 | if (operation == 6) | 704 | if (operation == 6) |
596 | perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 705 | perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; |
597 | else if (operation == 4) | 706 | else if (operation == 4) |
598 | perm = 1 << TOMOYO_TYPE_READ_ACL; | 707 | perm = 1 << TOMOYO_TYPE_READ_ACL; |
599 | else if (operation == 2) | 708 | else if (operation == 2) |
600 | perm = 1 << TOMOYO_TYPE_WRITE_ACL; | 709 | perm = 1 << TOMOYO_TYPE_WRITE_ACL; |
601 | else if (operation == 1) | 710 | else if (operation == 1) |
602 | perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; | 711 | perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; |
603 | else | 712 | else |
604 | BUG(); | 713 | BUG(); |
605 | return tomoyo_check_single_path_acl2(domain, filename, perm, | 714 | return tomoyo_check_single_path_acl2(domain, filename, perm, |
606 | operation != 1); | 715 | operation != 1); |
607 | } | 716 | } |
608 | 717 | ||
609 | /** | 718 | /** |
610 | * tomoyo_check_file_perm2 - Check permission for opening files. | 719 | * tomoyo_check_file_perm2 - Check permission for opening files. |
611 | * | 720 | * |
612 | * @domain: Pointer to "struct tomoyo_domain_info". | 721 | * @domain: Pointer to "struct tomoyo_domain_info". |
613 | * @filename: Filename to check. | 722 | * @filename: Filename to check. |
614 | * @perm: Mode ("read" or "write" or "read/write" or "execute"). | 723 | * @perm: Mode ("read" or "write" or "read/write" or "execute"). |
615 | * @operation: Operation name passed used for verbose mode. | 724 | * @operation: Operation name passed used for verbose mode. |
616 | * @mode: Access control mode. | 725 | * @mode: Access control mode. |
617 | * | 726 | * |
618 | * Returns 0 on success, negative value otherwise. | 727 | * Returns 0 on success, negative value otherwise. |
619 | */ | 728 | */ |
620 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | 729 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, |
621 | const struct tomoyo_path_info *filename, | 730 | const struct tomoyo_path_info *filename, |
622 | const u8 perm, const char *operation, | 731 | const u8 perm, const char *operation, |
623 | const u8 mode) | 732 | const u8 mode) |
624 | { | 733 | { |
625 | const bool is_enforce = (mode == 3); | 734 | const bool is_enforce = (mode == 3); |
626 | const char *msg = "<unknown>"; | 735 | const char *msg = "<unknown>"; |
627 | int error = 0; | 736 | int error = 0; |
628 | 737 | ||
629 | if (!filename) | 738 | if (!filename) |
630 | return 0; | 739 | return 0; |
631 | error = tomoyo_check_file_acl(domain, filename, perm); | 740 | error = tomoyo_check_file_acl(domain, filename, perm); |
632 | if (error && perm == 4 && | 741 | if (error && perm == 4 && |
633 | (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 | 742 | (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 |
634 | && tomoyo_is_globally_readable_file(filename)) | 743 | && tomoyo_is_globally_readable_file(filename)) |
635 | error = 0; | 744 | error = 0; |
636 | if (perm == 6) | 745 | if (perm == 6) |
637 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); | 746 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); |
638 | else if (perm == 4) | 747 | else if (perm == 4) |
639 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); | 748 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); |
640 | else if (perm == 2) | 749 | else if (perm == 2) |
641 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); | 750 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); |
642 | else if (perm == 1) | 751 | else if (perm == 1) |
643 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); | 752 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); |
644 | else | 753 | else |
645 | BUG(); | 754 | BUG(); |
646 | if (!error) | 755 | if (!error) |
647 | return 0; | 756 | return 0; |
648 | if (tomoyo_verbose_mode(domain)) | 757 | if (tomoyo_verbose_mode(domain)) |
649 | printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " | 758 | printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " |
650 | "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, | 759 | "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, |
651 | filename->name, tomoyo_get_last_name(domain)); | 760 | filename->name, tomoyo_get_last_name(domain)); |
652 | if (is_enforce) | 761 | if (is_enforce) |
653 | return error; | 762 | return error; |
654 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 763 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
655 | /* Don't use patterns for execute permission. */ | 764 | /* Don't use patterns for execute permission. */ |
656 | const struct tomoyo_path_info *patterned_file = (perm != 1) ? | 765 | const struct tomoyo_path_info *patterned_file = (perm != 1) ? |
657 | tomoyo_get_file_pattern(filename) : filename; | 766 | tomoyo_get_file_pattern(filename) : filename; |
658 | tomoyo_update_file_acl(patterned_file->name, perm, | 767 | tomoyo_update_file_acl(patterned_file->name, perm, |
659 | domain, false); | 768 | domain, false); |
660 | } | 769 | } |
661 | return 0; | 770 | return 0; |
662 | } | 771 | } |
663 | 772 | ||
664 | /** | 773 | /** |
665 | * tomoyo_write_file_policy - Update file related list. | 774 | * tomoyo_write_file_policy - Update file related list. |
666 | * | 775 | * |
667 | * @data: String to parse. | 776 | * @data: String to parse. |
668 | * @domain: Pointer to "struct tomoyo_domain_info". | 777 | * @domain: Pointer to "struct tomoyo_domain_info". |
669 | * @is_delete: True if it is a delete request. | 778 | * @is_delete: True if it is a delete request. |
670 | * | 779 | * |
671 | * Returns 0 on success, negative value otherwise. | 780 | * Returns 0 on success, negative value otherwise. |
672 | */ | 781 | */ |
673 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | 782 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, |
674 | const bool is_delete) | 783 | const bool is_delete) |
675 | { | 784 | { |
676 | char *filename = strchr(data, ' '); | 785 | char *filename = strchr(data, ' '); |
677 | char *filename2; | 786 | char *filename2; |
678 | unsigned int perm; | 787 | unsigned int perm; |
679 | u8 type; | 788 | u8 type; |
680 | 789 | ||
681 | if (!filename) | 790 | if (!filename) |
682 | return -EINVAL; | 791 | return -EINVAL; |
683 | *filename++ = '\0'; | 792 | *filename++ = '\0'; |
684 | if (sscanf(data, "%u", &perm) == 1) | 793 | if (sscanf(data, "%u", &perm) == 1) |
685 | return tomoyo_update_file_acl(filename, (u8) perm, domain, | 794 | return tomoyo_update_file_acl(filename, (u8) perm, domain, |
686 | is_delete); | 795 | is_delete); |
687 | if (strncmp(data, "allow_", 6)) | 796 | if (strncmp(data, "allow_", 6)) |
688 | goto out; | 797 | goto out; |
689 | data += 6; | 798 | data += 6; |
690 | for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { | 799 | for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { |
691 | if (strcmp(data, tomoyo_sp_keyword[type])) | 800 | if (strcmp(data, tomoyo_sp_keyword[type])) |
692 | continue; | 801 | continue; |
693 | return tomoyo_update_single_path_acl(type, filename, | 802 | return tomoyo_update_single_path_acl(type, filename, |
694 | domain, is_delete); | 803 | domain, is_delete); |
695 | } | 804 | } |
696 | filename2 = strchr(filename, ' '); | 805 | filename2 = strchr(filename, ' '); |
697 | if (!filename2) | 806 | if (!filename2) |
698 | goto out; | 807 | goto out; |
699 | *filename2++ = '\0'; | 808 | *filename2++ = '\0'; |
700 | for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { | 809 | for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { |
701 | if (strcmp(data, tomoyo_dp_keyword[type])) | 810 | if (strcmp(data, tomoyo_dp_keyword[type])) |
702 | continue; | 811 | continue; |
703 | return tomoyo_update_double_path_acl(type, filename, filename2, | 812 | return tomoyo_update_double_path_acl(type, filename, filename2, |
704 | domain, is_delete); | 813 | domain, is_delete); |
705 | } | 814 | } |
706 | out: | 815 | out: |
707 | return -EINVAL; | 816 | return -EINVAL; |
708 | } | 817 | } |
709 | 818 | ||
710 | /** | 819 | /** |
711 | * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. | 820 | * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. |
712 | * | 821 | * |
713 | * @type: Type of operation. | 822 | * @type: Type of operation. |
714 | * @filename: Filename. | 823 | * @filename: Filename. |
715 | * @domain: Pointer to "struct tomoyo_domain_info". | 824 | * @domain: Pointer to "struct tomoyo_domain_info". |
716 | * @is_delete: True if it is a delete request. | 825 | * @is_delete: True if it is a delete request. |
717 | * | 826 | * |
718 | * Returns 0 on success, negative value otherwise. | 827 | * Returns 0 on success, negative value otherwise. |
719 | */ | 828 | */ |
720 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | 829 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, |
721 | struct tomoyo_domain_info * | 830 | struct tomoyo_domain_info * |
722 | const domain, const bool is_delete) | 831 | const domain, const bool is_delete) |
723 | { | 832 | { |
724 | static const u16 rw_mask = | 833 | static const u16 rw_mask = |
725 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); | 834 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); |
726 | const struct tomoyo_path_info *saved_filename; | 835 | const struct tomoyo_path_info *saved_filename; |
727 | struct tomoyo_acl_info *ptr; | 836 | struct tomoyo_acl_info *ptr; |
728 | struct tomoyo_single_path_acl_record *acl; | 837 | struct tomoyo_single_path_acl_record *acl; |
729 | int error = -ENOMEM; | 838 | int error = -ENOMEM; |
730 | const u16 perm = 1 << type; | 839 | const u16 perm = 1 << type; |
731 | 840 | ||
732 | if (!domain) | 841 | if (!domain) |
733 | return -EINVAL; | 842 | return -EINVAL; |
734 | if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) | 843 | if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) |
735 | return -EINVAL; | 844 | return -EINVAL; |
736 | saved_filename = tomoyo_save_name(filename); | 845 | saved_filename = tomoyo_save_name(filename); |
737 | if (!saved_filename) | 846 | if (!saved_filename) |
738 | return -ENOMEM; | 847 | return -ENOMEM; |
739 | down_write(&tomoyo_domain_acl_info_list_lock); | 848 | down_write(&tomoyo_domain_acl_info_list_lock); |
740 | if (is_delete) | 849 | if (is_delete) |
741 | goto delete; | 850 | goto delete; |
742 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 851 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
743 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | 852 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) |
744 | continue; | 853 | continue; |
745 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | 854 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, |
746 | head); | 855 | head); |
747 | if (acl->filename != saved_filename) | 856 | if (acl->filename != saved_filename) |
748 | continue; | 857 | continue; |
749 | /* Special case. Clear all bits if marked as deleted. */ | 858 | /* Special case. Clear all bits if marked as deleted. */ |
750 | if (ptr->type & TOMOYO_ACL_DELETED) | 859 | if (ptr->type & TOMOYO_ACL_DELETED) |
751 | acl->perm = 0; | 860 | acl->perm = 0; |
752 | acl->perm |= perm; | 861 | acl->perm |= perm; |
753 | if ((acl->perm & rw_mask) == rw_mask) | 862 | if ((acl->perm & rw_mask) == rw_mask) |
754 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 863 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; |
755 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 864 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) |
756 | acl->perm |= rw_mask; | 865 | acl->perm |= rw_mask; |
757 | ptr->type &= ~TOMOYO_ACL_DELETED; | 866 | ptr->type &= ~TOMOYO_ACL_DELETED; |
758 | error = 0; | 867 | error = 0; |
759 | goto out; | 868 | goto out; |
760 | } | 869 | } |
761 | /* Not found. Append it to the tail. */ | 870 | /* Not found. Append it to the tail. */ |
762 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); | 871 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); |
763 | if (!acl) | 872 | if (!acl) |
764 | goto out; | 873 | goto out; |
765 | acl->perm = perm; | 874 | acl->perm = perm; |
766 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 875 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) |
767 | acl->perm |= rw_mask; | 876 | acl->perm |= rw_mask; |
768 | acl->filename = saved_filename; | 877 | acl->filename = saved_filename; |
769 | list_add_tail(&acl->head.list, &domain->acl_info_list); | 878 | list_add_tail(&acl->head.list, &domain->acl_info_list); |
770 | error = 0; | 879 | error = 0; |
771 | goto out; | 880 | goto out; |
772 | delete: | 881 | delete: |
773 | error = -ENOENT; | 882 | error = -ENOENT; |
774 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 883 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
775 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | 884 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) |
776 | continue; | 885 | continue; |
777 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | 886 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, |
778 | head); | 887 | head); |
779 | if (acl->filename != saved_filename) | 888 | if (acl->filename != saved_filename) |
780 | continue; | 889 | continue; |
781 | acl->perm &= ~perm; | 890 | acl->perm &= ~perm; |
782 | if ((acl->perm & rw_mask) != rw_mask) | 891 | if ((acl->perm & rw_mask) != rw_mask) |
783 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); | 892 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); |
784 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | 893 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) |
785 | acl->perm &= ~rw_mask; | 894 | acl->perm &= ~rw_mask; |
786 | if (!acl->perm) | 895 | if (!acl->perm) |
787 | ptr->type |= TOMOYO_ACL_DELETED; | 896 | ptr->type |= TOMOYO_ACL_DELETED; |
788 | error = 0; | 897 | error = 0; |
789 | break; | 898 | break; |
790 | } | 899 | } |
791 | out: | 900 | out: |
792 | up_write(&tomoyo_domain_acl_info_list_lock); | 901 | up_write(&tomoyo_domain_acl_info_list_lock); |
793 | return error; | 902 | return error; |
794 | } | 903 | } |
795 | 904 | ||
796 | /** | 905 | /** |
797 | * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. | 906 | * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. |
798 | * | 907 | * |
799 | * @type: Type of operation. | 908 | * @type: Type of operation. |
800 | * @filename1: First filename. | 909 | * @filename1: First filename. |
801 | * @filename2: Second filename. | 910 | * @filename2: Second filename. |
802 | * @domain: Pointer to "struct tomoyo_domain_info". | 911 | * @domain: Pointer to "struct tomoyo_domain_info". |
803 | * @is_delete: True if it is a delete request. | 912 | * @is_delete: True if it is a delete request. |
804 | * | 913 | * |
805 | * Returns 0 on success, negative value otherwise. | 914 | * Returns 0 on success, negative value otherwise. |
806 | */ | 915 | */ |
807 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 916 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, |
808 | const char *filename2, | 917 | const char *filename2, |
809 | struct tomoyo_domain_info * | 918 | struct tomoyo_domain_info * |
810 | const domain, const bool is_delete) | 919 | const domain, const bool is_delete) |
811 | { | 920 | { |
812 | const struct tomoyo_path_info *saved_filename1; | 921 | const struct tomoyo_path_info *saved_filename1; |
813 | const struct tomoyo_path_info *saved_filename2; | 922 | const struct tomoyo_path_info *saved_filename2; |
814 | struct tomoyo_acl_info *ptr; | 923 | struct tomoyo_acl_info *ptr; |
815 | struct tomoyo_double_path_acl_record *acl; | 924 | struct tomoyo_double_path_acl_record *acl; |
816 | int error = -ENOMEM; | 925 | int error = -ENOMEM; |
817 | const u8 perm = 1 << type; | 926 | const u8 perm = 1 << type; |
818 | 927 | ||
819 | if (!domain) | 928 | if (!domain) |
820 | return -EINVAL; | 929 | return -EINVAL; |
821 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || | 930 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || |
822 | !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) | 931 | !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) |
823 | return -EINVAL; | 932 | return -EINVAL; |
824 | saved_filename1 = tomoyo_save_name(filename1); | 933 | saved_filename1 = tomoyo_save_name(filename1); |
825 | saved_filename2 = tomoyo_save_name(filename2); | 934 | saved_filename2 = tomoyo_save_name(filename2); |
826 | if (!saved_filename1 || !saved_filename2) | 935 | if (!saved_filename1 || !saved_filename2) |
827 | return -ENOMEM; | 936 | return -ENOMEM; |
828 | down_write(&tomoyo_domain_acl_info_list_lock); | 937 | down_write(&tomoyo_domain_acl_info_list_lock); |
829 | if (is_delete) | 938 | if (is_delete) |
830 | goto delete; | 939 | goto delete; |
831 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 940 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
832 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | 941 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) |
833 | continue; | 942 | continue; |
834 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | 943 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, |
835 | head); | 944 | head); |
836 | if (acl->filename1 != saved_filename1 || | 945 | if (acl->filename1 != saved_filename1 || |
837 | acl->filename2 != saved_filename2) | 946 | acl->filename2 != saved_filename2) |
838 | continue; | 947 | continue; |
839 | /* Special case. Clear all bits if marked as deleted. */ | 948 | /* Special case. Clear all bits if marked as deleted. */ |
840 | if (ptr->type & TOMOYO_ACL_DELETED) | 949 | if (ptr->type & TOMOYO_ACL_DELETED) |
841 | acl->perm = 0; | 950 | acl->perm = 0; |
842 | acl->perm |= perm; | 951 | acl->perm |= perm; |
843 | ptr->type &= ~TOMOYO_ACL_DELETED; | 952 | ptr->type &= ~TOMOYO_ACL_DELETED; |
844 | error = 0; | 953 | error = 0; |
845 | goto out; | 954 | goto out; |
846 | } | 955 | } |
847 | /* Not found. Append it to the tail. */ | 956 | /* Not found. Append it to the tail. */ |
848 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); | 957 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); |
849 | if (!acl) | 958 | if (!acl) |
850 | goto out; | 959 | goto out; |
851 | acl->perm = perm; | 960 | acl->perm = perm; |
852 | acl->filename1 = saved_filename1; | 961 | acl->filename1 = saved_filename1; |
853 | acl->filename2 = saved_filename2; | 962 | acl->filename2 = saved_filename2; |
854 | list_add_tail(&acl->head.list, &domain->acl_info_list); | 963 | list_add_tail(&acl->head.list, &domain->acl_info_list); |
855 | error = 0; | 964 | error = 0; |
856 | goto out; | 965 | goto out; |
857 | delete: | 966 | delete: |
858 | error = -ENOENT; | 967 | error = -ENOENT; |
859 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 968 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
860 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | 969 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) |
861 | continue; | 970 | continue; |
862 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | 971 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, |
863 | head); | 972 | head); |
864 | if (acl->filename1 != saved_filename1 || | 973 | if (acl->filename1 != saved_filename1 || |
865 | acl->filename2 != saved_filename2) | 974 | acl->filename2 != saved_filename2) |
866 | continue; | 975 | continue; |
867 | acl->perm &= ~perm; | 976 | acl->perm &= ~perm; |
868 | if (!acl->perm) | 977 | if (!acl->perm) |
869 | ptr->type |= TOMOYO_ACL_DELETED; | 978 | ptr->type |= TOMOYO_ACL_DELETED; |
870 | error = 0; | 979 | error = 0; |
871 | break; | 980 | break; |
872 | } | 981 | } |
873 | out: | 982 | out: |
874 | up_write(&tomoyo_domain_acl_info_list_lock); | 983 | up_write(&tomoyo_domain_acl_info_list_lock); |
875 | return error; | 984 | return error; |
876 | } | 985 | } |
877 | 986 | ||
878 | /** | 987 | /** |
879 | * tomoyo_check_single_path_acl - Check permission for single path operation. | 988 | * tomoyo_check_single_path_acl - Check permission for single path operation. |
880 | * | 989 | * |
881 | * @domain: Pointer to "struct tomoyo_domain_info". | 990 | * @domain: Pointer to "struct tomoyo_domain_info". |
882 | * @type: Type of operation. | 991 | * @type: Type of operation. |
883 | * @filename: Filename to check. | 992 | * @filename: Filename to check. |
884 | * | 993 | * |
885 | * Returns 0 on success, negative value otherwise. | 994 | * Returns 0 on success, negative value otherwise. |
886 | */ | 995 | */ |
887 | static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | 996 | static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, |
888 | const u8 type, | 997 | const u8 type, |
889 | const struct tomoyo_path_info *filename) | 998 | const struct tomoyo_path_info *filename) |
890 | { | 999 | { |
891 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 1000 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
892 | return 0; | 1001 | return 0; |
893 | return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); | 1002 | return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); |
894 | } | 1003 | } |
895 | 1004 | ||
896 | /** | 1005 | /** |
897 | * tomoyo_check_double_path_acl - Check permission for double path operation. | 1006 | * tomoyo_check_double_path_acl - Check permission for double path operation. |
898 | * | 1007 | * |
899 | * @domain: Pointer to "struct tomoyo_domain_info". | 1008 | * @domain: Pointer to "struct tomoyo_domain_info". |
900 | * @type: Type of operation. | 1009 | * @type: Type of operation. |
901 | * @filename1: First filename to check. | 1010 | * @filename1: First filename to check. |
902 | * @filename2: Second filename to check. | 1011 | * @filename2: Second filename to check. |
903 | * | 1012 | * |
904 | * Returns 0 on success, -EPERM otherwise. | 1013 | * Returns 0 on success, -EPERM otherwise. |
905 | */ | 1014 | */ |
906 | static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | 1015 | static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, |
907 | const u8 type, | 1016 | const u8 type, |
908 | const struct tomoyo_path_info * | 1017 | const struct tomoyo_path_info * |
909 | filename1, | 1018 | filename1, |
910 | const struct tomoyo_path_info * | 1019 | const struct tomoyo_path_info * |
911 | filename2) | 1020 | filename2) |
912 | { | 1021 | { |
913 | struct tomoyo_acl_info *ptr; | 1022 | struct tomoyo_acl_info *ptr; |
914 | const u8 perm = 1 << type; | 1023 | const u8 perm = 1 << type; |
915 | int error = -EPERM; | 1024 | int error = -EPERM; |
916 | 1025 | ||
917 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 1026 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
918 | return 0; | 1027 | return 0; |
919 | down_read(&tomoyo_domain_acl_info_list_lock); | 1028 | down_read(&tomoyo_domain_acl_info_list_lock); |
920 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 1029 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
921 | struct tomoyo_double_path_acl_record *acl; | 1030 | struct tomoyo_double_path_acl_record *acl; |
922 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | 1031 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) |
923 | continue; | 1032 | continue; |
924 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | 1033 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, |
925 | head); | 1034 | head); |
926 | if (!(acl->perm & perm)) | 1035 | if (!(acl->perm & perm)) |
927 | continue; | 1036 | continue; |
928 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) | 1037 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) |
929 | continue; | 1038 | continue; |
930 | if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) | 1039 | if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) |
931 | continue; | 1040 | continue; |
932 | error = 0; | 1041 | error = 0; |
933 | break; | 1042 | break; |
934 | } | 1043 | } |
935 | up_read(&tomoyo_domain_acl_info_list_lock); | 1044 | up_read(&tomoyo_domain_acl_info_list_lock); |
936 | return error; | 1045 | return error; |
937 | } | 1046 | } |
938 | 1047 | ||
939 | /** | 1048 | /** |
940 | * tomoyo_check_single_path_permission2 - Check permission for single path operation. | 1049 | * tomoyo_check_single_path_permission2 - Check permission for single path operation. |
941 | * | 1050 | * |
942 | * @domain: Pointer to "struct tomoyo_domain_info". | 1051 | * @domain: Pointer to "struct tomoyo_domain_info". |
943 | * @operation: Type of operation. | 1052 | * @operation: Type of operation. |
944 | * @filename: Filename to check. | 1053 | * @filename: Filename to check. |
945 | * @mode: Access control mode. | 1054 | * @mode: Access control mode. |
946 | * | 1055 | * |
947 | * Returns 0 on success, negative value otherwise. | 1056 | * Returns 0 on success, negative value otherwise. |
948 | */ | 1057 | */ |
949 | static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | 1058 | static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * |
950 | const domain, u8 operation, | 1059 | const domain, u8 operation, |
951 | const struct tomoyo_path_info * | 1060 | const struct tomoyo_path_info * |
952 | filename, const u8 mode) | 1061 | filename, const u8 mode) |
953 | { | 1062 | { |
954 | const char *msg; | 1063 | const char *msg; |
955 | int error; | 1064 | int error; |
956 | const bool is_enforce = (mode == 3); | 1065 | const bool is_enforce = (mode == 3); |
957 | 1066 | ||
958 | if (!mode) | 1067 | if (!mode) |
959 | return 0; | 1068 | return 0; |
960 | next: | 1069 | next: |
961 | error = tomoyo_check_single_path_acl(domain, operation, filename); | 1070 | error = tomoyo_check_single_path_acl(domain, operation, filename); |
962 | msg = tomoyo_sp2keyword(operation); | 1071 | msg = tomoyo_sp2keyword(operation); |
963 | if (!error) | 1072 | if (!error) |
964 | goto ok; | 1073 | goto ok; |
965 | if (tomoyo_verbose_mode(domain)) | 1074 | if (tomoyo_verbose_mode(domain)) |
966 | printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", | 1075 | printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", |
967 | tomoyo_get_msg(is_enforce), msg, filename->name, | 1076 | tomoyo_get_msg(is_enforce), msg, filename->name, |
968 | tomoyo_get_last_name(domain)); | 1077 | tomoyo_get_last_name(domain)); |
969 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1078 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
970 | const char *name = tomoyo_get_file_pattern(filename)->name; | 1079 | const char *name = tomoyo_get_file_pattern(filename)->name; |
971 | tomoyo_update_single_path_acl(operation, name, domain, false); | 1080 | tomoyo_update_single_path_acl(operation, name, domain, false); |
972 | } | 1081 | } |
973 | if (!is_enforce) | 1082 | if (!is_enforce) |
974 | error = 0; | 1083 | error = 0; |
975 | ok: | 1084 | ok: |
976 | /* | 1085 | /* |
977 | * Since "allow_truncate" doesn't imply "allow_rewrite" permission, | 1086 | * Since "allow_truncate" doesn't imply "allow_rewrite" permission, |
978 | * we need to check "allow_rewrite" permission if the filename is | 1087 | * we need to check "allow_rewrite" permission if the filename is |
979 | * specified by "deny_rewrite" keyword. | 1088 | * specified by "deny_rewrite" keyword. |
980 | */ | 1089 | */ |
981 | if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && | 1090 | if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && |
982 | tomoyo_is_no_rewrite_file(filename)) { | 1091 | tomoyo_is_no_rewrite_file(filename)) { |
983 | operation = TOMOYO_TYPE_REWRITE_ACL; | 1092 | operation = TOMOYO_TYPE_REWRITE_ACL; |
984 | goto next; | 1093 | goto next; |
985 | } | 1094 | } |
986 | return error; | 1095 | return error; |
987 | } | 1096 | } |
988 | 1097 | ||
989 | /** | 1098 | /** |
990 | * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write". | 1099 | * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write". |
991 | * | 1100 | * |
992 | * @domain: Pointer to "struct tomoyo_domain_info". | 1101 | * @domain: Pointer to "struct tomoyo_domain_info". |
993 | * @filename: Filename to check. | 1102 | * @filename: Filename to check. |
994 | * @perm: Mode ("read" or "write" or "read/write"). | 1103 | * @perm: Mode ("read" or "write" or "read/write"). |
995 | * Returns 0 on success, negative value otherwise. | 1104 | * Returns 0 on success, negative value otherwise. |
996 | */ | 1105 | */ |
997 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | 1106 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, |
998 | const char *filename, const u8 perm) | 1107 | const char *filename, const u8 perm) |
999 | { | 1108 | { |
1000 | struct tomoyo_path_info name; | 1109 | struct tomoyo_path_info name; |
1001 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1110 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1002 | 1111 | ||
1003 | if (!mode) | 1112 | if (!mode) |
1004 | return 0; | 1113 | return 0; |
1005 | name.name = filename; | 1114 | name.name = filename; |
1006 | tomoyo_fill_path_info(&name); | 1115 | tomoyo_fill_path_info(&name); |
1007 | return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode); | 1116 | return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode); |
1008 | } | 1117 | } |
1009 | 1118 | ||
1010 | /** | 1119 | /** |
1011 | * tomoyo_check_exec_perm - Check permission for "execute". | 1120 | * tomoyo_check_exec_perm - Check permission for "execute". |
1012 | * | 1121 | * |
1013 | * @domain: Pointer to "struct tomoyo_domain_info". | 1122 | * @domain: Pointer to "struct tomoyo_domain_info". |
1014 | * @filename: Check permission for "execute". | 1123 | * @filename: Check permission for "execute". |
1015 | * | 1124 | * |
1016 | * Returns 0 on success, negativevalue otherwise. | 1125 | * Returns 0 on success, negativevalue otherwise. |
1017 | */ | 1126 | */ |
1018 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 1127 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
1019 | const struct tomoyo_path_info *filename) | 1128 | const struct tomoyo_path_info *filename) |
1020 | { | 1129 | { |
1021 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1130 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1022 | 1131 | ||
1023 | if (!mode) | 1132 | if (!mode) |
1024 | return 0; | 1133 | return 0; |
1025 | return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); | 1134 | return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); |
1026 | } | 1135 | } |
1027 | 1136 | ||
1028 | /** | 1137 | /** |
1029 | * tomoyo_check_open_permission - Check permission for "read" and "write". | 1138 | * tomoyo_check_open_permission - Check permission for "read" and "write". |
1030 | * | 1139 | * |
1031 | * @domain: Pointer to "struct tomoyo_domain_info". | 1140 | * @domain: Pointer to "struct tomoyo_domain_info". |
1032 | * @path: Pointer to "struct path". | 1141 | * @path: Pointer to "struct path". |
1033 | * @flag: Flags for open(). | 1142 | * @flag: Flags for open(). |
1034 | * | 1143 | * |
1035 | * Returns 0 on success, negative value otherwise. | 1144 | * Returns 0 on success, negative value otherwise. |
1036 | */ | 1145 | */ |
1037 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 1146 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
1038 | struct path *path, const int flag) | 1147 | struct path *path, const int flag) |
1039 | { | 1148 | { |
1040 | const u8 acc_mode = ACC_MODE(flag); | 1149 | const u8 acc_mode = ACC_MODE(flag); |
1041 | int error = -ENOMEM; | 1150 | int error = -ENOMEM; |
1042 | struct tomoyo_path_info *buf; | 1151 | struct tomoyo_path_info *buf; |
1043 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1152 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1044 | const bool is_enforce = (mode == 3); | 1153 | const bool is_enforce = (mode == 3); |
1045 | 1154 | ||
1046 | if (!mode || !path->mnt) | 1155 | if (!mode || !path->mnt) |
1047 | return 0; | 1156 | return 0; |
1048 | if (acc_mode == 0) | 1157 | if (acc_mode == 0) |
1049 | return 0; | 1158 | return 0; |
1050 | if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) | 1159 | if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) |
1051 | /* | 1160 | /* |
1052 | * I don't check directories here because mkdir() and rmdir() | 1161 | * I don't check directories here because mkdir() and rmdir() |
1053 | * don't call me. | 1162 | * don't call me. |
1054 | */ | 1163 | */ |
1055 | return 0; | 1164 | return 0; |
1056 | buf = tomoyo_get_path(path); | 1165 | buf = tomoyo_get_path(path); |
1057 | if (!buf) | 1166 | if (!buf) |
1058 | goto out; | 1167 | goto out; |
1059 | error = 0; | 1168 | error = 0; |
1060 | /* | 1169 | /* |
1061 | * If the filename is specified by "deny_rewrite" keyword, | 1170 | * If the filename is specified by "deny_rewrite" keyword, |
1062 | * we need to check "allow_rewrite" permission when the filename is not | 1171 | * we need to check "allow_rewrite" permission when the filename is not |
1063 | * opened for append mode or the filename is truncated at open time. | 1172 | * opened for append mode or the filename is truncated at open time. |
1064 | */ | 1173 | */ |
1065 | if ((acc_mode & MAY_WRITE) && | 1174 | if ((acc_mode & MAY_WRITE) && |
1066 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && | 1175 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && |
1067 | (tomoyo_is_no_rewrite_file(buf))) { | 1176 | (tomoyo_is_no_rewrite_file(buf))) { |
1068 | error = tomoyo_check_single_path_permission2(domain, | 1177 | error = tomoyo_check_single_path_permission2(domain, |
1069 | TOMOYO_TYPE_REWRITE_ACL, | 1178 | TOMOYO_TYPE_REWRITE_ACL, |
1070 | buf, mode); | 1179 | buf, mode); |
1071 | } | 1180 | } |
1072 | if (!error) | 1181 | if (!error) |
1073 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", | 1182 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", |
1074 | mode); | 1183 | mode); |
1075 | if (!error && (flag & O_TRUNC)) | 1184 | if (!error && (flag & O_TRUNC)) |
1076 | error = tomoyo_check_single_path_permission2(domain, | 1185 | error = tomoyo_check_single_path_permission2(domain, |
1077 | TOMOYO_TYPE_TRUNCATE_ACL, | 1186 | TOMOYO_TYPE_TRUNCATE_ACL, |
1078 | buf, mode); | 1187 | buf, mode); |
1079 | out: | 1188 | out: |
1080 | tomoyo_free(buf); | 1189 | tomoyo_free(buf); |
1081 | if (!is_enforce) | 1190 | if (!is_enforce) |
1082 | error = 0; | 1191 | error = 0; |
1083 | return error; | 1192 | return error; |
1084 | } | 1193 | } |
1085 | 1194 | ||
1086 | /** | 1195 | /** |
1087 | * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". | 1196 | * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". |
1088 | * | 1197 | * |
1089 | * @domain: Pointer to "struct tomoyo_domain_info". | 1198 | * @domain: Pointer to "struct tomoyo_domain_info". |
1090 | * @operation: Type of operation. | 1199 | * @operation: Type of operation. |
1091 | * @path: Pointer to "struct path". | 1200 | * @path: Pointer to "struct path". |
1092 | * | 1201 | * |
1093 | * Returns 0 on success, negative value otherwise. | 1202 | * Returns 0 on success, negative value otherwise. |
1094 | */ | 1203 | */ |
1095 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | 1204 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, |
1096 | const u8 operation, struct path *path) | 1205 | const u8 operation, struct path *path) |
1097 | { | 1206 | { |
1098 | int error = -ENOMEM; | 1207 | int error = -ENOMEM; |
1099 | struct tomoyo_path_info *buf; | 1208 | struct tomoyo_path_info *buf; |
1100 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1209 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1101 | const bool is_enforce = (mode == 3); | 1210 | const bool is_enforce = (mode == 3); |
1102 | 1211 | ||
1103 | if (!mode || !path->mnt) | 1212 | if (!mode || !path->mnt) |
1104 | return 0; | 1213 | return 0; |
1105 | buf = tomoyo_get_path(path); | 1214 | buf = tomoyo_get_path(path); |
1106 | if (!buf) | 1215 | if (!buf) |
1107 | goto out; | 1216 | goto out; |
1108 | switch (operation) { | 1217 | switch (operation) { |
1109 | case TOMOYO_TYPE_MKDIR_ACL: | 1218 | case TOMOYO_TYPE_MKDIR_ACL: |
1110 | case TOMOYO_TYPE_RMDIR_ACL: | 1219 | case TOMOYO_TYPE_RMDIR_ACL: |
1111 | if (!buf->is_dir) { | 1220 | if (!buf->is_dir) { |
1112 | /* | 1221 | /* |
1113 | * tomoyo_get_path() reserves space for appending "/." | 1222 | * tomoyo_get_path() reserves space for appending "/." |
1114 | */ | 1223 | */ |
1115 | strcat((char *) buf->name, "/"); | 1224 | strcat((char *) buf->name, "/"); |
1116 | tomoyo_fill_path_info(buf); | 1225 | tomoyo_fill_path_info(buf); |
1117 | } | 1226 | } |
1118 | } | 1227 | } |
1119 | error = tomoyo_check_single_path_permission2(domain, operation, buf, | 1228 | error = tomoyo_check_single_path_permission2(domain, operation, buf, |
1120 | mode); | 1229 | mode); |
1121 | out: | 1230 | out: |
1122 | tomoyo_free(buf); | 1231 | tomoyo_free(buf); |
1123 | if (!is_enforce) | 1232 | if (!is_enforce) |
1124 | error = 0; | 1233 | error = 0; |
1125 | return error; | 1234 | return error; |
1126 | } | 1235 | } |
1127 | 1236 | ||
1128 | /** | 1237 | /** |
1129 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". | 1238 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". |
1130 | * | 1239 | * |
1131 | * @domain: Pointer to "struct tomoyo_domain_info". | 1240 | * @domain: Pointer to "struct tomoyo_domain_info". |
1132 | * @filp: Pointer to "struct file". | 1241 | * @filp: Pointer to "struct file". |
1133 | * | 1242 | * |
1134 | * Returns 0 on success, negative value otherwise. | 1243 | * Returns 0 on success, negative value otherwise. |
1135 | */ | 1244 | */ |
1136 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 1245 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, |
1137 | struct file *filp) | 1246 | struct file *filp) |
1138 | { | 1247 | { |
1139 | int error = -ENOMEM; | 1248 | int error = -ENOMEM; |
1140 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1249 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1141 | const bool is_enforce = (mode == 3); | 1250 | const bool is_enforce = (mode == 3); |
1142 | struct tomoyo_path_info *buf; | 1251 | struct tomoyo_path_info *buf; |
1143 | 1252 | ||
1144 | if (!mode || !filp->f_path.mnt) | 1253 | if (!mode || !filp->f_path.mnt) |
1145 | return 0; | 1254 | return 0; |
1146 | buf = tomoyo_get_path(&filp->f_path); | 1255 | buf = tomoyo_get_path(&filp->f_path); |
1147 | if (!buf) | 1256 | if (!buf) |
1148 | goto out; | 1257 | goto out; |
1149 | if (!tomoyo_is_no_rewrite_file(buf)) { | 1258 | if (!tomoyo_is_no_rewrite_file(buf)) { |
1150 | error = 0; | 1259 | error = 0; |
1151 | goto out; | 1260 | goto out; |
1152 | } | 1261 | } |
1153 | error = tomoyo_check_single_path_permission2(domain, | 1262 | error = tomoyo_check_single_path_permission2(domain, |
1154 | TOMOYO_TYPE_REWRITE_ACL, | 1263 | TOMOYO_TYPE_REWRITE_ACL, |
1155 | buf, mode); | 1264 | buf, mode); |
1156 | out: | 1265 | out: |
1157 | tomoyo_free(buf); | 1266 | tomoyo_free(buf); |
1158 | if (!is_enforce) | 1267 | if (!is_enforce) |
1159 | error = 0; | 1268 | error = 0; |
1160 | return error; | 1269 | return error; |
1161 | } | 1270 | } |
1162 | 1271 | ||
1163 | /** | 1272 | /** |
1164 | * tomoyo_check_2path_perm - Check permission for "rename" and "link". | 1273 | * tomoyo_check_2path_perm - Check permission for "rename" and "link". |
1165 | * | 1274 | * |
1166 | * @domain: Pointer to "struct tomoyo_domain_info". | 1275 | * @domain: Pointer to "struct tomoyo_domain_info". |
1167 | * @operation: Type of operation. | 1276 | * @operation: Type of operation. |
1168 | * @path1: Pointer to "struct path". | 1277 | * @path1: Pointer to "struct path". |
1169 | * @path2: Pointer to "struct path". | 1278 | * @path2: Pointer to "struct path". |
1170 | * | 1279 | * |
1171 | * Returns 0 on success, negative value otherwise. | 1280 | * Returns 0 on success, negative value otherwise. |
1172 | */ | 1281 | */ |
1173 | int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | 1282 | int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, |
1174 | const u8 operation, struct path *path1, | 1283 | const u8 operation, struct path *path1, |
1175 | struct path *path2) | 1284 | struct path *path2) |
1176 | { | 1285 | { |
1177 | int error = -ENOMEM; | 1286 | int error = -ENOMEM; |
1178 | struct tomoyo_path_info *buf1, *buf2; | 1287 | struct tomoyo_path_info *buf1, *buf2; |
1179 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1288 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1180 | const bool is_enforce = (mode == 3); | 1289 | const bool is_enforce = (mode == 3); |
1181 | const char *msg; | 1290 | const char *msg; |
1182 | 1291 | ||
1183 | if (!mode || !path1->mnt || !path2->mnt) | 1292 | if (!mode || !path1->mnt || !path2->mnt) |
1184 | return 0; | 1293 | return 0; |
1185 | buf1 = tomoyo_get_path(path1); | 1294 | buf1 = tomoyo_get_path(path1); |
1186 | buf2 = tomoyo_get_path(path2); | 1295 | buf2 = tomoyo_get_path(path2); |
1187 | if (!buf1 || !buf2) | 1296 | if (!buf1 || !buf2) |
1188 | goto out; | 1297 | goto out; |
1189 | { | 1298 | { |
1190 | struct dentry *dentry = path1->dentry; | 1299 | struct dentry *dentry = path1->dentry; |
1191 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { | 1300 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { |
1192 | /* | 1301 | /* |
1193 | * tomoyo_get_path() reserves space for appending "/." | 1302 | * tomoyo_get_path() reserves space for appending "/." |
1194 | */ | 1303 | */ |
1195 | if (!buf1->is_dir) { | 1304 | if (!buf1->is_dir) { |
1196 | strcat((char *) buf1->name, "/"); | 1305 | strcat((char *) buf1->name, "/"); |
1197 | tomoyo_fill_path_info(buf1); | 1306 | tomoyo_fill_path_info(buf1); |
1198 | } | 1307 | } |
1199 | if (!buf2->is_dir) { | 1308 | if (!buf2->is_dir) { |
1200 | strcat((char *) buf2->name, "/"); | 1309 | strcat((char *) buf2->name, "/"); |
1201 | tomoyo_fill_path_info(buf2); | 1310 | tomoyo_fill_path_info(buf2); |
1202 | } | 1311 | } |
1203 | } | 1312 | } |
1204 | } | 1313 | } |
1205 | error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); | 1314 | error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); |
1206 | msg = tomoyo_dp2keyword(operation); | 1315 | msg = tomoyo_dp2keyword(operation); |
1207 | if (!error) | 1316 | if (!error) |
1208 | goto out; | 1317 | goto out; |
1209 | if (tomoyo_verbose_mode(domain)) | 1318 | if (tomoyo_verbose_mode(domain)) |
1210 | printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " | 1319 | printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " |
1211 | "denied for %s\n", tomoyo_get_msg(is_enforce), | 1320 | "denied for %s\n", tomoyo_get_msg(is_enforce), |
1212 | msg, buf1->name, buf2->name, | 1321 | msg, buf1->name, buf2->name, |
1213 | tomoyo_get_last_name(domain)); | 1322 | tomoyo_get_last_name(domain)); |
1214 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1323 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1215 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; | 1324 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; |
1216 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; | 1325 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; |
1217 | tomoyo_update_double_path_acl(operation, name1, name2, domain, | 1326 | tomoyo_update_double_path_acl(operation, name1, name2, domain, |
1218 | false); | 1327 | false); |
1219 | } | 1328 | } |
1220 | out: | 1329 | out: |
1221 | tomoyo_free(buf1); | 1330 | tomoyo_free(buf1); |
1222 | tomoyo_free(buf2); | 1331 | tomoyo_free(buf2); |
1223 | if (!is_enforce) | 1332 | if (!is_enforce) |
1224 | error = 0; | 1333 | error = 0; |
1225 | return error; | 1334 | return error; |
1226 | } | 1335 | } |
1227 | 1336 |
security/tomoyo/realpath.c
1 | /* | 1 | /* |
2 | * security/tomoyo/realpath.c | 2 | * security/tomoyo/realpath.c |
3 | * | 3 | * |
4 | * Get the canonicalized absolute pathnames. The basis for TOMOYO. | 4 | * Get the canonicalized absolute pathnames. The basis for TOMOYO. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * | 7 | * |
8 | * Version: 2.2.0 2009/04/01 | 8 | * Version: 2.2.0 2009/04/01 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/mount.h> | 13 | #include <linux/mount.h> |
14 | #include <linux/mnt_namespace.h> | 14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> | 15 | #include <linux/fs_struct.h> |
16 | #include "common.h" | 16 | #include "common.h" |
17 | #include "realpath.h" | 17 | #include "realpath.h" |
18 | 18 | ||
19 | /** | 19 | /** |
20 | * tomoyo_encode: Convert binary string to ascii string. | 20 | * tomoyo_encode: Convert binary string to ascii string. |
21 | * | 21 | * |
22 | * @buffer: Buffer for ASCII string. | 22 | * @buffer: Buffer for ASCII string. |
23 | * @buflen: Size of @buffer. | 23 | * @buflen: Size of @buffer. |
24 | * @str: Binary string. | 24 | * @str: Binary string. |
25 | * | 25 | * |
26 | * Returns 0 on success, -ENOMEM otherwise. | 26 | * Returns 0 on success, -ENOMEM otherwise. |
27 | */ | 27 | */ |
28 | int tomoyo_encode(char *buffer, int buflen, const char *str) | 28 | int tomoyo_encode(char *buffer, int buflen, const char *str) |
29 | { | 29 | { |
30 | while (1) { | 30 | while (1) { |
31 | const unsigned char c = *(unsigned char *) str++; | 31 | const unsigned char c = *(unsigned char *) str++; |
32 | 32 | ||
33 | if (tomoyo_is_valid(c)) { | 33 | if (tomoyo_is_valid(c)) { |
34 | if (--buflen <= 0) | 34 | if (--buflen <= 0) |
35 | break; | 35 | break; |
36 | *buffer++ = (char) c; | 36 | *buffer++ = (char) c; |
37 | if (c != '\\') | 37 | if (c != '\\') |
38 | continue; | 38 | continue; |
39 | if (--buflen <= 0) | 39 | if (--buflen <= 0) |
40 | break; | 40 | break; |
41 | *buffer++ = (char) c; | 41 | *buffer++ = (char) c; |
42 | continue; | 42 | continue; |
43 | } | 43 | } |
44 | if (!c) { | 44 | if (!c) { |
45 | if (--buflen <= 0) | 45 | if (--buflen <= 0) |
46 | break; | 46 | break; |
47 | *buffer = '\0'; | 47 | *buffer = '\0'; |
48 | return 0; | 48 | return 0; |
49 | } | 49 | } |
50 | buflen -= 4; | 50 | buflen -= 4; |
51 | if (buflen <= 0) | 51 | if (buflen <= 0) |
52 | break; | 52 | break; |
53 | *buffer++ = '\\'; | 53 | *buffer++ = '\\'; |
54 | *buffer++ = (c >> 6) + '0'; | 54 | *buffer++ = (c >> 6) + '0'; |
55 | *buffer++ = ((c >> 3) & 7) + '0'; | 55 | *buffer++ = ((c >> 3) & 7) + '0'; |
56 | *buffer++ = (c & 7) + '0'; | 56 | *buffer++ = (c & 7) + '0'; |
57 | } | 57 | } |
58 | return -ENOMEM; | 58 | return -ENOMEM; |
59 | } | 59 | } |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root. | 62 | * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root. |
63 | * | 63 | * |
64 | * @path: Pointer to "struct path". | 64 | * @path: Pointer to "struct path". |
65 | * @newname: Pointer to buffer to return value in. | 65 | * @newname: Pointer to buffer to return value in. |
66 | * @newname_len: Size of @newname. | 66 | * @newname_len: Size of @newname. |
67 | * | 67 | * |
68 | * Returns 0 on success, negative value otherwise. | 68 | * Returns 0 on success, negative value otherwise. |
69 | * | 69 | * |
70 | * If dentry is a directory, trailing '/' is appended. | 70 | * If dentry is a directory, trailing '/' is appended. |
71 | * Characters out of 0x20 < c < 0x7F range are converted to | 71 | * Characters out of 0x20 < c < 0x7F range are converted to |
72 | * \ooo style octal string. | 72 | * \ooo style octal string. |
73 | * Character \ is converted to \\ string. | 73 | * Character \ is converted to \\ string. |
74 | */ | 74 | */ |
75 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | 75 | int tomoyo_realpath_from_path2(struct path *path, char *newname, |
76 | int newname_len) | 76 | int newname_len) |
77 | { | 77 | { |
78 | int error = -ENOMEM; | 78 | int error = -ENOMEM; |
79 | struct dentry *dentry = path->dentry; | 79 | struct dentry *dentry = path->dentry; |
80 | char *sp; | 80 | char *sp; |
81 | 81 | ||
82 | if (!dentry || !path->mnt || !newname || newname_len <= 2048) | 82 | if (!dentry || !path->mnt || !newname || newname_len <= 2048) |
83 | return -EINVAL; | 83 | return -EINVAL; |
84 | if (dentry->d_op && dentry->d_op->d_dname) { | 84 | if (dentry->d_op && dentry->d_op->d_dname) { |
85 | /* For "socket:[\$]" and "pipe:[\$]". */ | 85 | /* For "socket:[\$]" and "pipe:[\$]". */ |
86 | static const int offset = 1536; | 86 | static const int offset = 1536; |
87 | sp = dentry->d_op->d_dname(dentry, newname + offset, | 87 | sp = dentry->d_op->d_dname(dentry, newname + offset, |
88 | newname_len - offset); | 88 | newname_len - offset); |
89 | } else { | 89 | } else { |
90 | /* Taken from d_namespace_path(). */ | 90 | /* Taken from d_namespace_path(). */ |
91 | struct path root; | 91 | struct path root; |
92 | struct path ns_root = { }; | 92 | struct path ns_root = { }; |
93 | struct path tmp; | 93 | struct path tmp; |
94 | 94 | ||
95 | read_lock(¤t->fs->lock); | 95 | read_lock(¤t->fs->lock); |
96 | root = current->fs->root; | 96 | root = current->fs->root; |
97 | path_get(&root); | 97 | path_get(&root); |
98 | read_unlock(¤t->fs->lock); | 98 | read_unlock(¤t->fs->lock); |
99 | spin_lock(&vfsmount_lock); | 99 | spin_lock(&vfsmount_lock); |
100 | if (root.mnt && root.mnt->mnt_ns) | 100 | if (root.mnt && root.mnt->mnt_ns) |
101 | ns_root.mnt = mntget(root.mnt->mnt_ns->root); | 101 | ns_root.mnt = mntget(root.mnt->mnt_ns->root); |
102 | if (ns_root.mnt) | 102 | if (ns_root.mnt) |
103 | ns_root.dentry = dget(ns_root.mnt->mnt_root); | 103 | ns_root.dentry = dget(ns_root.mnt->mnt_root); |
104 | spin_unlock(&vfsmount_lock); | 104 | spin_unlock(&vfsmount_lock); |
105 | spin_lock(&dcache_lock); | 105 | spin_lock(&dcache_lock); |
106 | tmp = ns_root; | 106 | tmp = ns_root; |
107 | sp = __d_path(path, &tmp, newname, newname_len); | 107 | sp = __d_path(path, &tmp, newname, newname_len); |
108 | spin_unlock(&dcache_lock); | 108 | spin_unlock(&dcache_lock); |
109 | path_put(&root); | 109 | path_put(&root); |
110 | path_put(&ns_root); | 110 | path_put(&ns_root); |
111 | } | 111 | } |
112 | if (IS_ERR(sp)) | 112 | if (IS_ERR(sp)) |
113 | error = PTR_ERR(sp); | 113 | error = PTR_ERR(sp); |
114 | else | 114 | else |
115 | error = tomoyo_encode(newname, sp - newname, sp); | 115 | error = tomoyo_encode(newname, sp - newname, sp); |
116 | /* Append trailing '/' if dentry is a directory. */ | 116 | /* Append trailing '/' if dentry is a directory. */ |
117 | if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) | 117 | if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) |
118 | && *newname) { | 118 | && *newname) { |
119 | sp = newname + strlen(newname); | 119 | sp = newname + strlen(newname); |
120 | if (*(sp - 1) != '/') { | 120 | if (*(sp - 1) != '/') { |
121 | if (sp < newname + newname_len - 4) { | 121 | if (sp < newname + newname_len - 4) { |
122 | *sp++ = '/'; | 122 | *sp++ = '/'; |
123 | *sp = '\0'; | 123 | *sp = '\0'; |
124 | } else { | 124 | } else { |
125 | error = -ENOMEM; | 125 | error = -ENOMEM; |
126 | } | 126 | } |
127 | } | 127 | } |
128 | } | 128 | } |
129 | if (error) | 129 | if (error) |
130 | printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); | 130 | printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); |
131 | return error; | 131 | return error; |
132 | } | 132 | } |
133 | 133 | ||
134 | /** | 134 | /** |
135 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. | 135 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. |
136 | * | 136 | * |
137 | * @path: Pointer to "struct path". | 137 | * @path: Pointer to "struct path". |
138 | * | 138 | * |
139 | * Returns the realpath of the given @path on success, NULL otherwise. | 139 | * Returns the realpath of the given @path on success, NULL otherwise. |
140 | * | 140 | * |
141 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() | 141 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() |
142 | * if these functions didn't return NULL. | 142 | * if these functions didn't return NULL. |
143 | */ | 143 | */ |
144 | char *tomoyo_realpath_from_path(struct path *path) | 144 | char *tomoyo_realpath_from_path(struct path *path) |
145 | { | 145 | { |
146 | char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer)); | 146 | char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer)); |
147 | 147 | ||
148 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | 148 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
149 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | 149 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
150 | if (!buf) | 150 | if (!buf) |
151 | return NULL; | 151 | return NULL; |
152 | if (tomoyo_realpath_from_path2(path, buf, | 152 | if (tomoyo_realpath_from_path2(path, buf, |
153 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) | 153 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) |
154 | return buf; | 154 | return buf; |
155 | tomoyo_free(buf); | 155 | tomoyo_free(buf); |
156 | return NULL; | 156 | return NULL; |
157 | } | 157 | } |
158 | 158 | ||
159 | /** | 159 | /** |
160 | * tomoyo_realpath - Get realpath of a pathname. | 160 | * tomoyo_realpath - Get realpath of a pathname. |
161 | * | 161 | * |
162 | * @pathname: The pathname to solve. | 162 | * @pathname: The pathname to solve. |
163 | * | 163 | * |
164 | * Returns the realpath of @pathname on success, NULL otherwise. | 164 | * Returns the realpath of @pathname on success, NULL otherwise. |
165 | */ | 165 | */ |
166 | char *tomoyo_realpath(const char *pathname) | 166 | char *tomoyo_realpath(const char *pathname) |
167 | { | 167 | { |
168 | struct path path; | 168 | struct path path; |
169 | 169 | ||
170 | if (pathname && kern_path(pathname, LOOKUP_FOLLOW, &path) == 0) { | 170 | if (pathname && kern_path(pathname, LOOKUP_FOLLOW, &path) == 0) { |
171 | char *buf = tomoyo_realpath_from_path(&path); | 171 | char *buf = tomoyo_realpath_from_path(&path); |
172 | path_put(&path); | 172 | path_put(&path); |
173 | return buf; | 173 | return buf; |
174 | } | 174 | } |
175 | return NULL; | 175 | return NULL; |
176 | } | 176 | } |
177 | 177 | ||
178 | /** | 178 | /** |
179 | * tomoyo_realpath_nofollow - Get realpath of a pathname. | 179 | * tomoyo_realpath_nofollow - Get realpath of a pathname. |
180 | * | 180 | * |
181 | * @pathname: The pathname to solve. | 181 | * @pathname: The pathname to solve. |
182 | * | 182 | * |
183 | * Returns the realpath of @pathname on success, NULL otherwise. | 183 | * Returns the realpath of @pathname on success, NULL otherwise. |
184 | */ | 184 | */ |
185 | char *tomoyo_realpath_nofollow(const char *pathname) | 185 | char *tomoyo_realpath_nofollow(const char *pathname) |
186 | { | 186 | { |
187 | struct path path; | 187 | struct path path; |
188 | 188 | ||
189 | if (pathname && kern_path(pathname, 0, &path) == 0) { | 189 | if (pathname && kern_path(pathname, 0, &path) == 0) { |
190 | char *buf = tomoyo_realpath_from_path(&path); | 190 | char *buf = tomoyo_realpath_from_path(&path); |
191 | path_put(&path); | 191 | path_put(&path); |
192 | return buf; | 192 | return buf; |
193 | } | 193 | } |
194 | return NULL; | 194 | return NULL; |
195 | } | 195 | } |
196 | 196 | ||
197 | /* Memory allocated for non-string data. */ | 197 | /* Memory allocated for non-string data. */ |
198 | static unsigned int tomoyo_allocated_memory_for_elements; | 198 | static unsigned int tomoyo_allocated_memory_for_elements; |
199 | /* Quota for holding non-string data. */ | 199 | /* Quota for holding non-string data. */ |
200 | static unsigned int tomoyo_quota_for_elements; | 200 | static unsigned int tomoyo_quota_for_elements; |
201 | 201 | ||
202 | /** | 202 | /** |
203 | * tomoyo_alloc_element - Allocate permanent memory for structures. | 203 | * tomoyo_alloc_element - Allocate permanent memory for structures. |
204 | * | 204 | * |
205 | * @size: Size in bytes. | 205 | * @size: Size in bytes. |
206 | * | 206 | * |
207 | * Returns pointer to allocated memory on success, NULL otherwise. | 207 | * Returns pointer to allocated memory on success, NULL otherwise. |
208 | * | 208 | * |
209 | * Memory has to be zeroed. | 209 | * Memory has to be zeroed. |
210 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. | 210 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. |
211 | */ | 211 | */ |
212 | void *tomoyo_alloc_element(const unsigned int size) | 212 | void *tomoyo_alloc_element(const unsigned int size) |
213 | { | 213 | { |
214 | static char *buf; | 214 | static char *buf; |
215 | static DEFINE_MUTEX(lock); | 215 | static DEFINE_MUTEX(lock); |
216 | static unsigned int buf_used_len = PATH_MAX; | 216 | static unsigned int buf_used_len = PATH_MAX; |
217 | char *ptr = NULL; | 217 | char *ptr = NULL; |
218 | /*Assumes sizeof(void *) >= sizeof(long) is true. */ | 218 | /*Assumes sizeof(void *) >= sizeof(long) is true. */ |
219 | const unsigned int word_aligned_size | 219 | const unsigned int word_aligned_size |
220 | = roundup(size, max(sizeof(void *), sizeof(long))); | 220 | = roundup(size, max(sizeof(void *), sizeof(long))); |
221 | if (word_aligned_size > PATH_MAX) | 221 | if (word_aligned_size > PATH_MAX) |
222 | return NULL; | 222 | return NULL; |
223 | mutex_lock(&lock); | 223 | mutex_lock(&lock); |
224 | if (buf_used_len + word_aligned_size > PATH_MAX) { | 224 | if (buf_used_len + word_aligned_size > PATH_MAX) { |
225 | if (!tomoyo_quota_for_elements || | 225 | if (!tomoyo_quota_for_elements || |
226 | tomoyo_allocated_memory_for_elements | 226 | tomoyo_allocated_memory_for_elements |
227 | + PATH_MAX <= tomoyo_quota_for_elements) | 227 | + PATH_MAX <= tomoyo_quota_for_elements) |
228 | ptr = kzalloc(PATH_MAX, GFP_KERNEL); | 228 | ptr = kzalloc(PATH_MAX, GFP_KERNEL); |
229 | if (!ptr) { | 229 | if (!ptr) { |
230 | printk(KERN_WARNING "ERROR: Out of memory " | 230 | printk(KERN_WARNING "ERROR: Out of memory " |
231 | "for tomoyo_alloc_element().\n"); | 231 | "for tomoyo_alloc_element().\n"); |
232 | if (!tomoyo_policy_loaded) | 232 | if (!tomoyo_policy_loaded) |
233 | panic("MAC Initialization failed.\n"); | 233 | panic("MAC Initialization failed.\n"); |
234 | } else { | 234 | } else { |
235 | buf = ptr; | 235 | buf = ptr; |
236 | tomoyo_allocated_memory_for_elements += PATH_MAX; | 236 | tomoyo_allocated_memory_for_elements += PATH_MAX; |
237 | buf_used_len = word_aligned_size; | 237 | buf_used_len = word_aligned_size; |
238 | ptr = buf; | 238 | ptr = buf; |
239 | } | 239 | } |
240 | } else if (word_aligned_size) { | 240 | } else if (word_aligned_size) { |
241 | int i; | 241 | int i; |
242 | ptr = buf + buf_used_len; | 242 | ptr = buf + buf_used_len; |
243 | buf_used_len += word_aligned_size; | 243 | buf_used_len += word_aligned_size; |
244 | for (i = 0; i < word_aligned_size; i++) { | 244 | for (i = 0; i < word_aligned_size; i++) { |
245 | if (!ptr[i]) | 245 | if (!ptr[i]) |
246 | continue; | 246 | continue; |
247 | printk(KERN_ERR "WARNING: Reserved memory was tainted! " | 247 | printk(KERN_ERR "WARNING: Reserved memory was tainted! " |
248 | "The system might go wrong.\n"); | 248 | "The system might go wrong.\n"); |
249 | ptr[i] = '\0'; | 249 | ptr[i] = '\0'; |
250 | } | 250 | } |
251 | } | 251 | } |
252 | mutex_unlock(&lock); | 252 | mutex_unlock(&lock); |
253 | return ptr; | 253 | return ptr; |
254 | } | 254 | } |
255 | 255 | ||
256 | /* Memory allocated for string data in bytes. */ | 256 | /* Memory allocated for string data in bytes. */ |
257 | static unsigned int tomoyo_allocated_memory_for_savename; | 257 | static unsigned int tomoyo_allocated_memory_for_savename; |
258 | /* Quota for holding string data in bytes. */ | 258 | /* Quota for holding string data in bytes. */ |
259 | static unsigned int tomoyo_quota_for_savename; | 259 | static unsigned int tomoyo_quota_for_savename; |
260 | 260 | ||
261 | /* | 261 | /* |
262 | * TOMOYO uses this hash only when appending a string into the string | 262 | * TOMOYO uses this hash only when appending a string into the string |
263 | * table. Frequency of appending strings is very low. So we don't need | 263 | * table. Frequency of appending strings is very low. So we don't need |
264 | * large (e.g. 64k) hash size. 256 will be sufficient. | 264 | * large (e.g. 64k) hash size. 256 will be sufficient. |
265 | */ | 265 | */ |
266 | #define TOMOYO_MAX_HASH 256 | 266 | #define TOMOYO_MAX_HASH 256 |
267 | 267 | ||
268 | /* Structure for string data. */ | 268 | /* |
269 | * tomoyo_name_entry is a structure which is used for linking | ||
270 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
271 | * | ||
272 | * Since tomoyo_name_list manages a list of strings which are shared by | ||
273 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
274 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
275 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
276 | * when TOMOYO starts supporting garbage collector. | ||
277 | */ | ||
269 | struct tomoyo_name_entry { | 278 | struct tomoyo_name_entry { |
270 | struct list_head list; | 279 | struct list_head list; |
271 | struct tomoyo_path_info entry; | 280 | struct tomoyo_path_info entry; |
272 | }; | 281 | }; |
273 | 282 | ||
274 | /* Structure for available memory region. */ | 283 | /* Structure for available memory region. */ |
275 | struct tomoyo_free_memory_block_list { | 284 | struct tomoyo_free_memory_block_list { |
276 | struct list_head list; | 285 | struct list_head list; |
277 | char *ptr; /* Pointer to a free area. */ | 286 | char *ptr; /* Pointer to a free area. */ |
278 | int len; /* Length of the area. */ | 287 | int len; /* Length of the area. */ |
279 | }; | 288 | }; |
280 | 289 | ||
281 | /* | 290 | /* |
282 | * The list for "struct tomoyo_name_entry". | 291 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
283 | * | 292 | * Since same string data is likely used for multiple times (e.g. |
284 | * This list is updated only inside tomoyo_save_name(), thus | 293 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
285 | * no global mutex exists. | 294 | * "const struct tomoyo_path_info *". |
286 | */ | 295 | */ |
287 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 296 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
288 | 297 | ||
289 | /** | 298 | /** |
290 | * tomoyo_save_name - Allocate permanent memory for string data. | 299 | * tomoyo_save_name - Allocate permanent memory for string data. |
291 | * | 300 | * |
292 | * @name: The string to store into the permernent memory. | 301 | * @name: The string to store into the permernent memory. |
293 | * | 302 | * |
294 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 303 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
295 | * | 304 | * |
296 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | 305 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. |
297 | */ | 306 | */ |
298 | const struct tomoyo_path_info *tomoyo_save_name(const char *name) | 307 | const struct tomoyo_path_info *tomoyo_save_name(const char *name) |
299 | { | 308 | { |
300 | static LIST_HEAD(fmb_list); | 309 | static LIST_HEAD(fmb_list); |
301 | static DEFINE_MUTEX(lock); | 310 | static DEFINE_MUTEX(lock); |
302 | struct tomoyo_name_entry *ptr; | 311 | struct tomoyo_name_entry *ptr; |
303 | unsigned int hash; | 312 | unsigned int hash; |
304 | /* fmb contains available size in bytes. | 313 | /* fmb contains available size in bytes. |
305 | fmb is removed from the fmb_list when fmb->len becomes 0. */ | 314 | fmb is removed from the fmb_list when fmb->len becomes 0. */ |
306 | struct tomoyo_free_memory_block_list *fmb; | 315 | struct tomoyo_free_memory_block_list *fmb; |
307 | int len; | 316 | int len; |
308 | char *cp; | 317 | char *cp; |
309 | 318 | ||
310 | if (!name) | 319 | if (!name) |
311 | return NULL; | 320 | return NULL; |
312 | len = strlen(name) + 1; | 321 | len = strlen(name) + 1; |
313 | if (len > TOMOYO_MAX_PATHNAME_LEN) { | 322 | if (len > TOMOYO_MAX_PATHNAME_LEN) { |
314 | printk(KERN_WARNING "ERROR: Name too long " | 323 | printk(KERN_WARNING "ERROR: Name too long " |
315 | "for tomoyo_save_name().\n"); | 324 | "for tomoyo_save_name().\n"); |
316 | return NULL; | 325 | return NULL; |
317 | } | 326 | } |
318 | hash = full_name_hash((const unsigned char *) name, len - 1); | 327 | hash = full_name_hash((const unsigned char *) name, len - 1); |
319 | mutex_lock(&lock); | 328 | mutex_lock(&lock); |
320 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], | 329 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], |
321 | list) { | 330 | list) { |
322 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) | 331 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) |
323 | goto out; | 332 | goto out; |
324 | } | 333 | } |
325 | list_for_each_entry(fmb, &fmb_list, list) { | 334 | list_for_each_entry(fmb, &fmb_list, list) { |
326 | if (len <= fmb->len) | 335 | if (len <= fmb->len) |
327 | goto ready; | 336 | goto ready; |
328 | } | 337 | } |
329 | if (!tomoyo_quota_for_savename || | 338 | if (!tomoyo_quota_for_savename || |
330 | tomoyo_allocated_memory_for_savename + PATH_MAX | 339 | tomoyo_allocated_memory_for_savename + PATH_MAX |
331 | <= tomoyo_quota_for_savename) | 340 | <= tomoyo_quota_for_savename) |
332 | cp = kzalloc(PATH_MAX, GFP_KERNEL); | 341 | cp = kzalloc(PATH_MAX, GFP_KERNEL); |
333 | else | 342 | else |
334 | cp = NULL; | 343 | cp = NULL; |
335 | fmb = kzalloc(sizeof(*fmb), GFP_KERNEL); | 344 | fmb = kzalloc(sizeof(*fmb), GFP_KERNEL); |
336 | if (!cp || !fmb) { | 345 | if (!cp || !fmb) { |
337 | kfree(cp); | 346 | kfree(cp); |
338 | kfree(fmb); | 347 | kfree(fmb); |
339 | printk(KERN_WARNING "ERROR: Out of memory " | 348 | printk(KERN_WARNING "ERROR: Out of memory " |
340 | "for tomoyo_save_name().\n"); | 349 | "for tomoyo_save_name().\n"); |
341 | if (!tomoyo_policy_loaded) | 350 | if (!tomoyo_policy_loaded) |
342 | panic("MAC Initialization failed.\n"); | 351 | panic("MAC Initialization failed.\n"); |
343 | ptr = NULL; | 352 | ptr = NULL; |
344 | goto out; | 353 | goto out; |
345 | } | 354 | } |
346 | tomoyo_allocated_memory_for_savename += PATH_MAX; | 355 | tomoyo_allocated_memory_for_savename += PATH_MAX; |
347 | list_add(&fmb->list, &fmb_list); | 356 | list_add(&fmb->list, &fmb_list); |
348 | fmb->ptr = cp; | 357 | fmb->ptr = cp; |
349 | fmb->len = PATH_MAX; | 358 | fmb->len = PATH_MAX; |
350 | ready: | 359 | ready: |
351 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | 360 | ptr = tomoyo_alloc_element(sizeof(*ptr)); |
352 | if (!ptr) | 361 | if (!ptr) |
353 | goto out; | 362 | goto out; |
354 | ptr->entry.name = fmb->ptr; | 363 | ptr->entry.name = fmb->ptr; |
355 | memmove(fmb->ptr, name, len); | 364 | memmove(fmb->ptr, name, len); |
356 | tomoyo_fill_path_info(&ptr->entry); | 365 | tomoyo_fill_path_info(&ptr->entry); |
357 | fmb->ptr += len; | 366 | fmb->ptr += len; |
358 | fmb->len -= len; | 367 | fmb->len -= len; |
359 | list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]); | 368 | list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]); |
360 | if (fmb->len == 0) { | 369 | if (fmb->len == 0) { |
361 | list_del(&fmb->list); | 370 | list_del(&fmb->list); |
362 | kfree(fmb); | 371 | kfree(fmb); |
363 | } | 372 | } |
364 | out: | 373 | out: |
365 | mutex_unlock(&lock); | 374 | mutex_unlock(&lock); |
366 | return ptr ? &ptr->entry : NULL; | 375 | return ptr ? &ptr->entry : NULL; |
367 | } | 376 | } |
368 | 377 | ||
369 | /** | 378 | /** |
370 | * tomoyo_realpath_init - Initialize realpath related code. | 379 | * tomoyo_realpath_init - Initialize realpath related code. |
371 | */ | 380 | */ |
372 | void __init tomoyo_realpath_init(void) | 381 | void __init tomoyo_realpath_init(void) |
373 | { | 382 | { |
374 | int i; | 383 | int i; |
375 | 384 | ||
376 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | 385 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); |
377 | for (i = 0; i < TOMOYO_MAX_HASH; i++) | 386 | for (i = 0; i < TOMOYO_MAX_HASH; i++) |
378 | INIT_LIST_HEAD(&tomoyo_name_list[i]); | 387 | INIT_LIST_HEAD(&tomoyo_name_list[i]); |
379 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 388 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
380 | tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); | 389 | tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); |
381 | list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 390 | list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); |
382 | down_read(&tomoyo_domain_list_lock); | 391 | down_read(&tomoyo_domain_list_lock); |
383 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | 392 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) |
384 | panic("Can't register tomoyo_kernel_domain"); | 393 | panic("Can't register tomoyo_kernel_domain"); |
385 | up_read(&tomoyo_domain_list_lock); | 394 | up_read(&tomoyo_domain_list_lock); |
386 | } | 395 | } |
387 | 396 | ||
388 | /* Memory allocated for temporary purpose. */ | 397 | /* Memory allocated for temporary purpose. */ |
389 | static atomic_t tomoyo_dynamic_memory_size; | 398 | static atomic_t tomoyo_dynamic_memory_size; |
390 | 399 | ||
391 | /** | 400 | /** |
392 | * tomoyo_alloc - Allocate memory for temporary purpose. | 401 | * tomoyo_alloc - Allocate memory for temporary purpose. |
393 | * | 402 | * |
394 | * @size: Size in bytes. | 403 | * @size: Size in bytes. |
395 | * | 404 | * |
396 | * Returns pointer to allocated memory on success, NULL otherwise. | 405 | * Returns pointer to allocated memory on success, NULL otherwise. |
397 | */ | 406 | */ |
398 | void *tomoyo_alloc(const size_t size) | 407 | void *tomoyo_alloc(const size_t size) |
399 | { | 408 | { |
400 | void *p = kzalloc(size, GFP_KERNEL); | 409 | void *p = kzalloc(size, GFP_KERNEL); |
401 | if (p) | 410 | if (p) |
402 | atomic_add(ksize(p), &tomoyo_dynamic_memory_size); | 411 | atomic_add(ksize(p), &tomoyo_dynamic_memory_size); |
403 | return p; | 412 | return p; |
404 | } | 413 | } |
405 | 414 | ||
406 | /** | 415 | /** |
407 | * tomoyo_free - Release memory allocated by tomoyo_alloc(). | 416 | * tomoyo_free - Release memory allocated by tomoyo_alloc(). |
408 | * | 417 | * |
409 | * @p: Pointer returned by tomoyo_alloc(). May be NULL. | 418 | * @p: Pointer returned by tomoyo_alloc(). May be NULL. |
410 | * | 419 | * |
411 | * Returns nothing. | 420 | * Returns nothing. |
412 | */ | 421 | */ |
413 | void tomoyo_free(const void *p) | 422 | void tomoyo_free(const void *p) |
414 | { | 423 | { |
415 | if (p) { | 424 | if (p) { |
416 | atomic_sub(ksize(p), &tomoyo_dynamic_memory_size); | 425 | atomic_sub(ksize(p), &tomoyo_dynamic_memory_size); |
417 | kfree(p); | 426 | kfree(p); |
418 | } | 427 | } |
419 | } | 428 | } |
420 | 429 | ||
421 | /** | 430 | /** |
422 | * tomoyo_read_memory_counter - Check for memory usage in bytes. | 431 | * tomoyo_read_memory_counter - Check for memory usage in bytes. |
423 | * | 432 | * |
424 | * @head: Pointer to "struct tomoyo_io_buffer". | 433 | * @head: Pointer to "struct tomoyo_io_buffer". |
425 | * | 434 | * |
426 | * Returns memory usage. | 435 | * Returns memory usage. |
427 | */ | 436 | */ |
428 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | 437 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
429 | { | 438 | { |
430 | if (!head->read_eof) { | 439 | if (!head->read_eof) { |
431 | const unsigned int shared | 440 | const unsigned int shared |
432 | = tomoyo_allocated_memory_for_savename; | 441 | = tomoyo_allocated_memory_for_savename; |
433 | const unsigned int private | 442 | const unsigned int private |
434 | = tomoyo_allocated_memory_for_elements; | 443 | = tomoyo_allocated_memory_for_elements; |
435 | const unsigned int dynamic | 444 | const unsigned int dynamic |
436 | = atomic_read(&tomoyo_dynamic_memory_size); | 445 | = atomic_read(&tomoyo_dynamic_memory_size); |
437 | char buffer[64]; | 446 | char buffer[64]; |
438 | 447 | ||
439 | memset(buffer, 0, sizeof(buffer)); | 448 | memset(buffer, 0, sizeof(buffer)); |
440 | if (tomoyo_quota_for_savename) | 449 | if (tomoyo_quota_for_savename) |
441 | snprintf(buffer, sizeof(buffer) - 1, | 450 | snprintf(buffer, sizeof(buffer) - 1, |
442 | " (Quota: %10u)", | 451 | " (Quota: %10u)", |
443 | tomoyo_quota_for_savename); | 452 | tomoyo_quota_for_savename); |
444 | else | 453 | else |
445 | buffer[0] = '\0'; | 454 | buffer[0] = '\0'; |
446 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); | 455 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); |
447 | if (tomoyo_quota_for_elements) | 456 | if (tomoyo_quota_for_elements) |
448 | snprintf(buffer, sizeof(buffer) - 1, | 457 | snprintf(buffer, sizeof(buffer) - 1, |
449 | " (Quota: %10u)", | 458 | " (Quota: %10u)", |
450 | tomoyo_quota_for_elements); | 459 | tomoyo_quota_for_elements); |
451 | else | 460 | else |
452 | buffer[0] = '\0'; | 461 | buffer[0] = '\0'; |
453 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); | 462 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); |
454 | tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic); | 463 | tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic); |
455 | tomoyo_io_printf(head, "Total: %10u\n", | 464 | tomoyo_io_printf(head, "Total: %10u\n", |
456 | shared + private + dynamic); | 465 | shared + private + dynamic); |
457 | head->read_eof = true; | 466 | head->read_eof = true; |
458 | } | 467 | } |
459 | return 0; | 468 | return 0; |
460 | } | 469 | } |
461 | 470 | ||
462 | /** | 471 | /** |
463 | * tomoyo_write_memory_quota - Set memory quota. | 472 | * tomoyo_write_memory_quota - Set memory quota. |
464 | * | 473 | * |
465 | * @head: Pointer to "struct tomoyo_io_buffer". | 474 | * @head: Pointer to "struct tomoyo_io_buffer". |
466 | * | 475 | * |
467 | * Returns 0. | 476 | * Returns 0. |
468 | */ | 477 | */ |
469 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | 478 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) |
470 | { | 479 | { |
471 | char *data = head->write_buf; | 480 | char *data = head->write_buf; |
472 | unsigned int size; | 481 | unsigned int size; |
473 | 482 | ||
474 | if (sscanf(data, "Shared: %u", &size) == 1) | 483 | if (sscanf(data, "Shared: %u", &size) == 1) |
475 | tomoyo_quota_for_savename = size; | 484 | tomoyo_quota_for_savename = size; |
476 | else if (sscanf(data, "Private: %u", &size) == 1) | 485 | else if (sscanf(data, "Private: %u", &size) == 1) |
477 | tomoyo_quota_for_elements = size; | 486 | tomoyo_quota_for_elements = size; |
478 | return 0; | 487 | return 0; |
479 | } | 488 | } |
480 | 489 |
security/tomoyo/tomoyo.c
1 | /* | 1 | /* |
2 | * security/tomoyo/tomoyo.c | 2 | * security/tomoyo/tomoyo.c |
3 | * | 3 | * |
4 | * LSM hooks for TOMOYO Linux. | 4 | * LSM hooks for TOMOYO Linux. |
5 | * | 5 | * |
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | 6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 | * | 7 | * |
8 | * Version: 2.2.0 2009/04/01 | 8 | * Version: 2.2.0 2009/04/01 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/security.h> | 12 | #include <linux/security.h> |
13 | #include "common.h" | 13 | #include "common.h" |
14 | #include "tomoyo.h" | 14 | #include "tomoyo.h" |
15 | #include "realpath.h" | 15 | #include "realpath.h" |
16 | 16 | ||
17 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 17 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
18 | gfp_t gfp) | 18 | gfp_t gfp) |
19 | { | 19 | { |
20 | /* | 20 | /* |
21 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | 21 | * Since "struct tomoyo_domain_info *" is a sharable pointer, |
22 | * we don't need to duplicate. | 22 | * we don't need to duplicate. |
23 | */ | 23 | */ |
24 | new->security = old->security; | 24 | new->security = old->security; |
25 | return 0; | 25 | return 0; |
26 | } | 26 | } |
27 | 27 | ||
28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
29 | { | 29 | { |
30 | int rc; | 30 | int rc; |
31 | 31 | ||
32 | rc = cap_bprm_set_creds(bprm); | 32 | rc = cap_bprm_set_creds(bprm); |
33 | if (rc) | 33 | if (rc) |
34 | return rc; | 34 | return rc; |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Do only if this function is called for the first time of an execve | 37 | * Do only if this function is called for the first time of an execve |
38 | * operation. | 38 | * operation. |
39 | */ | 39 | */ |
40 | if (bprm->cred_prepared) | 40 | if (bprm->cred_prepared) |
41 | return 0; | 41 | return 0; |
42 | /* | 42 | /* |
43 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested | 43 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested |
44 | * for the first time. | 44 | * for the first time. |
45 | */ | 45 | */ |
46 | if (!tomoyo_policy_loaded) | 46 | if (!tomoyo_policy_loaded) |
47 | tomoyo_load_policy(bprm->filename); | 47 | tomoyo_load_policy(bprm->filename); |
48 | /* | 48 | /* |
49 | * Tell tomoyo_bprm_check_security() is called for the first time of an | 49 | * Tell tomoyo_bprm_check_security() is called for the first time of an |
50 | * execve operation. | 50 | * execve operation. |
51 | */ | 51 | */ |
52 | bprm->cred->security = NULL; | 52 | bprm->cred->security = NULL; |
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
55 | 55 | ||
56 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | 56 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) |
57 | { | 57 | { |
58 | struct tomoyo_domain_info *domain = bprm->cred->security; | 58 | struct tomoyo_domain_info *domain = bprm->cred->security; |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Execute permission is checked against pathname passed to do_execve() | 61 | * Execute permission is checked against pathname passed to do_execve() |
62 | * using current domain. | 62 | * using current domain. |
63 | */ | 63 | */ |
64 | if (!domain) { | 64 | if (!domain) { |
65 | struct tomoyo_domain_info *next_domain = NULL; | 65 | struct tomoyo_domain_info *next_domain = NULL; |
66 | int retval = tomoyo_find_next_domain(bprm, &next_domain); | 66 | int retval = tomoyo_find_next_domain(bprm, &next_domain); |
67 | 67 | ||
68 | if (!retval) | 68 | if (!retval) |
69 | bprm->cred->security = next_domain; | 69 | bprm->cred->security = next_domain; |
70 | return retval; | 70 | return retval; |
71 | } | 71 | } |
72 | /* | 72 | /* |
73 | * Read permission is checked against interpreters using next domain. | 73 | * Read permission is checked against interpreters using next domain. |
74 | * '1' is the result of open_to_namei_flags(O_RDONLY). | 74 | * '1' is the result of open_to_namei_flags(O_RDONLY). |
75 | */ | 75 | */ |
76 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1); | 76 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1); |
77 | } | 77 | } |
78 | 78 | ||
79 | #ifdef CONFIG_SYSCTL | 79 | #ifdef CONFIG_SYSCTL |
80 | 80 | ||
81 | static int tomoyo_prepend(char **buffer, int *buflen, const char *str) | 81 | static int tomoyo_prepend(char **buffer, int *buflen, const char *str) |
82 | { | 82 | { |
83 | int namelen = strlen(str); | 83 | int namelen = strlen(str); |
84 | 84 | ||
85 | if (*buflen < namelen) | 85 | if (*buflen < namelen) |
86 | return -ENOMEM; | 86 | return -ENOMEM; |
87 | *buflen -= namelen; | 87 | *buflen -= namelen; |
88 | *buffer -= namelen; | 88 | *buffer -= namelen; |
89 | memcpy(*buffer, str, namelen); | 89 | memcpy(*buffer, str, namelen); |
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | /** | 93 | /** |
94 | * tomoyo_sysctl_path - return the realpath of a ctl_table. | 94 | * tomoyo_sysctl_path - return the realpath of a ctl_table. |
95 | * @table: pointer to "struct ctl_table". | 95 | * @table: pointer to "struct ctl_table". |
96 | * | 96 | * |
97 | * Returns realpath(3) of the @table on success. | 97 | * Returns realpath(3) of the @table on success. |
98 | * Returns NULL on failure. | 98 | * Returns NULL on failure. |
99 | * | 99 | * |
100 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() | 100 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() |
101 | * if this function didn't return NULL. | 101 | * if this function didn't return NULL. |
102 | */ | 102 | */ |
103 | static char *tomoyo_sysctl_path(struct ctl_table *table) | 103 | static char *tomoyo_sysctl_path(struct ctl_table *table) |
104 | { | 104 | { |
105 | int buflen = TOMOYO_MAX_PATHNAME_LEN; | 105 | int buflen = TOMOYO_MAX_PATHNAME_LEN; |
106 | char *buf = tomoyo_alloc(buflen); | 106 | char *buf = tomoyo_alloc(buflen); |
107 | char *end = buf + buflen; | 107 | char *end = buf + buflen; |
108 | int error = -ENOMEM; | 108 | int error = -ENOMEM; |
109 | 109 | ||
110 | if (!buf) | 110 | if (!buf) |
111 | return NULL; | 111 | return NULL; |
112 | 112 | ||
113 | *--end = '\0'; | 113 | *--end = '\0'; |
114 | buflen--; | 114 | buflen--; |
115 | while (table) { | 115 | while (table) { |
116 | char num[32]; | 116 | char num[32]; |
117 | const char *sp = table->procname; | 117 | const char *sp = table->procname; |
118 | 118 | ||
119 | if (!sp) { | 119 | if (!sp) { |
120 | memset(num, 0, sizeof(num)); | 120 | memset(num, 0, sizeof(num)); |
121 | snprintf(num, sizeof(num) - 1, "=%d=", table->ctl_name); | 121 | snprintf(num, sizeof(num) - 1, "=%d=", table->ctl_name); |
122 | sp = num; | 122 | sp = num; |
123 | } | 123 | } |
124 | if (tomoyo_prepend(&end, &buflen, sp) || | 124 | if (tomoyo_prepend(&end, &buflen, sp) || |
125 | tomoyo_prepend(&end, &buflen, "/")) | 125 | tomoyo_prepend(&end, &buflen, "/")) |
126 | goto out; | 126 | goto out; |
127 | table = table->parent; | 127 | table = table->parent; |
128 | } | 128 | } |
129 | if (tomoyo_prepend(&end, &buflen, "/proc/sys")) | 129 | if (tomoyo_prepend(&end, &buflen, "/proc/sys")) |
130 | goto out; | 130 | goto out; |
131 | error = tomoyo_encode(buf, end - buf, end); | 131 | error = tomoyo_encode(buf, end - buf, end); |
132 | out: | 132 | out: |
133 | if (!error) | 133 | if (!error) |
134 | return buf; | 134 | return buf; |
135 | tomoyo_free(buf); | 135 | tomoyo_free(buf); |
136 | return NULL; | 136 | return NULL; |
137 | } | 137 | } |
138 | 138 | ||
139 | static int tomoyo_sysctl(struct ctl_table *table, int op) | 139 | static int tomoyo_sysctl(struct ctl_table *table, int op) |
140 | { | 140 | { |
141 | int error; | 141 | int error; |
142 | char *name; | 142 | char *name; |
143 | 143 | ||
144 | op &= MAY_READ | MAY_WRITE; | 144 | op &= MAY_READ | MAY_WRITE; |
145 | if (!op) | 145 | if (!op) |
146 | return 0; | 146 | return 0; |
147 | name = tomoyo_sysctl_path(table); | 147 | name = tomoyo_sysctl_path(table); |
148 | if (!name) | 148 | if (!name) |
149 | return -ENOMEM; | 149 | return -ENOMEM; |
150 | error = tomoyo_check_file_perm(tomoyo_domain(), name, op); | 150 | error = tomoyo_check_file_perm(tomoyo_domain(), name, op); |
151 | tomoyo_free(name); | 151 | tomoyo_free(name); |
152 | return error; | 152 | return error; |
153 | } | 153 | } |
154 | #endif | 154 | #endif |
155 | 155 | ||
156 | static int tomoyo_path_truncate(struct path *path, loff_t length, | 156 | static int tomoyo_path_truncate(struct path *path, loff_t length, |
157 | unsigned int time_attrs) | 157 | unsigned int time_attrs) |
158 | { | 158 | { |
159 | return tomoyo_check_1path_perm(tomoyo_domain(), | 159 | return tomoyo_check_1path_perm(tomoyo_domain(), |
160 | TOMOYO_TYPE_TRUNCATE_ACL, | 160 | TOMOYO_TYPE_TRUNCATE_ACL, |
161 | path); | 161 | path); |
162 | } | 162 | } |
163 | 163 | ||
164 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) | 164 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) |
165 | { | 165 | { |
166 | struct path path = { parent->mnt, dentry }; | 166 | struct path path = { parent->mnt, dentry }; |
167 | return tomoyo_check_1path_perm(tomoyo_domain(), | 167 | return tomoyo_check_1path_perm(tomoyo_domain(), |
168 | TOMOYO_TYPE_UNLINK_ACL, | 168 | TOMOYO_TYPE_UNLINK_ACL, |
169 | &path); | 169 | &path); |
170 | } | 170 | } |
171 | 171 | ||
172 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, | 172 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, |
173 | int mode) | 173 | int mode) |
174 | { | 174 | { |
175 | struct path path = { parent->mnt, dentry }; | 175 | struct path path = { parent->mnt, dentry }; |
176 | return tomoyo_check_1path_perm(tomoyo_domain(), | 176 | return tomoyo_check_1path_perm(tomoyo_domain(), |
177 | TOMOYO_TYPE_MKDIR_ACL, | 177 | TOMOYO_TYPE_MKDIR_ACL, |
178 | &path); | 178 | &path); |
179 | } | 179 | } |
180 | 180 | ||
181 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) | 181 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) |
182 | { | 182 | { |
183 | struct path path = { parent->mnt, dentry }; | 183 | struct path path = { parent->mnt, dentry }; |
184 | return tomoyo_check_1path_perm(tomoyo_domain(), | 184 | return tomoyo_check_1path_perm(tomoyo_domain(), |
185 | TOMOYO_TYPE_RMDIR_ACL, | 185 | TOMOYO_TYPE_RMDIR_ACL, |
186 | &path); | 186 | &path); |
187 | } | 187 | } |
188 | 188 | ||
189 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, | 189 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, |
190 | const char *old_name) | 190 | const char *old_name) |
191 | { | 191 | { |
192 | struct path path = { parent->mnt, dentry }; | 192 | struct path path = { parent->mnt, dentry }; |
193 | return tomoyo_check_1path_perm(tomoyo_domain(), | 193 | return tomoyo_check_1path_perm(tomoyo_domain(), |
194 | TOMOYO_TYPE_SYMLINK_ACL, | 194 | TOMOYO_TYPE_SYMLINK_ACL, |
195 | &path); | 195 | &path); |
196 | } | 196 | } |
197 | 197 | ||
198 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, | 198 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, |
199 | int mode, unsigned int dev) | 199 | int mode, unsigned int dev) |
200 | { | 200 | { |
201 | struct path path = { parent->mnt, dentry }; | 201 | struct path path = { parent->mnt, dentry }; |
202 | int type = TOMOYO_TYPE_CREATE_ACL; | 202 | int type = TOMOYO_TYPE_CREATE_ACL; |
203 | 203 | ||
204 | switch (mode & S_IFMT) { | 204 | switch (mode & S_IFMT) { |
205 | case S_IFCHR: | 205 | case S_IFCHR: |
206 | type = TOMOYO_TYPE_MKCHAR_ACL; | 206 | type = TOMOYO_TYPE_MKCHAR_ACL; |
207 | break; | 207 | break; |
208 | case S_IFBLK: | 208 | case S_IFBLK: |
209 | type = TOMOYO_TYPE_MKBLOCK_ACL; | 209 | type = TOMOYO_TYPE_MKBLOCK_ACL; |
210 | break; | 210 | break; |
211 | case S_IFIFO: | 211 | case S_IFIFO: |
212 | type = TOMOYO_TYPE_MKFIFO_ACL; | 212 | type = TOMOYO_TYPE_MKFIFO_ACL; |
213 | break; | 213 | break; |
214 | case S_IFSOCK: | 214 | case S_IFSOCK: |
215 | type = TOMOYO_TYPE_MKSOCK_ACL; | 215 | type = TOMOYO_TYPE_MKSOCK_ACL; |
216 | break; | 216 | break; |
217 | } | 217 | } |
218 | return tomoyo_check_1path_perm(tomoyo_domain(), | 218 | return tomoyo_check_1path_perm(tomoyo_domain(), |
219 | type, &path); | 219 | type, &path); |
220 | } | 220 | } |
221 | 221 | ||
222 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | 222 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, |
223 | struct dentry *new_dentry) | 223 | struct dentry *new_dentry) |
224 | { | 224 | { |
225 | struct path path1 = { new_dir->mnt, old_dentry }; | 225 | struct path path1 = { new_dir->mnt, old_dentry }; |
226 | struct path path2 = { new_dir->mnt, new_dentry }; | 226 | struct path path2 = { new_dir->mnt, new_dentry }; |
227 | return tomoyo_check_2path_perm(tomoyo_domain(), | 227 | return tomoyo_check_2path_perm(tomoyo_domain(), |
228 | TOMOYO_TYPE_LINK_ACL, | 228 | TOMOYO_TYPE_LINK_ACL, |
229 | &path1, &path2); | 229 | &path1, &path2); |
230 | } | 230 | } |
231 | 231 | ||
232 | static int tomoyo_path_rename(struct path *old_parent, | 232 | static int tomoyo_path_rename(struct path *old_parent, |
233 | struct dentry *old_dentry, | 233 | struct dentry *old_dentry, |
234 | struct path *new_parent, | 234 | struct path *new_parent, |
235 | struct dentry *new_dentry) | 235 | struct dentry *new_dentry) |
236 | { | 236 | { |
237 | struct path path1 = { old_parent->mnt, old_dentry }; | 237 | struct path path1 = { old_parent->mnt, old_dentry }; |
238 | struct path path2 = { new_parent->mnt, new_dentry }; | 238 | struct path path2 = { new_parent->mnt, new_dentry }; |
239 | return tomoyo_check_2path_perm(tomoyo_domain(), | 239 | return tomoyo_check_2path_perm(tomoyo_domain(), |
240 | TOMOYO_TYPE_RENAME_ACL, | 240 | TOMOYO_TYPE_RENAME_ACL, |
241 | &path1, &path2); | 241 | &path1, &path2); |
242 | } | 242 | } |
243 | 243 | ||
244 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | 244 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, |
245 | unsigned long arg) | 245 | unsigned long arg) |
246 | { | 246 | { |
247 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) | 247 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) |
248 | return tomoyo_check_rewrite_permission(tomoyo_domain(), file); | 248 | return tomoyo_check_rewrite_permission(tomoyo_domain(), file); |
249 | return 0; | 249 | return 0; |
250 | } | 250 | } |
251 | 251 | ||
252 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | 252 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) |
253 | { | 253 | { |
254 | int flags = f->f_flags; | 254 | int flags = f->f_flags; |
255 | 255 | ||
256 | if ((flags + 1) & O_ACCMODE) | 256 | if ((flags + 1) & O_ACCMODE) |
257 | flags++; | 257 | flags++; |
258 | flags |= f->f_flags & (O_APPEND | O_TRUNC); | 258 | flags |= f->f_flags & (O_APPEND | O_TRUNC); |
259 | /* Don't check read permission here if called from do_execve(). */ | 259 | /* Don't check read permission here if called from do_execve(). */ |
260 | if (current->in_execve) | 260 | if (current->in_execve) |
261 | return 0; | 261 | return 0; |
262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
263 | } | 263 | } |
264 | 264 | ||
265 | /* | ||
266 | * tomoyo_security_ops is a "struct security_operations" which is used for | ||
267 | * registering TOMOYO. | ||
268 | */ | ||
265 | static struct security_operations tomoyo_security_ops = { | 269 | static struct security_operations tomoyo_security_ops = { |
266 | .name = "tomoyo", | 270 | .name = "tomoyo", |
267 | .cred_prepare = tomoyo_cred_prepare, | 271 | .cred_prepare = tomoyo_cred_prepare, |
268 | .bprm_set_creds = tomoyo_bprm_set_creds, | 272 | .bprm_set_creds = tomoyo_bprm_set_creds, |
269 | .bprm_check_security = tomoyo_bprm_check_security, | 273 | .bprm_check_security = tomoyo_bprm_check_security, |
270 | #ifdef CONFIG_SYSCTL | 274 | #ifdef CONFIG_SYSCTL |
271 | .sysctl = tomoyo_sysctl, | 275 | .sysctl = tomoyo_sysctl, |
272 | #endif | 276 | #endif |
273 | .file_fcntl = tomoyo_file_fcntl, | 277 | .file_fcntl = tomoyo_file_fcntl, |
274 | .dentry_open = tomoyo_dentry_open, | 278 | .dentry_open = tomoyo_dentry_open, |
275 | .path_truncate = tomoyo_path_truncate, | 279 | .path_truncate = tomoyo_path_truncate, |
276 | .path_unlink = tomoyo_path_unlink, | 280 | .path_unlink = tomoyo_path_unlink, |
277 | .path_mkdir = tomoyo_path_mkdir, | 281 | .path_mkdir = tomoyo_path_mkdir, |
278 | .path_rmdir = tomoyo_path_rmdir, | 282 | .path_rmdir = tomoyo_path_rmdir, |
279 | .path_symlink = tomoyo_path_symlink, | 283 | .path_symlink = tomoyo_path_symlink, |
280 | .path_mknod = tomoyo_path_mknod, | 284 | .path_mknod = tomoyo_path_mknod, |
281 | .path_link = tomoyo_path_link, | 285 | .path_link = tomoyo_path_link, |
282 | .path_rename = tomoyo_path_rename, | 286 | .path_rename = tomoyo_path_rename, |
283 | }; | 287 | }; |
284 | 288 | ||
285 | static int __init tomoyo_init(void) | 289 | static int __init tomoyo_init(void) |
286 | { | 290 | { |
287 | struct cred *cred = (struct cred *) current_cred(); | 291 | struct cred *cred = (struct cred *) current_cred(); |
288 | 292 | ||
289 | if (!security_module_enable(&tomoyo_security_ops)) | 293 | if (!security_module_enable(&tomoyo_security_ops)) |
290 | return 0; | 294 | return 0; |
291 | /* register ourselves with the security framework */ | 295 | /* register ourselves with the security framework */ |
292 | if (register_security(&tomoyo_security_ops)) | 296 | if (register_security(&tomoyo_security_ops)) |
293 | panic("Failure registering TOMOYO Linux"); | 297 | panic("Failure registering TOMOYO Linux"); |
294 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 298 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
295 | cred->security = &tomoyo_kernel_domain; | 299 | cred->security = &tomoyo_kernel_domain; |
296 | tomoyo_realpath_init(); | 300 | tomoyo_realpath_init(); |
297 | return 0; | 301 | return 0; |
298 | } | 302 | } |
299 | 303 | ||
300 | security_initcall(tomoyo_init); | 304 | security_initcall(tomoyo_init); |
301 | 305 |