Blame view

security/tomoyo/domain.c 24.9 KB
26a2a1c9e   Kentaro Takeda   Domain transition...
1
2
3
  /*
   * security/tomoyo/domain.c
   *
0f2a55d5b   Tetsuo Handa   TOMOYO: Update ke...
4
   * Copyright (C) 2005-2011  NTT DATA CORPORATION
26a2a1c9e   Kentaro Takeda   Domain transition...
5
6
7
   */
  
  #include "common.h"
26a2a1c9e   Kentaro Takeda   Domain transition...
8
  #include <linux/binfmts.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
9
  #include <linux/slab.h>
26a2a1c9e   Kentaro Takeda   Domain transition...
10
11
12
13
14
  
  /* Variables definitions.*/
  
  /* The initial domain. */
  struct tomoyo_domain_info tomoyo_kernel_domain;
237ab459f   Tetsuo Handa   TOMOYO: Use callb...
15
  /**
36f5e1ffb   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use struc...
20
   * @param:           Pointer to "struct tomoyo_acl_param".
36f5e1ffb   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use struc...
28
  			 struct tomoyo_acl_param *param,
36f5e1ffb   Tetsuo Handa   TOMOYO: Use callb...
29
30
31
32
33
  			 bool (*check_duplicate) (const struct tomoyo_acl_head
  						  *,
  						  const struct tomoyo_acl_head
  						  *))
  {
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
34
  	int error = param->is_delete ? -ENOENT : -ENOMEM;
36f5e1ffb   Tetsuo Handa   TOMOYO: Use callb...
35
  	struct tomoyo_acl_head *entry;
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
36
  	struct list_head *list = param->list;
36f5e1ffb   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Simplify ...
41
42
  		if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
  			continue;
36f5e1ffb   Tetsuo Handa   TOMOYO: Use callb...
43
44
  		if (!check_duplicate(entry, new_entry))
  			continue;
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
45
  		entry->is_deleted = param->is_delete;
36f5e1ffb   Tetsuo Handa   TOMOYO: Use callb...
46
47
48
  		error = 0;
  		break;
  	}
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
49
  	if (error && !param->is_delete) {
36f5e1ffb   Tetsuo Handa   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   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Allow usi...
71
  	return a->type == b->type && a->cond == b->cond;
0df7e8b8f   Tetsuo Handa   TOMOYO: Cleanup p...
72
73
74
  }
  
  /**
237ab459f   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use struc...
79
   * @param:           Pointer to "struct tomoyo_acl_param".
237ab459f   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use struc...
88
  			 struct tomoyo_acl_param *param,
237ab459f   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use struc...
97
  	const bool is_delete = param->is_delete;
237ab459f   Tetsuo Handa   TOMOYO: Use callb...
98
99
  	int error = is_delete ? -ENOENT : -ENOMEM;
  	struct tomoyo_acl_info *entry;
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
100
  	struct list_head * const list = param->list;
237ab459f   Tetsuo Handa   TOMOYO: Use callb...
101

2066a3612   Tetsuo Handa   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   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Allow usi...
115
  	}
237ab459f   Tetsuo Handa   TOMOYO: Use callb...
116
  	if (mutex_lock_interruptible(&tomoyo_policy_lock))
2066a3612   Tetsuo Handa   TOMOYO: Allow usi...
117
  		goto out;
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
118
  	list_for_each_entry_rcu(entry, list, list) {
f9732ea14   Tetsuo Handa   TOMOYO: Simplify ...
119
120
  		if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
  			continue;
0df7e8b8f   Tetsuo Handa   TOMOYO: Cleanup p...
121
122
  		if (!tomoyo_same_acl_head(entry, new_entry) ||
  		    !check_duplicate(entry, new_entry))
237ab459f   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use struc...
135
  			list_add_tail_rcu(&entry->list, list);
237ab459f   Tetsuo Handa   TOMOYO: Use callb...
136
137
138
139
  			error = 0;
  		}
  	}
  	mutex_unlock(&tomoyo_policy_lock);
2066a3612   Tetsuo Handa   TOMOYO: Allow usi...
140
141
  out:
  	tomoyo_put_condition(new_entry->cond);
237ab459f   Tetsuo Handa   TOMOYO: Use callb...
142
143
  	return error;
  }
32997144f   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use callb...
154
  void tomoyo_check_acl(struct tomoyo_request_info *r,
484ca79c6   Tetsuo Handa   TOMOYO: Use pathn...
155
  		      bool (*check_entry) (struct tomoyo_request_info *,
99a852596   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Add ACL g...
160
161
  	bool retried = false;
  	const struct list_head *list = &domain->acl_info_list;
99a852596   Tetsuo Handa   TOMOYO: Use callb...
162

32997144f   Tetsuo Handa   TOMOYO: Add ACL g...
163
164
  retry:
  	list_for_each_entry_rcu(ptr, list, list) {
99a852596   Tetsuo Handa   TOMOYO: Use callb...
165
166
  		if (ptr->is_deleted || ptr->type != r->param_type)
  			continue;
2066a3612   Tetsuo Handa   TOMOYO: Allow usi...
167
168
169
170
  		if (!check_entry(r, ptr))
  			continue;
  		if (!tomoyo_condition(r, ptr->cond))
  			continue;
1f067a682   Tetsuo Handa   TOMOYO: Allow con...
171
  		r->matched_acl = ptr;
2066a3612   Tetsuo Handa   TOMOYO: Allow usi...
172
173
  		r->granted = true;
  		return;
99a852596   Tetsuo Handa   TOMOYO: Use callb...
174
  	}
32997144f   Tetsuo Handa   TOMOYO: Add ACL g...
175
176
  	if (!retried) {
  		retried = true;
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
177
  		list = &domain->ns->acl_group[domain->group];
32997144f   Tetsuo Handa   TOMOYO: Add ACL g...
178
179
  		goto retry;
  	}
99a852596   Tetsuo Handa   TOMOYO: Use callb...
180
181
  	r->granted = false;
  }
a230f9e71   Tetsuo Handa   TOMOYO: Use array...
182
  /* The list for "struct tomoyo_domain_info". */
