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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 746 - (show annotations) (download) (as text)
Mon Dec 3 05:01:19 2007 UTC (16 years, 5 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch.tmp/include/linux/syaoran.h
File MIME type: text/x-chdr
File size: 27513 byte(s)


1 /*
2 * include/linux/syaoran.h
3 *
4 * Implementation of the Tamper-Proof Device Filesystem.
5 *
6 * Copyright (C) 2005-2007 NTT DATA CORPORATION
7 *
8 * Version: 1.5.3-pre 2007/12/03
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 Nexus".
18 * SYAORAN is a filesystem for /dev with Mandatory Access Control.
19 *
20 * /dev needs to be writable, but this means that files on /dev might be tampered with.
21 * SYAORAN can restrict combinations of (pathname, attribute) that the system can create.
22 * The attribute is one of directory, regular file, FIFO, UNIX domain socket,
23 * symbolic link, character or block device file with major/minor device numbers.
24 *
25 * You can use SYAORAN alone, but I recommend you to use with SAKURA and TOMOYO.
26 */
27
28 #ifndef _LINUX_SYAORAN_H
29 #define _LINUX_SYAORAN_H
30
31 #ifndef __user
32 #define __user
33 #endif
34
35 /***** SYAORAN start. *****/
36
37 #include <linux/version.h>
38
39 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
40 #define s_fs_info u.generic_sbp
41 #endif
42
43 #define list_for_each_cookie(pos, cookie, head) \
44 for ((cookie) || ((cookie) = (head)), pos = (cookie)->next; \
45 prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
46 (cookie) = pos, pos = pos->next)
47
48 #ifndef list_for_each_entry_safe
49 #define list_for_each_entry_safe(pos, n, head, member) \
50 for (pos = list_entry((head)->next, typeof(*pos), member), \
51 n = list_entry(pos->member.next, typeof(*pos), member); \
52 &pos->member != (head); \
53 pos = n, n = list_entry(n->member.next, typeof(*n), member))
54 #endif
55
56 /* The following constants are used to restrict operations.*/
57
58 #define MAY_CREATE 1 /* This file is allowed to mknod() */
59 #define MAY_DELETE 2 /* This file is allowed to unlink() */
60 #define MAY_CHMOD 4 /* This file is allowed to chmod() */
61 #define MAY_CHOWN 8 /* This file is allowed to chown() */
62 #define DEVICE_USED 16 /* This block or character device file is used. */
63 #define NO_CREATE_AT_MOUNT 32 /* Don't create this file at mount(). */
64
65 /* some random number */
66 #define SYAORAN_MAGIC 0x2F646576 /* = '/dev' */
67
68 static void syaoran_put_super(struct super_block *sb);
69 static int Syaoran_Initialize(struct super_block *sb, void *data);
70 static void MakeInitialNodes(struct super_block *sb);
71 static int MayCreateNode(struct dentry *dentry, int mode, int dev);
72 static int MayModifyNode(struct dentry *dentry, unsigned int flags);
73 static int syaoran_create_tracelog(struct super_block *sb, const char *filename);
74
75 /* Wraps blkdev_open() to trace open operation for block devices. */
76 static int (*org_blkdev_open) (struct inode * inode, struct file * filp) = NULL;
77 static struct file_operations wrapped_def_blk_fops;
78
79 static int wrapped_blkdev_open(struct inode * inode, struct file * filp)
80 {
81 int error = org_blkdev_open(inode, filp);
82 if (error != -ENXIO) MayModifyNode(filp->f_dentry, DEVICE_USED);
83 return error;
84 }
85
86 /* Wraps chrdev_open() to trace open operation for character devices. */
87 static int (*org_chrdev_open) (struct inode * inode, struct file * filp) = NULL;
88 static struct file_operations wrapped_def_chr_fops;
89
90 static int wrapped_chrdev_open(struct inode * inode, struct file * filp)
91 {
92 int error = org_chrdev_open(inode, filp);
93 if (error != -ENXIO) MayModifyNode(filp->f_dentry, DEVICE_USED);
94 return error;
95 }
96
97 /* lookup_create() without nameidata. Called only while initialization. */
98 static struct dentry *lookup_create2(const char *name, struct dentry *base, const u8 is_dir)
99 {
100 struct dentry *dentry;
101 const int len = name ? strlen(name) : 0;
102 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
103 mutex_lock(&base->d_inode->i_mutex);
104 #else
105 down(&base->d_inode->i_sem);
106 #endif
107 dentry = lookup_one_len(name, base, len);
108 if (IS_ERR(dentry)) goto fail;
109 if (!is_dir && name[len] && !dentry->d_inode) goto enoent;
110 return dentry;
111 enoent:
112 dput(dentry);
113 dentry = ERR_PTR(-ENOENT);
114 fail:
115 return dentry;
116 }
117
118 /* mkdir(). Called only while initialization. */
119 static int fs_mkdir(const char *pathname, struct dentry *base, int mode, uid_t user, gid_t group)
120 {
121 struct dentry *dentry = lookup_create2(pathname, base, 1);
122 int error = PTR_ERR(dentry);
123 if (!IS_ERR(dentry)) {
124 error = vfs_mkdir(base->d_inode, dentry, mode);
125 if (!error) {
126 lock_kernel();
127 dentry->d_inode->i_uid = user;
128 dentry->d_inode->i_gid = group;
129 unlock_kernel();
130 }
131 dput(dentry);
132 }
133 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
134 mutex_unlock(&base->d_inode->i_mutex);
135 #else
136 up(&base->d_inode->i_sem);
137 #endif
138 return error;
139 }
140
141 /* mknod(). Called only while initialization. */
142 static int fs_mknod(const char *filename, struct dentry *base, int mode, dev_t dev, uid_t user, gid_t group)
143 {
144 struct dentry *dentry;
145 int error;
146 switch (mode & S_IFMT) {
147 case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: case S_IFREG:
148 break;
149 default:
150 return -EPERM;
151 }
152 dentry = lookup_create2(filename, base, 0);
153 error = PTR_ERR(dentry);
154 if (!IS_ERR(dentry)) {
155 error = vfs_mknod(base->d_inode, dentry, mode, dev);
156 if (!error) {
157 lock_kernel();
158 dentry->d_inode->i_uid = user;
159 dentry->d_inode->i_gid = group;
160 unlock_kernel();
161 }
162 dput(dentry);
163 }
164 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
165 mutex_unlock(&base->d_inode->i_mutex);
166 #else
167 up(&base->d_inode->i_sem);
168 #endif
169 return error;
170 }
171
172 /* symlink(). Called only while initialization. */
173 static int fs_symlink(const char *pathname, struct dentry *base, char *oldname, int mode, uid_t user, gid_t group)
174 {
175 struct dentry *dentry = lookup_create2(pathname, base, 0);
176 int error = PTR_ERR(dentry);
177 if (!IS_ERR(dentry)) {
178 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
179 error = vfs_symlink(base->d_inode, dentry, oldname, S_IALLUGO);
180 #else
181 error = vfs_symlink(base->d_inode, dentry, oldname);
182 #endif
183 if (!error) {
184 lock_kernel();
185 dentry->d_inode->i_mode = mode;
186 dentry->d_inode->i_uid = user;
187 dentry->d_inode->i_gid = group;
188 unlock_kernel();
189 }
190 dput(dentry);
191 }
192 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
193 mutex_unlock(&base->d_inode->i_mutex);
194 #else
195 up(&base->d_inode->i_sem);
196 #endif
197 return error;
198 }
199
200 /*
201 * Format string.
202 * Leading and trailing whitespaces are removed.
203 * Multiple whitespaces are packed into single space.
204 */
205 static void NormalizeLine(unsigned char *buffer)
206 {
207 unsigned char *sp = buffer, *dp = buffer;
208 int first = 1;
209 while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;
210 while (*sp) {
211 if (!first) *dp++ = ' ';
212 first = 0;
213 while (*sp > ' ' && *sp < 127) *dp++ = *sp++;
214 while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;
215 }
216 *dp = '\0';
217 }
218
219 /* Convert text form of filename into binary form. */
220 static void UnEscape(char *filename)
221 {
222 char *cp = filename;
223 char c, d, e;
224 if (!cp) return;
225 while ((c = *filename++) != '\0') {
226 if (c != '\\') {
227 *cp++ = c;
228 continue;
229 }
230 if ((c = *filename++) == '\\') {
231 *cp++ = c;
232 continue;
233 }
234 if (c < '0' || c > '3' ||
235 (d = *filename++) < '0' || d > '7' ||
236 (e = *filename++) < '0' || e > '7') {
237 break;
238 }
239 * (unsigned char *) cp++ = (unsigned char) (((unsigned char) (c - '0') << 6) + ((unsigned char) (d - '0') << 3) + (unsigned char) (e - '0'));
240 }
241 *cp = '\0';
242 }
243
244 static char *strdup(const char *str)
245 {
246 char *cp;
247 const int len = str ? strlen(str) + 1 : 0;
248 if ((cp = kmalloc(len, GFP_KERNEL)) != NULL) memmove(cp, str, len);
249 return cp;
250 }
251
252 static int syaoran_default_mode = -1; /* -1: Not specified, 0: Enforce by default, 1: Accept by default. */
253
254 #if !defined(MODULE)
255 static int __init SYAORAN_Setup(char *str)
256 {
257 if (strcmp(str, "accept") == 0) syaoran_default_mode = 1;
258 else if (strcmp(str, "enforce") == 0) syaoran_default_mode = 0;
259 return 0;
260 }
261
262 __setup("SYAORAN=", SYAORAN_Setup);
263 #endif
264
265 struct dev_entry {
266 struct list_head list;
267 char *name; /* Binary form of pathname under mount point. Never NULL. */
268 mode_t mode; /* Mode and permissions. setuid/setgid/sticky bits are not supported. */
269 uid_t uid;
270 gid_t gid;
271 dev_t kdev;
272 char *symlink_data; /* Binary form of initial contents for the symlink. NULL if not symlink. */
273 unsigned int flags; /* File access control flags. */
274 const char *printable_name; /* Text form of pathname under mount point. Never NULL. */
275 const char *printable_symlink_data; /* Text form of initial contents for the symlink. NULL if not symlink. */
276 };
277
278 struct syaoran_sb_info {
279 struct list_head list;
280 int initialize_done; /* Zero if initialization is in progress. */
281 int is_permissive_mode; /* Nonzero if permissive mode. */
282 };
283
284 static int RegisterNodeInfo(char *buffer, struct super_block *sb)
285 {
286 enum {
287 ARG_FILENAME = 0,
288 ARG_PERMISSION = 1,
289 ARG_UID = 2,
290 ARG_GID = 3,
291 ARG_FLAGS = 4,
292 ARG_DEV_TYPE = 5,
293 ARG_SYMLINK_DATA = 6,
294 ARG_DEV_MAJOR = 6,
295 ARG_DEV_MINOR = 7,
296 MAX_ARG = 8
297 };
298 char *args[MAX_ARG];
299 int i;
300 int error = -EINVAL;
301 unsigned int perm, uid, gid, flags, major = 0, minor = 0;
302 struct syaoran_sb_info *info = (struct syaoran_sb_info *) sb->s_fs_info;
303 struct dev_entry *entry;
304 memset(args, 0, sizeof(args));
305 args[0] = buffer;
306 for (i = 1; i < MAX_ARG; i++) {
307 args[i] = strchr(args[i - 1] + 1, ' ');
308 if (!args[i]) break;
309 *args[i]++ = '\0';
310 }
311 /* printk("<%s> <%s> <%s> <%s> <%s> <%s> <%s> <%s>\n", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); */
312 if (!args[ARG_FILENAME] || !args[ARG_PERMISSION] || !args[ARG_UID] || !args[ARG_GID] || !args[ARG_DEV_TYPE] || !args[ARG_FLAGS]) goto out;
313 if (sscanf(args[ARG_PERMISSION], "%o", &perm) != 1 || !(perm <= 0777) || sscanf(args[ARG_UID], "%u", &uid) != 1
314 || sscanf(args[ARG_GID], "%u", &gid) != 1 || sscanf(args[ARG_FLAGS], "%u", &flags) != 1 || *(args[ARG_DEV_TYPE] + 1)) goto out;
315 switch (*args[ARG_DEV_TYPE]) {
316 case 'c':
317 perm |= S_IFCHR;
318 if (!args[ARG_DEV_MAJOR] || sscanf(args[ARG_DEV_MAJOR], "%u", &major) != 1
319 || !args[ARG_DEV_MINOR] || sscanf(args[ARG_DEV_MINOR], "%u", &minor) != 1) goto out;
320 break;
321 case 'b':
322 perm |= S_IFBLK;
323 if (!args[ARG_DEV_MAJOR] || sscanf(args[ARG_DEV_MAJOR], "%u", &major) != 1
324 || !args[ARG_DEV_MINOR] || sscanf(args[ARG_DEV_MINOR], "%u", &minor) != 1) goto out;
325 break;
326 case 'l':
327 perm |= S_IFLNK;
328 if (!args[ARG_SYMLINK_DATA]) goto out;
329 break;
330 case 'd':
331 perm |= S_IFDIR;
332 break;
333 case 's':
334 perm |= S_IFSOCK;
335 break;
336 case 'p':
337 perm |= S_IFIFO;
338 break;
339 case 'f':
340 perm |= S_IFREG;
341 break;
342 default:
343 goto out;
344 }
345 error = -ENOMEM;
346 if ((entry = kmalloc(sizeof(*entry), GFP_KERNEL)) == NULL) goto out;
347 memset(entry, 0, sizeof(*entry));
348 if (S_ISLNK(perm)) {
349 if ((entry->printable_symlink_data = strdup(args[ARG_SYMLINK_DATA])) == NULL) goto out_freemem;
350 }
351 if ((entry->printable_name = strdup(args[ARG_FILENAME])) == NULL) goto out_freemem;
352 if (S_ISLNK(perm)) {
353 if ((entry->symlink_data = strdup(entry->printable_symlink_data)) == NULL) goto out_freemem;
354 UnEscape(entry->symlink_data);
355 }
356 if ((entry->name = strdup(entry->printable_name)) == NULL) goto out_freemem;
357 UnEscape(entry->name);
358 { /* Drop trailing '/', for GetLocalAbsolutePath() doesn't append trailing '/'. */
359 const int len = strlen(entry->name);
360 if (len && entry->name[len - 1] == '/') entry->name[len - 1] = '\0';
361 }
362 entry->mode = perm;
363 entry->uid = uid;
364 entry->gid = gid;
365 entry->kdev = S_ISCHR(perm) || S_ISBLK(perm) ? MKDEV(major, minor) : 0;
366 entry->flags = flags;
367 list_add_tail(&entry->list, &info->list);
368 /* printk("Entry added.\n"); */
369 error = 0;
370 out:
371 return error;
372 out_freemem:
373 kfree(entry->printable_symlink_data);
374 kfree(entry->printable_name);
375 kfree(entry->symlink_data);
376 kfree(entry);
377 goto out;
378 }
379
380 static void syaoran_put_super(struct super_block *sb)
381 {
382 struct syaoran_sb_info *info;
383 struct dev_entry *entry, *tmp;
384 if (!sb) return;
385 info = (struct syaoran_sb_info *) sb->s_fs_info;
386 if (!info) return;
387 list_for_each_entry_safe(entry, tmp, &info->list, list) {
388 kfree(entry->name);
389 kfree(entry->symlink_data);
390 kfree(entry->printable_name);
391 kfree(entry->printable_symlink_data);
392 list_del(&entry->list);
393 /* printk("Entry removed.\n"); */
394 kfree(entry);
395 }
396 kfree(info);
397 sb->s_fs_info = NULL;
398 printk("%s: Unused memory freed.\n", __FUNCTION__);
399 }
400
401 static int ReadConfigFile(struct file *file, struct super_block *sb)
402 {
403 char *buffer;
404 int error = -ENOMEM;
405 if (!file) return -EINVAL;
406 if ((buffer = kmalloc(PAGE_SIZE, GFP_KERNEL)) != NULL) {
407 int len;
408 char *cp;
409 unsigned long offset = 0;
410 memset(buffer, 0, PAGE_SIZE);
411 while ((len = kernel_read(file, offset, buffer, PAGE_SIZE)) > 0 && (cp = memchr(buffer, '\n', len)) != NULL) {
412 *cp = '\0';
413 offset += cp - buffer + 1;
414 NormalizeLine(buffer);
415 if (RegisterNodeInfo(buffer, sb) == -ENOMEM) goto out;
416 }
417 error = 0;
418 }
419 out:
420 kfree(buffer);
421 return error;
422 }
423
424 static void MakeNode(struct dev_entry *entry, struct dentry *root)
425 {
426 struct dentry *base = dget(root);
427 char *filename = entry->name;
428 char *name = filename;
429 unsigned int c;
430 const mode_t perm = entry->mode;
431 const uid_t uid = entry->uid;
432 const gid_t gid = entry->gid;
433 goto start;
434 while ((c = * (unsigned char *) filename) != '\0') {
435 if (c == '/') {
436 struct dentry *new_base;
437 const int len = filename - name;
438 *filename = '\0';
439 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
440 mutex_lock(&base->d_inode->i_mutex);
441 new_base = lookup_one_len(name, base, len);
442 mutex_unlock(&base->d_inode->i_mutex);
443 #else
444 down(&base->d_inode->i_sem);
445 new_base = lookup_one_len(name, base, len);
446 up(&base->d_inode->i_sem);
447 #endif
448 dput(base);
449 /*
450 if (IS_ERR(new_base)) {
451 printk("'%s' = %ld\n", entry->name, PTR_ERR(new_base));
452 } else if (!new_base->d_inode || !S_ISDIR(new_base->d_inode->i_mode)) {
453 printk("Directory '%s' does not exist.\n", entry->name);
454 } else {
455 printk("Directory '%s' exists.\n", entry->name);
456 }
457 */
458 *filename = '/';
459 filename++;
460 if (IS_ERR(new_base)) {
461 return;
462 } else if (!new_base->d_inode || !S_ISDIR(new_base->d_inode->i_mode)) {
463 dput(new_base);
464 return;
465 }
466 base = new_base;
467 start:
468 name = filename;
469 } else {
470 filename++;
471 }
472 }
473 filename = (char *) name;
474 if (S_ISLNK(perm)) {
475 fs_symlink(filename, base, entry->symlink_data, perm, uid, gid);
476 } else if (S_ISDIR(perm)) {
477 fs_mkdir(filename, base, perm ^ S_IFDIR, uid, gid);
478 } else if (S_ISSOCK(perm) || S_ISFIFO(perm) || S_ISREG(perm)) {
479 fs_mknod(filename, base, perm, 0, uid, gid);
480 } else if (S_ISCHR(perm) || S_ISBLK(perm)) {
481 fs_mknod(filename, base, perm, entry->kdev, uid, gid);
482 }
483 dput(base);
484 }
485
486 /* Create files according to the policy file. */
487 static void MakeInitialNodes(struct super_block *sb)
488 {
489 struct syaoran_sb_info *info;
490 struct dev_entry *entry;
491 if (!sb) return;
492 info = (struct syaoran_sb_info *) sb->s_fs_info;
493 if (!info) return;
494 if (info->is_permissive_mode) {
495 syaoran_create_tracelog(sb, ".syaoran");
496 syaoran_create_tracelog(sb, ".syaoran_all");
497 }
498 list_for_each_entry(entry, &info->list, list) {
499 if ((entry->flags & NO_CREATE_AT_MOUNT) == 0) MakeNode(entry, sb->s_root);
500 }
501 info->initialize_done = 1;
502 }
503
504 /* Read policy file. */
505 static int Syaoran_Initialize(struct super_block *sb, void *data)
506 {
507 int error = -EINVAL;
508 static int first = 1;
509 if (first) {
510 first = 0;
511 printk("SYAORAN: 1.5.3-pre 2007/12/03\n");
512 }
513 {
514 struct inode *inode = new_inode(sb);
515 if (!inode) return -EINVAL;
516 /* Create /dev/ram0 to get the value of blkdev_open(). */
517 init_special_inode(inode, S_IFBLK | 0666, MKDEV(1, 0));
518 wrapped_def_blk_fops = *inode->i_fop;
519 iput(inode);
520 org_blkdev_open = wrapped_def_blk_fops.open;
521 wrapped_def_blk_fops.open = wrapped_blkdev_open;
522 }
523 {
524 struct inode *inode = new_inode(sb);
525 if (!inode) return -EINVAL;
526 /* Create /dev/null to get the value of chrdev_open(). */
527 init_special_inode(inode, S_IFCHR | 0666, MKDEV(1, 3));
528 wrapped_def_chr_fops = *inode->i_fop;
529 iput(inode);
530 org_chrdev_open = wrapped_def_chr_fops.open;
531 wrapped_def_chr_fops.open = wrapped_chrdev_open;
532 }
533 if (data) {
534 struct file *f;
535 char *filename = (char *) data;
536 int is_permissive_mode = syaoran_default_mode;
537 /* If mode is given with mount operation, use it. */
538 if (strncmp(filename, "accept=", 7) == 0) {
539 filename += 7;
540 is_permissive_mode = 1;
541 } else if (strncmp(filename, "enforce=", 8) == 0) {
542 filename += 8;
543 is_permissive_mode = 0;
544 } else if (is_permissive_mode == -1) {
545 /* If mode is not given with command line, abort mount. */
546 printk("SYAORAN: Missing 'accept=' or 'enforce='.\n");
547 return -EINVAL;
548 }
549 f = filp_open(filename, O_RDONLY, 0600);
550 if (!IS_ERR(f)) {
551 struct syaoran_sb_info *p;
552 if (!S_ISREG(f->f_dentry->d_inode->i_mode)) goto out;
553 if ((p = sb->s_fs_info = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) goto out;
554 memset(p, 0, sizeof(*p));
555 p->is_permissive_mode = is_permissive_mode;
556 INIT_LIST_HEAD(&((struct syaoran_sb_info *) sb->s_fs_info)->list);
557 printk("SYAORAN: Reading '%s'\n", filename);
558 error = ReadConfigFile(f, sb);
559 out:
560 if (error) printk("SYAORAN: Can't read '%s'\n", filename);
561 filp_close(f, NULL);
562 } else {
563 printk("SYAORAN: Can't open '%s'\n", filename);
564 }
565 } else {
566 printk("SYAORAN: Missing config-file path.\n");
567 }
568 return error;
569 }
570
571 /* Get absolute pathname from mount point. */
572 static int GetLocalAbsolutePath(struct dentry *dentry, char *buffer, int buflen)
573 {
574 char *start = buffer;
575 char *end = buffer + buflen;
576 int namelen;
577
578 if (buflen < 256) goto out;
579
580 *--end = '\0';
581 buflen--;
582 for (;;) {
583 struct dentry *parent;
584 if (IS_ROOT(dentry)) break;
585 parent = dentry->d_parent;
586 namelen = dentry->d_name.len;
587 buflen -= namelen + 1;
588 if (buflen < 0) goto out;
589 end -= namelen;
590 memcpy(end, dentry->d_name.name, namelen);
591 *--end = '/';
592 dentry = parent;
593 }
594 if (*end == '/') { buflen++; end++; }
595 namelen = dentry->d_name.len;
596 buflen -= namelen;
597 if (buflen < 0) goto out;
598 end -= namelen;
599 memcpy(end, dentry->d_name.name, namelen);
600 memmove(start, end, strlen(end) + 1);
601 return 0;
602 out:
603 return -ENOMEM;
604 }
605
606 /* Get absolute pathname of the given dentry from mount point. */
607 static int local_realpath_from_dentry(struct dentry *dentry, char *newname, int newname_len)
608 {
609 int error;
610 struct dentry *d_dentry;
611 if (!dentry || !newname || newname_len <= 0) return -EINVAL;
612 d_dentry = dget(dentry);
613 /***** CRITICAL SECTION START *****/
614 spin_lock(&dcache_lock);
615 error = GetLocalAbsolutePath(d_dentry, newname, newname_len);
616 spin_unlock(&dcache_lock);
617 /***** CRITICAL SECTION END *****/
618 dput(d_dentry);
619 return error;
620 }
621
622 static int CheckFlags(struct syaoran_sb_info *info, struct dentry *dentry, int mode, int dev, unsigned int flags)
623 {
624 int error = -EPERM;
625 /* I use static buffer, for local_realpath_from_dentry() needs dcache_lock. */
626 static char filename[PAGE_SIZE];
627 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
628 spin_lock(&lock);
629 memset(filename, 0, sizeof(filename));
630 if (local_realpath_from_dentry(dentry, filename, sizeof(filename) - 1) == 0) {
631 struct dev_entry *entry;
632 list_for_each_entry(entry, &info->list, list) {
633 if ((mode & S_IFMT) != (entry->mode & S_IFMT)) continue;
634 if ((S_ISBLK(mode) || S_ISCHR(mode)) && dev != entry->kdev) continue;
635 if (strcmp(entry->name, filename + 1)) continue;
636 if (info->is_permissive_mode) {
637 entry->flags |= flags;
638 error = 0;
639 } else {
640 if ((entry->flags & flags) == flags) error = 0;
641 }
642 break;
643 }
644 }
645 if (error && strlen(filename) < (sizeof(filename) / 4) - 16) {
646 const char *name;
647 const uid_t uid = current->fsuid;
648 const gid_t gid = current->fsgid;
649 const mode_t perm = mode & 0777;
650 flags &= ~DEVICE_USED;
651 {
652 char *end = filename + sizeof(filename) - 1;
653 const char *cp = strchr(filename, '\0') - 1;
654 while (cp > filename) {
655 const unsigned char c = *cp--;
656 if (c == '\\') {
657 *--end = '\\';
658 *--end = '\\';
659 } else if (c > ' ' && c < 127) {
660 *--end = c;
661 } else {
662 *--end = (c & 7) + '0';
663 *--end = ((c >> 3) & 7) + '0';
664 *--end = (c >> 6) + '0';
665 *--end = '\\';
666 }
667 }
668 name = end;
669 }
670 switch (mode & S_IFMT) {
671 case S_IFCHR:
672 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c %3u %3u\n", name, perm, uid, gid, flags, 'c', MAJOR(dev), MINOR(dev));
673 break;
674 case S_IFBLK:
675 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c %3u %3u\n", name, perm, uid, gid, flags, 'b', MAJOR(dev), MINOR(dev));
676 break;
677 case S_IFIFO:
678 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 'p');
679 break;
680 case S_IFSOCK:
681 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 's');
682 break;
683 case S_IFDIR:
684 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 'd');
685 break;
686 case S_IFLNK:
687 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c %s\n", name, perm, uid, gid, flags, 'l', "unknown");
688 break;
689 case S_IFREG:
690 printk(KERN_DEBUG "SYAORAN-ERROR: %s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 'f');
691 break;
692 }
693 }
694 spin_unlock(&lock);
695 return error;
696 }
697
698 /* Check whether the given dentry is allowed to mknod. */
699 static int MayCreateNode(struct dentry *dentry, int mode, int dev)
700 {
701 struct syaoran_sb_info *info = (struct syaoran_sb_info *) dentry->d_sb->s_fs_info;
702 if (!info) {
703 printk("%s: dentry->d_sb->s_fs_info == NULL\n", __FUNCTION__);
704 return -EPERM;
705 }
706 if (!info->initialize_done) return 0;
707 return CheckFlags(info, dentry, mode, dev, MAY_CREATE);
708 }
709
710 /* Check whether the given dentry is allowed to chmod/chown/unlink. */
711 static int MayModifyNode(struct dentry *dentry, unsigned int flags)
712 {
713 struct syaoran_sb_info *info = (struct syaoran_sb_info *) dentry->d_sb->s_fs_info;
714 if (!info) {
715 printk("%s: dentry->d_sb->s_fs_info == NULL\n", __FUNCTION__);
716 return -EPERM;
717 }
718 if (flags == DEVICE_USED && !info->is_permissive_mode) return 0;
719 if (!dentry->d_inode) return -ENOENT;
720 return CheckFlags(info, dentry, dentry->d_inode->i_mode, dentry->d_inode->i_rdev, flags);
721 }
722
723 /*
724 * The following structure and codes are used for transferring data to interfaces files.
725 */
726
727 struct syaoran_read_struct {
728 char *buf; /* Buffer for reading. */
729 int avail; /* Bytes available for reading. */
730 struct super_block *sb; /* The super_block of this partition. */
731 struct dev_entry *entry; /* The entry currently reading from. */
732 _Bool read_all; /* Dump all entries? */
733 struct list_head *pos; /* Current position. */
734 };
735
736 static void ReadTable(struct syaoran_read_struct *head, char *buf, int count)
737 {
738 struct super_block *sb = head->sb;
739 struct syaoran_sb_info *info = (struct syaoran_sb_info *) sb->s_fs_info;
740 struct list_head *pos;
741 const _Bool read_all = head->read_all;
742 if (!info) return;
743 if (!head->pos) return;
744 list_for_each_cookie(pos, head->pos, &info->list) {
745 struct dev_entry *entry = list_entry(pos, struct dev_entry, list);
746 const unsigned int flags = read_all ? entry->flags : entry->flags & ~DEVICE_USED;
747 const char *name = entry->printable_name;
748 const uid_t uid = entry->uid;
749 const gid_t gid = entry->gid;
750 const mode_t perm = entry->mode & 0777;
751 int len = 0;
752 switch (entry->mode & S_IFMT) {
753 case S_IFCHR:
754 if (!head->read_all && !(entry->flags & DEVICE_USED)) break;
755 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c %3u %3u\n", name, perm, uid, gid, flags, 'c', MAJOR(entry->kdev), MINOR(entry->kdev));
756 break;
757 case S_IFBLK:
758 if (!head->read_all && !(entry->flags & DEVICE_USED)) break;
759 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c %3u %3u\n", name, perm, uid, gid, flags, 'b', MAJOR(entry->kdev), MINOR(entry->kdev));
760 break;
761 case S_IFIFO:
762 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 'p');
763 break;
764 case S_IFSOCK:
765 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 's');
766 break;
767 case S_IFDIR:
768 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 'd');
769 break;
770 case S_IFLNK:
771 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c %s\n", name, perm, uid, gid, flags, 'l', entry->printable_symlink_data);
772 break;
773 case S_IFREG:
774 len = snprintf(buf, count, "%-20s %3o %3u %3u %2u %c\n", name, perm, uid, gid, flags, 'f');
775 break;
776 }
777 if (len < 0 || count <= len) break;
778 count -= len;
779 buf += len;
780 head->avail += len;
781 }
782 }
783
784 static int syaoran_trace_open(struct inode *inode, struct file *file)
785 {
786 struct syaoran_read_struct *head;
787 if ((head = kmalloc(sizeof(*head), GFP_KERNEL)) == NULL) return -ENOMEM;
788 memset(head, 0, sizeof(*head));
789 head->sb = inode->i_sb;
790 head->read_all = (strcmp(file->f_dentry->d_name.name, ".syaoran_all") == 0);
791 head->pos = &((struct syaoran_sb_info *) head->sb->s_fs_info)->list;
792 if ((head->buf = kmalloc(PAGE_SIZE * 2, GFP_KERNEL)) == NULL) {
793 kfree(head);
794 return -ENOMEM;
795 }
796 memset(head->buf, 0, PAGE_SIZE * 2);
797 file->private_data = head;
798 return 0;
799 }
800
801 static int syaoran_trace_release(struct inode *inode, struct file *file)
802 {
803 struct syaoran_read_struct *head = file->private_data;
804 kfree(head->buf);
805 kfree(head);
806 file->private_data = NULL;
807 return 0;
808 }
809
810 static ssize_t syaoran_trace_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
811 {
812 struct syaoran_read_struct *head = (struct syaoran_read_struct *) file->private_data;
813 int len = head->avail;
814 char *cp = head->buf;
815 if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT;
816 ReadTable(head, cp + len, PAGE_SIZE * 2 - len);
817 len = head->avail;
818 if (len > count) len = count;
819 if (len > 0) {
820 if (copy_to_user(buf, cp, len)) return -EFAULT;
821 head->avail -= len;
822 memmove(cp, cp + len, head->avail);
823 }
824 return len;
825 }
826
827 static struct file_operations syaoran_trace_operations = {
828 open: syaoran_trace_open,
829 release: syaoran_trace_release,
830 read: syaoran_trace_read,
831 };
832
833 /* Create interface files for reading status. */
834 static int syaoran_create_tracelog(struct super_block *sb, const char *filename)
835 {
836 struct dentry *base = dget(sb->s_root);
837 struct dentry *dentry = lookup_create2(filename, base, 0);
838 int error = PTR_ERR(dentry);
839 if (!IS_ERR(dentry)) {
840 struct inode *inode = new_inode(sb);
841 if (inode) {
842 inode->i_mode = S_IFREG | 0400;
843 inode->i_uid = 0;
844 inode->i_gid = 0;
845 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
846 inode->i_blksize = PAGE_CACHE_SIZE;
847 #endif
848 inode->i_blocks = 0;
849 inode->i_mapping->a_ops = &syaoran_aops;
850 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
851 inode->i_mapping->backing_dev_info = &syaoran_backing_dev_info;
852 inode->i_op = &syaoran_file_inode_operations;
853 #else
854 inode->i_rdev = NODEV;
855 #endif
856 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
857 inode->i_fop = &syaoran_trace_operations;
858 d_instantiate(dentry, inode);
859 dget(dentry); /* Extra count - pin the dentry in core */
860 error = 0;
861 }
862 dput(dentry);
863 }
864 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
865 mutex_unlock(&base->d_inode->i_mutex);
866 #else
867 up(&base->d_inode->i_sem);
868 #endif
869 dput(base);
870 return error;
871 }
872
873 /***** SYAORAN end. *****/
874 #endif

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