2dffe07309180cbe85cb08e479aa822b30676067
[pandora-kernel.git] / security / tomoyo / file.c
1 /*
2  * security/tomoyo/file.c
3  *
4  * Implementation of the Domain-Based Mandatory Access Control.
5  *
6  * Copyright (C) 2005-2009  NTT DATA CORPORATION
7  *
8  * Version: 2.2.0   2009/04/01
9  *
10  */
11
12 #include "common.h"
13 #include <linux/slab.h>
14
15 /* Keyword array for single path operations. */
16 static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
17         [TOMOYO_TYPE_READ_WRITE] = "read/write",
18         [TOMOYO_TYPE_EXECUTE]    = "execute",
19         [TOMOYO_TYPE_READ]       = "read",
20         [TOMOYO_TYPE_WRITE]      = "write",
21         [TOMOYO_TYPE_CREATE]     = "create",
22         [TOMOYO_TYPE_UNLINK]     = "unlink",
23         [TOMOYO_TYPE_MKDIR]      = "mkdir",
24         [TOMOYO_TYPE_RMDIR]      = "rmdir",
25         [TOMOYO_TYPE_MKFIFO]     = "mkfifo",
26         [TOMOYO_TYPE_MKSOCK]     = "mksock",
27         [TOMOYO_TYPE_MKBLOCK]    = "mkblock",
28         [TOMOYO_TYPE_MKCHAR]     = "mkchar",
29         [TOMOYO_TYPE_TRUNCATE]   = "truncate",
30         [TOMOYO_TYPE_SYMLINK]    = "symlink",
31         [TOMOYO_TYPE_REWRITE]    = "rewrite",
32         [TOMOYO_TYPE_IOCTL]      = "ioctl",
33         [TOMOYO_TYPE_CHMOD]      = "chmod",
34         [TOMOYO_TYPE_CHOWN]      = "chown",
35         [TOMOYO_TYPE_CHGRP]      = "chgrp",
36         [TOMOYO_TYPE_CHROOT]     = "chroot",
37         [TOMOYO_TYPE_MOUNT]      = "mount",
38         [TOMOYO_TYPE_UMOUNT]     = "unmount",
39 };
40
41 /* Keyword array for double path operations. */
42 static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
43         [TOMOYO_TYPE_LINK]    = "link",
44         [TOMOYO_TYPE_RENAME]  = "rename",
45         [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
46 };
47
48 void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
49 {
50         if (!ptr)
51                 return;
52         if (ptr->is_group)
53                 tomoyo_put_path_group(ptr->group);
54         else
55                 tomoyo_put_name(ptr->filename);
56 }
57
58 bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
59                                const struct tomoyo_name_union *ptr)
60 {
61         if (ptr->is_group)
62                 return tomoyo_path_matches_group(name, ptr->group, 1);
63         return tomoyo_path_matches_pattern(name, ptr->filename);
64 }
65
66 static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info
67                                               *name,
68                                               const struct tomoyo_name_union
69                                               *ptr, const bool may_use_pattern)
70 {
71         if (ptr->is_group)
72                 return tomoyo_path_matches_group(name, ptr->group,
73                                                  may_use_pattern);
74         if (may_use_pattern || !ptr->filename->is_patterned)
75                 return tomoyo_path_matches_pattern(name, ptr->filename);
76         return false;
77 }
78
79 void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
80 {
81         if (ptr && ptr->is_group)
82                 tomoyo_put_number_group(ptr->group);
83 }
84
85 bool tomoyo_compare_number_union(const unsigned long value,
86                                  const struct tomoyo_number_union *ptr)
87 {
88         if (ptr->is_group)
89                 return tomoyo_number_matches_group(value, value, ptr->group);
90         return value >= ptr->values[0] && value <= ptr->values[1];
91 }
92
93 /**
94  * tomoyo_path2keyword - Get the name of single path operation.
95  *
96  * @operation: Type of operation.
97  *
98  * Returns the name of single path operation.
99  */
100 const char *tomoyo_path2keyword(const u8 operation)
101 {
102         return (operation < TOMOYO_MAX_PATH_OPERATION)
103                 ? tomoyo_path_keyword[operation] : NULL;
104 }
105
106 /**
107  * tomoyo_path22keyword - Get the name of double path operation.
108  *
109  * @operation: Type of operation.
110  *
111  * Returns the name of double path operation.
112  */
113 const char *tomoyo_path22keyword(const u8 operation)
114 {
115         return (operation < TOMOYO_MAX_PATH2_OPERATION)
116                 ? tomoyo_path2_keyword[operation] : NULL;
117 }
118
119 /**
120  * tomoyo_strendswith - Check whether the token ends with the given token.
121  *
122  * @name: The token to check.
123  * @tail: The token to find.
124  *
125  * Returns true if @name ends with @tail, false otherwise.
126  */
127 static bool tomoyo_strendswith(const char *name, const char *tail)
128 {
129         int len;
130
131         if (!name || !tail)
132                 return false;
133         len = strlen(name) - strlen(tail);
134         return len >= 0 && !strcmp(name + len, tail);
135 }
136
137 /**
138  * tomoyo_get_path - Get realpath.
139  *
140  * @path: Pointer to "struct path".
141  *
142  * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
143  */
144 static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
145 {
146         int error;
147         struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
148                                                          GFP_NOFS);
149
150         if (!buf)
151                 return NULL;
152         /* Reserve one byte for appending "/". */
153         error = tomoyo_realpath_from_path2(path, buf->body,
154                                            sizeof(buf->body) - 2);
155         if (!error) {
156                 buf->head.name = buf->body;
157                 tomoyo_fill_path_info(&buf->head);
158                 return &buf->head;
159         }
160         kfree(buf);
161         return NULL;
162 }
163
164 static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
165                                    const char *filename2,
166                                    struct tomoyo_domain_info *const domain,
167                                    const bool is_delete);
168 static int tomoyo_update_path_acl(const u8 type, const char *filename,
169                                   struct tomoyo_domain_info *const domain,
170                                   const bool is_delete);
171
172 /*
173  * tomoyo_globally_readable_list is used for holding list of pathnames which
174  * are by default allowed to be open()ed for reading by any process.
175  *
176  * An entry is added by
177  *
178  * # echo 'allow_read /lib/libc-2.5.so' > \
179  *                               /sys/kernel/security/tomoyo/exception_policy
180  *
181  * and is deleted by
182  *
183  * # echo 'delete allow_read /lib/libc-2.5.so' > \
184  *                               /sys/kernel/security/tomoyo/exception_policy
185  *
186  * and all entries are retrieved by
187  *
188  * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy
189  *
190  * In the example above, any process is allowed to
191  * open("/lib/libc-2.5.so", O_RDONLY).
192  * One exception is, if the domain which current process belongs to is marked
193  * as "ignore_global_allow_read", current process can't do so unless explicitly
194  * given "allow_read /lib/libc-2.5.so" to the domain which current process
195  * belongs to.
196  */
197 LIST_HEAD(tomoyo_globally_readable_list);
198
199 /**
200  * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
201  *
202  * @filename:  Filename unconditionally permitted to open() for reading.
203  * @is_delete: True if it is a delete request.
204  *
205  * Returns 0 on success, negative value otherwise.
206  *
207  * Caller holds tomoyo_read_lock().
208  */
209 static int tomoyo_update_globally_readable_entry(const char *filename,
210                                                  const bool is_delete)
211 {
212         struct tomoyo_globally_readable_file_entry *ptr;
213         struct tomoyo_globally_readable_file_entry e = { };
214         int error = is_delete ? -ENOENT : -ENOMEM;
215
216         if (!tomoyo_is_correct_path(filename, 1, 0, -1))
217                 return -EINVAL;
218         e.filename = tomoyo_get_name(filename);
219         if (!e.filename)
220                 return -ENOMEM;
221         if (mutex_lock_interruptible(&tomoyo_policy_lock))
222                 goto out;
223         list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
224                 if (ptr->filename != e.filename)
225                         continue;
226                 ptr->is_deleted = is_delete;
227                 error = 0;
228                 break;
229         }
230         if (!is_delete && error) {
231                 struct tomoyo_globally_readable_file_entry *entry =
232                         tomoyo_commit_ok(&e, sizeof(e));
233                 if (entry) {
234                         list_add_tail_rcu(&entry->list,
235                                           &tomoyo_globally_readable_list);
236                         error = 0;
237                 }
238         }
239         mutex_unlock(&tomoyo_policy_lock);
240  out:
241         tomoyo_put_name(e.filename);
242         return error;
243 }
244
245 /**
246  * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
247  *
248  * @filename: The filename to check.
249  *
250  * Returns true if any domain can open @filename for reading, false otherwise.
251  *
252  * Caller holds tomoyo_read_lock().
253  */
254 static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
255                                              filename)
256 {
257         struct tomoyo_globally_readable_file_entry *ptr;
258         bool found = false;
259
260         list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
261                 if (!ptr->is_deleted &&
262                     tomoyo_path_matches_pattern(filename, ptr->filename)) {
263                         found = true;
264                         break;
265                 }
266         }
267         return found;
268 }
269
270 /**
271  * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
272  *
273  * @data:      String to parse.
274  * @is_delete: True if it is a delete request.
275  *
276  * Returns 0 on success, negative value otherwise.
277  *
278  * Caller holds tomoyo_read_lock().
279  */
280 int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
281 {
282         return tomoyo_update_globally_readable_entry(data, is_delete);
283 }
284
285 /**
286  * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
287  *
288  * @head: Pointer to "struct tomoyo_io_buffer".
289  *
290  * Returns true on success, false otherwise.
291  *
292  * Caller holds tomoyo_read_lock().
293  */
294 bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
295 {
296         struct list_head *pos;
297         bool done = true;
298
299         list_for_each_cookie(pos, head->read_var2,
300                              &tomoyo_globally_readable_list) {
301                 struct tomoyo_globally_readable_file_entry *ptr;
302                 ptr = list_entry(pos,
303                                  struct tomoyo_globally_readable_file_entry,
304                                  list);
305                 if (ptr->is_deleted)
306                         continue;
307                 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
308                                         ptr->filename->name);
309                 if (!done)
310                         break;
311         }
312         return done;
313 }
314
315 /* tomoyo_pattern_list is used for holding list of pathnames which are used for
316  * converting pathnames to pathname patterns during learning mode.
317  *
318  * An entry is added by
319  *
320  * # echo 'file_pattern /proc/\$/mounts' > \
321  *                             /sys/kernel/security/tomoyo/exception_policy
322  *
323  * and is deleted by
324  *
325  * # echo 'delete file_pattern /proc/\$/mounts' > \
326  *                             /sys/kernel/security/tomoyo/exception_policy
327  *
328  * and all entries are retrieved by
329  *
330  * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy
331  *
332  * In the example above, if a process which belongs to a domain which is in
333  * learning mode requested open("/proc/1/mounts", O_RDONLY),
334  * "allow_read /proc/\$/mounts" is automatically added to the domain which that
335  * process belongs to.
336  *
337  * It is not a desirable behavior that we have to use /proc/\$/ instead of
338  * /proc/self/ when current process needs to access only current process's
339  * information. As of now, LSM version of TOMOYO is using __d_path() for
340  * calculating pathname. Non LSM version of TOMOYO is using its own function
341  * which pretends as if /proc/self/ is not a symlink; so that we can forbid
342  * current process from accessing other process's information.
343  */
344 LIST_HEAD(tomoyo_pattern_list);
345
346 /**
347  * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
348  *
349  * @pattern:   Pathname pattern.
350  * @is_delete: True if it is a delete request.
351  *
352  * Returns 0 on success, negative value otherwise.
353  *
354  * Caller holds tomoyo_read_lock().
355  */
356 static int tomoyo_update_file_pattern_entry(const char *pattern,
357                                             const bool is_delete)
358 {
359         struct tomoyo_pattern_entry *ptr;
360         struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
361         int error = is_delete ? -ENOENT : -ENOMEM;
362
363         if (!e.pattern)
364                 return error;
365         if (!e.pattern->is_patterned)
366                 goto out;
367         if (mutex_lock_interruptible(&tomoyo_policy_lock))
368                 goto out;
369         list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
370                 if (e.pattern != ptr->pattern)
371                         continue;
372                 ptr->is_deleted = is_delete;
373                 error = 0;
374                 break;
375         }
376         if (!is_delete && error) {
377                 struct tomoyo_pattern_entry *entry =
378                         tomoyo_commit_ok(&e, sizeof(e));
379                 if (entry) {
380                         list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
381                         error = 0;
382                 }
383         }
384         mutex_unlock(&tomoyo_policy_lock);
385  out:
386         tomoyo_put_name(e.pattern);
387         return error;
388 }
389
390 /**
391  * tomoyo_get_file_pattern - Get patterned pathname.
392  *
393  * @filename: The filename to find patterned pathname.
394  *
395  * Returns pointer to pathname pattern if matched, @filename otherwise.
396  *
397  * Caller holds tomoyo_read_lock().
398  */
399 static const struct tomoyo_path_info *
400 tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
401 {
402         struct tomoyo_pattern_entry *ptr;
403         const struct tomoyo_path_info *pattern = NULL;
404
405         list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
406                 if (ptr->is_deleted)
407                         continue;
408                 if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
409                         continue;
410                 pattern = ptr->pattern;
411                 if (tomoyo_strendswith(pattern->name, "/\\*")) {
412                         /* Do nothing. Try to find the better match. */
413                 } else {
414                         /* This would be the better match. Use this. */
415                         break;
416                 }
417         }
418         if (pattern)
419                 filename = pattern;
420         return filename;
421 }
422
423 /**
424  * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
425  *
426  * @data:      String to parse.
427  * @is_delete: True if it is a delete request.
428  *
429  * Returns 0 on success, negative value otherwise.
430  *
431  * Caller holds tomoyo_read_lock().
432  */
433 int tomoyo_write_pattern_policy(char *data, const bool is_delete)
434 {
435         return tomoyo_update_file_pattern_entry(data, is_delete);
436 }
437
438 /**
439  * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
440  *
441  * @head: Pointer to "struct tomoyo_io_buffer".
442  *
443  * Returns true on success, false otherwise.
444  *
445  * Caller holds tomoyo_read_lock().
446  */
447 bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
448 {
449         struct list_head *pos;
450         bool done = true;
451
452         list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
453                 struct tomoyo_pattern_entry *ptr;
454                 ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
455                 if (ptr->is_deleted)
456                         continue;
457                 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
458                                         "%s\n", ptr->pattern->name);
459                 if (!done)
460                         break;
461         }
462         return done;
463 }
464
465 /*
466  * tomoyo_no_rewrite_list is used for holding list of pathnames which are by
467  * default forbidden to modify already written content of a file.
468  *
469  * An entry is added by
470  *
471  * # echo 'deny_rewrite /var/log/messages' > \
472  *                              /sys/kernel/security/tomoyo/exception_policy
473  *
474  * and is deleted by
475  *
476  * # echo 'delete deny_rewrite /var/log/messages' > \
477  *                              /sys/kernel/security/tomoyo/exception_policy
478  *
479  * and all entries are retrieved by
480  *
481  * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy
482  *
483  * In the example above, if a process requested to rewrite /var/log/messages ,
484  * the process can't rewrite unless the domain which that process belongs to
485  * has "allow_rewrite /var/log/messages" entry.
486  *
487  * It is not a desirable behavior that we have to add "\040(deleted)" suffix
488  * when we want to allow rewriting already unlink()ed file. As of now,
489  * LSM version of TOMOYO is using __d_path() for calculating pathname.
490  * Non LSM version of TOMOYO is using its own function which doesn't append
491  * " (deleted)" suffix if the file is already unlink()ed; so that we don't
492  * need to worry whether the file is already unlink()ed or not.
493  */
494 LIST_HEAD(tomoyo_no_rewrite_list);
495
496 /**
497  * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
498  *
499  * @pattern:   Pathname pattern that are not rewritable by default.
500  * @is_delete: True if it is a delete request.
501  *
502  * Returns 0 on success, negative value otherwise.
503  *
504  * Caller holds tomoyo_read_lock().
505  */
506 static int tomoyo_update_no_rewrite_entry(const char *pattern,
507                                           const bool is_delete)
508 {
509         struct tomoyo_no_rewrite_entry *ptr;
510         struct tomoyo_no_rewrite_entry e = { };
511         int error = is_delete ? -ENOENT : -ENOMEM;
512
513         if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
514                 return -EINVAL;
515         e.pattern = tomoyo_get_name(pattern);
516         if (!e.pattern)
517                 return error;
518         if (mutex_lock_interruptible(&tomoyo_policy_lock))
519                 goto out;
520         list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
521                 if (ptr->pattern != e.pattern)
522                         continue;
523                 ptr->is_deleted = is_delete;
524                 error = 0;
525                 break;
526         }
527         if (!is_delete && error) {
528                 struct tomoyo_no_rewrite_entry *entry =
529                         tomoyo_commit_ok(&e, sizeof(e));
530                 if (entry) {
531                         list_add_tail_rcu(&entry->list,
532                                           &tomoyo_no_rewrite_list);
533                         error = 0;
534                 }
535         }
536         mutex_unlock(&tomoyo_policy_lock);
537  out:
538         tomoyo_put_name(e.pattern);
539         return error;
540 }
541
542 /**
543  * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
544  *
545  * @filename: Filename to check.
546  *
547  * Returns true if @filename is specified by "deny_rewrite" directive,
548  * false otherwise.
549  *
550  * Caller holds tomoyo_read_lock().
551  */
552 static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
553 {
554         struct tomoyo_no_rewrite_entry *ptr;
555         bool found = false;
556
557         list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
558                 if (ptr->is_deleted)
559                         continue;
560                 if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
561                         continue;
562                 found = true;
563                 break;
564         }
565         return found;
566 }
567
568 /**
569  * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
570  *
571  * @data:      String to parse.
572  * @is_delete: True if it is a delete request.
573  *
574  * Returns 0 on success, negative value otherwise.
575  *
576  * Caller holds tomoyo_read_lock().
577  */
578 int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
579 {
580         return tomoyo_update_no_rewrite_entry(data, is_delete);
581 }
582
583 /**
584  * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
585  *
586  * @head: Pointer to "struct tomoyo_io_buffer".
587  *
588  * Returns true on success, false otherwise.
589  *
590  * Caller holds tomoyo_read_lock().
591  */
592 bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
593 {
594         struct list_head *pos;
595         bool done = true;
596
597         list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
598                 struct tomoyo_no_rewrite_entry *ptr;
599                 ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
600                 if (ptr->is_deleted)
601                         continue;
602                 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
603                                         "%s\n", ptr->pattern->name);
604                 if (!done)
605                         break;
606         }
607         return done;
608 }
609
610 /**
611  * tomoyo_update_file_acl - Update file's read/write/execute ACL.
612  *
613  * @filename:  Filename.
614  * @perm:      Permission (between 1 to 7).
615  * @domain:    Pointer to "struct tomoyo_domain_info".
616  * @is_delete: True if it is a delete request.
617  *
618  * Returns 0 on success, negative value otherwise.
619  *
620  * This is legacy support interface for older policy syntax.
621  * Current policy syntax uses "allow_read/write" instead of "6",
622  * "allow_read" instead of "4", "allow_write" instead of "2",
623  * "allow_execute" instead of "1".
624  *
625  * Caller holds tomoyo_read_lock().
626  */
627 static int tomoyo_update_file_acl(const char *filename, u8 perm,
628                                   struct tomoyo_domain_info * const domain,
629                                   const bool is_delete)
630 {
631         if (perm > 7 || !perm) {
632                 printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
633                        __func__, perm, filename);
634                 return -EINVAL;
635         }
636         if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
637                 /*
638                  * Only 'allow_mkdir' and 'allow_rmdir' are valid for
639                  * directory permissions.
640                  */
641                 return 0;
642         if (perm & 4)
643                 tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
644                                        is_delete);
645         if (perm & 2)
646                 tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
647                                        is_delete);
648         if (perm & 1)
649                 tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
650                                        is_delete);
651         return 0;
652 }
653
654 /**
655  * tomoyo_path_acl2 - Check permission for single path operation.
656  *
657  * @domain:          Pointer to "struct tomoyo_domain_info".
658  * @filename:        Filename to check.
659  * @perm:            Permission.
660  * @may_use_pattern: True if patterned ACL is permitted.
661  *
662  * Returns 0 on success, -EPERM otherwise.
663  *
664  * Caller holds tomoyo_read_lock().
665  */
666 static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
667                             const struct tomoyo_path_info *filename,
668                             const u32 perm, const bool may_use_pattern)
669 {
670         struct tomoyo_acl_info *ptr;
671         int error = -EPERM;
672
673         list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
674                 struct tomoyo_path_acl *acl;
675                 if (ptr->type != TOMOYO_TYPE_PATH_ACL)
676                         continue;
677                 acl = container_of(ptr, struct tomoyo_path_acl, head);
678                 if (perm <= 0xFFFF) {
679                         if (!(acl->perm & perm))
680                                 continue;
681                 } else {
682                         if (!(acl->perm_high & (perm >> 16)))
683                                 continue;
684                 }
685                 if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
686                                                        may_use_pattern))
687                         continue;
688                 error = 0;
689                 break;
690         }
691         return error;
692 }
693
694 /**
695  * tomoyo_check_file_acl - Check permission for opening files.
696  *
697  * @domain:    Pointer to "struct tomoyo_domain_info".
698  * @filename:  Filename to check.
699  * @operation: Mode ("read" or "write" or "read/write" or "execute").
700  *
701  * Returns 0 on success, -EPERM otherwise.
702  *
703  * Caller holds tomoyo_read_lock().
704  */
705 static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
706                                  const struct tomoyo_path_info *filename,
707                                  const u8 operation)
708 {
709         u32 perm = 0;
710
711         if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
712                 return 0;
713         if (operation == 6)
714                 perm = 1 << TOMOYO_TYPE_READ_WRITE;
715         else if (operation == 4)
716                 perm = 1 << TOMOYO_TYPE_READ;
717         else if (operation == 2)
718                 perm = 1 << TOMOYO_TYPE_WRITE;
719         else if (operation == 1)
720                 perm = 1 << TOMOYO_TYPE_EXECUTE;
721         else
722                 BUG();
723         return tomoyo_path_acl2(domain, filename, perm, operation != 1);
724 }
725
726 /**
727  * tomoyo_check_file_perm2 - Check permission for opening files.
728  *
729  * @domain:    Pointer to "struct tomoyo_domain_info".
730  * @filename:  Filename to check.
731  * @perm:      Mode ("read" or "write" or "read/write" or "execute").
732  * @operation: Operation name passed used for verbose mode.
733  * @mode:      Access control mode.
734  *
735  * Returns 0 on success, negative value otherwise.
736  *
737  * Caller holds tomoyo_read_lock().
738  */
739 static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
740                                    const struct tomoyo_path_info *filename,
741                                    const u8 perm, const char *operation,
742                                    const u8 mode)
743 {
744         const bool is_enforce = (mode == 3);
745         const char *msg = "<unknown>";
746         int error = 0;
747
748         if (!filename)
749                 return 0;
750         error = tomoyo_check_file_acl(domain, filename, perm);
751         if (error && perm == 4 && !domain->ignore_global_allow_read
752             && tomoyo_is_globally_readable_file(filename))
753                 error = 0;
754         if (perm == 6)
755                 msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE);
756         else if (perm == 4)
757                 msg = tomoyo_path2keyword(TOMOYO_TYPE_READ);
758         else if (perm == 2)
759                 msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE);
760         else if (perm == 1)
761                 msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE);
762         else
763                 BUG();
764         if (!error)
765                 return 0;
766         if (tomoyo_verbose_mode(domain))
767                 printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
768                        "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
769                        filename->name, tomoyo_get_last_name(domain));
770         if (is_enforce)
771                 return error;
772         if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
773                 /* Don't use patterns for execute permission. */
774                 const struct tomoyo_path_info *patterned_file = (perm != 1) ?
775                         tomoyo_get_file_pattern(filename) : filename;
776                 tomoyo_update_file_acl(patterned_file->name, perm,
777                                        domain, false);
778         }
779         return 0;
780 }
781
782 /**
783  * tomoyo_write_file_policy - Update file related list.
784  *
785  * @data:      String to parse.
786  * @domain:    Pointer to "struct tomoyo_domain_info".
787  * @is_delete: True if it is a delete request.
788  *
789  * Returns 0 on success, negative value otherwise.
790  *
791  * Caller holds tomoyo_read_lock().
792  */
793 int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
794                              const bool is_delete)
795 {
796         char *filename = strchr(data, ' ');
797         char *filename2;
798         unsigned int perm;
799         u8 type;
800
801         if (!filename)
802                 return -EINVAL;
803         *filename++ = '\0';
804         if (sscanf(data, "%u", &perm) == 1)
805                 return tomoyo_update_file_acl(filename, (u8) perm, domain,
806                                               is_delete);
807         if (strncmp(data, "allow_", 6))
808                 goto out;
809         data += 6;
810         for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
811                 if (strcmp(data, tomoyo_path_keyword[type]))
812                         continue;
813                 return tomoyo_update_path_acl(type, filename, domain,
814                                               is_delete);
815         }
816         filename2 = strchr(filename, ' ');
817         if (!filename2)
818                 goto out;
819         *filename2++ = '\0';
820         for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
821                 if (strcmp(data, tomoyo_path2_keyword[type]))
822                         continue;
823                 return tomoyo_update_path2_acl(type, filename, filename2,
824                                                domain, is_delete);
825         }
826  out:
827         return -EINVAL;
828 }
829
830 /**
831  * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
832  *
833  * @type:      Type of operation.
834  * @filename:  Filename.
835  * @domain:    Pointer to "struct tomoyo_domain_info".
836  * @is_delete: True if it is a delete request.
837  *
838  * Returns 0 on success, negative value otherwise.
839  *
840  * Caller holds tomoyo_read_lock().
841  */
842 static int tomoyo_update_path_acl(const u8 type, const char *filename,
843                                   struct tomoyo_domain_info *const domain,
844                                   const bool is_delete)
845 {
846         static const u32 tomoyo_rw_mask =
847                 (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
848         const u32 perm = 1 << type;
849         struct tomoyo_acl_info *ptr;
850         struct tomoyo_path_acl e = {
851                 .head.type = TOMOYO_TYPE_PATH_ACL,
852                 .perm_high = perm >> 16,
853                 .perm = perm
854         };
855         int error = is_delete ? -ENOENT : -ENOMEM;
856
857         if (type == TOMOYO_TYPE_READ_WRITE)
858                 e.perm |= tomoyo_rw_mask;
859         if (!domain)
860                 return -EINVAL;
861         if (!tomoyo_parse_name_union(filename, &e.name))
862                 return -EINVAL;
863         if (mutex_lock_interruptible(&tomoyo_policy_lock))
864                 goto out;
865         list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
866                 struct tomoyo_path_acl *acl =
867                         container_of(ptr, struct tomoyo_path_acl, head);
868                 if (!tomoyo_is_same_path_acl(acl, &e))
869                         continue;
870                 if (is_delete) {
871                         if (perm <= 0xFFFF)
872                                 acl->perm &= ~perm;
873                         else
874                                 acl->perm_high &= ~(perm >> 16);
875                         if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
876                                 acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
877                         else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
878                                 acl->perm &= ~tomoyo_rw_mask;
879                 } else {
880                         if (perm <= 0xFFFF)
881                                 acl->perm |= perm;
882                         else
883                                 acl->perm_high |= (perm >> 16);
884                         if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
885                                 acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
886                         else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
887                                 acl->perm |= tomoyo_rw_mask;
888                 }
889                 error = 0;
890                 break;
891         }
892         if (!is_delete && error) {
893                 struct tomoyo_path_acl *entry =
894                         tomoyo_commit_ok(&e, sizeof(e));
895                 if (entry) {
896                         list_add_tail_rcu(&entry->head.list,
897                                           &domain->acl_info_list);
898                         error = 0;
899                 }
900         }
901         mutex_unlock(&tomoyo_policy_lock);
902  out:
903         tomoyo_put_name_union(&e.name);
904         return error;
905 }
906
907 /**
908  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
909  *
910  * @type:      Type of operation.
911  * @filename1: First filename.
912  * @filename2: Second filename.
913  * @domain:    Pointer to "struct tomoyo_domain_info".
914  * @is_delete: True if it is a delete request.
915  *
916  * Returns 0 on success, negative value otherwise.
917  *
918  * Caller holds tomoyo_read_lock().
919  */
920 static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
921                                    const char *filename2,
922                                    struct tomoyo_domain_info *const domain,
923                                    const bool is_delete)
924 {
925         const u8 perm = 1 << type;
926         struct tomoyo_path2_acl e = {
927                 .head.type = TOMOYO_TYPE_PATH2_ACL,
928                 .perm = perm
929         };
930         struct tomoyo_acl_info *ptr;
931         int error = is_delete ? -ENOENT : -ENOMEM;
932
933         if (!domain)
934                 return -EINVAL;
935         if (!tomoyo_parse_name_union(filename1, &e.name1) ||
936             !tomoyo_parse_name_union(filename2, &e.name2))
937                 goto out;
938         if (mutex_lock_interruptible(&tomoyo_policy_lock))
939                 goto out;
940         list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
941                 struct tomoyo_path2_acl *acl =
942                         container_of(ptr, struct tomoyo_path2_acl, head);
943                 if (!tomoyo_is_same_path2_acl(acl, &e))
944                         continue;
945                 if (is_delete)
946                         acl->perm &= ~perm;
947                 else
948                         acl->perm |= perm;
949                 error = 0;
950                 break;
951         }
952         if (!is_delete && error) {
953                 struct tomoyo_path2_acl *entry =
954                         tomoyo_commit_ok(&e, sizeof(e));
955                 if (entry) {
956                         list_add_tail_rcu(&entry->head.list,
957                                           &domain->acl_info_list);
958                         error = 0;
959                 }
960         }
961         mutex_unlock(&tomoyo_policy_lock);
962  out:
963         tomoyo_put_name_union(&e.name1);
964         tomoyo_put_name_union(&e.name2);
965         return error;
966 }
967
968 /**
969  * tomoyo_path_acl - Check permission for single path operation.
970  *
971  * @domain:   Pointer to "struct tomoyo_domain_info".
972  * @type:     Type of operation.
973  * @filename: Filename to check.
974  *
975  * Returns 0 on success, negative value otherwise.
976  *
977  * Caller holds tomoyo_read_lock().
978  */
979 static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
980                            const struct tomoyo_path_info *filename)
981 {
982         if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
983                 return 0;
984         return tomoyo_path_acl2(domain, filename, 1 << type, 1);
985 }
986
987 /**
988  * tomoyo_path2_acl - Check permission for double path operation.
989  *
990  * @domain:    Pointer to "struct tomoyo_domain_info".
991  * @type:      Type of operation.
992  * @filename1: First filename to check.
993  * @filename2: Second filename to check.
994  *
995  * Returns 0 on success, -EPERM otherwise.
996  *
997  * Caller holds tomoyo_read_lock().
998  */
999 static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
1000                             const u8 type,
1001                             const struct tomoyo_path_info *filename1,
1002                             const struct tomoyo_path_info *filename2)
1003 {
1004         struct tomoyo_acl_info *ptr;
1005         const u8 perm = 1 << type;
1006         int error = -EPERM;
1007
1008         if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
1009                 return 0;
1010         list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1011                 struct tomoyo_path2_acl *acl;
1012                 if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
1013                         continue;
1014                 acl = container_of(ptr, struct tomoyo_path2_acl, head);
1015                 if (!(acl->perm & perm))
1016                         continue;
1017                 if (!tomoyo_compare_name_union(filename1, &acl->name1))
1018                         continue;
1019                 if (!tomoyo_compare_name_union(filename2, &acl->name2))
1020                         continue;
1021                 error = 0;
1022                 break;
1023         }
1024         return error;
1025 }
1026
1027 /**
1028  * tomoyo_path_permission2 - Check permission for single path operation.
1029  *
1030  * @domain:    Pointer to "struct tomoyo_domain_info".
1031  * @operation: Type of operation.
1032  * @filename:  Filename to check.
1033  * @mode:      Access control mode.
1034  *
1035  * Returns 0 on success, negative value otherwise.
1036  *
1037  * Caller holds tomoyo_read_lock().
1038  */
1039 static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
1040                                    u8 operation,
1041                                    const struct tomoyo_path_info *filename,
1042                                    const u8 mode)
1043 {
1044         const char *msg;
1045         int error;
1046         const bool is_enforce = (mode == 3);
1047
1048         if (!mode)
1049                 return 0;
1050  next:
1051         error = tomoyo_path_acl(domain, operation, filename);
1052         msg = tomoyo_path2keyword(operation);
1053         if (!error)
1054                 goto ok;
1055         if (tomoyo_verbose_mode(domain))
1056                 printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
1057                        tomoyo_get_msg(is_enforce), msg, filename->name,
1058                        tomoyo_get_last_name(domain));
1059         if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
1060                 const char *name = tomoyo_get_file_pattern(filename)->name;
1061                 tomoyo_update_path_acl(operation, name, domain, false);
1062         }
1063         if (!is_enforce)
1064                 error = 0;
1065  ok:
1066         /*
1067          * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
1068          * we need to check "allow_rewrite" permission if the filename is
1069          * specified by "deny_rewrite" keyword.
1070          */
1071         if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
1072             tomoyo_is_no_rewrite_file(filename)) {
1073                 operation = TOMOYO_TYPE_REWRITE;
1074                 goto next;
1075         }
1076         return error;
1077 }
1078
1079 /**
1080  * tomoyo_check_exec_perm - Check permission for "execute".
1081  *
1082  * @domain:   Pointer to "struct tomoyo_domain_info".
1083  * @filename: Check permission for "execute".
1084  *
1085  * Returns 0 on success, negativevalue otherwise.
1086  *
1087  * Caller holds tomoyo_read_lock().
1088  */
1089 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
1090                            const struct tomoyo_path_info *filename)
1091 {
1092         const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1093
1094         if (!mode)
1095                 return 0;
1096         return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
1097 }
1098
1099 /**
1100  * tomoyo_check_open_permission - Check permission for "read" and "write".
1101  *
1102  * @domain: Pointer to "struct tomoyo_domain_info".
1103  * @path:   Pointer to "struct path".
1104  * @flag:   Flags for open().
1105  *
1106  * Returns 0 on success, negative value otherwise.
1107  */
1108 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
1109                                  struct path *path, const int flag)
1110 {
1111         const u8 acc_mode = ACC_MODE(flag);
1112         int error = -ENOMEM;
1113         struct tomoyo_path_info *buf;
1114         const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1115         const bool is_enforce = (mode == 3);
1116         int idx;
1117
1118         if (!mode || !path->mnt)
1119                 return 0;
1120         if (acc_mode == 0)
1121                 return 0;
1122         if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
1123                 /*
1124                  * I don't check directories here because mkdir() and rmdir()
1125                  * don't call me.
1126                  */
1127                 return 0;
1128         idx = tomoyo_read_lock();
1129         buf = tomoyo_get_path(path);
1130         if (!buf)
1131                 goto out;
1132         error = 0;
1133         /*
1134          * If the filename is specified by "deny_rewrite" keyword,
1135          * we need to check "allow_rewrite" permission when the filename is not
1136          * opened for append mode or the filename is truncated at open time.
1137          */
1138         if ((acc_mode & MAY_WRITE) &&
1139             ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
1140             (tomoyo_is_no_rewrite_file(buf))) {
1141                 error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE,
1142                                                 buf, mode);
1143         }
1144         if (!error)
1145                 error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
1146                                                 mode);
1147         if (!error && (flag & O_TRUNC))
1148                 error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE,
1149                                                 buf, mode);
1150  out:
1151         kfree(buf);
1152         tomoyo_read_unlock(idx);
1153         if (!is_enforce)
1154                 error = 0;
1155         return error;
1156 }
1157
1158 /**
1159  * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
1160  *
1161  * @operation: Type of operation.
1162  * @path:      Pointer to "struct path".
1163  *
1164  * Returns 0 on success, negative value otherwise.
1165  */
1166 int tomoyo_path_perm(const u8 operation, struct path *path)
1167 {
1168         int error = -ENOMEM;
1169         struct tomoyo_path_info *buf;
1170         struct tomoyo_domain_info *domain = tomoyo_domain();
1171         const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1172         const bool is_enforce = (mode == 3);
1173         int idx;
1174
1175         if (!mode || !path->mnt)
1176                 return 0;
1177         idx = tomoyo_read_lock();
1178         buf = tomoyo_get_path(path);
1179         if (!buf)
1180                 goto out;
1181         switch (operation) {
1182         case TOMOYO_TYPE_MKDIR:
1183         case TOMOYO_TYPE_RMDIR:
1184         case TOMOYO_TYPE_CHROOT:
1185                 if (!buf->is_dir) {
1186                         /*
1187                          * tomoyo_get_path() reserves space for appending "/."
1188                          */
1189                         strcat((char *) buf->name, "/");
1190                         tomoyo_fill_path_info(buf);
1191                 }
1192         }
1193         error = tomoyo_path_permission2(domain, operation, buf, mode);
1194  out:
1195         kfree(buf);
1196         tomoyo_read_unlock(idx);
1197         if (!is_enforce)
1198                 error = 0;
1199         return error;
1200 }
1201
1202 /**
1203  * tomoyo_check_rewrite_permission - Check permission for "rewrite".
1204  *
1205  * @filp: Pointer to "struct file".
1206  *
1207  * Returns 0 on success, negative value otherwise.
1208  */
1209 int tomoyo_check_rewrite_permission(struct file *filp)
1210 {
1211         int error = -ENOMEM;
1212         struct tomoyo_domain_info *domain = tomoyo_domain();
1213         const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1214         const bool is_enforce = (mode == 3);
1215         struct tomoyo_path_info *buf;
1216         int idx;
1217
1218         if (!mode || !filp->f_path.mnt)
1219                 return 0;
1220
1221         idx = tomoyo_read_lock();
1222         buf = tomoyo_get_path(&filp->f_path);
1223         if (!buf)
1224                 goto out;
1225         if (!tomoyo_is_no_rewrite_file(buf)) {
1226                 error = 0;
1227                 goto out;
1228         }
1229         error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode);
1230  out:
1231         kfree(buf);
1232         tomoyo_read_unlock(idx);
1233         if (!is_enforce)
1234                 error = 0;
1235         return error;
1236 }
1237
1238 /**
1239  * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
1240  *
1241  * @operation: Type of operation.
1242  * @path1:      Pointer to "struct path".
1243  * @path2:      Pointer to "struct path".
1244  *
1245  * Returns 0 on success, negative value otherwise.
1246  */
1247 int tomoyo_path2_perm(const u8 operation, struct path *path1,
1248                       struct path *path2)
1249 {
1250         int error = -ENOMEM;
1251         struct tomoyo_path_info *buf1, *buf2;
1252         struct tomoyo_domain_info *domain = tomoyo_domain();
1253         const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1254         const bool is_enforce = (mode == 3);
1255         const char *msg;
1256         int idx;
1257
1258         if (!mode || !path1->mnt || !path2->mnt)
1259                 return 0;
1260         idx = tomoyo_read_lock();
1261         buf1 = tomoyo_get_path(path1);
1262         buf2 = tomoyo_get_path(path2);
1263         if (!buf1 || !buf2)
1264                 goto out;
1265         {
1266                 struct dentry *dentry = path1->dentry;
1267                 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
1268                         /*
1269                          * tomoyo_get_path() reserves space for appending "/."
1270                          */
1271                         if (!buf1->is_dir) {
1272                                 strcat((char *) buf1->name, "/");
1273                                 tomoyo_fill_path_info(buf1);
1274                         }
1275                         if (!buf2->is_dir) {
1276                                 strcat((char *) buf2->name, "/");
1277                                 tomoyo_fill_path_info(buf2);
1278                         }
1279                 }
1280         }
1281         error = tomoyo_path2_acl(domain, operation, buf1, buf2);
1282         msg = tomoyo_path22keyword(operation);
1283         if (!error)
1284                 goto out;
1285         if (tomoyo_verbose_mode(domain))
1286                 printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
1287                        "denied for %s\n", tomoyo_get_msg(is_enforce),
1288                        msg, buf1->name, buf2->name,
1289                        tomoyo_get_last_name(domain));
1290         if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
1291                 const char *name1 = tomoyo_get_file_pattern(buf1)->name;
1292                 const char *name2 = tomoyo_get_file_pattern(buf2)->name;
1293                 tomoyo_update_path2_acl(operation, name1, name2, domain,
1294                                         false);
1295         }
1296  out:
1297         kfree(buf1);
1298         kfree(buf2);
1299         tomoyo_read_unlock(idx);
1300         if (!is_enforce)
1301                 error = 0;
1302         return error;
1303 }