26a2a1c9e   Kentaro Takeda   Domain transition...
183
  LIST_HEAD(tomoyo_domain_list);
26a2a1c9e   Kentaro Takeda   Domain transition...
184

26a2a1c9e   Kentaro Takeda   Domain transition...
185
  /**
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
186
   * tomoyo_last_word - Get last component of a domainname.
26a2a1c9e   Kentaro Takeda   Domain transition...
187
   *
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
188
   * @name: Domainname to check.
26a2a1c9e   Kentaro Takeda   Domain transition...
189
   *
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
190
   * Returns the last word of @domainname.
26a2a1c9e   Kentaro Takeda   Domain transition...
191
   */
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
192
  static const char *tomoyo_last_word(const char *name)
26a2a1c9e   Kentaro Takeda   Domain transition...
193
  {
0f2a55d5b   Tetsuo Handa   TOMOYO: Update ke...
194
195
196
197
  	const char *cp = strrchr(name, ' ');
  	if (cp)
  		return cp + 1;
  	return name;
26a2a1c9e   Kentaro Takeda   Domain transition...
198
  }
a238cf5b8   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Rename sy...
207
208
  static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
  					   const struct tomoyo_acl_head *b)
36f5e1ffb   Tetsuo Handa   TOMOYO: Use callb...
209
  {
5448ec4f5   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use callb...
217
218
219
  		&& p1->domainname == p2->domainname
  		&& p1->program == p2->program;
  }
26a2a1c9e   Kentaro Takeda   Domain transition...
220
  /**
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
221
   * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
26a2a1c9e   Kentaro Takeda   Domain transition...
222
   *
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
223
224
   * @param: Pointer to "struct tomoyo_acl_param".
   * @type:  Type of this entry.
26a2a1c9e   Kentaro Takeda   Domain transition...
225
226
227
   *
   * Returns 0 on success, negative value otherwise.
   */
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
228
229
  int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
  				    const u8 type)
