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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/include/linux/syaoran.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2690 - (show annotations) (download) (as text)
Wed Jun 24 04:50:19 2009 UTC (14 years, 11 months ago) by kumaneko
File MIME type: text/x-chdr
File size: 29287 byte(s)


1 /*
2 * include/linux/syaoran.h
3 *
4 * Implementation of the Tamper-Proof Device Filesystem.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
8 * Version: 1.6.8 2009/05/28
9 *
10 * This file is applicable to both 2.4.30 and 2.6.11 and later.
11 * See README.ccs for ChangeLog.
12 *
13 */
14 /*
15 * A brief description about SYAORAN:
16 *
17 * SYAORAN stands for "Simple Yet All-important Object Realizing Abiding
18 * Nexus". SYAORAN is a filesystem for /dev with Mandatory Access Control.
19 *
20 * /dev cannot be mounted for read-only mode, but this means that files on
21 * /dev might be tampered with. In other words, a device file might have
22 * inappropriate attributes (e.g. /dev/null has char-1-5 attributes).
23 * SYAORAN can restrict combinations of (pathname, attribute) that
24 * the system can create so that all files on this filesystem have appropriate
25 * attributes (e.g. /dev/null has char-1-3 attributes).
26 *
27 * The attribute is one of directory, regular file, FIFO, UNIX domain socket,
28 * symbolic link, character or block device file with major/minor device
29 * numbers.
30 *
31 * You can use SYAORAN alone, but I recommend you to use SYAORAN
32 * with SAKURA and TOMOYO.
33 */
34
35 #ifndef _LINUX_SYAORAN_H
36 #define _LINUX_SYAORAN_H
37
38 #include <linux/version.h>
39 #include <linux/ccs_compat.h>
40
41 /**
42 * list_for_each_cookie - iterate over a list with cookie.
43 * @pos: the &struct list_head to use as a loop cursor.
44 * @cookie: the &struct list_head to use as a cookie.
45 * @head: the head for your list.
46 *
47 * Same with list_for_each except that this primitive uses cookie
48 * so that we can continue iteration.
49 */
50 #define list_for_each_cookie(pos, cookie, head) \
51 for (({ if (!cookie) \
52 cookie = head; }), pos = (cookie)->next; \
53 prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
54 (cookie) = pos, pos = pos->next)
55
56 /* The following constants are used to restrict operations.*/
57 #define MAY_CREATE 1 /* This file is allowed to mknod() */
58 #define MAY_DELETE 2 /* This file is allowed to unlink() */
59 #define MAY_CHMOD 4 /* This file is allowed to chmod() */
60 #define MAY_CHOWN 8 /* This file is allowed to chown() */
61 #define DEVICE_USED 16 /* This block or character device file is used. */
62 #define NO_CREATE_AT_MOUNT 32 /* Don't create this file at mount(). */
63
64 /* some random number */
65 #define CCS_MAGIC 0x2F646576 /* = '/dev' */
66
67 static void ccs_put_super(struct super_block *sb);
68 static int ccs_initialize(struct super_block *sb, void *data);
69 static void ccs_make_initial_nodes(struct super_block *sb);
70 static int ccs_may_create_node(struct dentry *dentry, int mode, int dev);
71 static int ccs_may_modify_node(struct dentry *dentry, unsigned int flags);
72 static int ccs_create_tracelog(struct super_block *sb,
73 const char *filename);
74
75 /* Wraps blkdev_open() to trace open operation for block devices. */
76 static int (*ccs_org_blkdev_open) (struct inode *inode, struct file *filp);
77 static struct file_operations ccs_wrapped_def_blk_fops;
78
79 static int ccs_wrapped_blkdev_open(struct inode *inode, struct file *filp)
80 {
81 int error = ccs_org_blkdev_open(inode, filp);
82 if (error != -ENXIO)
83 ccs_may_modify_node(filp->f_dentry, DEVICE_USED);
84 return error;
85 }
86
87 /* Wraps chrdev_open() to trace open operation for character devices. */
88 static int (*ccs_org_chrdev_open) (struct inode *inode, struct file *filp);
89 static struct file_operations ccs_wrapped_def_chr_fops;
90
91 static int ccs_wrapped_chrdev_open(struct inode *inode, struct file *filp)
92 {
93 int error = ccs_org_chrdev_open(inode, filp);
94 if (error != -ENXIO)
95 ccs_may_modify_node(filp->f_dentry, DEVICE_USED);
96 return error;
97 }
98
99 /* lookup_create() without nameidata. Called only while initialization. */
100 static struct dentry *ccs_lookup_create2(const char *name, struct dentry *base,
101 const bool is_dir)
102 {
103 struct dentry *dentry;
104 const int len = name ? strlen(name) : 0;
105 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
106 mutex_lock(&base->d_inode->i_mutex);
107 #else
108 down(&base->d_inode->i_sem);
109 #endif
110 dentry = lookup_one_len(name, base, len);
111 if (IS_ERR(dentry))
112 goto fail;
113 if (!is_dir && name[len] && !dentry->d_inode)
114 goto enoent;
115 return dentry;
116 enoent:
117 dput(dentry);
118 dentry = ERR_PTR(-ENOENT);
119 fail:
120 return dentry;
121 }
122
123 /* mkdir(). Called only while initialization. */
124 static int ccs_fs_mkdir(const char *pathname, struct dentry *base, int mode,
125 uid_t user, gid_t group)
126 {
127 struct dentry *dentry = ccs_lookup_create2(pathname, base, 1);
128 int error = PTR_ERR(dentry);
129 if (!IS_ERR(dentry)) {
130 #ifdef HAVE_VFSMOUNT_IN_VFS_HELPER
131 error = vfs_mkdir(base->d_inode, dentry, NULL, mode);
132 #else
133 error = vfs_mkdir(base->d_inode, dentry, mode);
134 #endif
135 if (!error) {
136 lock_kernel();
137 dentry->d_inode->i_uid = user;
138 dentry->d_inode->i_gid = group;
139 unlock_kernel();
140 }
141 dput(dentry);
142 }
143 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
144 mutex_unlock(&base->d_inode->i_mutex);
145 #else
146 up(&base->d_inode->i_sem);
147 #endif
148 return error;
149 }
150
151 /* mknod(). Called only while initialization. */
152 static int ccs_fs_mknod(const char *filename, struct dentry *base, int mode,
153 dev_t dev, uid_t user, gid_t group)
154 {
155 struct dentry *dentry;
156 int error;
157 switch (mode & S_IFMT) {
158 case S_IFCHR:
159 case S_IFBLK:
160 case S_IFIFO:
161 case S_IFSOCK:
162 case S_IFREG:
163 break;
164 default:
165 return -EPERM;
166 }
167 dentry = ccs_lookup_create2(filename, base, 0);
168 error = PTR_ERR(dentry);
169 if (!IS_ERR(dentry)) {
170 #ifdef HAVE_VFSMOUNT_IN_VFS_HELPER
171 error = vfs_mknod(base->d_inode, dentry, NULL, mode, dev);
172 #else
173 error = vfs_mknod(base->d_inode, dentry, mode, dev);
174 #endif
175 if (!error) {
176 lock_kernel();
177 dentry->d_inode->i_uid = user;
178 dentry->d_inode->i_gid = group;
179 unlock_kernel();
180 }
181 dput(dentry);
182 }
183 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
184 mutex_unlock(&base->d_inode->i_mutex);
185 #else
186 up(&base->d_inode->i_sem);
187 #endif
188 return error;
189 }
190
191 /* symlink(). Called only while initialization. */
192 static int ccs_fs_symlink(const char *pathname, struct dentry *base,
193 char *oldname, int mode, uid_t user, gid_t group)
194 {
195 struct dentry *dentry = ccs_lookup_create2(pathname, base, 0);
196 int error = PTR_ERR(dentry);
197 if (!IS_ERR(dentry)) {
198 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26)
199 #ifdef HAVE_VFSMOUNT_IN_VFS_HELPER
200 error = vfs_symlink(base->d_inode, dentry, NULL, oldname,
201 S_IALLUGO);
202 #else
203 error = vfs_symlink(base->d_inode, dentry, oldname, S_IALLUGO);
204 #endif
205 #else
206 #ifdef HAVE_VFSMOUNT_IN_VFS_HELPER
207 error = vfs_symlink(base->d_inode, dentry, NULL, oldname);
208 #else
209 error = vfs_symlink(base->d_inode, dentry, oldname);
210 #endif
211 #endif
212 if (!error) {
213 lock_kernel();
214 dentry->d_inode->i_mode = mode;
215 dentry->d_inode->i_uid = user;
216 dentry->d_inode->i_gid = group;
217 unlock_kernel();
218 }
219 dput(dentry);
220 }
221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
222 mutex_unlock(&base->d_inode->i_mutex);
223 #else
224 up(&base->d_inode->i_sem);
225 #endif
226 return error;
227 }
228
229 /*
230 * Format string.
231 * Leading and trailing whitespaces are removed.
232 * Multiple whitespaces are packed into single space.
233 */
234 static void ccs_normalize_line(unsigned char *buffer)
235 {
236 unsigned char *sp = buffer;
237 unsigned char *dp = buffer;
238 bool first = true;
239 while (*sp && (*sp <= ' ' || *sp >= 127))
240 sp++;
241 while (*sp) {
242 if (!first)
243 *dp++ = ' ';
244 first = false;
245 while (*sp > ' ' && *sp < 127)
246 *dp++ = *sp++;
247 while (*sp && (*sp <= ' ' || *sp >= 127))
248 sp++;
249 }
250 *dp = '\0';
251 }
252
253 /* Convert text form of filename into binary form. */
254 static void ccs_unescape(char *filename)
255 {
256 char *cp = filename;
257 char c;
258 char d;
259 char e;
260 if (!cp)
261 return;
262 while (1) {
263 c = *filename++;
264 if (!c)
265 break;
266 if (c != '\\') {
267 *cp++ = c;
268 continue;
269 }
270 c = *filename++;
271 if (c == '\\') {
272 *cp++ = c;
273 continue;
274 }
275 if (c < '0' || c > '3')
276 break;
277 d = *filename++;
278 if (d < '0' || d > '7')
279 break;
280 e = *filename++;
281 if (e < '0' || e > '7')
282 break;
283 *(unsigned char *) cp++ = (unsigned char)
284 (((unsigned char) (c - '0') << 6)
285 + ((unsigned char) (d - '0') << 3)
286 + (unsigned char) (e - '0'));
287 }
288 *cp = '\0';
289 }
290
291 static char *strdup(const char *str)
292 {
293 const int len = str ? strlen(str) + 1 : 0;
294 char *cp = kzalloc(len, GFP_KERNEL);
295 if (cp)
296 memmove(cp, str, len);
297 return cp;
298 }
299
300 /* -1: Not specified, 0: Enforce by default, 1: Accept by default. */
301 static int ccs_default_mode = -1;
302
303 #if !defined(MODULE)
304 static int __init ccs_setup(char *str)
305 {
306 if (!strcmp(str, "accept"))
307 ccs_default_mode = 1;
308 else if (!strcmp(str, "enforce"))
309 ccs_default_mode = 0;
310 return 0;
311 }
312
313 __setup("SYAORAN=", ccs_setup);
314 #endif
315
316 /* The structure for possible device list. */
317 struct dev_entry {
318 struct list_head list;
319 /* Binary form of pathname under mount point. Never NULL. */
320 char *name;
321 /*
322 * Mode and permissions.
323 * setuid/setgid/sticky bits are not supported.
324 */
325 mode_t mode;
326 uid_t uid;
327 gid_t gid;
328 dev_t kdev;
329 /*
330 * Binary form of initial contents for the symlink. NULL if not symlink.
331 */
332 char *symlink_data;
333 /* File access control flags. */
334 unsigned int flags;
335 /* Text form of pathname under mount point. Never NULL. */
336 const char *printable_name;
337 /*
338 * Text form of initial contents for the symlink. NULL if not symlink.
339 */
340 const char *printable_symlink_data;
341 };
342
343 struct ccs_sb_info {
344 struct list_head list;
345 bool initialize_done; /* False if initialization is in progress. */
346 bool is_permissive_mode; /* True if permissive mode. */
347 };
348
349 static int ccs_register_node_info(char *buffer, struct super_block *sb)
350 {
351 enum {
352 ARG_FILENAME = 0,
353 ARG_PERMISSION = 1,
354 ARG_UID = 2,
355 ARG_GID = 3,
356 ARG_FLAGS = 4,
357 ARG_DEV_TYPE = 5,
358 ARG_SYMLINK_DATA = 6,
359 ARG_DEV_MAJOR = 6,
360 ARG_DEV_MINOR = 7,
361 MAX_ARG = 8
362 };
363 char *args[MAX_ARG];
364 int i;
365 int error = -EINVAL;
366 unsigned int perm;
367 unsigned int uid;
368 unsigned int gid;
369 unsigned int flags;
370 unsigned int major = 0;
371 unsigned int minor = 0;
372 struct ccs_sb_info *info =
373 (struct ccs_sb_info *) sb->s_fs_info;
374 struct dev_entry *entry;
375 if (!info)
376 return -EINVAL;
377 memset(args, 0, sizeof(args));
378 args[0] = buffer;
379 for (i = 1; i < MAX_ARG; i++) {
380 args[i] = strchr(args[i - 1] + 1, ' ');
381 if (!args[i])
382 break;
383 *args[i]++ = '\0';
384 }
385 /*
386 printk(KERN_DEBUG "<%s> <%s> <%s> <%s> <%s> <%s> <%s> <%s>\n",
387 args[0], args[1], args[2], args[3], args[4], args[5], args[6],
388 args[7]);
389 */
390 if (!args[ARG_FILENAME] || !args[ARG_PERMISSION] || !args[ARG_UID] ||
391 !args[ARG_GID] || !args[ARG_DEV_TYPE] || !args[ARG_FLAGS])
392 goto out;
393 if (sscanf(args[ARG_PERMISSION], "%o", &perm) != 1 ||
394 !(perm <= 0777) || sscanf(args[ARG_UID], "%u", &uid) != 1 ||
395 sscanf(args[ARG_GID], "%u", &gid) != 1 ||
396 sscanf(args[ARG_FLAGS], "%u", &flags) != 1 ||
397 *(args[ARG_DEV_TYPE] + 1))
398 goto out;
399 switch (*args[ARG_DEV_TYPE]) {
400 case 'c':
401 perm |= S_IFCHR;
402 if (!args[ARG_DEV_MAJOR] ||
403 sscanf(args[ARG_DEV_MAJOR], "%u", &major) != 1 ||
404 !args[ARG_DEV_MINOR] ||
405 sscanf(args[ARG_DEV_MINOR], "%u", &minor) != 1)
406 goto out;
407 break;
408 case 'b':
409 perm |= S_IFBLK;
410 if (!args[ARG_DEV_MAJOR] ||
411 sscanf(args[ARG_DEV_MAJOR], "%u", &major) != 1 ||
412 !args[ARG_DEV_MINOR] ||
413 sscanf(args[ARG_DEV_MINOR], "%u", &minor) != 1)
414 goto out;
415 break;
416 case 'l':
417 perm |= S_IFLNK;
418 if (!args[ARG_SYMLINK_DATA])
419 goto out;
420 break;
421 case 'd':
422 perm |= S_IFDIR;
423 break;
424 case 's':
425 perm |= S_IFSOCK;
426 break;
427 case 'p':
428 perm |= S_IFIFO;
429 break;
430 case 'f':
431 perm |= S_IFREG;
432 break;
433 default:
434 goto out;
435 }
436 error = -ENOMEM;
437 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
438 if (!entry)
439 goto out;
440 if (S_ISLNK(perm)) {
441 entry->printable_symlink_data = strdup(args[ARG_SYMLINK_DATA]);
442 if (!entry->printable_symlink_data)
443 goto out_freemem;
444 }
445 entry->printable_name = strdup(args[ARG_FILENAME]);
446 if (!entry->printable_name)
447 goto out_freemem;
448 if (S_ISLNK(perm)) {
449 entry->symlink_data = strdup(entry->printable_symlink_data);
450 if (!entry->symlink_data)
451 goto out_freemem;
452 ccs_unescape(entry->symlink_data);
453 }
454 entry->name = strdup(entry->printable_name);
455 if (!entry->name)
456 goto out_freemem;
457 ccs_unescape(entry->name);
458 {
459 /*
460 * Drop trailing '/', for get_local_absolute_path() doesn't
461 * append trailing '/'.
462 */
463 const int len = strlen(entry->name);
464 if (len && entry->name[len - 1] == '/')
465 entry->name[len - 1] = '\0';
466 }
467 entry->mode = perm;
468 entry->uid = uid;
469 entry->gid = gid;
470 entry->kdev = S_ISCHR(perm) || S_ISBLK(perm) ? MKDEV(major, minor) : 0;
471 entry->flags = flags;
472 list_add_tail(&entry->list, &info->list);
473 /* printk(KERN_DEBUG "Entry added.\n"); */
474 error = 0;
475 out:
476 return error;
477 out_freemem:
478 kfree(entry->printable_symlink_data);
479 kfree(entry->printable_name);
480 kfree(entry->symlink_data);
481 kfree(entry);
482 goto out;
483 }
484
485 static void ccs_put_super(struct super_block *sb)
486 {
487 struct ccs_sb_info *info;
488 struct dev_entry *entry;
489 struct dev_entry *tmp;
490 if (!sb)
491 return;
492 info = (struct ccs_sb_info *) sb->s_fs_info;
493 if (!info)
494 return;
495 sb->s_fs_info = NULL;
496 list_for_each_entry_safe(entry, tmp, &info->list, list) {
497 kfree(entry->name);
498 kfree(entry->symlink_data);
499 kfree(entry->printable_name);
500 kfree(entry->printable_symlink_data);
501 list_del(&entry->list);
502 /* printk(KERN_DEBUG "Entry removed.\n"); */
503 kfree(entry);
504 }
505 kfree(info);
506 printk(KERN_INFO "%s: Unused memory freed.\n", __func__);
507 }
508
509 static int ccs_read_config_file(struct file *file, struct super_block *sb)
510 {
511 char *buffer;
512 int len;
513 char *cp;
514 unsigned long offset = 0;
515 int error = -ENOMEM;
516 if (!file)
517 return -EINVAL;
518 buffer = kzalloc(PAGE_SIZE, GFP_KERNEL);
519 if (!buffer)
520 goto out;
521 while (1) {
522 len = kernel_read(file, offset, buffer, PAGE_SIZE);
523 if (len <= 0)
524 break;
525 cp = memchr(buffer, '\n', len);
526 if (!cp)
527 break;
528 *cp = '\0';
529 offset += cp - buffer + 1;
530 ccs_normalize_line(buffer);
531 if (ccs_register_node_info(buffer, sb) == -ENOMEM)
532 goto out;
533 }
534 error = 0;
535 out:
536 kfree(buffer);
537 return error;
538 }
539
540 static void ccs_make_node(struct dev_entry *entry, struct dentry *root)
541 {
542 struct dentry *base = dget(root);
543 char *filename = entry->name;
544 char *name = filename;
545 unsigned int c;
546 const mode_t perm = entry->mode;
547 const uid_t uid = entry->uid;
548 const gid_t gid = entry->gid;
549 goto start;
550 while (1) {
551 c = *(unsigned char *) filename;
552 if (!c)
553 break;
554 if (c == '/') {
555 struct dentry *new_base;
556 const int len = filename - name;
557 *filename = '\0';
558 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
559 mutex_lock(&base->d_inode->i_mutex);
560 new_base = lookup_one_len(name, base, len);
561 mutex_unlock(&base->d_inode->i_mutex);
562 #else
563 down(&base->d_inode->i_sem);
564 new_base = lookup_one_len(name, base, len);
565 up(&base->d_inode->i_sem);
566 #endif
567 dput(base);
568 *filename++ = '/';
569 if (IS_ERR(new_base)) {
570 /*
571 printk(KERN_DEBUG "'%s' = %ld\n", entry->name,
572 PTR_ERR(new_base));
573 */
574 return;
575 } else if (!new_base->d_inode ||
576 !S_ISDIR(new_base->d_inode->i_mode)) {
577 /*
578 printk(KERN_DEBUG
579 "Directory '%s' does not exist.\n",
580 entry->name);
581 */
582 dput(new_base);
583 return;
584 }
585 /*
586 printk(KERN_DEBUG "Directory '%s' exists.\n",
587 entry->name);
588 */
589 base = new_base;
590 start:
591 name = filename;
592 } else {
593 filename++;
594 }
595 }
596 filename = (char *) name;
597 if (S_ISLNK(perm))
598 ccs_fs_symlink(filename, base, entry->symlink_data, perm, uid,
599 gid);
600 else if (S_ISDIR(perm))
601 ccs_fs_mkdir(filename, base, perm ^ S_IFDIR, uid, gid);
602 else if (S_ISSOCK(perm) || S_ISFIFO(perm) || S_ISREG(perm))
603 ccs_fs_mknod(filename, base, perm, 0, uid, gid);
604 else if (S_ISCHR(perm) || S_ISBLK(perm))
605 ccs_fs_mknod(filename, base, perm, entry->kdev, uid, gid);
606 dput(base);
607 }
608
609 /* Create files according to the policy file. */
610 static void ccs_make_initial_nodes(struct super_block *sb)
611 {
612 struct ccs_sb_info *info;
613 struct dev_entry *entry;
614 if (!sb)
615 return;
616 info = (struct ccs_sb_info *) sb->s_fs_info;
617 if (!info)
618 return;
619 if (info->is_permissive_mode) {
620 ccs_create_tracelog(sb, ".syaoran");
621 ccs_create_tracelog(sb, ".syaoran_all");
622 }
623 list_for_each_entry(entry, &info->list, list) {
624 if ((entry->flags & NO_CREATE_AT_MOUNT) == 0)
625 ccs_make_node(entry, sb->s_root);
626 }
627 info->initialize_done = true;
628 }
629
630 /* Read policy file. */
631 static int ccs_initialize(struct super_block *sb, void *data)
632 {
633 int error = -EINVAL;
634 struct file *f;
635 char *filename = (char *) data;
636 bool is_permissive_mode = ccs_default_mode;
637 static bool first = true;
638 if (first) {
639 first = false;
640 printk(KERN_INFO "SYAORAN: 1.6.8 2009/05/28\n");
641 }
642 {
643 struct inode *inode = new_inode(sb);
644 if (!inode)
645 return -EINVAL;
646 /* Create /dev/ram0 to get the value of blkdev_open(). */
647 init_special_inode(inode, S_IFBLK | 0666, MKDEV(1, 0));
648 ccs_wrapped_def_blk_fops = *inode->i_fop;
649 iput(inode);
650 ccs_org_blkdev_open = ccs_wrapped_def_blk_fops.open;
651 ccs_wrapped_def_blk_fops.open = ccs_wrapped_blkdev_open;
652 }
653 {
654 struct inode *inode = new_inode(sb);
655 if (!inode)
656 return -EINVAL;
657 /* Create /dev/null to get the value of chrdev_open(). */
658 init_special_inode(inode, S_IFCHR | 0666, MKDEV(1, 3));
659 ccs_wrapped_def_chr_fops = *inode->i_fop;
660 iput(inode);
661 ccs_org_chrdev_open = ccs_wrapped_def_chr_fops.open;
662 ccs_wrapped_def_chr_fops.open = ccs_wrapped_chrdev_open;
663 }
664 if (!filename) {
665 printk(KERN_WARNING "SYAORAN: Missing config-file path.\n");
666 return -EINVAL;
667 }
668 /* If mode is given with mount operation, use it. */
669 if (!strncmp(filename, "accept=", 7)) {
670 filename += 7;
671 is_permissive_mode = true;
672 } else if (!strncmp(filename, "enforce=", 8)) {
673 filename += 8;
674 is_permissive_mode = false;
675 } else if (ccs_default_mode == -1) {
676 /*
677 * If mode is not given with command line,
678 * abort mount.
679 */
680 printk(KERN_WARNING
681 "SYAORAN: Missing 'accept=' or 'enforce='.\n");
682 return -EINVAL;
683 }
684 f = filp_open(filename, O_RDONLY, 0600);
685 if (IS_ERR(f)) {
686 printk(KERN_WARNING "SYAORAN: Can't open '%s'\n", filename);
687 return -EINVAL;
688 }
689 if (!S_ISREG(f->f_dentry->d_inode->i_mode))
690 goto out;
691 sb->s_fs_info = kzalloc(sizeof(struct ccs_sb_info), GFP_KERNEL);
692 if (!sb->s_fs_info)
693 goto out;
694 ((struct ccs_sb_info *) sb->s_fs_info)->is_permissive_mode
695 = is_permissive_mode;
696 INIT_LIST_HEAD(&((struct ccs_sb_info *) sb->s_fs_info)->list);
697 printk(KERN_INFO "SYAORAN: Reading '%s'\n", filename);
698 error = ccs_read_config_file(f, sb);
699 out:
700 if (error)
701 printk(KERN_WARNING "SYAORAN: Can't read '%s'\n", filename);
702 filp_close(f, NULL);
703 return error;
704 }
705
706 /* Get absolute pathname from mount point. */
707 static int get_local_absolute_path(struct dentry *dentry, char *buffer,
708 int buflen)
709 {
710 /***** CRITICAL SECTION START *****/
711 char *start = buffer;
712 char *end = buffer + buflen;
713 int namelen;
714
715 if (buflen < 256)
716 goto out;
717
718 *--end = '\0';
719 buflen--;
720 for (;;) {
721 struct dentry *parent;
722 if (IS_ROOT(dentry))
723 break;
724 parent = dentry->d_parent;
725 namelen = dentry->d_name.len;
726 buflen -= namelen + 1;
727 if (buflen < 0)
728 goto out;
729 end -= namelen;
730 memcpy(end, dentry->d_name.name, namelen);
731 *--end = '/';
732 dentry = parent;
733 }
734 if (*end == '/') {
735 buflen++;
736 end++;
737 }
738 namelen = dentry->d_name.len;
739 buflen -= namelen;
740 if (buflen < 0)
741 goto out;
742 end -= namelen;
743 memcpy(end, dentry->d_name.name, namelen);
744 memmove(start, end, strlen(end) + 1);
745 return 0;
746 out:
747 return -ENOMEM;
748 /***** CRITICAL SECTION END *****/
749 }
750
751 /* Get absolute pathname of the given dentry from mount point. */
752 static int ccs_local_realpath_from_dentry(struct dentry *dentry, char *newname,
753 int newname_len)
754 {
755 /***** CRITICAL SECTION START *****/
756 int error;
757 struct dentry *d_dentry;
758 if (!dentry || !newname || newname_len <= 0)
759 return -EINVAL;
760 d_dentry = dget(dentry);
761 spin_lock(&dcache_lock);
762 error = get_local_absolute_path(d_dentry, newname, newname_len);
763 spin_unlock(&dcache_lock);
764 dput(d_dentry);
765 return error;
766 /***** CRITICAL SECTION END *****/
767 }
768
769 static int ccs_check_flags(struct ccs_sb_info *info,
770 struct dentry *dentry,
771 int mode, int dev, unsigned int flags)
772 {
773 int error;
774 /*
775 * I use static buffer, for ccs_local_realpath_from_dentry() needs
776 * dcache_lock.
777 */
778 static char filename[PAGE_SIZE];
779 static DEFINE_SPINLOCK(lock);
780 /***** CRITICAL SECTION START *****/
781 spin_lock(&lock);
782 memset(filename, 0, sizeof(filename));
783 error = ccs_local_realpath_from_dentry(dentry, filename,
784 sizeof(filename) - 1);
785 if (!error) {
786 struct dev_entry *entry;
787 error = -EPERM;
788 list_for_each_entry(entry, &info->list, list) {
789 if ((mode & S_IFMT) != (entry->mode & S_IFMT))
790 continue;
791 if ((S_ISBLK(mode) || S_ISCHR(mode)) &&
792 dev != entry->kdev)
793 continue;
794 if (strcmp(entry->name, filename + 1))
795 continue;
796 if (info->is_permissive_mode) {
797 entry->flags |= flags;
798 error = 0;
799 } else if ((entry->flags & flags) == flags)
800 error = 0;
801 break;
802 }
803 }
804 if (error == -EPERM) {
805 const char *name;
806 const uid_t uid = current_fsuid();
807 const gid_t gid = current_fsgid();
808 const mode_t perm = mode & 0777;
809 flags &= ~DEVICE_USED;
810 {
811 char *end = filename + sizeof(filename) - 1;
812 const char *cp = filename + strlen(filename) - 1;
813 while (cp > filename && end > cp &&
814 end > filename + 16) {
815 const unsigned char c = *cp--;
816 if (c == '\\') {
817 *--end = '\\';
818 *--end = '\\';
819 } else if (c > ' ' && c < 127) {
820 *--end = c;
821 } else {
822 *--end = (c & 7) + '0';
823 *--end = ((c >> 3) & 7) + '0';
824 *--end = (c >> 6) + '0';
825 *--end = '\\';
826 }
827 }
828 name = end;
829 }
830 switch (mode & S_IFMT) {
831 case S_IFCHR:
832 printk(KERN_DEBUG
833 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c %3u %3u\n",
834 name, perm, uid, gid, flags, 'c',
835 MAJOR(dev), MINOR(dev));
836 break;
837 case S_IFBLK:
838 printk(KERN_DEBUG
839 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c %3u %3u\n",
840 name, perm, uid, gid, flags, 'b',
841 MAJOR(dev), MINOR(dev));
842 break;
843 case S_IFIFO:
844 printk(KERN_DEBUG
845 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name,
846 perm, uid, gid, flags, 'p');
847 break;
848 case S_IFSOCK:
849 printk(KERN_DEBUG
850 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name,
851 perm, uid, gid, flags, 's');
852 break;
853 case S_IFDIR:
854 printk(KERN_DEBUG
855 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name,
856 perm, uid, gid, flags, 'd');
857 break;
858 case S_IFLNK:
859 printk(KERN_DEBUG
860 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c %s\n",
861 name, perm, uid, gid, flags, 'l', "unknown");
862 break;
863 case S_IFREG:
864 printk(KERN_DEBUG
865 "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name,
866 perm, uid, gid, flags, 'f');
867 break;
868 }
869 }
870 spin_unlock(&lock);
871 /***** CRITICAL SECTION END *****/
872 return error;
873 }
874
875 /* Check whether the given dentry is allowed to mknod. */
876 static int ccs_may_create_node(struct dentry *dentry, int mode, int dev)
877 {
878 struct ccs_sb_info *info
879 = (struct ccs_sb_info *) dentry->d_sb->s_fs_info;
880 if (!info) {
881 printk(KERN_WARNING "%s: dentry->d_sb->s_fs_info == NULL\n",
882 __func__);
883 return -EPERM;
884 }
885 if (!info->initialize_done)
886 return 0;
887 return ccs_check_flags(info, dentry, mode, dev, MAY_CREATE);
888 }
889
890 /* Check whether the given dentry is allowed to chmod/chown/unlink. */
891 static int ccs_may_modify_node(struct dentry *dentry, unsigned int flags)
892 {
893 struct ccs_sb_info *info
894 = (struct ccs_sb_info *) dentry->d_sb->s_fs_info;
895 if (!info) {
896 printk(KERN_WARNING "%s: dentry->d_sb->s_fs_info == NULL\n",
897 __func__);
898 return -EPERM;
899 }
900 if (flags == DEVICE_USED && !info->is_permissive_mode)
901 return 0;
902 if (!dentry->d_inode)
903 return -ENOENT;
904 return ccs_check_flags(info, dentry, dentry->d_inode->i_mode,
905 dentry->d_inode->i_rdev, flags);
906 }
907
908 /*
909 * The following structure and codes are used for transferring data
910 * to interfaces files.
911 */
912
913 struct ccs_read_struct {
914 char *buf; /* Buffer for reading. */
915 int avail; /* Bytes available for reading. */
916 struct super_block *sb; /* The super_block of this partition. */
917 struct dev_entry *entry; /* The entry currently reading from. */
918 bool read_all; /* Print all entries? */
919 struct list_head *pos; /* Current position. */
920 };
921
922 static void ccs_read_table(struct ccs_read_struct *head, char *buf,
923 int count)
924 {
925 struct super_block *sb = head->sb;
926 struct ccs_sb_info *info = (struct ccs_sb_info *) sb->s_fs_info;
927 struct list_head *pos;
928 const bool read_all = head->read_all;
929 if (!info)
930 return;
931 if (!head->pos)
932 return;
933 list_for_each_cookie(pos, head->pos, &info->list) {
934 struct dev_entry *entry
935 = list_entry(pos, struct dev_entry, list);
936 const unsigned int flags
937 = read_all ? entry->flags : entry->flags & ~DEVICE_USED;
938 const char *name = entry->printable_name;
939 const uid_t uid = entry->uid;
940 const gid_t gid = entry->gid;
941 const mode_t perm = entry->mode & 0777;
942 int len = 0;
943 switch (entry->mode & S_IFMT) {
944 case S_IFCHR:
945 if (!head->read_all && !(entry->flags & DEVICE_USED))
946 break;
947 len = snprintf(buf, count,
948 "%-20s %3o %3u %3u %2u %c %3u %3u\n",
949 name, perm, uid, gid, flags, 'c',
950 MAJOR(entry->kdev), MINOR(entry->kdev));
951 break;
952 case S_IFBLK:
953 if (!head->read_all && !(entry->flags & DEVICE_USED))
954 break;
955 len = snprintf(buf, count,
956 "%-20s %3o %3u %3u %2u %c %3u %3u\n",
957 name, perm, uid, gid, flags, 'b',
958 MAJOR(entry->kdev), MINOR(entry->kdev));
959 break;
960 case S_IFIFO:
961 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n",
962 name, perm, uid, gid, flags, 'p');
963 break;
964 case S_IFSOCK:
965 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n",
966 name, perm, uid, gid, flags, 's');
967 break;
968 case S_IFDIR:
969 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n",
970 name, perm, uid, gid, flags, 'd');
971 break;
972 case S_IFLNK:
973 len = snprintf(buf, count,
974 "%-20s %3o %3u %3u %2u %c %s\n", name,
975 perm, uid, gid, flags, 'l',
976 entry->printable_symlink_data);
977 break;
978 case S_IFREG:
979 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n",
980 name, perm, uid, gid, flags, 'f');
981 break;
982 }
983 if (len < 0 || count <= len)
984 break;
985 count -= len;
986 buf += len;
987 head->avail += len;
988 }
989 }
990
991 static int ccs_trace_open(struct inode *inode, struct file *file)
992 {
993 struct ccs_read_struct *head = kzalloc(sizeof(*head), GFP_KERNEL);
994 if (!head)
995 return -ENOMEM;
996 head->sb = inode->i_sb;
997 head->read_all
998 = (strcmp(file->f_dentry->d_name.name, ".syaoran_all") == 0);
999 head->pos = &((struct ccs_sb_info *) head->sb->s_fs_info)->list;
1000 /* Don't allow open() after unmount() */
1001 if (head->sb->s_fs_info)
1002 head->buf = kzalloc(PAGE_SIZE * 2, GFP_KERNEL);
1003 if (!head->buf) {
1004 kfree(head);
1005 return -ENOMEM;
1006 }
1007 file->private_data = head;
1008 return 0;
1009 }
1010
1011 static int ccs_trace_release(struct inode *inode, struct file *file)
1012 {
1013 struct ccs_read_struct *head = file->private_data;
1014 kfree(head->buf);
1015 kfree(head);
1016 file->private_data = NULL;
1017 return 0;
1018 }
1019
1020 static ssize_t ccs_trace_read(struct file *file, char __user *buf,
1021 size_t count, loff_t *ppos)
1022 {
1023 struct ccs_read_struct *head
1024 = (struct ccs_read_struct *) file->private_data;
1025 int len = head->avail;
1026 char *cp = head->buf;
1027 if (!access_ok(VERIFY_WRITE, buf, count))
1028 return -EFAULT;
1029 ccs_read_table(head, cp + len, PAGE_SIZE * 2 - len);
1030 len = head->avail;
1031 if (len > count)
1032 len = count;
1033 if (len > 0) {
1034 if (copy_to_user(buf, cp, len))
1035 return -EFAULT;
1036 head->avail -= len;
1037 memmove(cp, cp + len, head->avail);
1038 }
1039 return len;
1040 }
1041
1042 static struct file_operations ccs_trace_operations = {
1043 .open = ccs_trace_open,
1044 .release = ccs_trace_release,
1045 .read = ccs_trace_read,
1046 };
1047
1048 /* Create interface files for reading status. */
1049 static int ccs_create_tracelog(struct super_block *sb, const char *filename)
1050 {
1051 struct dentry *base = dget(sb->s_root);
1052 struct dentry *dentry = ccs_lookup_create2(filename, base, 0);
1053 int error = PTR_ERR(dentry);
1054 if (!IS_ERR(dentry)) {
1055 struct inode *inode = new_inode(sb);
1056 if (inode) {
1057 inode->i_mode = S_IFREG | 0400;
1058 inode->i_uid = 0;
1059 inode->i_gid = 0;
1060 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
1061 #ifndef HAVE_NO_I_BLKSIZE_IN_INODE
1062 inode->i_blksize = PAGE_CACHE_SIZE;
1063 #endif
1064 #endif
1065 inode->i_blocks = 0;
1066 inode->i_mapping->a_ops = &ccs_aops;
1067 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1068 inode->i_mapping->backing_dev_info
1069 = &ccs_backing_dev_info;
1070 inode->i_op = &ccs_file_inode_operations;
1071 #else
1072 inode->i_rdev = NODEV;
1073 #endif
1074 inode->i_ctime = CURRENT_TIME;
1075 inode->i_mtime = inode->i_ctime;
1076 inode->i_atime = inode->i_mtime;
1077 inode->i_fop = &ccs_trace_operations;
1078 d_instantiate(dentry, inode);
1079 dget(dentry); /* Extra count - pin the dentry in core */
1080 error = 0;
1081 }
1082 dput(dentry);
1083 }
1084 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
1085 mutex_unlock(&base->d_inode->i_mutex);
1086 #else
1087 up(&base->d_inode->i_sem);
1088 #endif
1089 dput(base);
1090 return error;
1091 }
1092
1093 #endif

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