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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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