26a2a1c9e   Kentaro Takeda   Domain transition...
230
  {
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
231
  	struct tomoyo_transition_control e = { .type = type };
a238cf5b8   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Rename di...
243
  	if (program && strcmp(program, "any")) {
5448ec4f5   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Rename di...
250
  	if (domainname && strcmp(domainname, "any")) {
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
251
252
253
  		if (!tomoyo_correct_domain(domainname)) {
  			if (!tomoyo_correct_path(domainname))
  				goto out;
9e4b50e93   Tetsuo Handa   TOMOYO: Use stack...
254
  			e.is_last_name = true;
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
255
  		}
9e4b50e93   Tetsuo Handa   TOMOYO: Use stack...
256
257
  		e.domainname = tomoyo_get_name(domainname);
  		if (!e.domainname)
ca0b7df33   Tetsuo Handa   TOMOYO: Reduce li...
258
  			goto out;
26a2a1c9e   Kentaro Takeda   Domain transition...
259
  	}
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
260
  	param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
261
  	error = tomoyo_update_policy(&e.head, sizeof(e), param,
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
262
  				     tomoyo_same_transition_control);
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
263
  out:
9e4b50e93   Tetsuo Handa   TOMOYO: Use stack...
264
265
  	tomoyo_put_name(e.domainname);
  	tomoyo_put_name(e.program);
26a2a1c9e   Kentaro Takeda   Domain transition...
266
267
268
269
  	return error;
  }
  
  /**
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
270
   * tomoyo_scan_transition - Try to find specific domain transition type.
26a2a1c9e   Kentaro Takeda   Domain transition...
271
   *
bd03a3e4c   Tetsuo Handa   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   Kentaro Takeda   Domain transition...
277
   *
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
278
   * Returns true if found one, false otherwise.
fdb8ebb72   Tetsuo Handa   TOMOYO: Use RCU p...
279
280
   *
   * Caller holds tomoyo_read_lock().
26a2a1c9e   Kentaro Takeda   Domain transition...
281
   */
bd03a3e4c   Tetsuo Handa   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   Kentaro Takeda   Domain transition...
286
  {
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
287
  	const struct tomoyo_transition_control *ptr;
bd03a3e4c   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use commo...
296
  				/*
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
297
298
  				 * Use direct strcmp() since this is
  				 * unlikely used.
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
299
  				 */
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
300
301
  				if (strcmp(ptr->domainname->name, last_name))
  					continue;
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
302
  			}
26a2a1c9e   Kentaro Takeda   Domain transition...
303
  		}
bd03a3e4c   Tetsuo Handa   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   Kentaro Takeda   Domain transition...
351
  	}
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
352
  	return type;
26a2a1c9e   Kentaro Takeda   Domain transition...
353
  }
a238cf5b8   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Rename sy...
362
363
  static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
  				   const struct tomoyo_acl_head *b)
36f5e1ffb   Tetsuo Handa   TOMOYO: Use callb...
364
  {
a238cf5b8   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use callb...
369
370
371
  	return p1->original_name == p2->original_name &&
  		p1->aggregated_name == p2->aggregated_name;
  }
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
372
  /**
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
373
   * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
374
   *
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
375
   * @param: Pointer to "struct tomoyo_acl_param".
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
376
377
378
379
380
   *
   * Returns 0 on success, negative value otherwise.
   *
   * Caller holds tomoyo_read_lock().
   */
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
381
  int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
382
  {
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
383
  	struct tomoyo_aggregator e = { };
a238cf5b8   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Rename sy...
388
  	    !tomoyo_correct_path(aggregated_name))
1084307ca   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Add polic...
395
  	param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
396
  	error = tomoyo_update_policy(&e.head, sizeof(e), param,
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
397
  				     tomoyo_same_aggregator);
a238cf5b8   Tetsuo Handa   TOMOYO: Use struc...
398
  out:
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
399
400
401
402
403
404
  	tomoyo_put_name(e.original_name);
  	tomoyo_put_name(e.aggregated_name);
  	return error;
  }
  
  /**
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
405
   * tomoyo_find_namespace - Find specified namespace.
26a2a1c9e   Kentaro Takeda   Domain transition...
406
   *
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
407
408
   * @name: Name of namespace to find.
   * @len:  Length of @name.
26a2a1c9e   Kentaro Takeda   Domain transition...
409
   *
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
410
411
   * Returns pointer to "struct tomoyo_policy_namespace" if found,
   * NULL otherwise.
fdb8ebb72   Tetsuo Handa   TOMOYO: Use RCU p...
412
413
   *
   * Caller holds tomoyo_read_lock().
26a2a1c9e   Kentaro Takeda   Domain transition...
414
   */
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
415
416
  static struct tomoyo_policy_namespace *tomoyo_find_namespace
  (const char *name, const unsigned int len)
26a2a1c9e   Kentaro Takeda   Domain transition...
417
  {
bd03a3e4c   Tetsuo Handa   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   Kentaro Takeda   Domain transition...
427

bd03a3e4c   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Reduce li...
450
  		return NULL;
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
451
452
  	entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
  	if (!entry)
ca0b7df33   Tetsuo Handa   TOMOYO: Reduce li...
453
  		return NULL;
292823814   Tetsuo Handa   TOMOYO: Use mutex...
454
455
  	if (mutex_lock_interruptible(&tomoyo_policy_lock))
  		goto out;
bd03a3e4c   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Reduce li...
464
  		entry = NULL;
26a2a1c9e   Kentaro Takeda   Domain transition...
465
  	}
f737d95dd   Tetsuo Handa   TOMOYO: Replace r...
466
  	mutex_unlock(&tomoyo_policy_lock);
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
467
  out:
