Blame view
security/tomoyo/domain.c
24.9 KB
26a2a1c9e Domain transition... |
1 2 3 |
/* * security/tomoyo/domain.c * |
0f2a55d5b TOMOYO: Update ke... |
4 |
* Copyright (C) 2005-2011 NTT DATA CORPORATION |
26a2a1c9e Domain transition... |
5 6 7 |
*/ #include "common.h" |
26a2a1c9e Domain transition... |
8 |
#include <linux/binfmts.h> |
5a0e3ad6a include cleanup: ... |
9 |
#include <linux/slab.h> |
26a2a1c9e Domain transition... |
10 11 12 13 14 |
/* Variables definitions.*/ /* The initial domain. */ struct tomoyo_domain_info tomoyo_kernel_domain; |
237ab459f TOMOYO: Use callb... |
15 |
/** |
36f5e1ffb TOMOYO: Use callb... |
16 17 18 19 |
* tomoyo_update_policy - Update an entry for exception policy. * * @new_entry: Pointer to "struct tomoyo_acl_info". * @size: Size of @new_entry in bytes. |
a238cf5b8 TOMOYO: Use struc... |
20 |
* @param: Pointer to "struct tomoyo_acl_param". |
36f5e1ffb TOMOYO: Use callb... |
21 22 23 24 25 26 27 |
* @check_duplicate: Callback function to find duplicated entry. * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
a238cf5b8 TOMOYO: Use struc... |
28 |
struct tomoyo_acl_param *param, |
36f5e1ffb TOMOYO: Use callb... |
29 30 31 32 33 |
bool (*check_duplicate) (const struct tomoyo_acl_head *, const struct tomoyo_acl_head *)) { |
a238cf5b8 TOMOYO: Use struc... |
34 |
int error = param->is_delete ? -ENOENT : -ENOMEM; |
36f5e1ffb TOMOYO: Use callb... |
35 |
struct tomoyo_acl_head *entry; |
a238cf5b8 TOMOYO: Use struc... |
36 |
struct list_head *list = param->list; |
36f5e1ffb TOMOYO: Use callb... |
37 38 39 40 |
if (mutex_lock_interruptible(&tomoyo_policy_lock)) return -ENOMEM; list_for_each_entry_rcu(entry, list, list) { |
f9732ea14 TOMOYO: Simplify ... |
41 42 |
if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) continue; |
36f5e1ffb TOMOYO: Use callb... |
43 44 |
if (!check_duplicate(entry, new_entry)) continue; |
a238cf5b8 TOMOYO: Use struc... |
45 |
entry->is_deleted = param->is_delete; |
36f5e1ffb TOMOYO: Use callb... |
46 47 48 |
error = 0; break; } |
a238cf5b8 TOMOYO: Use struc... |
49 |
if (error && !param->is_delete) { |
36f5e1ffb TOMOYO: Use callb... |
50 51 52 53 54 55 56 57 58 59 60 |
entry = tomoyo_commit_ok(new_entry, size); if (entry) { list_add_tail_rcu(&entry->list, list); error = 0; } } mutex_unlock(&tomoyo_policy_lock); return error; } /** |
0df7e8b8f TOMOYO: Cleanup p... |
61 62 63 64 65 66 67 68 69 70 |
* tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry. * * @a: Pointer to "struct tomoyo_acl_info". * @b: Pointer to "struct tomoyo_acl_info". * * Returns true if @a == @b, false otherwise. */ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, const struct tomoyo_acl_info *b) { |
2066a3612 TOMOYO: Allow usi... |
71 |
return a->type == b->type && a->cond == b->cond; |
0df7e8b8f TOMOYO: Cleanup p... |
72 73 74 |
} /** |
237ab459f TOMOYO: Use callb... |
75 76 77 78 |
* tomoyo_update_domain - Update an entry for domain policy. * * @new_entry: Pointer to "struct tomoyo_acl_info". * @size: Size of @new_entry in bytes. |
a238cf5b8 TOMOYO: Use struc... |
79 |
* @param: Pointer to "struct tomoyo_acl_param". |
237ab459f TOMOYO: Use callb... |
80 81 82 83 84 85 86 87 |
* @check_duplicate: Callback function to find duplicated entry. * @merge_duplicate: Callback function to merge duplicated entry. * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
a238cf5b8 TOMOYO: Use struc... |
88 |
struct tomoyo_acl_param *param, |
237ab459f TOMOYO: Use callb... |
89 90 91 92 93 94 95 96 |
bool (*check_duplicate) (const struct tomoyo_acl_info *, const struct tomoyo_acl_info *), bool (*merge_duplicate) (struct tomoyo_acl_info *, struct tomoyo_acl_info *, const bool)) { |
a238cf5b8 TOMOYO: Use struc... |
97 |
const bool is_delete = param->is_delete; |
237ab459f TOMOYO: Use callb... |
98 99 |
int error = is_delete ? -ENOENT : -ENOMEM; struct tomoyo_acl_info *entry; |
a238cf5b8 TOMOYO: Use struc... |
100 |
struct list_head * const list = param->list; |
237ab459f TOMOYO: Use callb... |
101 |
|
2066a3612 TOMOYO: Allow usi... |
102 103 104 105 |
if (param->data[0]) { new_entry->cond = tomoyo_get_condition(param); if (!new_entry->cond) return -EINVAL; |
6bce98edc TOMOYO: Allow spe... |
106 107 108 109 110 111 112 113 114 |
/* * Domain transition preference is allowed for only * "file execute" entries. */ if (new_entry->cond->transit && !(new_entry->type == TOMOYO_TYPE_PATH_ACL && container_of(new_entry, struct tomoyo_path_acl, head) ->perm == 1 << TOMOYO_TYPE_EXECUTE)) goto out; |
2066a3612 TOMOYO: Allow usi... |
115 |
} |
237ab459f TOMOYO: Use callb... |
116 |
if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
2066a3612 TOMOYO: Allow usi... |
117 |
goto out; |
a238cf5b8 TOMOYO: Use struc... |
118 |
list_for_each_entry_rcu(entry, list, list) { |
f9732ea14 TOMOYO: Simplify ... |
119 120 |
if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) continue; |
0df7e8b8f TOMOYO: Cleanup p... |
121 122 |
if (!tomoyo_same_acl_head(entry, new_entry) || !check_duplicate(entry, new_entry)) |
237ab459f TOMOYO: Use callb... |
123 124 125 126 127 128 129 130 131 132 133 134 |
continue; if (merge_duplicate) entry->is_deleted = merge_duplicate(entry, new_entry, is_delete); else entry->is_deleted = is_delete; error = 0; break; } if (error && !is_delete) { entry = tomoyo_commit_ok(new_entry, size); if (entry) { |
a238cf5b8 TOMOYO: Use struc... |
135 |
list_add_tail_rcu(&entry->list, list); |
237ab459f TOMOYO: Use callb... |
136 137 138 139 |
error = 0; } } mutex_unlock(&tomoyo_policy_lock); |
2066a3612 TOMOYO: Allow usi... |
140 141 |
out: tomoyo_put_condition(new_entry->cond); |
237ab459f TOMOYO: Use callb... |
142 143 |
return error; } |
32997144f TOMOYO: Add ACL g... |
144 145 146 147 148 149 150 151 152 153 |
/** * tomoyo_check_acl - Do permission check. * * @r: Pointer to "struct tomoyo_request_info". * @check_entry: Callback function to check type specific parameters. * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ |
99a852596 TOMOYO: Use callb... |
154 |
void tomoyo_check_acl(struct tomoyo_request_info *r, |
484ca79c6 TOMOYO: Use pathn... |
155 |
bool (*check_entry) (struct tomoyo_request_info *, |
99a852596 TOMOYO: Use callb... |
156 157 158 159 |
const struct tomoyo_acl_info *)) { const struct tomoyo_domain_info *domain = r->domain; struct tomoyo_acl_info *ptr; |
32997144f TOMOYO: Add ACL g... |
160 161 |
bool retried = false; const struct list_head *list = &domain->acl_info_list; |
99a852596 TOMOYO: Use callb... |
162 |
|
32997144f TOMOYO: Add ACL g... |
163 164 |
retry: list_for_each_entry_rcu(ptr, list, list) { |
99a852596 TOMOYO: Use callb... |
165 166 |
if (ptr->is_deleted || ptr->type != r->param_type) continue; |
2066a3612 TOMOYO: Allow usi... |
167 168 169 170 |
if (!check_entry(r, ptr)) continue; if (!tomoyo_condition(r, ptr->cond)) continue; |
1f067a682 TOMOYO: Allow con... |
171 |
r->matched_acl = ptr; |
2066a3612 TOMOYO: Allow usi... |
172 173 |
r->granted = true; return; |
99a852596 TOMOYO: Use callb... |
174 |
} |
32997144f TOMOYO: Add ACL g... |
175 176 |
if (!retried) { retried = true; |
bd03a3e4c TOMOYO: Add polic... |
177 |
list = &domain->ns->acl_group[domain->group]; |
32997144f TOMOYO: Add ACL g... |
178 179 |
goto retry; } |
99a852596 TOMOYO: Use callb... |
180 181 |
r->granted = false; } |
a230f9e71 TOMOYO: Use array... |
182 |
/* The list for "struct tomoyo_domain_info". */ |
26a2a1c9e Domain transition... |
183 |
LIST_HEAD(tomoyo_domain_list); |
26a2a1c9e Domain transition... |
184 |
|
26a2a1c9e Domain transition... |
185 |
/** |
e2bf69077 TOMOYO: Rename sy... |
186 |
* tomoyo_last_word - Get last component of a domainname. |
26a2a1c9e Domain transition... |
187 |
* |
bd03a3e4c TOMOYO: Add polic... |
188 |
* @name: Domainname to check. |
26a2a1c9e Domain transition... |
189 |
* |
e2bf69077 TOMOYO: Rename sy... |
190 |
* Returns the last word of @domainname. |
26a2a1c9e Domain transition... |
191 |
*/ |
e2bf69077 TOMOYO: Rename sy... |
192 |
static const char *tomoyo_last_word(const char *name) |
26a2a1c9e Domain transition... |
193 |
{ |
0f2a55d5b TOMOYO: Update ke... |
194 195 196 197 |
const char *cp = strrchr(name, ' '); if (cp) return cp + 1; return name; |
26a2a1c9e Domain transition... |
198 |
} |
a238cf5b8 TOMOYO: Use struc... |
199 200 201 202 203 204 205 206 |
/** * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry. * * @a: Pointer to "struct tomoyo_acl_head". * @b: Pointer to "struct tomoyo_acl_head". * * Returns true if @a == @b, false otherwise. */ |
e2bf69077 TOMOYO: Rename sy... |
207 208 |
static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, const struct tomoyo_acl_head *b) |
36f5e1ffb TOMOYO: Use callb... |
209 |
{ |
5448ec4f5 TOMOYO: Use commo... |
210 211 212 213 214 215 216 |
const struct tomoyo_transition_control *p1 = container_of(a, typeof(*p1), head); const struct tomoyo_transition_control *p2 = container_of(b, typeof(*p2), head); return p1->type == p2->type && p1->is_last_name == p2->is_last_name |
36f5e1ffb TOMOYO: Use callb... |
217 218 219 |
&& p1->domainname == p2->domainname && p1->program == p2->program; } |
26a2a1c9e Domain transition... |
220 |
/** |
a238cf5b8 TOMOYO: Use struc... |
221 |
* tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
26a2a1c9e Domain transition... |
222 |
* |
a238cf5b8 TOMOYO: Use struc... |
223 224 |
* @param: Pointer to "struct tomoyo_acl_param". * @type: Type of this entry. |
26a2a1c9e Domain transition... |
225 226 227 |
* * Returns 0 on success, negative value otherwise. */ |
a238cf5b8 TOMOYO: Use struc... |
228 229 |
int tomoyo_write_transition_control(struct tomoyo_acl_param *param, const u8 type) |
26a2a1c9e Domain transition... |
230 |
{ |
5448ec4f5 TOMOYO: Use commo... |
231 |
struct tomoyo_transition_control e = { .type = type }; |
a238cf5b8 TOMOYO: Use struc... |
232 233 234 235 236 237 238 239 240 241 242 |
int error = param->is_delete ? -ENOENT : -ENOMEM; char *program = param->data; char *domainname = strstr(program, " from "); if (domainname) { *domainname = '\0'; domainname += 6; } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || type == TOMOYO_TRANSITION_CONTROL_KEEP) { domainname = program; program = NULL; } |
0d2171d71 TOMOYO: Rename di... |
243 |
if (program && strcmp(program, "any")) { |
5448ec4f5 TOMOYO: Use commo... |
244 245 246 247 248 249 |
if (!tomoyo_correct_path(program)) return -EINVAL; e.program = tomoyo_get_name(program); if (!e.program) goto out; } |
0d2171d71 TOMOYO: Rename di... |
250 |
if (domainname && strcmp(domainname, "any")) { |
5448ec4f5 TOMOYO: Use commo... |
251 252 253 |
if (!tomoyo_correct_domain(domainname)) { if (!tomoyo_correct_path(domainname)) goto out; |
9e4b50e93 TOMOYO: Use stack... |
254 |
e.is_last_name = true; |
5448ec4f5 TOMOYO: Use commo... |
255 |
} |
9e4b50e93 TOMOYO: Use stack... |
256 257 |
e.domainname = tomoyo_get_name(domainname); if (!e.domainname) |
ca0b7df33 TOMOYO: Reduce li... |
258 |
goto out; |
26a2a1c9e Domain transition... |
259 |
} |
bd03a3e4c TOMOYO: Add polic... |
260 |
param->list = ¶m->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
a238cf5b8 TOMOYO: Use struc... |
261 |
error = tomoyo_update_policy(&e.head, sizeof(e), param, |
e2bf69077 TOMOYO: Rename sy... |
262 |
tomoyo_same_transition_control); |
a238cf5b8 TOMOYO: Use struc... |
263 |
out: |
9e4b50e93 TOMOYO: Use stack... |
264 265 |
tomoyo_put_name(e.domainname); tomoyo_put_name(e.program); |
26a2a1c9e Domain transition... |
266 267 268 269 |
return error; } /** |
bd03a3e4c TOMOYO: Add polic... |
270 |
* tomoyo_scan_transition - Try to find specific domain transition type. |
26a2a1c9e Domain transition... |
271 |
* |
bd03a3e4c TOMOYO: Add polic... |
272 273 274 275 276 |
* @list: Pointer to "struct list_head". * @domainname: The name of current domain. * @program: The name of requested program. * @last_name: The last component of @domainname. * @type: One of values in "enum tomoyo_transition_type". |
26a2a1c9e Domain transition... |
277 |
* |
bd03a3e4c TOMOYO: Add polic... |
278 |
* Returns true if found one, false otherwise. |
fdb8ebb72 TOMOYO: Use RCU p... |
279 280 |
* * Caller holds tomoyo_read_lock(). |
26a2a1c9e Domain transition... |
281 |
*/ |
bd03a3e4c TOMOYO: Add polic... |
282 283 284 285 |
static inline bool tomoyo_scan_transition (const struct list_head *list, const struct tomoyo_path_info *domainname, const struct tomoyo_path_info *program, const char *last_name, const enum tomoyo_transition_type type) |
26a2a1c9e Domain transition... |
286 |
{ |
5448ec4f5 TOMOYO: Use commo... |
287 |
const struct tomoyo_transition_control *ptr; |
bd03a3e4c TOMOYO: Add polic... |
288 289 290 291 292 293 294 295 |
list_for_each_entry_rcu(ptr, list, head.list) { if (ptr->head.is_deleted || ptr->type != type) continue; if (ptr->domainname) { if (!ptr->is_last_name) { if (ptr->domainname != domainname) continue; } else { |
5448ec4f5 TOMOYO: Use commo... |
296 |
/* |
bd03a3e4c TOMOYO: Add polic... |
297 298 |
* Use direct strcmp() since this is * unlikely used. |
5448ec4f5 TOMOYO: Use commo... |
299 |
*/ |
bd03a3e4c TOMOYO: Add polic... |
300 301 |
if (strcmp(ptr->domainname->name, last_name)) continue; |
5448ec4f5 TOMOYO: Use commo... |
302 |
} |
26a2a1c9e Domain transition... |
303 |
} |
bd03a3e4c TOMOYO: Add polic... |
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
if (ptr->program && tomoyo_pathcmp(ptr->program, program)) continue; return true; } return false; } /** * tomoyo_transition_type - Get domain transition type. * * @ns: Pointer to "struct tomoyo_policy_namespace". * @domainname: The name of current domain. * @program: The name of requested program. * * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if * executing @program reinitializes domain transition within that namespace, * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname , * others otherwise. * * Caller holds tomoyo_read_lock(). */ static enum tomoyo_transition_type tomoyo_transition_type (const struct tomoyo_policy_namespace *ns, const struct tomoyo_path_info *domainname, const struct tomoyo_path_info *program) { const char *last_name = tomoyo_last_word(domainname->name); enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; while (type < TOMOYO_MAX_TRANSITION_TYPE) { const struct list_head * const list = &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; if (!tomoyo_scan_transition(list, domainname, program, last_name, type)) { type++; continue; } if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET && type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) break; /* * Do not check for reset_domain if no_reset_domain matched. * Do not check for initialize_domain if no_initialize_domain * matched. */ type++; type++; |
26a2a1c9e Domain transition... |
351 |
} |
5448ec4f5 TOMOYO: Use commo... |
352 |
return type; |
26a2a1c9e Domain transition... |
353 |
} |
a238cf5b8 TOMOYO: Use struc... |
354 355 356 357 358 359 360 361 |
/** * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry. * * @a: Pointer to "struct tomoyo_acl_head". * @b: Pointer to "struct tomoyo_acl_head". * * Returns true if @a == @b, false otherwise. */ |
e2bf69077 TOMOYO: Rename sy... |
362 363 |
static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, const struct tomoyo_acl_head *b) |
36f5e1ffb TOMOYO: Use callb... |
364 |
{ |
a238cf5b8 TOMOYO: Use struc... |
365 366 367 368 |
const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head); const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head); |
36f5e1ffb TOMOYO: Use callb... |
369 370 371 |
return p1->original_name == p2->original_name && p1->aggregated_name == p2->aggregated_name; } |
1084307ca TOMOYO: Add pathn... |
372 |
/** |
a238cf5b8 TOMOYO: Use struc... |
373 |
* tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. |
1084307ca TOMOYO: Add pathn... |
374 |
* |
a238cf5b8 TOMOYO: Use struc... |
375 |
* @param: Pointer to "struct tomoyo_acl_param". |
1084307ca TOMOYO: Add pathn... |
376 377 378 379 380 |
* * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ |
a238cf5b8 TOMOYO: Use struc... |
381 |
int tomoyo_write_aggregator(struct tomoyo_acl_param *param) |
1084307ca TOMOYO: Add pathn... |
382 |
{ |
e2bf69077 TOMOYO: Rename sy... |
383 |
struct tomoyo_aggregator e = { }; |
a238cf5b8 TOMOYO: Use struc... |
384 385 386 387 |
int error = param->is_delete ? -ENOENT : -ENOMEM; const char *original_name = tomoyo_read_token(param); const char *aggregated_name = tomoyo_read_token(param); if (!tomoyo_correct_word(original_name) || |
75093152a TOMOYO: Rename sy... |
388 |
!tomoyo_correct_path(aggregated_name)) |
1084307ca TOMOYO: Add pathn... |
389 390 391 392 393 394 |
return -EINVAL; e.original_name = tomoyo_get_name(original_name); e.aggregated_name = tomoyo_get_name(aggregated_name); if (!e.original_name || !e.aggregated_name || e.aggregated_name->is_patterned) /* No patterns allowed. */ goto out; |
bd03a3e4c TOMOYO: Add polic... |
395 |
param->list = ¶m->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
a238cf5b8 TOMOYO: Use struc... |
396 |
error = tomoyo_update_policy(&e.head, sizeof(e), param, |
e2bf69077 TOMOYO: Rename sy... |
397 |
tomoyo_same_aggregator); |
a238cf5b8 TOMOYO: Use struc... |
398 |
out: |
1084307ca TOMOYO: Add pathn... |
399 400 401 402 403 404 |
tomoyo_put_name(e.original_name); tomoyo_put_name(e.aggregated_name); return error; } /** |
bd03a3e4c TOMOYO: Add polic... |
405 |
* tomoyo_find_namespace - Find specified namespace. |
26a2a1c9e Domain transition... |
406 |
* |
bd03a3e4c TOMOYO: Add polic... |
407 408 |
* @name: Name of namespace to find. * @len: Length of @name. |
26a2a1c9e Domain transition... |
409 |
* |
bd03a3e4c TOMOYO: Add polic... |
410 411 |
* Returns pointer to "struct tomoyo_policy_namespace" if found, * NULL otherwise. |
fdb8ebb72 TOMOYO: Use RCU p... |
412 413 |
* * Caller holds tomoyo_read_lock(). |
26a2a1c9e Domain transition... |
414 |
*/ |
bd03a3e4c TOMOYO: Add polic... |
415 416 |
static struct tomoyo_policy_namespace *tomoyo_find_namespace (const char *name, const unsigned int len) |
26a2a1c9e Domain transition... |
417 |
{ |
bd03a3e4c TOMOYO: Add polic... |
418 419 420 421 422 423 424 425 426 |
struct tomoyo_policy_namespace *ns; list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { if (strncmp(name, ns->name, len) || (name[len] && name[len] != ' ')) continue; return ns; } return NULL; } |
26a2a1c9e Domain transition... |
427 |
|
bd03a3e4c TOMOYO: Add polic... |
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
/** * tomoyo_assign_namespace - Create a new namespace. * * @domainname: Name of namespace to create. * * Returns pointer to "struct tomoyo_policy_namespace" on success, * NULL otherwise. * * Caller holds tomoyo_read_lock(). */ struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) { struct tomoyo_policy_namespace *ptr; struct tomoyo_policy_namespace *entry; const char *cp = domainname; unsigned int len = 0; while (*cp && *cp++ != ' ') len++; ptr = tomoyo_find_namespace(domainname, len); if (ptr) return ptr; if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname)) |
ca0b7df33 TOMOYO: Reduce li... |
450 |
return NULL; |
bd03a3e4c TOMOYO: Add polic... |
451 452 |
entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS); if (!entry) |
ca0b7df33 TOMOYO: Reduce li... |
453 |
return NULL; |
292823814 TOMOYO: Use mutex... |
454 455 |
if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; |
bd03a3e4c TOMOYO: Add polic... |
456 457 458 459 460 461 462 463 |
ptr = tomoyo_find_namespace(domainname, len); if (!ptr && tomoyo_memory_ok(entry)) { char *name = (char *) (entry + 1); ptr = entry; memmove(name, domainname, len); name[len] = '\0'; entry->name = name; tomoyo_init_policy_namespace(entry); |
ca0b7df33 TOMOYO: Reduce li... |
464 |
entry = NULL; |
26a2a1c9e Domain transition... |
465 |
} |
f737d95dd TOMOYO: Replace r... |
466 |
mutex_unlock(&tomoyo_policy_lock); |
bd03a3e4c TOMOYO: Add polic... |
467 |
out: |
ca0b7df33 TOMOYO: Reduce li... |
468 |
kfree(entry); |
bd03a3e4c TOMOYO: Add polic... |
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
return ptr; } /** * tomoyo_namespace_jump - Check for namespace jump. * * @domainname: Name of domain. * * Returns true if namespace differs, false otherwise. */ static bool tomoyo_namespace_jump(const char *domainname) { const char *namespace = tomoyo_current_namespace()->name; const int len = strlen(namespace); return strncmp(domainname, namespace, len) || (domainname[len] && domainname[len] != ' '); } /** * tomoyo_assign_domain - Create a domain or a namespace. * * @domainname: The name of domain. * @transit: True if transit to domain found or created. * * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. * * Caller holds tomoyo_read_lock(). */ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, const bool transit) { struct tomoyo_domain_info e = { }; struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); bool created = false; if (entry) { if (transit) { /* * Since namespace is created at runtime, profiles may * not be created by the moment the process transits to * that domain. Do not perform domain transition if * profile for that domain is not yet created. */ |
e00fb3f7a TOMOYO: Fix domai... |
511 512 |
if (tomoyo_policy_loaded && !entry->ns->profile_ptr[entry->profile]) |
bd03a3e4c TOMOYO: Add polic... |
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
return NULL; } return entry; } /* Requested domain does not exist. */ /* Don't create requested domain if domainname is invalid. */ if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_correct_domain(domainname)) return NULL; /* * Since definition of profiles and acl_groups may differ across * namespaces, do not inherit "use_profile" and "use_group" settings * by automatically creating requested domain upon domain transition. */ if (transit && tomoyo_namespace_jump(domainname)) return NULL; e.ns = tomoyo_assign_namespace(domainname); if (!e.ns) return NULL; /* * "use_profile" and "use_group" settings for automatically created * domains are inherited from current domain. These are 0 for manually * created domains. */ if (transit) { const struct tomoyo_domain_info *domain = tomoyo_domain(); e.profile = domain->profile; e.group = domain->group; } e.domainname = tomoyo_get_name(domainname); if (!e.domainname) return NULL; if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; entry = tomoyo_find_domain(domainname); if (!entry) { entry = tomoyo_commit_ok(&e, sizeof(e)); if (entry) { INIT_LIST_HEAD(&entry->acl_info_list); list_add_tail_rcu(&entry->list, &tomoyo_domain_list); created = true; } } mutex_unlock(&tomoyo_policy_lock); out: tomoyo_put_name(e.domainname); if (entry && transit) { if (created) { struct tomoyo_request_info r; tomoyo_init_request_info(&r, entry, TOMOYO_MAC_FILE_EXECUTE); r.granted = false; tomoyo_write_log(&r, "use_profile %u ", entry->profile); tomoyo_write_log(&r, "use_group %u ", entry->group); |
778c4a4d6 TOMOYO: Fix make ... |
570 |
tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); |
bd03a3e4c TOMOYO: Add polic... |
571 572 573 |
} } return entry; |
26a2a1c9e Domain transition... |
574 575 576 |
} /** |
d58e0da85 TOMOYO: Add envir... |
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 |
* tomoyo_environ - Check permission for environment variable names. * * @ee: Pointer to "struct tomoyo_execve". * * Returns 0 on success, negative value otherwise. */ static int tomoyo_environ(struct tomoyo_execve *ee) { struct tomoyo_request_info *r = &ee->r; struct linux_binprm *bprm = ee->bprm; /* env_page.data is allocated by tomoyo_dump_page(). */ struct tomoyo_page_dump env_page = { }; char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */ int arg_len = 0; unsigned long pos = bprm->p; int offset = pos % PAGE_SIZE; int argv_count = bprm->argc; int envp_count = bprm->envc; int error = -ENOMEM; ee->r.type = TOMOYO_MAC_ENVIRON; ee->r.profile = r->domain->profile; ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile, TOMOYO_MAC_ENVIRON); if (!r->mode || !envp_count) return 0; arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); if (!arg_ptr) goto out; while (error == -ENOMEM) { if (!tomoyo_dump_page(bprm, pos, &env_page)) goto out; pos += PAGE_SIZE - offset; /* Read. */ while (argv_count && offset < PAGE_SIZE) { if (!env_page.data[offset++]) argv_count--; } if (argv_count) { offset = 0; continue; } while (offset < PAGE_SIZE) { const unsigned char c = env_page.data[offset++]; if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { if (c == '=') { arg_ptr[arg_len++] = '\0'; } else if (c == '\\') { arg_ptr[arg_len++] = '\\'; arg_ptr[arg_len++] = '\\'; } else if (c > ' ' && c < 127) { arg_ptr[arg_len++] = c; } else { arg_ptr[arg_len++] = '\\'; arg_ptr[arg_len++] = (c >> 6) + '0'; arg_ptr[arg_len++] = ((c >> 3) & 7) + '0'; arg_ptr[arg_len++] = (c & 7) + '0'; } } else { arg_ptr[arg_len] = '\0'; } if (c) continue; if (tomoyo_env_perm(r, arg_ptr)) { error = -EPERM; break; } if (!--envp_count) { error = 0; break; } arg_len = 0; } offset = 0; } out: if (r->mode != TOMOYO_CONFIG_ENFORCING) error = 0; kfree(env_page.data); kfree(arg_ptr); return error; } /** |
26a2a1c9e Domain transition... |
663 664 |
* tomoyo_find_next_domain - Find a domain. * |
56f8c9bc4 TOMOYO: Remove ne... |
665 |
* @bprm: Pointer to "struct linux_binprm". |
26a2a1c9e Domain transition... |
666 667 |
* * Returns 0 on success, negative value otherwise. |
fdb8ebb72 TOMOYO: Use RCU p... |
668 669 |
* * Caller holds tomoyo_read_lock(). |
26a2a1c9e Domain transition... |
670 |
*/ |
56f8c9bc4 TOMOYO: Remove ne... |
671 |
int tomoyo_find_next_domain(struct linux_binprm *bprm) |
26a2a1c9e Domain transition... |
672 |
{ |
26a2a1c9e Domain transition... |
673 674 |
struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *domain = NULL; |
26a2a1c9e Domain transition... |
675 |
const char *original_name = bprm->filename; |
26a2a1c9e Domain transition... |
676 |
int retval = -ENOMEM; |
bd03a3e4c TOMOYO: Add polic... |
677 |
bool reject_on_transition_failure = false; |
a8f764096 TOMOYO: Avoid rac... |
678 679 |
const struct tomoyo_path_info *candidate; struct tomoyo_path_info exename; |
97fb35e41 TOMOYO: Enable co... |
680 |
struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); |
d58e0da85 TOMOYO: Add envir... |
681 |
|
97fb35e41 TOMOYO: Enable co... |
682 683 684 685 686 687 688 689 690 691 692 693 694 |
if (!ee) return -ENOMEM; ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); if (!ee->tmp) { kfree(ee); return -ENOMEM; } /* ee->dump->data is allocated by tomoyo_dump_page(). */ tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE); ee->r.ee = ee; ee->bprm = bprm; ee->r.obj = &ee->obj; ee->obj.path1 = bprm->file->f_path; |
0617c7ff3 TOMOYO: Remove al... |
695 |
/* Get symlink's pathname of program. */ |
26a2a1c9e Domain transition... |
696 |
retval = -ENOENT; |
a8f764096 TOMOYO: Avoid rac... |
697 698 |
exename.name = tomoyo_realpath_nofollow(original_name); if (!exename.name) |
26a2a1c9e Domain transition... |
699 |
goto out; |
a8f764096 TOMOYO: Avoid rac... |
700 701 |
tomoyo_fill_path_info(&exename); retry: |
1084307ca TOMOYO: Add pathn... |
702 703 |
/* Check 'aggregator' directive. */ { |
e2bf69077 TOMOYO: Rename sy... |
704 |
struct tomoyo_aggregator *ptr; |
bd03a3e4c TOMOYO: Add polic... |
705 706 707 |
struct list_head *list = &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; /* Check 'aggregator' directive. */ |
a8f764096 TOMOYO: Avoid rac... |
708 |
candidate = &exename; |
bd03a3e4c TOMOYO: Add polic... |
709 |
list_for_each_entry_rcu(ptr, list, head.list) { |
82e0f001a TOMOYO: Use commo... |
710 |
if (ptr->head.is_deleted || |
a8f764096 TOMOYO: Avoid rac... |
711 |
!tomoyo_path_matches_pattern(&exename, |
1084307ca TOMOYO: Add pathn... |
712 713 |
ptr->original_name)) continue; |
a8f764096 TOMOYO: Avoid rac... |
714 |
candidate = ptr->aggregated_name; |
1084307ca TOMOYO: Add pathn... |
715 716 717 |
break; } } |
26a2a1c9e Domain transition... |
718 |
/* Check execute permission. */ |
6bce98edc TOMOYO: Allow spe... |
719 |
retval = tomoyo_execute_permission(&ee->r, candidate); |
17fcfbd9d TOMOYO: Add inter... |
720 721 |
if (retval == TOMOYO_RETRY_REQUEST) goto retry; |
26a2a1c9e Domain transition... |
722 723 |
if (retval < 0) goto out; |
484ca79c6 TOMOYO: Use pathn... |
724 725 726 727 728 729 |
/* * To be able to specify domainnames with wildcards, use the * pathname specified in the policy (which may contain * wildcard) rather than the pathname passed to execve() * (which never contains wildcard). */ |
a8f764096 TOMOYO: Avoid rac... |
730 731 |
if (ee->r.param.path.matched_path) candidate = ee->r.param.path.matched_path; |
26a2a1c9e Domain transition... |
732 |
|
6bce98edc TOMOYO: Allow spe... |
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 |
/* * Check for domain transition preference if "file execute" matched. * If preference is given, make do_execve() fail if domain transition * has failed, for domain transition preference should be used with * destination domain defined. */ if (ee->transition) { const char *domainname = ee->transition->name; reject_on_transition_failure = true; if (!strcmp(domainname, "keep")) goto force_keep_domain; if (!strcmp(domainname, "child")) goto force_child_domain; if (!strcmp(domainname, "reset")) goto force_reset_domain; if (!strcmp(domainname, "initialize")) goto force_initialize_domain; if (!strcmp(domainname, "parent")) { char *cp; strncpy(ee->tmp, old_domain->domainname->name, TOMOYO_EXEC_TMPSIZE - 1); cp = strrchr(ee->tmp, ' '); if (cp) *cp = '\0'; } else if (*domainname == '<') strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1); else snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->domainname->name, domainname); goto force_jump_domain; } /* * No domain transition preference specified. * Calculate domain to transit to. */ |
bd03a3e4c TOMOYO: Add polic... |
768 |
switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, |
a8f764096 TOMOYO: Avoid rac... |
769 |
candidate)) { |
bd03a3e4c TOMOYO: Add polic... |
770 |
case TOMOYO_TRANSITION_CONTROL_RESET: |
6bce98edc TOMOYO: Allow spe... |
771 |
force_reset_domain: |
bd03a3e4c TOMOYO: Add polic... |
772 |
/* Transit to the root of specified namespace. */ |
a8f764096 TOMOYO: Avoid rac... |
773 774 |
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", candidate->name); |
bd03a3e4c TOMOYO: Add polic... |
775 776 777 778 779 780 |
/* * Make do_execve() fail if domain transition across namespaces * has failed. */ reject_on_transition_failure = true; break; |
5448ec4f5 TOMOYO: Use commo... |
781 |
case TOMOYO_TRANSITION_CONTROL_INITIALIZE: |
6bce98edc TOMOYO: Allow spe... |
782 |
force_initialize_domain: |
bd03a3e4c TOMOYO: Add polic... |
783 |
/* Transit to the child of current namespace's root. */ |
97fb35e41 TOMOYO: Enable co... |
784 |
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
a8f764096 TOMOYO: Avoid rac... |
785 |
old_domain->ns->name, candidate->name); |
5448ec4f5 TOMOYO: Use commo... |
786 787 |
break; case TOMOYO_TRANSITION_CONTROL_KEEP: |
6bce98edc TOMOYO: Allow spe... |
788 |
force_keep_domain: |
26a2a1c9e Domain transition... |
789 790 |
/* Keep current domain. */ domain = old_domain; |
5448ec4f5 TOMOYO: Use commo... |
791 792 793 794 795 796 797 798 799 800 801 |
break; default: if (old_domain == &tomoyo_kernel_domain && !tomoyo_policy_loaded) { /* * Needn't to transit from kernel domain before * starting /sbin/init. But transit from kernel domain * if executing initializers because they might start * before /sbin/init. */ domain = old_domain; |
a8f764096 TOMOYO: Avoid rac... |
802 |
break; |
5448ec4f5 TOMOYO: Use commo... |
803 |
} |
6bce98edc TOMOYO: Allow spe... |
804 |
force_child_domain: |
a8f764096 TOMOYO: Avoid rac... |
805 806 807 |
/* Normal domain transition. */ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->domainname->name, candidate->name); |
5448ec4f5 TOMOYO: Use commo... |
808 |
break; |
26a2a1c9e Domain transition... |
809 |
} |
6bce98edc TOMOYO: Allow spe... |
810 |
force_jump_domain: |
7c75964f4 TOMOYO: Cleanup p... |
811 |
if (!domain) |
97fb35e41 TOMOYO: Enable co... |
812 |
domain = tomoyo_assign_domain(ee->tmp, true); |
26a2a1c9e Domain transition... |
813 |
if (domain) |
bd03a3e4c TOMOYO: Add polic... |
814 815 |
retval = 0; else if (reject_on_transition_failure) { |
97fb35e41 TOMOYO: Enable co... |
816 817 818 |
printk(KERN_WARNING "ERROR: Domain '%s' not ready. ", ee->tmp); |
bd03a3e4c TOMOYO: Add polic... |
819 |
retval = -ENOMEM; |
97fb35e41 TOMOYO: Enable co... |
820 |
} else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) |
bd03a3e4c TOMOYO: Add polic... |
821 822 823 |
retval = -ENOMEM; else { retval = 0; |
2c47ab935 TOMOYO: Cleanup p... |
824 825 |
if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) { old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true; |
97fb35e41 TOMOYO: Enable co... |
826 827 |
ee->r.granted = false; tomoyo_write_log(&ee->r, "%s", tomoyo_dif |
2c47ab935 TOMOYO: Cleanup p... |
828 |
[TOMOYO_DIF_TRANSITION_FAILED]); |
bd03a3e4c TOMOYO: Add polic... |
829 |
printk(KERN_WARNING |
97fb35e41 TOMOYO: Enable co... |
830 831 |
"ERROR: Domain '%s' not defined. ", ee->tmp); |
bd03a3e4c TOMOYO: Add polic... |
832 833 |
} } |
26a2a1c9e Domain transition... |
834 |
out: |
56f8c9bc4 TOMOYO: Remove ne... |
835 836 |
if (!domain) domain = old_domain; |
ec8e6a4e0 TOMOYO: Add refco... |
837 838 |
/* Update reference count on "struct tomoyo_domain_info". */ atomic_inc(&domain->users); |
56f8c9bc4 TOMOYO: Remove ne... |
839 |
bprm->cred->security = domain; |
a8f764096 TOMOYO: Avoid rac... |
840 |
kfree(exename.name); |
d58e0da85 TOMOYO: Add envir... |
841 842 843 844 |
if (!retval) { ee->r.domain = domain; retval = tomoyo_environ(ee); } |
97fb35e41 TOMOYO: Enable co... |
845 846 847 |
kfree(ee->tmp); kfree(ee->dump.data); kfree(ee); |
26a2a1c9e Domain transition... |
848 849 |
return retval; } |
5b636857f TOMOYO: Allow usi... |
850 851 852 853 854 855 856 857 858 859 860 861 862 863 |
/** * tomoyo_dump_page - Dump a page to buffer. * * @bprm: Pointer to "struct linux_binprm". * @pos: Location to dump. * @dump: Poiner to "struct tomoyo_page_dump". * * Returns true on success, false otherwise. */ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, struct tomoyo_page_dump *dump) { struct page *page; |
d58e0da85 TOMOYO: Add envir... |
864 865 |
/* dump->data is released by tomoyo_find_next_domain(). */ |
5b636857f TOMOYO: Allow usi... |
866 867 868 869 870 871 872 |
if (!dump->data) { dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); if (!dump->data) return false; } /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ #ifdef CONFIG_MMU |
1e9877902 mm/gup: Introduce... |
873 874 875 876 877 878 879 |
/* * This is called at execve() time in order to dig around * in the argv/environment of the new proceess * (represented by bprm). 'current' is the process doing * the execve(). */ if (get_user_pages_remote(current, bprm->mm, pos, 1, |
9beae1ea8 mm: replace get_u... |
880 |
FOLL_FORCE, &page, NULL) <= 0) |
5b636857f TOMOYO: Allow usi... |
881 882 883 884 885 886 887 888 889 890 891 |
return false; #else page = bprm->page[pos / PAGE_SIZE]; #endif if (page != dump->page) { const unsigned int offset = pos % PAGE_SIZE; /* * Maybe kmap()/kunmap() should be used here. * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic(). * So do I. */ |
c58e0377d tomoyo: remove th... |
892 |
char *kaddr = kmap_atomic(page); |
d58e0da85 TOMOYO: Add envir... |
893 |
|
5b636857f TOMOYO: Allow usi... |
894 895 896 |
dump->page = page; memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset); |
c58e0377d tomoyo: remove th... |
897 |
kunmap_atomic(kaddr); |
5b636857f TOMOYO: Allow usi... |
898 899 900 901 902 903 904 |
} /* Same with put_arg_page(page) in fs/exec.c */ #ifdef CONFIG_MMU put_page(page); #endif return true; } |