オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /trunk/1.7.x/ccs-patch/security/ccsecurity/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3494 - (show annotations) (download) (as text)
Wed Mar 3 11:44:18 2010 UTC (14 years, 3 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 70779 byte(s)


1 /*
2 * security/ccsecurity/file.c
3 *
4 * Copyright (C) 2005-2010 NTT DATA CORPORATION
5 *
6 * Version: 1.7.2-pre 2010/03/02
7 *
8 * This file is applicable to both 2.4.30 and 2.6.11 and later.
9 * See README.ccs for ChangeLog.
10 *
11 */
12
13 #include "internal.h"
14 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
15 #include <linux/mount.h>
16 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17 #include <linux/namespace.h>
18 #endif
19 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
20 #include <linux/dcache.h>
21 #include <linux/namei.h>
22 #endif
23 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 33)
24 /*
25 * ACC_MODE() in this file uses old definition because may_open() receives
26 * open flags modified by open_to_namei_flags() until 2.6.33.
27 * may_open() receives unmodified flags after 2.6.34.
28 */
29 #undef ACC_MODE
30 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
31 #endif
32
33 static const char *ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
34 [CCS_TYPE_READ_WRITE] = "read/write",
35 [CCS_TYPE_EXECUTE] = "execute",
36 [CCS_TYPE_READ] = "read",
37 [CCS_TYPE_WRITE] = "write",
38 [CCS_TYPE_UNLINK] = "unlink",
39 [CCS_TYPE_RMDIR] = "rmdir",
40 [CCS_TYPE_TRUNCATE] = "truncate",
41 [CCS_TYPE_SYMLINK] = "symlink",
42 [CCS_TYPE_REWRITE] = "rewrite",
43 [CCS_TYPE_CHROOT] = "chroot",
44 [CCS_TYPE_UMOUNT] = "unmount",
45 [CCS_TYPE_TRANSIT] = "transit",
46 };
47
48 static const char *ccs_path_number3_keyword[CCS_MAX_PATH_NUMBER3_OPERATION] = {
49 [CCS_TYPE_MKBLOCK] = "mkblock",
50 [CCS_TYPE_MKCHAR] = "mkchar",
51 };
52
53 static const char *ccs_path2_keyword[CCS_MAX_PATH2_OPERATION] = {
54 [CCS_TYPE_LINK] = "link",
55 [CCS_TYPE_RENAME] = "rename",
56 [CCS_TYPE_PIVOT_ROOT] = "pivot_root",
57 };
58
59 static const char *ccs_path_number_keyword[CCS_MAX_PATH_NUMBER_OPERATION] = {
60 [CCS_TYPE_CREATE] = "create",
61 [CCS_TYPE_MKDIR] = "mkdir",
62 [CCS_TYPE_MKFIFO] = "mkfifo",
63 [CCS_TYPE_MKSOCK] = "mksock",
64 [CCS_TYPE_IOCTL] = "ioctl",
65 [CCS_TYPE_CHMOD] = "chmod",
66 [CCS_TYPE_CHOWN] = "chown",
67 [CCS_TYPE_CHGRP] = "chgrp",
68 };
69
70 static const u8 ccs_p2mac[CCS_MAX_PATH_OPERATION] = {
71 [CCS_TYPE_READ_WRITE] = CCS_MAC_FILE_OPEN,
72 [CCS_TYPE_EXECUTE] = CCS_MAC_FILE_EXECUTE,
73 [CCS_TYPE_READ] = CCS_MAC_FILE_OPEN,
74 [CCS_TYPE_WRITE] = CCS_MAC_FILE_OPEN,
75 [CCS_TYPE_UNLINK] = CCS_MAC_FILE_UNLINK,
76 [CCS_TYPE_RMDIR] = CCS_MAC_FILE_RMDIR,
77 [CCS_TYPE_TRUNCATE] = CCS_MAC_FILE_TRUNCATE,
78 [CCS_TYPE_SYMLINK] = CCS_MAC_FILE_SYMLINK,
79 [CCS_TYPE_REWRITE] = CCS_MAC_FILE_REWRITE,
80 [CCS_TYPE_CHROOT] = CCS_MAC_FILE_CHROOT,
81 [CCS_TYPE_UMOUNT] = CCS_MAC_FILE_UMOUNT,
82 [CCS_TYPE_TRANSIT] = CCS_MAC_FILE_TRANSIT,
83 };
84
85 static const u8 ccs_pnnn2mac[CCS_MAX_PATH_NUMBER3_OPERATION] = {
86 [CCS_TYPE_MKBLOCK] = CCS_MAC_FILE_MKBLOCK,
87 [CCS_TYPE_MKCHAR] = CCS_MAC_FILE_MKCHAR,
88 };
89
90 static const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION] = {
91 [CCS_TYPE_LINK] = CCS_MAC_FILE_LINK,
92 [CCS_TYPE_RENAME] = CCS_MAC_FILE_RENAME,
93 [CCS_TYPE_PIVOT_ROOT] = CCS_MAC_FILE_PIVOT_ROOT,
94 };
95
96 static const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION] = {
97 [CCS_TYPE_CREATE] = CCS_MAC_FILE_CREATE,
98 [CCS_TYPE_MKDIR] = CCS_MAC_FILE_MKDIR,
99 [CCS_TYPE_MKFIFO] = CCS_MAC_FILE_MKFIFO,
100 [CCS_TYPE_MKSOCK] = CCS_MAC_FILE_MKSOCK,
101 [CCS_TYPE_IOCTL] = CCS_MAC_FILE_IOCTL,
102 [CCS_TYPE_CHMOD] = CCS_MAC_FILE_CHMOD,
103 [CCS_TYPE_CHOWN] = CCS_MAC_FILE_CHOWN,
104 [CCS_TYPE_CHGRP] = CCS_MAC_FILE_CHGRP,
105 };
106
107 /*
108 * Below part contains copy of some of VFS helper functions.
109 *
110 * Since TOMOYO Linux requires "struct vfsmount" parameter to calculate
111 * an absolute pathname of the requested "struct dentry" parameter
112 * but the VFS helper functions don't receive "struct vfsmount" parameter,
113 * TOMOYO Linux checks permission outside VFS helper functions.
114 * To keep the DAC's permission checks are performed before the
115 * TOMOYO Linux's permission checks are performed, I'm manually copying
116 * these functions that performs the DAC's permission checks from fs/namei.c .
117 */
118
119 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
120
121 /* Permission checks from vfs_create(). */
122 static inline int ccs_pre_vfs_create(struct inode *dir, struct dentry *dentry)
123 {
124 int error;
125 down(&dir->i_zombie);
126 error = ccs_may_create(dir, dentry);
127 if (!error && (!dir->i_op || !dir->i_op->create))
128 error = -EACCES;
129 up(&dir->i_zombie);
130 return error;
131 }
132
133 /* Permission checks from vfs_mknod(). */
134 static int ccs_pre_vfs_mknod(struct inode *dir, struct dentry *dentry)
135 {
136 int error;
137 down(&dir->i_zombie);
138 error = ccs_may_create(dir, dentry);
139 if (!error && (!dir->i_op || !dir->i_op->mknod))
140 error = -EPERM;
141 up(&dir->i_zombie);
142 return error;
143 }
144
145 /* Permission checks from vfs_mkdir(). */
146 static inline int ccs_pre_vfs_mkdir(struct inode *dir, struct dentry *dentry)
147 {
148 int error;
149 down(&dir->i_zombie);
150 error = ccs_may_create(dir, dentry);
151 if (!error && (!dir->i_op || !dir->i_op->mkdir))
152 error = -EPERM;
153 up(&dir->i_zombie);
154 return error;
155 }
156
157 /* Permission checks from vfs_rmdir(). */
158 static inline int ccs_pre_vfs_rmdir(struct inode *dir, struct dentry *dentry)
159 {
160 int error = ccs_may_delete(dir, dentry, 1);
161 if (!error && (!dir->i_op || !dir->i_op->rmdir))
162 error = -EPERM;
163 return error;
164 }
165
166 /* Permission checks from vfs_unlink(). */
167 static inline int ccs_pre_vfs_unlink(struct inode *dir, struct dentry *dentry)
168 {
169 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 33)
170 int error;
171 down(&dir->i_zombie);
172 error = ccs_may_delete(dir, dentry, 0);
173 if (!error && (!dir->i_op || !dir->i_op->unlink))
174 error = -EPERM;
175 up(&dir->i_zombie);
176 return error;
177 #else
178 int error;
179 struct inode *inode;
180 error = ccs_may_delete(dir, dentry, 0);
181 if (error)
182 return error;
183 inode = dentry->d_inode;
184 atomic_inc(&inode->i_count);
185 double_down(&dir->i_zombie, &inode->i_zombie);
186 error = -EPERM;
187 if (dir->i_op && dir->i_op->unlink)
188 error = 0;
189 double_up(&dir->i_zombie, &inode->i_zombie);
190 iput(inode);
191 return error;
192 #endif
193 }
194
195 /* Permission checks from vfs_symlink(). */
196 static inline int ccs_pre_vfs_symlink(struct inode *dir, struct dentry *dentry)
197 {
198 int error;
199 down(&dir->i_zombie);
200 error = ccs_may_create(dir, dentry);
201 if (error)
202 goto exit_lock;
203 if (!dir->i_op || !dir->i_op->symlink)
204 error = -EPERM;
205 exit_lock:
206 up(&dir->i_zombie);
207 return error;
208 }
209
210 /* Permission checks from vfs_link(). */
211 static inline int ccs_pre_vfs_link(struct dentry *old_dentry,
212 struct inode *dir,
213 struct dentry *new_dentry)
214 {
215 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 33)
216 struct inode *inode;
217 int error;
218 down(&dir->i_zombie);
219 error = -ENOENT;
220 inode = old_dentry->d_inode;
221 if (!inode)
222 goto exit_lock;
223 error = ccs_may_create(dir, new_dentry);
224 if (error)
225 goto exit_lock;
226 error = -EXDEV;
227 if (dir->i_dev != inode->i_dev)
228 goto exit_lock;
229 error = -EPERM;
230 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
231 goto exit_lock;
232 if (!dir->i_op || !dir->i_op->link)
233 goto exit_lock;
234 error = 0;
235 exit_lock:
236 up(&dir->i_zombie);
237 return error;
238 #else
239 struct inode *inode;
240 int error;
241 error = -ENOENT;
242 inode = old_dentry->d_inode;
243 if (!inode)
244 goto exit;
245 error = -EXDEV;
246 if (dir->i_dev != inode->i_dev)
247 goto exit;
248 double_down(&dir->i_zombie, &old_dentry->d_inode->i_zombie);
249 error = ccs_may_create(dir, new_dentry);
250 if (error)
251 goto exit_lock;
252 error = -EPERM;
253 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
254 goto exit_lock;
255 if (!dir->i_op || !dir->i_op->link)
256 goto exit_lock;
257 error = 0;
258 exit_lock:
259 double_up(&dir->i_zombie, &old_dentry->d_inode->i_zombie);
260 exit:
261 return error;
262 #endif
263 }
264
265 /* Permission checks from vfs_rename_dir(). */
266 static inline int ccs_pre_vfs_rename_dir(struct inode *old_dir,
267 struct dentry *old_dentry,
268 struct inode *new_dir,
269 struct dentry *new_dentry)
270 {
271 int error;
272 if (old_dentry->d_inode == new_dentry->d_inode)
273 return 0;
274 error = ccs_may_delete(old_dir, old_dentry, 1);
275 if (error)
276 return error;
277 if (new_dir->i_dev != old_dir->i_dev)
278 return -EXDEV;
279 if (!new_dentry->d_inode)
280 error = ccs_may_create(new_dir, new_dentry);
281 else
282 error = ccs_may_delete(new_dir, new_dentry, 1);
283 if (error)
284 return error;
285 if (!old_dir->i_op || !old_dir->i_op->rename)
286 return -EPERM;
287 if (new_dir != old_dir)
288 error = permission(old_dentry->d_inode, MAY_WRITE);
289 return error;
290 }
291
292 /* Permission checks from vfs_rename_other(). */
293 static inline int ccs_pre_vfs_rename_other(struct inode *old_dir,
294 struct dentry *old_dentry,
295 struct inode *new_dir,
296 struct dentry *new_dentry)
297 {
298 int error;
299 if (old_dentry->d_inode == new_dentry->d_inode)
300 return 0;
301 error = ccs_may_delete(old_dir, old_dentry, 0);
302 if (error)
303 return error;
304 if (new_dir->i_dev != old_dir->i_dev)
305 return -EXDEV;
306 if (!new_dentry->d_inode)
307 error = ccs_may_create(new_dir, new_dentry);
308 else
309 error = ccs_may_delete(new_dir, new_dentry, 0);
310 if (error)
311 return error;
312 if (!old_dir->i_op || !old_dir->i_op->rename)
313 return -EPERM;
314 return 0;
315 }
316
317 /* Permission checks from vfs_rename(). */
318 static inline int ccs_pre_vfs_rename(struct inode *old_dir,
319 struct dentry *old_dentry,
320 struct inode *new_dir,
321 struct dentry *new_dentry)
322 {
323 int error;
324 lock_kernel(); /* From do_rename(). */
325 if (S_ISDIR(old_dentry->d_inode->i_mode))
326 error = ccs_pre_vfs_rename_dir(old_dir, old_dentry,
327 new_dir, new_dentry);
328 else
329 error = ccs_pre_vfs_rename_other(old_dir, old_dentry,
330 new_dir, new_dentry);
331 unlock_kernel(); /* From do_rename(). */
332 return error;
333 }
334
335 #else
336
337 /* Permission checks from vfs_create(). */
338 static inline int ccs_pre_vfs_create(struct inode *dir, struct dentry *dentry)
339 {
340 int error = ccs_may_create(dir, dentry, 0);
341 if (error)
342 return error;
343 if (!dir->i_op || !dir->i_op->create)
344 return -EACCES; /* shouldn't it be ENOSYS? */
345 return 0;
346 }
347
348 /* Permission checks from vfs_mknod(). */
349 static int ccs_pre_vfs_mknod(struct inode *dir, struct dentry *dentry)
350 {
351 int error = ccs_may_create(dir, dentry, 0);
352 if (error)
353 return error;
354 if (!dir->i_op || !dir->i_op->mknod)
355 return -EPERM;
356 return 0;
357 }
358
359 /* Permission checks from vfs_mkdir(). */
360 static inline int ccs_pre_vfs_mkdir(struct inode *dir, struct dentry *dentry)
361 {
362 int error = ccs_may_create(dir, dentry, 1);
363 if (error)
364 return error;
365 if (!dir->i_op || !dir->i_op->mkdir)
366 return -EPERM;
367 return 0;
368 }
369
370 /* Permission checks from vfs_rmdir(). */
371 static inline int ccs_pre_vfs_rmdir(struct inode *dir, struct dentry *dentry)
372 {
373 int error = ccs_may_delete(dir, dentry, 1);
374 if (error)
375 return error;
376 if (!dir->i_op || !dir->i_op->rmdir)
377 return -EPERM;
378 return 0;
379 }
380
381 /* Permission checks from vfs_unlink(). */
382 static inline int ccs_pre_vfs_unlink(struct inode *dir, struct dentry *dentry)
383 {
384 int error = ccs_may_delete(dir, dentry, 0);
385 if (error)
386 return error;
387 if (!dir->i_op || !dir->i_op->unlink)
388 return -EPERM;
389 return 0;
390 }
391
392 /* Permission checks from vfs_link(). */
393 static inline int ccs_pre_vfs_link(struct dentry *old_dentry,
394 struct inode *dir,
395 struct dentry *new_dentry)
396 {
397 struct inode *inode = old_dentry->d_inode;
398 int error;
399 if (!inode)
400 return -ENOENT;
401 error = ccs_may_create(dir, new_dentry, 0);
402 if (error)
403 return error;
404 if (dir->i_sb != inode->i_sb)
405 return -EXDEV;
406 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
407 return -EPERM;
408 if (!dir->i_op || !dir->i_op->link)
409 return -EPERM;
410 if (S_ISDIR(old_dentry->d_inode->i_mode))
411 return -EPERM;
412 return 0;
413 }
414
415 /* Permission checks from vfs_symlink(). */
416 static inline int ccs_pre_vfs_symlink(struct inode *dir, struct dentry *dentry)
417 {
418 int error = ccs_may_create(dir, dentry, 0);
419 if (error)
420 return error;
421 if (!dir->i_op || !dir->i_op->symlink)
422 return -EPERM;
423 return 0;
424 }
425
426 /* Permission checks from vfs_rename(). */
427 static inline int ccs_pre_vfs_rename(struct inode *old_dir,
428 struct dentry *old_dentry,
429 struct inode *new_dir,
430 struct dentry *new_dentry)
431 {
432 int error;
433 const int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
434 if (old_dentry->d_inode == new_dentry->d_inode)
435 return 0;
436 error = ccs_may_delete(old_dir, old_dentry, is_dir);
437 if (error)
438 return error;
439 if (!new_dentry->d_inode)
440 error = ccs_may_create(new_dir, new_dentry, is_dir);
441 else
442 error = ccs_may_delete(new_dir, new_dentry, is_dir);
443 if (error)
444 return error;
445 if (!old_dir->i_op || !old_dir->i_op->rename)
446 return -EPERM;
447 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
448 if (is_dir && new_dir != old_dir)
449 error = permission(old_dentry->d_inode, MAY_WRITE, NULL);
450 #else
451 if (is_dir && new_dir != old_dir)
452 error = inode_permission(old_dentry->d_inode, MAY_WRITE);
453 #endif
454 return error;
455 }
456
457 #endif
458
459 /* Main functions. */
460
461 void ccs_put_name_union(struct ccs_name_union *ptr)
462 {
463 if (!ptr)
464 return;
465 if (ptr->is_group)
466 ccs_put_path_group(ptr->group);
467 else
468 ccs_put_name(ptr->filename);
469 }
470
471 void ccs_put_number_union(struct ccs_number_union *ptr)
472 {
473 if (ptr && ptr->is_group)
474 ccs_put_number_group(ptr->group);
475 }
476
477 bool ccs_compare_number_union(const unsigned long value,
478 const struct ccs_number_union *ptr)
479 {
480 if (ptr->is_group)
481 return ccs_number_matches_group(value, value, ptr->group);
482 return value >= ptr->values[0] && value <= ptr->values[1];
483 }
484
485 bool ccs_compare_name_union(const struct ccs_path_info *name,
486 const struct ccs_name_union *ptr)
487 {
488 if (ptr->is_group)
489 return ccs_path_matches_group(name, ptr->group, 1);
490 return ccs_path_matches_pattern(name, ptr->filename);
491 }
492
493 static bool ccs_compare_name_union_pattern(const struct ccs_path_info *name,
494 const struct ccs_name_union *ptr,
495 const bool may_use_pattern)
496 {
497 if (ptr->is_group)
498 return ccs_path_matches_group(name, ptr->group,
499 may_use_pattern);
500 if (may_use_pattern || !ptr->filename->is_patterned)
501 return ccs_path_matches_pattern(name, ptr->filename);
502 return false;
503 }
504
505 /**
506 * ccs_path2keyword - Get the name of path operations.
507 *
508 * @operation: Type of operation.
509 *
510 * Returns the name of path operation.
511 */
512 const char *ccs_path2keyword(const u8 operation)
513 {
514 return (operation < CCS_MAX_PATH_OPERATION)
515 ? ccs_path_keyword[operation] : NULL;
516 }
517
518 /**
519 * ccs_path_number32keyword - Get the name of path/number/number/number operations.
520 *
521 * @operation: Type of operation.
522 *
523 * Returns the name of path/number/number/number operation.
524 */
525 const char *ccs_path_number32keyword(const u8 operation)
526 {
527 return (operation < CCS_MAX_PATH_NUMBER3_OPERATION)
528 ? ccs_path_number3_keyword[operation] : NULL;
529 }
530
531 /**
532 * ccs_path22keyword - Get the name of path/path operations.
533 *
534 * @operation: Type of operation.
535 *
536 * Returns the name of path/path operation.
537 */
538 const char *ccs_path22keyword(const u8 operation)
539 {
540 return (operation < CCS_MAX_PATH2_OPERATION)
541 ? ccs_path2_keyword[operation] : NULL;
542 }
543
544 /**
545 * ccs_path_number2keyword - Get the name of path/number operations.
546 *
547 * @operation: Type of operation.
548 *
549 * Returns the name of path/number operation.
550 */
551 const char *ccs_path_number2keyword(const u8 operation)
552 {
553 return (operation < CCS_MAX_PATH_NUMBER_OPERATION)
554 ? ccs_path_number_keyword[operation] : NULL;
555 }
556
557 static void ccs_add_slash(struct ccs_path_info *buf)
558 {
559 if (buf->is_dir)
560 return;
561 /* This is OK because ccs_encode() reserves space for appending "/". */
562 strcat((char *) buf->name, "/");
563 ccs_fill_path_info(buf);
564 }
565
566 /**
567 * ccs_strendswith - Check whether the token ends with the given token.
568 *
569 * @name: The token to check.
570 * @tail: The token to find.
571 *
572 * Returns true if @name ends with @tail, false otherwise.
573 */
574 static bool ccs_strendswith(const char *name, const char *tail)
575 {
576 int len;
577 if (!name || !tail)
578 return false;
579 len = strlen(name) - strlen(tail);
580 return len >= 0 && !strcmp(name + len, tail);
581 }
582
583 /**
584 * ccs_get_realpath - Get realpath.
585 *
586 * @buf: Pointer to "struct ccs_path_info".
587 * @dentry: Pointer to "struct dentry".
588 * @mnt: Pointer to "struct vfsmount".
589 *
590 * Returns true success, false otherwise.
591 */
592 static bool ccs_get_realpath(struct ccs_path_info *buf, struct dentry *dentry,
593 struct vfsmount *mnt)
594 {
595 struct path path = { mnt, dentry };
596 buf->name = ccs_realpath_from_path(&path);
597 if (buf->name) {
598 ccs_fill_path_info(buf);
599 return true;
600 }
601 return false;
602 }
603
604 static int ccs_update_path_acl(const u8 type, const char *filename,
605 struct ccs_domain_info * const domain,
606 struct ccs_condition *condition,
607 const bool is_delete);
608
609 /**
610 * ccs_audit_path_log - Audit path request log.
611 *
612 * @r: Pointer to "struct ccs_request_info".
613 * @operation: The name of operation.
614 * @filename: Pathname.
615 * @is_granted: True if this is a granted log.
616 *
617 * Returns 0 on success, negative value otherwise.
618 */
619 static int ccs_audit_path_log(struct ccs_request_info *r,
620 const char *operation, const char *filename,
621 const bool is_granted)
622 {
623 if (!is_granted)
624 ccs_warn_log(r, "%s %s", operation, filename);
625 return ccs_write_audit_log(is_granted, r, "allow_%s %s\n", operation,
626 filename);
627 }
628
629 /**
630 * ccs_audit_path2_log - Audit path/path request log.
631 *
632 * @r: Pointer to "struct ccs_request_info".
633 * @operation: The name of operation.
634 * @filename1: First pathname.
635 * @filename2: Second pathname.
636 * @is_granted: True if this is a granted log.
637 *
638 * Returns 0 on success, negative value otherwise.
639 */
640 static int ccs_audit_path2_log(struct ccs_request_info *r,
641 const char *operation, const char *filename1,
642 const char *filename2, const bool is_granted)
643 {
644 if (!is_granted)
645 ccs_warn_log(r, "%s %s %s", operation, filename1, filename2);
646 return ccs_write_audit_log(is_granted, r, "allow_%s %s %s\n",
647 operation, filename1, filename2);
648 }
649
650 /**
651 * ccs_audit_path_number3_log - Audit path/number/number/number request log.
652 *
653 * @r: Pointer to "struct ccs_request_info".
654 * @operation: The name of operation.
655 * @filename: First pathname.
656 * @mode: Create mode.
657 * @major: Device major number.
658 * @minor: Device minor number.
659 * @is_granted: True if this is a granted log.
660 *
661 * Returns 0 on success, negative value otherwise.
662 */
663 static int ccs_audit_path_number3_log(struct ccs_request_info *r,
664 const char *operation,
665 const char *filename,
666 const unsigned int mode,
667 const unsigned int major,
668 const unsigned int minor,
669 const bool is_granted)
670 {
671 if (!is_granted)
672 ccs_warn_log(r, "%s %s 0%o %u %u", operation, filename, mode,
673 major, minor);
674 return ccs_write_audit_log(is_granted, r, "allow_%s %s 0%o %u %u\n",
675 operation, filename, mode, major, minor);
676 }
677
678 /**
679 * ccs_audit_path_number_log - Audit path/number request log.
680 *
681 * @r: Pointer to "struct ccs_request_info".
682 * @type: Type of operation.
683 * @filename: Pathname.
684 * @value: Value.
685 * @is_granted: True if this is a granted log.
686 *
687 * Returns 0 on success, negative value otherwise.
688 */
689 static int ccs_audit_path_number_log(struct ccs_request_info *r,
690 const char *operation,
691 const char *filename, const char *value,
692 const bool is_granted)
693 {
694 if (!is_granted)
695 ccs_warn_log(r, "%s %s %s", operation, filename, value);
696 return ccs_write_audit_log(is_granted, r, "allow_%s %s %s\n",
697 operation, filename, value);
698 }
699
700 /* The list for "struct ccs_globally_readable_file_entry". */
701 LIST_HEAD(ccs_globally_readable_list);
702
703 /**
704 * ccs_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
705 *
706 * @filename: The filename to check.
707 *
708 * Returns true if any domain can open @filename for reading, false otherwise.
709 *
710 * Caller holds ccs_read_lock().
711 */
712 static bool ccs_is_globally_readable_file(const struct ccs_path_info *filename)
713 {
714 struct ccs_globally_readable_file_entry *ptr;
715 bool found = false;
716 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list, list) {
717 if (ptr->is_deleted ||
718 !ccs_path_matches_pattern(filename, ptr->filename))
719 continue;
720 found = true;
721 break;
722 }
723 return found;
724 }
725
726 /**
727 * ccs_write_globally_readable_policy - Write "struct ccs_globally_readable_file_entry" list.
728 *
729 * @data: String to parse.
730 * @is_delete: True if it is a delete request.
731 *
732 * Returns 0 on success, negative value otherwise.
733 */
734 int ccs_write_globally_readable_policy(char *data, const bool is_delete)
735 {
736 struct ccs_globally_readable_file_entry *entry = NULL;
737 struct ccs_globally_readable_file_entry *ptr;
738 struct ccs_globally_readable_file_entry e = { };
739 int error = is_delete ? -ENOENT : -ENOMEM;
740 if (!ccs_is_correct_path(data, 1, 0, -1))
741 return -EINVAL;
742 e.filename = ccs_get_name(data);
743 if (!e.filename)
744 return -ENOMEM;
745 if (!is_delete)
746 entry = kmalloc(sizeof(e), GFP_KERNEL);
747 mutex_lock(&ccs_policy_lock);
748 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list, list) {
749 if (ptr->filename != e.filename)
750 continue;
751 ptr->is_deleted = is_delete;
752 error = 0;
753 break;
754 }
755 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
756 list_add_tail_rcu(&entry->list, &ccs_globally_readable_list);
757 entry = NULL;
758 error = 0;
759 }
760 mutex_unlock(&ccs_policy_lock);
761 ccs_put_name(e.filename);
762 kfree(entry);
763 return error;
764 }
765
766 /**
767 * ccs_read_globally_readable_policy - Read "struct ccs_globally_readable_file_entry" list.
768 *
769 * @head: Pointer to "struct ccs_io_buffer".
770 *
771 * Returns true on success, false otherwise.
772 *
773 * Caller holds ccs_read_lock().
774 */
775 bool ccs_read_globally_readable_policy(struct ccs_io_buffer *head)
776 {
777 struct list_head *pos;
778 bool done = true;
779 list_for_each_cookie(pos, head->read_var2,
780 &ccs_globally_readable_list) {
781 struct ccs_globally_readable_file_entry *ptr;
782 ptr = list_entry(pos, struct ccs_globally_readable_file_entry,
783 list);
784 if (ptr->is_deleted)
785 continue;
786 done = ccs_io_printf(head, CCS_KEYWORD_ALLOW_READ "%s\n",
787 ptr->filename->name);
788 if (!done)
789 break;
790 }
791 return done;
792 }
793
794 /* The list for "struct ccs_pattern_entry". */
795 LIST_HEAD(ccs_pattern_list);
796
797 /**
798 * ccs_file_pattern - Get patterned pathname.
799 *
800 * @filename: Pointer to "struct ccs_path_info".
801 *
802 * Returns pointer to patterned pathname.
803 *
804 * Caller holds ccs_read_lock().
805 */
806 const char *ccs_file_pattern(const struct ccs_path_info *filename)
807 {
808 struct ccs_pattern_entry *ptr;
809 const struct ccs_path_info *pattern = NULL;
810 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
811 if (ptr->is_deleted)
812 continue;
813 if (!ccs_path_matches_pattern(filename, ptr->pattern))
814 continue;
815 pattern = ptr->pattern;
816 if (ccs_strendswith(pattern->name, "/\\*")) {
817 /* Do nothing. Try to find the better match. */
818 } else {
819 /* This would be the better match. Use this. */
820 break;
821 }
822 }
823 return pattern ? pattern->name : filename->name;
824 }
825
826 /**
827 * ccs_write_pattern_policy - Write "struct ccs_pattern_entry" list.
828 *
829 * @data: String to parse.
830 * @is_delete: True if it is a delete request.
831 *
832 * Returns 0 on success, negative value otherwise.
833 */
834 int ccs_write_pattern_policy(char *data, const bool is_delete)
835 {
836 struct ccs_pattern_entry *entry = NULL;
837 struct ccs_pattern_entry *ptr;
838 struct ccs_pattern_entry e = { .pattern = ccs_get_name(data) };
839 int error = is_delete ? -ENOENT : -ENOMEM;
840 if (!e.pattern)
841 return error;
842 if (!e.pattern->is_patterned)
843 goto out;
844 if (!is_delete)
845 entry = kmalloc(sizeof(e), GFP_KERNEL);
846 mutex_lock(&ccs_policy_lock);
847 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
848 if (e.pattern != ptr->pattern)
849 continue;
850 ptr->is_deleted = is_delete;
851 error = 0;
852 break;
853 }
854 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
855 list_add_tail_rcu(&entry->list, &ccs_pattern_list);
856 entry = NULL;
857 error = 0;
858 }
859 mutex_unlock(&ccs_policy_lock);
860 out:
861 ccs_put_name(e.pattern);
862 kfree(entry);
863 return error;
864 }
865
866 /**
867 * ccs_read_file_pattern - Read "struct ccs_pattern_entry" list.
868 *
869 * @head: Pointer to "struct ccs_io_buffer".
870 *
871 * Returns true on success, false otherwise.
872 *
873 * Caller holds ccs_read_lock().
874 */
875 bool ccs_read_file_pattern(struct ccs_io_buffer *head)
876 {
877 struct list_head *pos;
878 bool done = true;
879 list_for_each_cookie(pos, head->read_var2, &ccs_pattern_list) {
880 struct ccs_pattern_entry *ptr;
881 ptr = list_entry(pos, struct ccs_pattern_entry, list);
882 if (ptr->is_deleted)
883 continue;
884 done = ccs_io_printf(head, CCS_KEYWORD_FILE_PATTERN "%s\n",
885 ptr->pattern->name);
886 if (!done)
887 break;
888 }
889 return done;
890 }
891
892 /* The list for "struct ccs_no_rewrite_entry". */
893 LIST_HEAD(ccs_no_rewrite_list);
894
895 /**
896 * ccs_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
897 *
898 * @filename: Filename to check.
899 *
900 * Returns true if @filename is specified by "deny_rewrite" directive,
901 * false otherwise.
902 *
903 * Caller holds ccs_read_lock().
904 */
905 static bool ccs_is_no_rewrite_file(const struct ccs_path_info *filename)
906 {
907 struct ccs_no_rewrite_entry *ptr;
908 bool matched = false;
909 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
910 if (ptr->is_deleted)
911 continue;
912 if (!ccs_path_matches_pattern(filename, ptr->pattern))
913 continue;
914 matched = true;
915 break;
916 }
917 return matched;
918 }
919
920 /**
921 * ccs_write_no_rewrite_policy - Write "struct ccs_no_rewrite_entry" list.
922 *
923 * @data: String to parse.
924 * @is_delete: True if it is a delete request.
925 *
926 * Returns 0 on success, negative value otherwise.
927 */
928 int ccs_write_no_rewrite_policy(char *data, const bool is_delete)
929 {
930 struct ccs_no_rewrite_entry *entry = NULL;
931 struct ccs_no_rewrite_entry *ptr;
932 struct ccs_no_rewrite_entry e = { };
933 int error = is_delete ? -ENOENT : -ENOMEM;
934 if (!ccs_is_correct_path(data, 0, 0, 0))
935 return -EINVAL;
936 e.pattern = ccs_get_name(data);
937 if (!e.pattern)
938 return error;
939 if (!is_delete)
940 entry = kmalloc(sizeof(e), GFP_KERNEL);
941 mutex_lock(&ccs_policy_lock);
942 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
943 if (ptr->pattern != e.pattern)
944 continue;
945 ptr->is_deleted = is_delete;
946 error = 0;
947 break;
948 }
949 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
950 list_add_tail_rcu(&entry->list, &ccs_no_rewrite_list);
951 entry = NULL;
952 error = 0;
953 }
954 mutex_unlock(&ccs_policy_lock);
955 ccs_put_name(e.pattern);
956 kfree(entry);
957 return error;
958 }
959
960 /**
961 * ccs_read_no_rewrite_policy - Read "struct ccs_no_rewrite_entry" list.
962 *
963 * @head: Pointer to "struct ccs_io_buffer".
964 *
965 * Returns true on success, false otherwise.
966 *
967 * Caller holds ccs_read_lock().
968 */
969 bool ccs_read_no_rewrite_policy(struct ccs_io_buffer *head)
970 {
971 struct list_head *pos;
972 bool done = true;
973 list_for_each_cookie(pos, head->read_var2, &ccs_no_rewrite_list) {
974 struct ccs_no_rewrite_entry *ptr;
975 ptr = list_entry(pos, struct ccs_no_rewrite_entry, list);
976 if (ptr->is_deleted)
977 continue;
978 done = ccs_io_printf(head, CCS_KEYWORD_DENY_REWRITE "%s\n",
979 ptr->pattern->name);
980 if (!done)
981 break;
982 }
983 return done;
984 }
985
986 /**
987 * ccs_update_file_acl - Update file's read/write/execute ACL.
988 *
989 * @perm: Permission (between 1 to 7).
990 * @filename: Filename.
991 * @domain: Pointer to "struct ccs_domain_info".
992 * @condition: Pointer to "struct ccs_condition". May be NULL.
993 * @is_delete: True if it is a delete request.
994 *
995 * Returns 0 on success, negative value otherwise.
996 *
997 * This is legacy support interface for older policy syntax.
998 * Current policy syntax uses "allow_read/write" instead of "6",
999 * "allow_read" instead of "4", "allow_write" instead of "2",
1000 * "allow_execute" instead of "1".
1001 */
1002 static inline int ccs_update_file_acl(u8 perm, const char *filename,
1003 struct ccs_domain_info * const domain,
1004 struct ccs_condition *condition,
1005 const bool is_delete)
1006 {
1007 if (perm > 7 || !perm)
1008 return -EINVAL;
1009 if (filename[0] != '@' && ccs_strendswith(filename, "/"))
1010 /*
1011 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
1012 * directory permissions.
1013 */
1014 return 0;
1015 if (perm & 4)
1016 ccs_update_path_acl(CCS_TYPE_READ, filename, domain,
1017 condition, is_delete);
1018 if (perm & 2)
1019 ccs_update_path_acl(CCS_TYPE_WRITE, filename,
1020 domain, condition, is_delete);
1021 if (perm & 1)
1022 ccs_update_path_acl(CCS_TYPE_EXECUTE, filename,
1023 domain, condition, is_delete);
1024 return 0;
1025 }
1026
1027 /**
1028 * ccs_path_acl - Check permission for path operation.
1029 *
1030 * @r: Pointer to "struct ccs_request_info".
1031 * @filename: Filename to check.
1032 * @perm: Permission.
1033 * @may_use_pattern: True if patterned ACL is permitted.
1034 *
1035 * Returns 0 on success, -EPERM otherwise.
1036 *
1037 * Caller holds ccs_read_lock().
1038 */
1039 static int ccs_path_acl(struct ccs_request_info *r,
1040 const struct ccs_path_info *filename,
1041 const u16 perm, const bool may_use_pattern)
1042 {
1043 struct ccs_domain_info *domain = r->domain;
1044 struct ccs_acl_info *ptr;
1045 int error = -EPERM;
1046 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1047 struct ccs_path_acl *acl;
1048 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH_ACL)
1049 continue;
1050 acl = container_of(ptr, struct ccs_path_acl, head);
1051 if (!(acl->perm & perm) || !ccs_condition(r, ptr) ||
1052 !ccs_compare_name_union_pattern(filename, &acl->name,
1053 may_use_pattern))
1054 continue;
1055 r->cond = ptr->cond;
1056 error = 0;
1057 break;
1058 }
1059 return error;
1060 }
1061
1062 /**
1063 * ccs_path_number3_acl - Check permission for path/number/number/number operation.
1064 *
1065 * @r: Pointer to "struct ccs_request_info".
1066 * @filename: Filename to check.
1067 * @perm: Permission.
1068 * @mode: Create mode.
1069 * @major: Device major number.
1070 * @minor: Device minor number.
1071 *
1072 * Returns 0 on success, -EPERM otherwise.
1073 *
1074 * Caller holds ccs_read_lock().
1075 */
1076 static int ccs_path_number3_acl(struct ccs_request_info *r,
1077 const struct ccs_path_info *filename,
1078 const u16 perm, const unsigned int mode,
1079 const unsigned int major,
1080 const unsigned int minor)
1081 {
1082 struct ccs_domain_info *domain = r->domain;
1083 struct ccs_acl_info *ptr;
1084 int error = -EPERM;
1085 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1086 struct ccs_path_number3_acl *acl;
1087 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH_NUMBER3_ACL)
1088 continue;
1089 acl = container_of(ptr, struct ccs_path_number3_acl, head);
1090 if (!ccs_compare_number_union(mode, &acl->mode))
1091 continue;
1092 if (!ccs_compare_number_union(major, &acl->major))
1093 continue;
1094 if (!ccs_compare_number_union(minor, &acl->minor))
1095 continue;
1096 if (!(acl->perm & perm) || !ccs_condition(r, ptr))
1097 continue;
1098 if (!ccs_compare_name_union(filename, &acl->name))
1099 continue;
1100 r->cond = ptr->cond;
1101 error = 0;
1102 break;
1103 }
1104 return error;
1105 }
1106
1107 /**
1108 * ccs_file_perm - Check permission for opening files.
1109 *
1110 * @r: Pointer to "struct ccs_request_info".
1111 * @filename: Filename to check.
1112 * @mode: Mode ("read" or "write" or "read/write" or "execute").
1113 *
1114 * Returns 0 on success, 1 on retry, negative value otherwise.
1115 *
1116 * Caller holds ccs_read_lock().
1117 */
1118 static int ccs_file_perm(struct ccs_request_info *r,
1119 const struct ccs_path_info *filename, const u8 mode)
1120 {
1121 const char *msg = "<unknown>";
1122 int error = 0;
1123 u16 perm = 0;
1124 if (!filename)
1125 return 0;
1126 if (mode == 6) {
1127 msg = ccs_path2keyword(CCS_TYPE_READ_WRITE);
1128 perm = 1 << CCS_TYPE_READ_WRITE;
1129 } else if (mode == 4) {
1130 msg = ccs_path2keyword(CCS_TYPE_READ);
1131 perm = 1 << CCS_TYPE_READ;
1132 } else if (mode == 2) {
1133 msg = ccs_path2keyword(CCS_TYPE_WRITE);
1134 perm = 1 << CCS_TYPE_WRITE;
1135 } else if (mode == 1) {
1136 msg = ccs_path2keyword(CCS_TYPE_EXECUTE);
1137 perm = 1 << CCS_TYPE_EXECUTE;
1138 } else
1139 BUG();
1140 do {
1141 error = ccs_path_acl(r, filename, perm, mode != 1);
1142 if (error && mode == 4 && !r->domain->ignore_global_allow_read
1143 && ccs_is_globally_readable_file(filename))
1144 error = 0;
1145 ccs_audit_path_log(r, msg, filename->name, !error);
1146 if (!error)
1147 break;
1148 error = ccs_supervisor(r, "allow_%s %s\n", msg,
1149 mode == 1 ? filename->name :
1150 ccs_file_pattern(filename));
1151 /*
1152 * Do not retry for execute request, for aggregator may have
1153 * changed.
1154 */
1155 } while (error == CCS_RETRY_REQUEST && !r->ee);
1156 if (r->mode != CCS_CONFIG_ENFORCING)
1157 error = 0;
1158 return error;
1159 }
1160
1161 /**
1162 * ccs_update_execute_handler - Update "struct ccs_execute_handler_record" list.
1163 *
1164 * @type: Type of execute handler.
1165 * @filename: Pathname to the execute handler.
1166 * @domain: Pointer to "struct ccs_domain_info".
1167 * @is_delete: True if it is a delete request.
1168 *
1169 * Returns 0 on success, negative value otherwise.
1170 */
1171 static inline int ccs_update_execute_handler(const u8 type,
1172 const char *filename,
1173 struct ccs_domain_info * const
1174 domain, const bool is_delete)
1175 {
1176 struct ccs_acl_info *ptr;
1177 struct ccs_execute_handler_record e = { .head.type = type };
1178 struct ccs_execute_handler_record *entry = NULL;
1179 int error = is_delete ? -ENOENT : -ENOMEM;
1180 if (!domain)
1181 return -EINVAL;
1182 if (!ccs_is_correct_path(filename, 1, -1, -1))
1183 return -EINVAL;
1184 e.handler = ccs_get_name(filename);
1185 if (!e.handler)
1186 return -ENOMEM;
1187 if (!is_delete)
1188 entry = kmalloc(sizeof(e), GFP_KERNEL);
1189 mutex_lock(&ccs_policy_lock);
1190 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1191 struct ccs_execute_handler_record *acl;
1192 if (ptr->type != type)
1193 continue;
1194 /* Condition not supported. */
1195 acl = container_of(ptr, struct ccs_execute_handler_record,
1196 head);
1197 if (acl->handler != e.handler)
1198 continue;
1199 if (!is_delete) {
1200 /* Only one entry can exist in a domain. */
1201 struct ccs_acl_info *ptr2;
1202 list_for_each_entry_rcu(ptr2, &domain->acl_info_list,
1203 list) {
1204 if (ptr2->type == type)
1205 ptr2->is_deleted = true;
1206 }
1207 }
1208 ptr->is_deleted = is_delete;
1209 error = 0;
1210 break;
1211 }
1212 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
1213 /* Only one entry can exist in a domain. */
1214 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1215 if (ptr->type == type)
1216 ptr->is_deleted = true;
1217 }
1218 ccs_add_domain_acl(domain, &entry->head);
1219 entry = NULL;
1220 error = 0;
1221 }
1222 mutex_unlock(&ccs_policy_lock);
1223 ccs_put_name(e.handler);
1224 kfree(entry);
1225 return error;
1226 }
1227
1228 /**
1229 * ccs_update_path_acl - Update "struct ccs_path_acl" list.
1230 *
1231 * @type: Type of operation.
1232 * @filename: Filename.
1233 * @domain: Pointer to "struct ccs_domain_info".
1234 * @condition: Pointer to "struct ccs_condition". May be NULL.
1235 * @is_delete: True if it is a delete request.
1236 *
1237 * Returns 0 on success, negative value otherwise.
1238 */
1239 static int ccs_update_path_acl(const u8 type, const char *filename,
1240 struct ccs_domain_info * const domain,
1241 struct ccs_condition *condition,
1242 const bool is_delete)
1243 {
1244 static const u16 ccs_rw_mask =
1245 (1 << CCS_TYPE_READ) | (1 << CCS_TYPE_WRITE);
1246 const u16 perm = 1 << type;
1247 struct ccs_acl_info *ptr;
1248 struct ccs_path_acl e = {
1249 .head.type = CCS_TYPE_PATH_ACL,
1250 .head.cond = condition,
1251 .perm = perm
1252 };
1253 struct ccs_path_acl *entry = NULL;
1254 int error = is_delete ? -ENOENT : -ENOMEM;
1255 if (type == CCS_TYPE_READ_WRITE)
1256 e.perm |= ccs_rw_mask;
1257 if (!ccs_parse_name_union(filename, &e.name))
1258 return -EINVAL;
1259 if (!is_delete)
1260 entry = kmalloc(sizeof(e), GFP_KERNEL);
1261 mutex_lock(&ccs_policy_lock);
1262 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1263 struct ccs_path_acl *acl =
1264 container_of(ptr, struct ccs_path_acl, head);
1265 if (ptr->type != CCS_TYPE_PATH_ACL ||
1266 ptr->cond != condition ||
1267 ccs_memcmp(acl, &e, offsetof(typeof(e), name), sizeof(e)))
1268 continue;
1269 if (is_delete) {
1270 acl->perm &= ~perm;
1271 if ((acl->perm & ccs_rw_mask) != ccs_rw_mask)
1272 acl->perm &= ~(1 << CCS_TYPE_READ_WRITE);
1273 else if (!(acl->perm & (1 << CCS_TYPE_READ_WRITE)))
1274 acl->perm &= ~ccs_rw_mask;
1275 if (!acl->perm)
1276 ptr->is_deleted = true;
1277 } else {
1278 if (ptr->is_deleted)
1279 acl->perm = 0;
1280 acl->perm |= perm;
1281 if ((acl->perm & ccs_rw_mask) == ccs_rw_mask)
1282 acl->perm |= 1 << CCS_TYPE_READ_WRITE;
1283 else if (acl->perm & (1 << CCS_TYPE_READ_WRITE))
1284 acl->perm |= ccs_rw_mask;
1285 ptr->is_deleted = false;
1286 }
1287 error = 0;
1288 break;
1289 }
1290 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
1291 ccs_add_domain_acl(domain, &entry->head);
1292 entry = NULL;
1293 error = 0;
1294 }
1295 mutex_unlock(&ccs_policy_lock);
1296 ccs_put_name_union(&e.name);
1297 kfree(entry);
1298 return error;
1299 }
1300
1301 /**
1302 * ccs_update_path_number3_acl - Update "struct ccs_path_number3_acl" list.
1303 *
1304 * @type: Type of operation.
1305 * @filename: Filename.
1306 * @mode: Create mode.
1307 * @major: Device major number.
1308 * @minor: Device minor number.
1309 * @domain: Pointer to "struct ccs_domain_info".
1310 * @condition: Pointer to "struct ccs_condition". May be NULL.
1311 * @is_delete: True if it is a delete request.
1312 *
1313 * Returns 0 on success, negative value otherwise.
1314 */
1315 static inline int ccs_update_path_number3_acl(const u8 type,
1316 const char *filename, char *mode,
1317 char *major, char *minor,
1318 struct ccs_domain_info * const
1319 domain,
1320 struct ccs_condition *condition,
1321 const bool is_delete)
1322 {
1323 const u8 perm = 1 << type;
1324 struct ccs_acl_info *ptr;
1325 struct ccs_path_number3_acl e = {
1326 .head.type = CCS_TYPE_PATH_NUMBER3_ACL,
1327 .head.cond = condition,
1328 .perm = perm
1329 };
1330 struct ccs_path_number3_acl *entry = NULL;
1331 int error = is_delete ? -ENOENT : -ENOMEM;
1332 if (!ccs_parse_name_union(filename, &e.name) ||
1333 !ccs_parse_number_union(mode, &e.mode) ||
1334 !ccs_parse_number_union(major, &e.major) ||
1335 !ccs_parse_number_union(minor, &e.minor))
1336 goto out;
1337 if (!is_delete)
1338 entry = kmalloc(sizeof(e), GFP_KERNEL);
1339 mutex_lock(&ccs_policy_lock);
1340 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1341 struct ccs_path_number3_acl *acl =
1342 container_of(ptr, struct ccs_path_number3_acl, head);
1343 if (ptr->type != CCS_TYPE_PATH_NUMBER3_ACL ||
1344 ptr->cond != condition ||
1345 ccs_memcmp(acl, &e, offsetof(typeof(e), name), sizeof(e)))
1346 continue;
1347 if (is_delete) {
1348 acl->perm &= ~perm;
1349 if (!acl->perm)
1350 ptr->is_deleted = true;
1351 } else {
1352 if (ptr->is_deleted)
1353 acl->perm = 0;
1354 acl->perm |= perm;
1355 ptr->is_deleted = false;
1356 }
1357 error = 0;
1358 break;
1359 }
1360 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
1361 ccs_add_domain_acl(domain, &entry->head);
1362 entry = NULL;
1363 error = 0;
1364 }
1365 mutex_unlock(&ccs_policy_lock);
1366 out:
1367 ccs_put_name_union(&e.name);
1368 ccs_put_number_union(&e.mode);
1369 ccs_put_number_union(&e.major);
1370 ccs_put_number_union(&e.minor);
1371 kfree(entry);
1372 return error;
1373 }
1374
1375 /**
1376 * ccs_update_path2_acl - Update "struct ccs_path2_acl" list.
1377 *
1378 * @type: Type of operation.
1379 * @filename1: First filename.
1380 * @filename2: Second filename.
1381 * @domain: Pointer to "struct ccs_domain_info".
1382 * @condition: Pointer to "struct ccs_condition". May be NULL.
1383 * @is_delete: True if it is a delete request.
1384 *
1385 * Returns 0 on success, negative value otherwise.
1386 */
1387 static inline int ccs_update_path2_acl(const u8 type,
1388 const char *filename1,
1389 const char *filename2,
1390 struct ccs_domain_info * const
1391 domain,
1392 struct ccs_condition *condition,
1393 const bool is_delete)
1394 {
1395 const u8 perm = 1 << type;
1396 struct ccs_acl_info *ptr;
1397 struct ccs_path2_acl e = {
1398 .head.type = CCS_TYPE_PATH2_ACL,
1399 .head.cond = condition,
1400 .perm = perm
1401 };
1402 struct ccs_path2_acl *entry = NULL;
1403 int error = is_delete ? -ENOENT : -ENOMEM;
1404 if (!ccs_parse_name_union(filename1, &e.name1) ||
1405 !ccs_parse_name_union(filename2, &e.name2))
1406 goto out;
1407 if (!is_delete)
1408 entry = kmalloc(sizeof(e), GFP_KERNEL);
1409 mutex_lock(&ccs_policy_lock);
1410 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1411 struct ccs_path2_acl *acl =
1412 container_of(ptr, struct ccs_path2_acl, head);
1413 if (ptr->type != CCS_TYPE_PATH2_ACL ||
1414 ptr->cond != condition ||
1415 ccs_memcmp(acl, &e, offsetof(typeof(e), name1), sizeof(e)))
1416 continue;
1417 if (is_delete) {
1418 acl->perm &= ~perm;
1419 if (!acl->perm)
1420 ptr->is_deleted = true;
1421 } else {
1422 if (ptr->is_deleted)
1423 acl->perm = 0;
1424 acl->perm |= perm;
1425 ptr->is_deleted = false;
1426 }
1427 error = 0;
1428 break;
1429 }
1430 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
1431 ccs_add_domain_acl(domain, &entry->head);
1432 entry = NULL;
1433 error = 0;
1434 }
1435 mutex_unlock(&ccs_policy_lock);
1436 out:
1437 ccs_put_name_union(&e.name1);
1438 ccs_put_name_union(&e.name2);
1439 kfree(entry);
1440 return error;
1441 }
1442
1443 /**
1444 * ccs_path2_acl - Check permission for path/path operation.
1445 *
1446 * @r: Pointer to "struct ccs_request_info".
1447 * @type: Type of operation.
1448 * @filename1: First filename to check.
1449 * @filename2: Second filename to check.
1450 *
1451 * Returns 0 on success, -EPERM otherwise.
1452 *
1453 * Caller holds ccs_read_lock().
1454 */
1455 static int ccs_path2_acl(struct ccs_request_info *r, const u8 type,
1456 const struct ccs_path_info *filename1,
1457 const struct ccs_path_info *filename2)
1458 {
1459 const struct ccs_domain_info *domain = r->domain;
1460 struct ccs_acl_info *ptr;
1461 const u8 perm = 1 << type;
1462 int error = -EPERM;
1463 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1464 struct ccs_path2_acl *acl;
1465 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH2_ACL)
1466 continue;
1467 acl = container_of(ptr, struct ccs_path2_acl, head);
1468 if (!(acl->perm & perm) || !ccs_condition(r, ptr) ||
1469 !ccs_compare_name_union(filename1, &acl->name1) ||
1470 !ccs_compare_name_union(filename2, &acl->name2))
1471 continue;
1472 r->cond = ptr->cond;
1473 error = 0;
1474 break;
1475 }
1476 return error;
1477 }
1478
1479 /**
1480 * ccs_path_permission - Check permission for path operation.
1481 *
1482 * @r: Pointer to "struct ccs_request_info".
1483 * @operation: Type of operation.
1484 * @filename: Filename to check.
1485 *
1486 * Returns 0 on success, negative value otherwise.
1487 *
1488 * Caller holds ccs_read_lock().
1489 */
1490 int ccs_path_permission(struct ccs_request_info *r, u8 operation,
1491 const struct ccs_path_info *filename)
1492 {
1493 const char *msg;
1494 int error;
1495 repeat:
1496 r->mode = ccs_get_mode(r->profile, ccs_p2mac[operation]);
1497 if (r->mode == CCS_CONFIG_DISABLED)
1498 return 0;
1499 do {
1500 error = ccs_path_acl(r, filename, 1 << operation,
1501 operation != CCS_TYPE_TRANSIT);
1502 msg = ccs_path2keyword(operation);
1503 ccs_audit_path_log(r, msg, filename->name, !error);
1504 if (!error)
1505 break;
1506 error = ccs_supervisor(r, "allow_%s %s\n", msg,
1507 ccs_file_pattern(filename));
1508 } while (error == CCS_RETRY_REQUEST);
1509 if (r->mode != CCS_CONFIG_ENFORCING)
1510 error = 0;
1511 /*
1512 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
1513 * we need to check "allow_rewrite" permission if the filename is
1514 * specified by "deny_rewrite" keyword.
1515 */
1516 if (!error && operation == CCS_TYPE_TRUNCATE &&
1517 ccs_is_no_rewrite_file(filename)) {
1518 operation = CCS_TYPE_REWRITE;
1519 goto repeat;
1520 }
1521 return error;
1522 }
1523
1524 /**
1525 * ccs_path_number3_perm2 - Check permission for path/number/number/number operation.
1526 *
1527 * @r: Pointer to "struct ccs_request_info".
1528 * @operation: Type of operation.
1529 * @filename: Filename to check.
1530 * @mode: Create mode.
1531 * @dev: Device number.
1532 *
1533 * Returns 0 on success, negative value otherwise.
1534 *
1535 * Caller holds ccs_read_lock().
1536 */
1537 static int ccs_path_number3_perm2(struct ccs_request_info *r,
1538 const u8 operation,
1539 const struct ccs_path_info *filename,
1540 const unsigned int mode,
1541 const unsigned int dev)
1542 {
1543 int error;
1544 const char *msg = ccs_path_number32keyword(operation);
1545 const unsigned int major = MAJOR(dev);
1546 const unsigned int minor = MINOR(dev);
1547 if (!r->mode)
1548 return 0;
1549 do {
1550 error = ccs_path_number3_acl(r, filename, 1 << operation, mode,
1551 major, minor);
1552 ccs_audit_path_number3_log(r, msg, filename->name, mode, major,
1553 minor, !error);
1554 if (!error)
1555 break;
1556 error = ccs_supervisor(r, "allow_%s %s 0%o %u %u\n", msg,
1557 ccs_file_pattern(filename), mode,
1558 major, minor);
1559 } while (error == CCS_RETRY_REQUEST);
1560 if (r->mode != CCS_CONFIG_ENFORCING)
1561 error = 0;
1562 return error;
1563 }
1564
1565 /**
1566 * ccs_exec_perm - Check permission for "execute".
1567 *
1568 * @r: Pointer to "struct ccs_request_info".
1569 * @filename: Check permission for "execute".
1570 *
1571 * Returns 0 on success, 1 on retry, negative value otherwise.
1572 *
1573 * Caller holds ccs_read_lock().
1574 */
1575 int ccs_exec_perm(struct ccs_request_info *r,
1576 const struct ccs_path_info *filename)
1577 {
1578 if (r->mode == CCS_CONFIG_DISABLED)
1579 return 0;
1580 return ccs_file_perm(r, filename, 1);
1581 }
1582
1583 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1584 /*
1585 * Save original flags passed to sys_open().
1586 *
1587 * TOMOYO does not check "allow_write" if open(path, O_TRUNC | O_RDONLY) was
1588 * requested because write() is not permitted. Instead, TOMOYO checks
1589 * "allow_truncate" if O_TRUNC is passed.
1590 *
1591 * TOMOYO does not check "allow_read/write" if open(path, 3) was requested
1592 * because read()/write() are not permitted. Instead, TOMOYO checks
1593 * "allow_ioctl" when ioctl() is requested.
1594 */
1595 void ccs_save_open_mode(int mode)
1596 {
1597 if ((mode & 3) == 3)
1598 current->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
1599 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
1600 /* O_TRUNC passes MAY_WRITE to ccs_open_permission(). */
1601 else if (!(mode & 3) && (mode & O_TRUNC))
1602 current->ccs_flags |= CCS_OPEN_FOR_READ_TRUNCATE;
1603 #endif
1604 }
1605
1606 void ccs_clear_open_mode(void)
1607 {
1608 current->ccs_flags &= ~(CCS_OPEN_FOR_IOCTL_ONLY |
1609 CCS_OPEN_FOR_READ_TRUNCATE);
1610 }
1611 #endif
1612
1613 /**
1614 * ccs_open_permission - Check permission for "read" and "write".
1615 *
1616 * @dentry: Pointer to "struct dentry".
1617 * @mnt: Pointer to "struct vfsmount".
1618 * @flag: Flags for open().
1619 *
1620 * Returns 0 on success, negative value otherwise.
1621 */
1622 int ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
1623 const int flag)
1624 {
1625 struct ccs_request_info r;
1626 struct ccs_obj_info obj = {
1627 .path1.dentry = dentry,
1628 .path1.mnt = mnt
1629 };
1630 struct task_struct * const task = current;
1631 const u32 ccs_flags = task->ccs_flags;
1632 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
1633 const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
1634 #else
1635 const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
1636 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
1637 (ccs_flags & CCS_OPEN_FOR_READ_TRUNCATE) ? 4 :
1638 #endif
1639 ACC_MODE(flag);
1640 #endif
1641 int error = 0;
1642 struct ccs_path_info buf;
1643 int idx;
1644 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
1645 if (task->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
1646 return 0;
1647 #endif
1648 if (!mnt || (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)))
1649 return 0;
1650 buf.name = NULL;
1651 r.mode = 0;
1652 idx = ccs_read_lock();
1653 /*
1654 * If the filename is specified by "deny_rewrite" keyword,
1655 * we need to check "allow_rewrite" permission when the filename is not
1656 * opened for append mode or the filename is truncated at open time.
1657 */
1658 if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
1659 && ccs_init_request_info(&r, NULL, CCS_MAC_FILE_REWRITE)
1660 != CCS_CONFIG_DISABLED) {
1661 if (!ccs_get_realpath(&buf, dentry, mnt)) {
1662 error = -ENOMEM;
1663 goto out;
1664 }
1665 if (ccs_is_no_rewrite_file(&buf)) {
1666 r.obj = &obj;
1667 error = ccs_path_permission(&r, CCS_TYPE_REWRITE,
1668 &buf);
1669 }
1670 }
1671 if (!error && acc_mode &&
1672 ccs_init_request_info(&r, NULL, CCS_MAC_FILE_OPEN)
1673 != CCS_CONFIG_DISABLED) {
1674 if (!buf.name && !ccs_get_realpath(&buf, dentry, mnt)) {
1675 error = -ENOMEM;
1676 goto out;
1677 }
1678 r.obj = &obj;
1679 error = ccs_file_perm(&r, &buf, acc_mode);
1680 }
1681 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
1682 if (!error && (flag & O_TRUNC) &&
1683 ccs_init_request_info(&r, NULL, CCS_MAC_FILE_TRUNCATE)
1684 != CCS_CONFIG_DISABLED) {
1685 if (!buf.name && !ccs_get_realpath(&buf, dentry, mnt)) {
1686 error = -ENOMEM;
1687 goto out;
1688 }
1689 r.obj = &obj;
1690 error = ccs_path_permission(&r, CCS_TYPE_TRUNCATE, &buf);
1691 }
1692 #endif
1693 out:
1694 kfree(buf.name);
1695 ccs_read_unlock(idx);
1696 if (r.mode != CCS_CONFIG_ENFORCING)
1697 error = 0;
1698 return error;
1699 }
1700
1701 /**
1702 * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "chroot" and "unmount".
1703 *
1704 * @operation: Type of operation.
1705 * @dir: Pointer to "struct inode". May be NULL.
1706 * @dentry: Pointer to "struct dentry".
1707 * @mnt: Pointer to "struct vfsmount".
1708 * @target: Symlink's target if @operation is CCS_TYPE_SYMLINK.
1709 *
1710 * Returns 0 on success, negative value otherwise.
1711 */
1712 static int ccs_path_perm(const u8 operation, struct inode *dir,
1713 struct dentry *dentry, struct vfsmount *mnt,
1714 const char *target)
1715 {
1716 struct ccs_request_info r;
1717 struct ccs_obj_info obj = {
1718 .path1.dentry = dentry,
1719 .path1.mnt = mnt
1720 };
1721 int error = 0;
1722 struct ccs_path_info buf;
1723 bool is_enforce = false;
1724 struct ccs_path_info symlink_target;
1725 int idx;
1726 if (!mnt)
1727 return 0;
1728 buf.name = NULL;
1729 symlink_target.name = NULL;
1730 idx = ccs_read_lock();
1731 if (ccs_init_request_info(&r, NULL, ccs_p2mac[operation])
1732 == CCS_CONFIG_DISABLED)
1733 goto out;
1734 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1735 switch (operation) {
1736 case CCS_TYPE_RMDIR:
1737 error = ccs_pre_vfs_rmdir(dir, dentry);
1738 break;
1739 case CCS_TYPE_UNLINK:
1740 error = ccs_pre_vfs_unlink(dir, dentry);
1741 break;
1742 case CCS_TYPE_SYMLINK:
1743 error = ccs_pre_vfs_symlink(dir, dentry);
1744 break;
1745 }
1746 if (error)
1747 goto out;
1748 error = -ENOMEM;
1749 if (!ccs_get_realpath(&buf, dentry, mnt))
1750 goto out;
1751 r.obj = &obj;
1752 switch (operation) {
1753 case CCS_TYPE_RMDIR:
1754 case CCS_TYPE_CHROOT:
1755 case CCS_TYPE_UMOUNT:
1756 ccs_add_slash(&buf);
1757 break;
1758 case CCS_TYPE_SYMLINK:
1759 symlink_target.name = ccs_encode(target);
1760 if (!symlink_target.name)
1761 goto out;
1762 ccs_fill_path_info(&symlink_target);
1763 obj.symlink_target = &symlink_target;
1764 break;
1765 }
1766 error = ccs_path_permission(&r, operation, &buf);
1767 if (operation == CCS_TYPE_SYMLINK)
1768 kfree(symlink_target.name);
1769 out:
1770 kfree(buf.name);
1771 ccs_read_unlock(idx);
1772 if (!is_enforce)
1773 error = 0;
1774 return error;
1775 }
1776
1777 /**
1778 * ccs_path_number3_perm - Check permission for "mkblock" and "mkchar".
1779 *
1780 * @operation: Type of operation. (CCS_TYPE_MKCHAR or CCS_TYPE_MKBLOCK)
1781 * @dir: Pointer to "struct inode".
1782 * @dentry: Pointer to "struct dentry".
1783 * @mnt: Pointer to "struct vfsmount".
1784 * @mode: Create mode.
1785 * @dev: Device number.
1786 *
1787 * Returns 0 on success, negative value otherwise.
1788 */
1789 static int ccs_path_number3_perm(const u8 operation, struct inode *dir,
1790 struct dentry *dentry, struct vfsmount *mnt,
1791 const unsigned int mode, unsigned int dev)
1792 {
1793 struct ccs_request_info r;
1794 struct ccs_obj_info obj = {
1795 .path1.dentry = dentry,
1796 .path1.mnt = mnt,
1797 .dev = dev
1798 };
1799 int error = 0;
1800 struct ccs_path_info buf;
1801 bool is_enforce = false;
1802 int idx;
1803 if (!mnt)
1804 return 0;
1805 buf.name = NULL;
1806 idx = ccs_read_lock();
1807 if (ccs_init_request_info(&r, NULL, ccs_pnnn2mac[operation])
1808 == CCS_CONFIG_DISABLED)
1809 goto out;
1810 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1811 error = ccs_pre_vfs_mknod(dir, dentry);
1812 if (error)
1813 goto out;
1814 error = -EPERM;
1815 if (!capable(CAP_MKNOD))
1816 goto out;
1817 error = -ENOMEM;
1818 if (!ccs_get_realpath(&buf, dentry, mnt))
1819 goto out;
1820 r.obj = &obj;
1821 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1822 dev = new_decode_dev(dev);
1823 #endif
1824 error = ccs_path_number3_perm2(&r, operation, &buf, mode, dev);
1825 out:
1826 kfree(buf.name);
1827 ccs_read_unlock(idx);
1828 if (!is_enforce)
1829 error = 0;
1830 return error;
1831 }
1832
1833 /**
1834 * ccs_rewrite_permission - Check permission for "rewrite".
1835 *
1836 * @filp: Pointer to "struct file".
1837 *
1838 * Returns 0 on success, negative value otherwise.
1839 */
1840 int ccs_rewrite_permission(struct file *filp)
1841 {
1842 struct ccs_request_info r;
1843 struct ccs_obj_info obj = {
1844 .path1.dentry = filp->f_dentry,
1845 .path1.mnt = filp->f_vfsmnt
1846 };
1847 int error = 0;
1848 bool is_enforce = false;
1849 struct ccs_path_info buf;
1850 int idx;
1851 if (!filp->f_vfsmnt)
1852 return 0;
1853 buf.name = NULL;
1854 idx = ccs_read_lock();
1855 if (ccs_init_request_info(&r, NULL, CCS_MAC_FILE_REWRITE)
1856 == CCS_CONFIG_DISABLED)
1857 goto out;
1858 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1859 r.obj = &obj;
1860 error = -ENOMEM;
1861 if (!ccs_get_realpath(&buf, filp->f_dentry, filp->f_vfsmnt))
1862 goto out;
1863 error = 0;
1864 if (ccs_is_no_rewrite_file(&buf))
1865 error = ccs_path_permission(&r, CCS_TYPE_REWRITE, &buf);
1866 out:
1867 kfree(buf.name);
1868 ccs_read_unlock(idx);
1869 if (!is_enforce)
1870 error = 0;
1871 return error;
1872 }
1873
1874 /**
1875 * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
1876 *
1877 * @operation: Type of operation.
1878 * @dir1: Pointer to "struct inode". May be NULL.
1879 * @dentry1: Pointer to "struct dentry".
1880 * @mnt1: Pointer to "struct vfsmount".
1881 * @dir2: Pointer to "struct inode". May be NULL.
1882 * @dentry2: Pointer to "struct dentry".
1883 * @mnt2: Pointer to "struct vfsmount".
1884 *
1885 * Returns 0 on success, negative value otherwise.
1886 */
1887 static int ccs_path2_perm(const u8 operation, struct inode *dir1,
1888 struct dentry *dentry1, struct vfsmount *mnt1,
1889 struct inode *dir2, struct dentry *dentry2,
1890 struct vfsmount *mnt2)
1891 {
1892 struct ccs_request_info r;
1893 int error = 0;
1894 const char *msg = ccs_path22keyword(operation);
1895 struct ccs_path_info buf1;
1896 struct ccs_path_info buf2;
1897 bool is_enforce = false;
1898 struct ccs_obj_info obj = {
1899 .path1.dentry = dentry1,
1900 .path1.mnt = mnt1,
1901 .path2.dentry = dentry2,
1902 .path2.mnt = mnt2
1903 };
1904 int idx;
1905 if (!mnt1 || !mnt2)
1906 return 0;
1907 buf1.name = NULL;
1908 buf2.name = NULL;
1909 idx = ccs_read_lock();
1910 if (ccs_init_request_info(&r, NULL, ccs_pp2mac[operation])
1911 == CCS_CONFIG_DISABLED)
1912 goto out;
1913 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1914 switch (operation) {
1915 case CCS_TYPE_RENAME:
1916 error = ccs_pre_vfs_rename(dir1, dentry1, dir2, dentry2);
1917 break;
1918 case CCS_TYPE_LINK:
1919 error = ccs_pre_vfs_link(dentry1, dir2, dentry2);
1920 break;
1921 }
1922 if (error)
1923 goto out;
1924 error = -ENOMEM;
1925 if (!ccs_get_realpath(&buf1, dentry1, mnt1) ||
1926 !ccs_get_realpath(&buf2, dentry2, mnt2))
1927 goto out;
1928 switch (operation) {
1929 case CCS_TYPE_RENAME:
1930 case CCS_TYPE_LINK:
1931 if (!dentry1->d_inode || !S_ISDIR(dentry1->d_inode->i_mode))
1932 break;
1933 /* fall through */
1934 case CCS_TYPE_PIVOT_ROOT:
1935 ccs_add_slash(&buf1);
1936 ccs_add_slash(&buf2);
1937 }
1938 r.obj = &obj;
1939 do {
1940 error = ccs_path2_acl(&r, operation, &buf1, &buf2);
1941 ccs_audit_path2_log(&r, msg, buf1.name, buf2.name, !error);
1942 if (!error)
1943 break;
1944 error = ccs_supervisor(&r, "allow_%s %s %s\n", msg,
1945 ccs_file_pattern(&buf1),
1946 ccs_file_pattern(&buf2));
1947 } while (error == CCS_RETRY_REQUEST);
1948 out:
1949 kfree(buf1.name);
1950 kfree(buf2.name);
1951 ccs_read_unlock(idx);
1952 if (!is_enforce)
1953 error = 0;
1954 return error;
1955 }
1956
1957 /**
1958 * ccs_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
1959 *
1960 * @type: Type of operation.
1961 * @filename: Filename.
1962 * @number: Number.
1963 * @domain: Pointer to "struct ccs_domain_info".
1964 * @condition: Pointer to "struct ccs_condition". May be NULL.
1965 * @is_delete: True if it is a delete request.
1966 *
1967 * Returns 0 on success, negative value otherwise.
1968 */
1969 static inline int ccs_update_path_number_acl(const u8 type,
1970 const char *filename,
1971 char *number,
1972 struct ccs_domain_info * const
1973 domain,
1974 struct ccs_condition *condition,
1975 const bool is_delete)
1976 {
1977 const u8 perm = 1 << type;
1978 struct ccs_acl_info *ptr;
1979 struct ccs_path_number_acl e = {
1980 .head.type = CCS_TYPE_PATH_NUMBER_ACL,
1981 .head.cond = condition,
1982 .perm = perm
1983 };
1984 struct ccs_path_number_acl *entry = NULL;
1985 int error = is_delete ? -ENOENT : -ENOMEM;
1986 if (!domain)
1987 return -EINVAL;
1988 if (!ccs_parse_name_union(filename, &e.name))
1989 return -EINVAL;
1990 if (!ccs_parse_number_union(number, &e.number))
1991 goto out;
1992 if (!is_delete)
1993 entry = kmalloc(sizeof(e), GFP_KERNEL);
1994 mutex_lock(&ccs_policy_lock);
1995 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1996 struct ccs_path_number_acl *acl =
1997 container_of(ptr, struct ccs_path_number_acl, head);
1998 if (ptr->type != CCS_TYPE_PATH_NUMBER_ACL ||
1999 ptr->cond != condition ||
2000 ccs_memcmp(acl, &e, offsetof(typeof(e), name), sizeof(e)))
2001 continue;
2002 if (is_delete) {
2003 acl->perm &= ~perm;
2004 if (!acl->perm)
2005 ptr->is_deleted = true;
2006 } else {
2007 if (ptr->is_deleted)
2008 acl->perm = 0;
2009 acl->perm |= perm;
2010 ptr->is_deleted = false;
2011 }
2012 error = 0;
2013 break;
2014 }
2015 if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
2016 ccs_add_domain_acl(domain, &entry->head);
2017 entry = NULL;
2018 error = 0;
2019 }
2020 mutex_unlock(&ccs_policy_lock);
2021 out:
2022 ccs_put_name_union(&e.name);
2023 ccs_put_number_union(&e.number);
2024 kfree(entry);
2025 return error;
2026 }
2027
2028 /**
2029 * ccs_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation.
2030 *
2031 * @r: Pointer to "struct ccs_request_info".
2032 * @type: Operation.
2033 * @filename: Filename to check.
2034 * @number: Number.
2035 *
2036 * Returns 0 on success, -EPERM otherwise.
2037 *
2038 * Caller holds ccs_read_lock().
2039 */
2040 static int ccs_path_number_acl(struct ccs_request_info *r, const u8 type,
2041 const struct ccs_path_info *filename,
2042 const unsigned long number)
2043 {
2044 struct ccs_domain_info *domain = r->domain;
2045 struct ccs_acl_info *ptr;
2046 const u8 perm = 1 << type;
2047 int error = -EPERM;
2048 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
2049 struct ccs_path_number_acl *acl;
2050 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH_NUMBER_ACL)
2051 continue;
2052 acl = container_of(ptr, struct ccs_path_number_acl, head);
2053 if (!(acl->perm & perm) || !ccs_condition(r, ptr) ||
2054 !ccs_compare_number_union(number, &acl->number) ||
2055 !ccs_compare_name_union(filename, &acl->name))
2056 continue;
2057 r->cond = ptr->cond;
2058 error = 0;
2059 break;
2060 }
2061 return error;
2062 }
2063
2064 /**
2065 * ccs_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
2066 *
2067 * @r: Pointer to "struct ccs_request_info".
2068 * @filename: Filename to check.
2069 * @number: Number.
2070 *
2071 * Returns 0 on success, 1 on retry, negative value otherwise.
2072 *
2073 * Caller holds ccs_read_lock().
2074 */
2075 static int ccs_path_number_perm2(struct ccs_request_info *r, const u8 type,
2076 const struct ccs_path_info *filename,
2077 const unsigned long number)
2078 {
2079 char buffer[64];
2080 int error;
2081 u8 radix;
2082 const char *msg = ccs_path_number2keyword(type);
2083 if (!filename)
2084 return 0;
2085 switch (type) {
2086 case CCS_TYPE_CREATE:
2087 case CCS_TYPE_MKDIR:
2088 case CCS_TYPE_MKFIFO:
2089 case CCS_TYPE_MKSOCK:
2090 case CCS_TYPE_CHMOD:
2091 radix = CCS_VALUE_TYPE_OCTAL;
2092 break;
2093 case CCS_TYPE_IOCTL:
2094 radix = CCS_VALUE_TYPE_HEXADECIMAL;
2095 break;
2096 default:
2097 radix = CCS_VALUE_TYPE_DECIMAL;
2098 break;
2099 }
2100 ccs_print_ulong(buffer, sizeof(buffer), number, radix);
2101 do {
2102 error = ccs_path_number_acl(r, type, filename, number);
2103 ccs_audit_path_number_log(r, msg, filename->name, buffer,
2104 !error);
2105 if (!error)
2106 return 0;
2107 error = ccs_supervisor(r, "allow_%s %s %s\n", msg,
2108 ccs_file_pattern(filename), buffer);
2109 } while (error == CCS_RETRY_REQUEST);
2110 if (r->mode != CCS_CONFIG_ENFORCING)
2111 error = 0;
2112 return error;
2113 }
2114
2115 /**
2116 * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
2117 *
2118 * @type: Type of operation.
2119 * @dir: Pointer to "struct inode". May be NULL.
2120 * @dentry: Pointer to "struct dentry".
2121 * @vfsmnt: Pointer to "struct vfsmount".
2122 * @number: Number.
2123 *
2124 * Returns 0 on success, negative value otherwise.
2125 */
2126 static int ccs_path_number_perm(const u8 type, struct inode *dir,
2127 struct dentry *dentry, struct vfsmount *vfsmnt,
2128 unsigned long number)
2129 {
2130 struct ccs_request_info r;
2131 struct ccs_obj_info obj = {
2132 .path1.dentry = dentry,
2133 .path1.mnt = vfsmnt
2134 };
2135 int error = 0;
2136 struct ccs_path_info buf;
2137 int idx;
2138 if (!vfsmnt || !dentry)
2139 return 0;
2140 buf.name = NULL;
2141 idx = ccs_read_lock();
2142 if (ccs_init_request_info(&r, NULL, ccs_pn2mac[type])
2143 == CCS_CONFIG_DISABLED)
2144 goto out;
2145 switch (type) {
2146 case CCS_TYPE_CREATE:
2147 error = ccs_pre_vfs_create(dir, dentry);
2148 break;
2149 case CCS_TYPE_MKDIR:
2150 error = ccs_pre_vfs_mkdir(dir, dentry);
2151 break;
2152 case CCS_TYPE_MKFIFO:
2153 case CCS_TYPE_MKSOCK:
2154 error = ccs_pre_vfs_mknod(dir, dentry);
2155 break;
2156 }
2157 if (error)
2158 goto out;
2159 error = -ENOMEM;
2160 if (!ccs_get_realpath(&buf, dentry, vfsmnt))
2161 goto out;
2162 r.obj = &obj;
2163 if (type == CCS_TYPE_MKDIR)
2164 ccs_add_slash(&buf);
2165 error = ccs_path_number_perm2(&r, type, &buf, number);
2166 out:
2167 kfree(buf.name);
2168 ccs_read_unlock(idx);
2169 if (r.mode != CCS_CONFIG_ENFORCING)
2170 error = 0;
2171 return error;
2172 }
2173
2174 /**
2175 * ccs_ioctl_permission - Check permission for "ioctl".
2176 *
2177 * @file: Pointer to "struct file".
2178 * @cmd: Ioctl command number.
2179 * @arg: Param for @cmd .
2180 *
2181 * Returns 0 on success, negative value otherwise.
2182 */
2183 int ccs_ioctl_permission(struct file *filp, unsigned int cmd,
2184 unsigned long arg)
2185 {
2186 return ccs_path_number_perm(CCS_TYPE_IOCTL, NULL, filp->f_dentry,
2187 filp->f_vfsmnt, cmd);
2188 }
2189
2190 /**
2191 * ccs_chmod_permission - Check permission for "chmod".
2192 *
2193 * @dentry: Pointer to "struct dentry".
2194 * @vfsmnt: Pointer to "struct vfsmount".
2195 * @mode: Mode.
2196 *
2197 * Returns 0 on success, negative value otherwise.
2198 */
2199 int ccs_chmod_permission(struct dentry *dentry, struct vfsmount *vfsmnt,
2200 mode_t mode)
2201 {
2202 if (mode == (mode_t) -1)
2203 return 0;
2204 if (!ccs_capable(CCS_SYS_CHMOD))
2205 return -EPERM;
2206 return ccs_path_number_perm(CCS_TYPE_CHMOD, NULL, dentry, vfsmnt,
2207 mode & S_IALLUGO);
2208 }
2209
2210 /**
2211 * ccs_chown_permission - Check permission for "chown/chgrp".
2212 *
2213 * @dentry: Pointer to "struct dentry".
2214 * @vfsmnt: Pointer to "struct vfsmount".
2215 * @user: User ID.
2216 * @group: Group ID.
2217 *
2218 * Returns 0 on success, negative value otherwise.
2219 */
2220 int ccs_chown_permission(struct dentry *dentry, struct vfsmount *vfsmnt,
2221 uid_t user, gid_t group)
2222 {
2223 int error = 0;
2224 if (user == (uid_t) -1 && group == (gid_t) -1)
2225 return 0;
2226 if (!ccs_capable(CCS_SYS_CHOWN))
2227 return -EPERM;
2228 if (user != (uid_t) -1)
2229 error = ccs_path_number_perm(CCS_TYPE_CHOWN, NULL, dentry,
2230 vfsmnt, user);
2231 if (!error && group != (gid_t) -1)
2232 error = ccs_path_number_perm(CCS_TYPE_CHGRP, NULL, dentry,
2233 vfsmnt, group);
2234 return error;
2235 }
2236
2237 /**
2238 * ccs_pivot_root_permission - Check permission for pivot_root().
2239 *
2240 * @old_path: Pointer to "struct path".
2241 * @new_path: Pointer to "struct path".
2242 *
2243 * Returns 0 on success, negative value otherwise.
2244 */
2245 int ccs_pivot_root_permission(struct path *old_path, struct path *new_path)
2246 {
2247 if (!ccs_capable(CCS_SYS_PIVOT_ROOT))
2248 return -EPERM;
2249 return ccs_path2_perm(CCS_TYPE_PIVOT_ROOT, NULL, new_path->dentry,
2250 new_path->mnt, NULL, old_path->dentry,
2251 old_path->mnt);
2252 }
2253
2254 /**
2255 * ccs_chroot_permission - Check permission for chroot().
2256 *
2257 * @path: Pointer to "struct path".
2258 *
2259 * Returns 0 on success, negative value otherwise.
2260 */
2261 int ccs_chroot_permission(struct path *path)
2262 {
2263 if (!ccs_capable(CCS_SYS_CHROOT))
2264 return -EPERM;
2265 return ccs_path_perm(CCS_TYPE_CHROOT, NULL, path->dentry, path->mnt,
2266 NULL);
2267 }
2268
2269 /**
2270 * ccs_umount_permission - Check permission for unmount.
2271 *
2272 * @mnt: Pointer to "struct vfsmount".
2273 * @flags: Umount flags.
2274 *
2275 * Returns 0 on success, negative value otherwise.
2276 */
2277 int ccs_umount_permission(struct vfsmount *mnt, int flags)
2278 {
2279 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2280 if (!ccs_capable(CCS_SYS_UMOUNT))
2281 return -EPERM;
2282 #endif
2283 return ccs_path_perm(CCS_TYPE_UMOUNT, NULL, mnt->mnt_root, mnt, NULL);
2284 }
2285
2286 /**
2287 * ccs_write_file_policy - Update file related list.
2288 *
2289 * @data: String to parse.
2290 * @domain: Pointer to "struct ccs_domain_info".
2291 * @condition: Pointer to "struct ccs_condition". May be NULL.
2292 * @is_delete: True if it is a delete request.
2293 *
2294 * Returns 0 on success, negative value otherwise.
2295 */
2296 int ccs_write_file_policy(char *data, struct ccs_domain_info *domain,
2297 struct ccs_condition *condition,
2298 const bool is_delete)
2299 {
2300 char *w[5];
2301 u8 type;
2302 if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
2303 return -EINVAL;
2304 if (strncmp(w[0], "allow_", 6)) {
2305 unsigned int perm;
2306 if (sscanf(w[0], "%u", &perm) == 1)
2307 return ccs_update_file_acl((u8) perm, w[1], domain,
2308 condition, is_delete);
2309 if (!strcmp(w[0], CCS_KEYWORD_EXECUTE_HANDLER))
2310 type = CCS_TYPE_EXECUTE_HANDLER;
2311 else if (!strcmp(w[0], CCS_KEYWORD_DENIED_EXECUTE_HANDLER))
2312 type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
2313 else
2314 goto out;
2315 return ccs_update_execute_handler(type, w[1], domain,
2316 is_delete);
2317 }
2318 w[0] += 6;
2319 for (type = 0; type < CCS_MAX_PATH_OPERATION; type++) {
2320 if (strcmp(w[0], ccs_path_keyword[type]))
2321 continue;
2322 return ccs_update_path_acl(type, w[1], domain, condition,
2323 is_delete);
2324 }
2325 if (!w[2][0])
2326 goto out;
2327 for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++) {
2328 if (strcmp(w[0], ccs_path2_keyword[type]))
2329 continue;
2330 return ccs_update_path2_acl(type, w[1], w[2], domain,
2331 condition, is_delete);
2332 }
2333 for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++) {
2334 if (strcmp(w[0], ccs_path_number_keyword[type]))
2335 continue;
2336 return ccs_update_path_number_acl(type, w[1], w[2], domain,
2337 condition, is_delete);
2338 }
2339 if (!w[3][0] || !w[4][0])
2340 goto out;
2341 for (type = 0; type < CCS_MAX_PATH_NUMBER3_OPERATION; type++) {
2342 if (strcmp(w[0], ccs_path_number3_keyword[type]))
2343 continue;
2344 return ccs_update_path_number3_acl(type, w[1], w[2], w[3],
2345 w[4], domain, condition,
2346 is_delete);
2347 }
2348 out:
2349 return -EINVAL;
2350 }
2351
2352 /*
2353 * Permission checks from vfs_mknod().
2354 *
2355 * This function is exported because
2356 * vfs_mknod() is called from net/unix/af_unix.c.
2357 */
2358 int ccs_mknod_permission(struct inode *dir, struct dentry *dentry,
2359 struct vfsmount *mnt, const unsigned int mode,
2360 unsigned int dev)
2361 {
2362 int error = 0;
2363 const unsigned int perm = mode & S_IALLUGO;
2364 switch (mode & S_IFMT) {
2365 case S_IFCHR:
2366 if (!ccs_capable(CCS_CREATE_CHAR_DEV))
2367 error = -EPERM;
2368 else
2369 error = ccs_path_number3_perm(CCS_TYPE_MKCHAR, dir,
2370 dentry, mnt, perm, dev);
2371 break;
2372 case S_IFBLK:
2373 if (!ccs_capable(CCS_CREATE_BLOCK_DEV))
2374 error = -EPERM;
2375 else
2376 error = ccs_path_number3_perm(CCS_TYPE_MKBLOCK, dir,
2377 dentry, mnt, perm, dev);
2378 break;
2379 case S_IFIFO:
2380 if (!ccs_capable(CCS_CREATE_FIFO))
2381 error = -EPERM;
2382 else
2383 error = ccs_path_number_perm(CCS_TYPE_MKFIFO, dir,
2384 dentry, mnt, perm);
2385 break;
2386 case S_IFSOCK:
2387 if (!ccs_capable(CCS_CREATE_UNIX_SOCKET))
2388 error = -EPERM;
2389 else
2390 error = ccs_path_number_perm(CCS_TYPE_MKSOCK, dir,
2391 dentry, mnt, perm);
2392 break;
2393 case 0:
2394 case S_IFREG:
2395 error = ccs_path_number_perm(CCS_TYPE_CREATE, dir, dentry, mnt,
2396 perm);
2397 break;
2398 }
2399 return error;
2400 }
2401 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
2402 EXPORT_SYMBOL(ccs_mknod_permission); /* for net/unix/af_unix.c */
2403 #endif
2404
2405 /* Permission checks for vfs_mkdir(). */
2406 int ccs_mkdir_permission(struct inode *dir, struct dentry *dentry,
2407 struct vfsmount *mnt, unsigned int mode)
2408 {
2409 return ccs_path_number_perm(CCS_TYPE_MKDIR, dir, dentry, mnt, mode);
2410 }
2411
2412 /* Permission checks for vfs_rmdir(). */
2413 int ccs_rmdir_permission(struct inode *dir, struct dentry *dentry,
2414 struct vfsmount *mnt)
2415 {
2416 return ccs_path_perm(CCS_TYPE_RMDIR, dir, dentry, mnt, NULL);
2417 }
2418
2419 /* Permission checks for vfs_unlink(). */
2420 int ccs_unlink_permission(struct inode *dir, struct dentry *dentry,
2421 struct vfsmount *mnt)
2422 {
2423 if (!ccs_capable(CCS_SYS_UNLINK))
2424 return -EPERM;
2425 return ccs_path_perm(CCS_TYPE_UNLINK, dir, dentry, mnt, NULL);
2426 }
2427
2428 /* Permission checks for vfs_symlink(). */
2429 int ccs_symlink_permission(struct inode *dir, struct dentry *dentry,
2430 struct vfsmount *mnt, const char *from)
2431 {
2432 if (!ccs_capable(CCS_SYS_SYMLINK))
2433 return -EPERM;
2434 return ccs_path_perm(CCS_TYPE_SYMLINK, dir, dentry, mnt, from);
2435 }
2436
2437 /* Permission checks for notify_change(). */
2438 int ccs_truncate_permission(struct dentry *dentry, struct vfsmount *mnt,
2439 loff_t length, unsigned int time_attrs)
2440 {
2441 return ccs_path_perm(CCS_TYPE_TRUNCATE, NULL, dentry, mnt, NULL);
2442 }
2443
2444 /* Permission checks for vfs_rename(). */
2445 int ccs_rename_permission(struct inode *old_dir, struct dentry *old_dentry,
2446 struct inode *new_dir, struct dentry *new_dentry,
2447 struct vfsmount *mnt)
2448 {
2449 if (!ccs_capable(CCS_SYS_RENAME))
2450 return -EPERM;
2451 return ccs_path2_perm(CCS_TYPE_RENAME, old_dir, old_dentry, mnt,
2452 new_dir, new_dentry, mnt);
2453 }
2454
2455 /* Permission checks for vfs_link(). */
2456 int ccs_link_permission(struct dentry *old_dentry, struct inode *new_dir,
2457 struct dentry *new_dentry, struct vfsmount *mnt)
2458 {
2459 if (!ccs_capable(CCS_SYS_LINK))
2460 return -EPERM;
2461 return ccs_path2_perm(CCS_TYPE_LINK, NULL, old_dentry, mnt,
2462 new_dir, new_dentry, mnt);
2463 }
2464
2465 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
2466 /* Permission checks for open_exec(). */
2467 int ccs_open_exec_permission(struct dentry *dentry, struct vfsmount *mnt)
2468 {
2469 return (current->ccs_flags & CCS_TASK_IS_IN_EXECVE) ?
2470 /* 01 means "read". */
2471 ccs_open_permission(dentry, mnt, 01) : 0;
2472 }
2473
2474 /* Permission checks for sys_uselib(). */
2475 int ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
2476 {
2477 /* 01 means "read". */
2478 return ccs_open_permission(dentry, mnt, 01);
2479 }
2480 #endif
2481
2482 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
2483 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || defined(CONFIG_SYSCTL_SYSCALL)
2484
2485 #include <linux/sysctl.h>
2486
2487 /* Permission checks for parse_table(). */
2488 int ccs_parse_table(int __user *name, int nlen, void __user *oldval,
2489 void __user *newval, struct ctl_table *table)
2490 {
2491 int n;
2492 int error = -ENOMEM;
2493 int op = 0;
2494 struct ccs_path_info buf;
2495 char *buffer = NULL;
2496 struct ccs_request_info r;
2497 int idx;
2498 if (oldval)
2499 op |= 004;
2500 if (newval)
2501 op |= 002;
2502 if (!op) /* Neither read nor write */
2503 return 0;
2504 idx = ccs_read_lock();
2505 if (ccs_init_request_info(&r, NULL, CCS_MAC_FILE_OPEN)
2506 == CCS_CONFIG_DISABLED) {
2507 error = 0;
2508 goto out;
2509 }
2510 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
2511 if (!buffer)
2512 goto out;
2513 snprintf(buffer, PAGE_SIZE - 1, "/proc/sys");
2514 repeat:
2515 if (!nlen) {
2516 error = -ENOTDIR;
2517 goto out;
2518 }
2519 if (get_user(n, name)) {
2520 error = -EFAULT;
2521 goto out;
2522 }
2523 for ( ; table->ctl_name
2524 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
2525 || table->procname
2526 #endif
2527 ; table++) {
2528 int pos;
2529 const char *cp;
2530 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2531 if (n != table->ctl_name && table->ctl_name != CTL_ANY)
2532 continue;
2533 #else
2534 if (!n || n != table->ctl_name)
2535 continue;
2536 #endif
2537 pos = strlen(buffer);
2538 cp = table->procname;
2539 error = -ENOMEM;
2540 if (cp) {
2541 int len = strlen(cp);
2542 if (len + 2 > PAGE_SIZE - 1)
2543 goto out;
2544 buffer[pos++] = '/';
2545 memmove(buffer + pos, cp, len + 1);
2546 } else {
2547 /* Assume nobody assigns "=\$=" for procname. */
2548 snprintf(buffer + pos, PAGE_SIZE - pos - 1,
2549 "/=%d=", table->ctl_name);
2550 if (!memchr(buffer, '\0', PAGE_SIZE - 2))
2551 goto out;
2552 }
2553 if (table->child) {
2554 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2555 if (table->strategy) {
2556 /* printk("sysctl='%s'\n", buffer); */
2557 buf.name = ccs_encode(buffer);
2558 if (buf.name) {
2559 ccs_fill_path_info(&buf);
2560 error = ccs_file_perm(&r, &buf, op);
2561 kfree(buf.name);
2562 }
2563 if (error)
2564 goto out;
2565 }
2566 #endif
2567 name++;
2568 nlen--;
2569 table = table->child;
2570 goto repeat;
2571 }
2572 /* printk("sysctl='%s'\n", buffer); */
2573 buf.name = ccs_encode(buffer);
2574 if (buf.name) {
2575 ccs_fill_path_info(&buf);
2576 error = ccs_file_perm(&r, &buf, op);
2577 kfree(buf.name);
2578 }
2579 goto out;
2580 }
2581 error = -ENOTDIR;
2582 out:
2583 ccs_read_unlock(idx);
2584 kfree(buffer);
2585 return error;
2586 }
2587 #endif
2588 #endif

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26