ca0b7df33   Tetsuo Handa   TOMOYO: Reduce li...
468
  	kfree(entry);
bd03a3e4c   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Fix domai...
511
512
  			if (tomoyo_policy_loaded &&
  			    !entry->ns->profile_ptr[entry->profile])
bd03a3e4c   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Fix make ...
570
  			tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
571
572
573
  		}
  	}
  	return entry;
26a2a1c9e   Kentaro Takeda   Domain transition...
574
575
576
  }
  
  /**
d58e0da85   Tetsuo Handa   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   Kentaro Takeda   Domain transition...
663
664
   * tomoyo_find_next_domain - Find a domain.
   *
56f8c9bc4   Tetsuo Handa   TOMOYO: Remove ne...
665
   * @bprm: Pointer to "struct linux_binprm".
26a2a1c9e   Kentaro Takeda   Domain transition...
666
667
   *
   * Returns 0 on success, negative value otherwise.
fdb8ebb72   Tetsuo Handa   TOMOYO: Use RCU p...
668
669
   *
   * Caller holds tomoyo_read_lock().
26a2a1c9e   Kentaro Takeda   Domain transition...
670
   */
56f8c9bc4   Tetsuo Handa   TOMOYO: Remove ne...
671
  int tomoyo_find_next_domain(struct linux_binprm *bprm)
26a2a1c9e   Kentaro Takeda   Domain transition...
672
  {
26a2a1c9e   Kentaro Takeda   Domain transition...
673
674
  	struct tomoyo_domain_info *old_domain = tomoyo_domain();
  	struct tomoyo_domain_info *domain = NULL;
26a2a1c9e   Kentaro Takeda   Domain transition...
675
  	const char *original_name = bprm->filename;
26a2a1c9e   Kentaro Takeda   Domain transition...
676
  	int retval = -ENOMEM;
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
677
  	bool reject_on_transition_failure = false;
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
678
679
  	const struct tomoyo_path_info *candidate;
  	struct tomoyo_path_info exename;
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
680
  	struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
d58e0da85   Tetsuo Handa   TOMOYO: Add envir...
681

97fb35e41   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Remove al...
695
  	/* Get symlink's pathname of program. */
26a2a1c9e   Kentaro Takeda   Domain transition...
696
  	retval = -ENOENT;
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
697
698
  	exename.name = tomoyo_realpath_nofollow(original_name);
  	if (!exename.name)
26a2a1c9e   Kentaro Takeda   Domain transition...
699
  		goto out;
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
700
701
  	tomoyo_fill_path_info(&exename);
  retry:
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
702
703
  	/* Check 'aggregator' directive. */
  	{
e2bf69077   Tetsuo Handa   TOMOYO: Rename sy...
704
  		struct tomoyo_aggregator *ptr;
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
705
706
707
  		struct list_head *list =
  			&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
  		/* Check 'aggregator' directive. */
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
708
  		candidate = &exename;
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
709
  		list_for_each_entry_rcu(ptr, list, head.list) {
82e0f001a   Tetsuo Handa   TOMOYO: Use commo...
710
  			if (ptr->head.is_deleted ||
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
711
  			    !tomoyo_path_matches_pattern(&exename,
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
712
713
  							 ptr->original_name))
  				continue;
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
714
  			candidate = ptr->aggregated_name;
1084307ca   Tetsuo Handa   TOMOYO: Add pathn...
715
716
717
  			break;
  		}
  	}
26a2a1c9e   Kentaro Takeda   Domain transition...
718
  	/* Check execute permission. */
6bce98edc   Tetsuo Handa   TOMOYO: Allow spe...
719
  	retval = tomoyo_execute_permission(&ee->r, candidate);
17fcfbd9d   Tetsuo Handa   TOMOYO: Add inter...
720
721
  	if (retval == TOMOYO_RETRY_REQUEST)
  		goto retry;
26a2a1c9e   Kentaro Takeda   Domain transition...
722
723
  	if (retval < 0)
  		goto out;
484ca79c6   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Avoid rac...
730
731
  	if (ee->r.param.path.matched_path)
  		candidate = ee->r.param.path.matched_path;
26a2a1c9e   Kentaro Takeda   Domain transition...
732

6bce98edc   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Add polic...
768
  	switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
769
  				       candidate)) {
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
770
  	case TOMOYO_TRANSITION_CONTROL_RESET:
6bce98edc   Tetsuo Handa   TOMOYO: Allow spe...
771
  force_reset_domain:
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
772
  		/* Transit to the root of specified namespace. */
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
773
774
  		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
  			 candidate->name);
