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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 473 - (hide annotations) (download) (as text)
Thu Sep 20 12:18:18 2007 UTC (16 years, 7 months ago) by kumaneko
File MIME type: text/x-chdr
File size: 27504 byte(s)
1.5.0-rc
1 kumaneko 111 /*
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 kumaneko 473 * Version: 1.5.0-rc 2007/09/20
9 kumaneko 111 *
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, int 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 kumaneko 118 unsigned int perm, uid, gid, flags, major = 0, minor = 0;
289 kumaneko 111 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 kumaneko 118 if (sscanf(args[ARG_PERMISSION], "%o", &perm) != 1 || !(perm <= 0777) || sscanf(args[ARG_UID], "%u", &uid) != 1
301 kumaneko 111 || 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 kumaneko 214 if ((entry = kmalloc(sizeof(*entry), GFP_KERNEL)) == NULL) goto out;
334     memset(entry, 0, sizeof(*entry));
335 kumaneko 111 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 kumaneko 473 printk("SYAORAN: 1.5.0-rc 2007/09/20\n");
505 kumaneko 111 }
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 kumaneko 214 if ((p = sb->s_fs_info = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) goto out;
547     memset(p, 0, sizeof(*p));
548 kumaneko 111 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 kumaneko 214 if ((head = kmalloc(sizeof(*head), GFP_KERNEL)) == NULL) return -ENOMEM;
777     memset(head, 0, sizeof(*head));
778 kumaneko 111 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