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

Subversion リポジトリの参照

Contents of /trunk/1.6.x/ccs-patch/include/linux/syaoran.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1903 - (show annotations) (download) (as text)
Mon Dec 1 06:16:16 2008 UTC (15 years, 5 months ago) by kumaneko
File MIME type: text/x-chdr
File size: 30645 byte(s)


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

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