bd03a3e4c   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use commo...
781
  	case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
6bce98edc   Tetsuo Handa   TOMOYO: Allow spe...
782
  force_initialize_domain:
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
783
  		/* Transit to the child of current namespace's root. */
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
784
  		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
785
  			 old_domain->ns->name, candidate->name);
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
786
787
  		break;
  	case TOMOYO_TRANSITION_CONTROL_KEEP:
6bce98edc   Tetsuo Handa   TOMOYO: Allow spe...
788
  force_keep_domain:
26a2a1c9e   Kentaro Takeda   Domain transition...
789
790
  		/* Keep current domain. */
  		domain = old_domain;
5448ec4f5   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Avoid rac...
802
  			break;
5448ec4f5   Tetsuo Handa   TOMOYO: Use commo...
803
  		}
6bce98edc   Tetsuo Handa   TOMOYO: Allow spe...
804
  force_child_domain:
a8f764096   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Use commo...
808
  		break;
26a2a1c9e   Kentaro Takeda   Domain transition...
809
  	}
6bce98edc   Tetsuo Handa   TOMOYO: Allow spe...
810
  force_jump_domain:
7c75964f4   Tetsuo Handa   TOMOYO: Cleanup p...
811
  	if (!domain)
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
812
  		domain = tomoyo_assign_domain(ee->tmp, true);
26a2a1c9e   Kentaro Takeda   Domain transition...
813
  	if (domain)
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
814
815
  		retval = 0;
  	else if (reject_on_transition_failure) {
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
816
817
818
  		printk(KERN_WARNING "ERROR: Domain '%s' not ready.
  ",
  		       ee->tmp);
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
819
  		retval = -ENOMEM;
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
820
  	} else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
821
822
823
  		retval = -ENOMEM;
  	else {
  		retval = 0;
2c47ab935   Tetsuo Handa   TOMOYO: Cleanup p...
824
825
  		if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
  			old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
826
827
  			ee->r.granted = false;
  			tomoyo_write_log(&ee->r, "%s", tomoyo_dif
2c47ab935   Tetsuo Handa   TOMOYO: Cleanup p...
828
  					 [TOMOYO_DIF_TRANSITION_FAILED]);
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
829
  			printk(KERN_WARNING
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
830
831
  			       "ERROR: Domain '%s' not defined.
  ", ee->tmp);
bd03a3e4c   Tetsuo Handa   TOMOYO: Add polic...
832
833
  		}
  	}
26a2a1c9e   Kentaro Takeda   Domain transition...
834
   out:
56f8c9bc4   Tetsuo Handa   TOMOYO: Remove ne...
835
836
  	if (!domain)
  		domain = old_domain;
ec8e6a4e0   Tetsuo Handa   TOMOYO: Add refco...
837
838
  	/* Update reference count on "struct tomoyo_domain_info". */
  	atomic_inc(&domain->users);
56f8c9bc4   Tetsuo Handa   TOMOYO: Remove ne...
839
  	bprm->cred->security = domain;
a8f764096   Tetsuo Handa   TOMOYO: Avoid rac...
840
  	kfree(exename.name);
d58e0da85   Tetsuo Handa   TOMOYO: Add envir...
841
842
843
844
  	if (!retval) {
  		ee->r.domain = domain;
  		retval = tomoyo_environ(ee);
  	}
97fb35e41   Tetsuo Handa   TOMOYO: Enable co...
845
846
847
  	kfree(ee->tmp);
  	kfree(ee->dump.data);
  	kfree(ee);
26a2a1c9e   Kentaro Takeda   Domain transition...
848
849
  	return retval;
  }
5b636857f   Tetsuo Handa   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   Tetsuo Handa   TOMOYO: Add envir...
864
865
  
  	/* dump->data is released by tomoyo_find_next_domain(). */
5b636857f   Tetsuo Handa   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   Dave Hansen   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   Lorenzo Stoakes   mm: replace get_u...
880
  				FOLL_FORCE, &page, NULL) <= 0)
5b636857f   Tetsuo Handa   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   Cong Wang   tomoyo: remove th...
892
  		char *kaddr = kmap_atomic(page);
d58e0da85   Tetsuo Handa   TOMOYO: Add envir...
893

5b636857f   Tetsuo Handa   TOMOYO: Allow usi...
894
895
896
  		dump->page = page;
  		memcpy(dump->data + offset, kaddr + offset,
  		       PAGE_SIZE - offset);
c58e0377d   Cong Wang   tomoyo: remove th...
897
  		kunmap_atomic(kaddr);
5b636857f   Tetsuo Handa   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;
  }