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

Subversion リポジトリの参照

Annotation of /trunk/1.5.x/ccs-patch/fs/sakura_mount.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 224 - (hide annotations) (download) (as text)
Sun May 20 03:25:13 2007 UTC (17 years ago) by kumaneko
Original Path: trunk/ccs-patch/fs/sakura_mount.c
File MIME type: text/x-csrc
File size: 16836 byte(s)


1 kumaneko 111 /*
2     * fs/sakura_mount.c
3     *
4     * Implementation of the Domain-Free Mandatory Access Control.
5     *
6     * Copyright (C) 2005-2007 NTT DATA CORPORATION
7     *
8 kumaneko 224 * Version: 1.4.1-rc1 2007/05/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     /***** SAKURA Linux start. *****/
15    
16     #include <linux/ccs_common.h>
17     #include <linux/sakura.h>
18     #include <linux/realpath.h>
19     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
20     #include <linux/namespace.h>
21     #endif
22    
23     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
24     #define MS_UNBINDABLE (1<<17) /* change to unbindable */
25     #define MS_PRIVATE (1<<18) /* change to private */
26     #define MS_SLAVE (1<<19) /* change to slave */
27     #define MS_SHARED (1<<20) /* change to shared */
28     #endif
29    
30     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
31     #include <linux/namei.h>
32     #else
33     static inline void module_put(struct module *module)
34     {
35     if (module) __MOD_DEC_USE_COUNT(module);
36     }
37     #endif
38    
39     extern const char *ccs_log_level;
40    
41     /***** KEYWORDS for mount restrictions. *****/
42    
43     #define MOUNT_BIND_KEYWORD "--bind" /* Allow to call 'mount --bind /source_dir /dest_dir' */
44     #define MOUNT_MOVE_KEYWORD "--move" /* Allow to call 'mount --move /old_dir /new_dir ' */
45     #define MOUNT_REMOUNT_KEYWORD "--remount" /* Allow to call 'mount -o remount /dir ' */
46     #define MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable" /* Allow to call 'mount --make-unbindable /dir' */
47     #define MOUNT_MAKE_PRIVATE_KEYWORD "--make-private" /* Allow to call 'mount --make-private /dir' */
48     #define MOUNT_MAKE_SLAVE_KEYWORD "--make-slave" /* Allow to call 'mount --make-slave /dir' */
49     #define MOUNT_MAKE_SHARED_KEYWORD "--make-shared" /* Allow to call 'mount --make-shared /dir' */
50    
51     /***** The structure for mount restrictions. *****/
52    
53 kumaneko 214 struct mount_entry {
54 kumaneko 111 struct mount_entry *next;
55     const struct path_info *dev_name;
56     const struct path_info *dir_name;
57     const struct path_info *fs_type;
58     unsigned int disabled_options; /* Options to forcefully disable. */
59     unsigned int enabled_options; /* Options to forcefully enable. */
60     int is_deleted;
61 kumaneko 214 };
62 kumaneko 111
63     /************************* MOUNT RESTRICTION HANDLER *************************/
64    
65     static void ParseMountOptions(char *arg, unsigned int *enabled_options, unsigned int *disabled_options)
66     {
67     char *sp = arg, *cp;
68     unsigned int enable = 0, disable = 0;
69     while ((cp = strsep(&sp, " ,")) != NULL) {
70     if (strcmp(cp, "rw") == 0) disable |= MS_RDONLY;
71     else if (strcmp(cp, "ro") == 0) enable |= MS_RDONLY;
72     else if (strcmp(cp, "suid") == 0) disable |= MS_NOSUID;
73     else if (strcmp(cp, "nosuid") == 0) enable |= MS_NOSUID;
74     else if (strcmp(cp, "dev") == 0) disable |= MS_NODEV;
75     else if (strcmp(cp, "nodev") == 0) enable |= MS_NODEV;
76     else if (strcmp(cp, "exec") == 0) disable |= MS_NOEXEC;
77     else if (strcmp(cp, "noexec") == 0) enable |= MS_NOEXEC;
78     else if (strcmp(cp, "atime") == 0) disable |= MS_NOATIME;
79     else if (strcmp(cp, "noatime") == 0) enable |= MS_NOATIME;
80     else if (strcmp(cp, "diratime") == 0) disable |= MS_NODIRATIME;
81     else if (strcmp(cp, "nodiratime") == 0) enable |= MS_NODIRATIME;
82     else if (strcmp(cp, "norecurse") == 0) disable |= MS_REC;
83     else if (strcmp(cp, "recurse") == 0) enable |= MS_REC;
84     }
85     *enabled_options = enable;
86     *disabled_options = disable;
87     }
88    
89     static void MakeMountOptions(char *buffer, const int buffer_len, const unsigned int enabled, const unsigned int disabled)
90     {
91     memset(buffer, 0, buffer_len);
92     if (enabled == 0 && disabled == 0) {
93     snprintf(buffer, buffer_len - 1, "defaults");
94     } else {
95     snprintf(buffer, buffer_len - 1, "%s%s%s%s%s%s%s",
96     enabled & MS_RDONLY ? "ro " : (disabled & MS_RDONLY ? "rw " : ""),
97     enabled & MS_NOSUID ? "nosuid " : (disabled & MS_NOSUID ? "suid " : ""),
98     enabled & MS_NODEV ? "nodev " : (disabled & MS_NODEV ? "dev " : ""),
99     enabled & MS_NOEXEC ? "noexec " : (disabled & MS_NOEXEC ? "exec " : ""),
100     enabled & MS_NOATIME ? "noatime" : (disabled & MS_NOATIME ? "atime" : ""),
101     enabled & MS_NODIRATIME ? "nodiratime " : (disabled & MS_NODIRATIME ? "diratime " : ""),
102     enabled & MS_REC ? "recurse " : (disabled & MS_REC ? "norecurse " : ""));
103     }
104     }
105    
106     static void put_filesystem(struct file_system_type *fs)
107     {
108     module_put(fs->owner);
109     }
110    
111 kumaneko 214 static struct mount_entry *mount_list = NULL;
112 kumaneko 111
113     static int AddMountACL(const char *dev_name, const char *dir_name, const char *fs_type, const unsigned int enable, const unsigned int disable, const int is_delete)
114     {
115 kumaneko 214 struct mount_entry *new_entry, *ptr;
116 kumaneko 111 const struct path_info *fs, *dev, *dir;
117     static DECLARE_MUTEX(lock);
118     int error = -ENOMEM;
119     if (enable & disable) return -EINVAL; /* options mismatch. */
120     if ((fs = SaveName(fs_type)) == NULL) return -EINVAL;
121     if (!dev_name) dev_name = "<NULL>"; /* Map dev_name to "<NULL>" for if no dev_name given. */
122     if (strcmp(fs->name, MOUNT_REMOUNT_KEYWORD) == 0) dev_name = "any"; /* Fix dev_name to "any" for remount permission. */
123     if (strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
124     strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
125     strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
126     strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD) == 0) dev_name = "any";
127     if (!IsCorrectPath(dev_name, 0, 0, 0, __FUNCTION__) || !IsCorrectPath(dir_name, 1, 0, 1, __FUNCTION__)) return -EINVAL;
128     if ((dev = SaveName(dev_name)) == NULL || (dir = SaveName(dir_name)) == NULL) return -ENOMEM;
129     down(&lock);
130     for (ptr = mount_list; ptr; ptr = ptr->next) {
131     if (pathcmp(ptr->dev_name, dev) || pathcmp(ptr->dir_name, dir) || pathcmp(ptr->fs_type, fs)) continue;
132     if (is_delete) {
133     if (ptr->disabled_options != disable || ptr->enabled_options != enable) continue;
134     ptr->is_deleted = 1;
135     error = 0;
136     goto out;
137     } else {
138     if (ptr->is_deleted) {
139     ptr->enabled_options = enable;
140     ptr->disabled_options = disable;
141     ptr->is_deleted = 0;
142     } else {
143     if ((ptr->enabled_options & disable) || (ptr->disabled_options | enable)) {
144     error = -EINVAL; goto out; /* options mismatch. */
145     }
146     if ((ptr->enabled_options & enable) == enable && (ptr->disabled_options & disable) == disable) {
147     error = 0; goto out; /* No changes. */
148     }
149     ptr->enabled_options |= enable;
150     ptr->disabled_options |= disable;
151     }
152     error = 0;
153     goto update;
154     }
155     }
156     if (is_delete) {
157     error = -ENOENT;
158     goto out;
159     }
160 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
161 kumaneko 111 new_entry->dev_name = dev;
162     new_entry->dir_name = dir;
163     new_entry->fs_type = fs;
164     new_entry->enabled_options = enable;
165     new_entry->disabled_options = disable;
166     mb(); /* Instead of using spinlock. */
167     if ((ptr = mount_list) != NULL) {
168     while (ptr->next) ptr = ptr->next; ptr->next = new_entry;
169     } else {
170     mount_list = new_entry;
171     }
172     error = 0;
173     ptr = new_entry;
174     update:
175     {
176     struct file_system_type *type = NULL;
177     char options[64];
178     MakeMountOptions(options, sizeof(options), ptr->enabled_options, ptr->disabled_options);
179     if (strcmp(fs->name, MOUNT_REMOUNT_KEYWORD) == 0) {
180     printk("%sAllow remount %s with options %s.\n", ccs_log_level, dir->name, options);
181     } else if (strcmp(fs->name, MOUNT_BIND_KEYWORD) == 0 || strcmp(fs->name, MOUNT_MOVE_KEYWORD) == 0) {
182     printk("%sAllow mount %s %s %s\n", ccs_log_level, fs->name, dev->name, dir->name);
183     } else if (strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
184     strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
185     strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
186     strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD) == 0) {
187     printk("%sAllow mount %s %s with options %s.\n", ccs_log_level, fs->name, dir->name, options);
188     } else if ((type = get_fs_type(fs->name)) != NULL && (type->fs_flags & FS_REQUIRES_DEV) != 0) {
189     printk("%sAllow mount -t %s %s %s with options %s.\n", ccs_log_level, fs->name, dev->name, dir->name, options);
190     } else {
191     printk("%sAllow mount %s on %s with options %s.\n", ccs_log_level, fs->name, dir->name, options);
192     }
193     if (type) put_filesystem(type);
194     }
195     out:
196     up(&lock);
197     return error;
198     }
199    
200     int CheckMountPermission(char *dev_name, char *dir_name, char *type, unsigned long *flags)
201     {
202     const int is_enforce = CheckCCSEnforce(CCS_SAKURA_RESTRICT_MOUNT);
203     int error_flag = 1;
204     if (!CheckCCSFlags(CCS_SAKURA_RESTRICT_MOUNT)) return 0;
205     if (!type) type = "<NULL>";
206     if ((*flags & MS_MGC_MSK) == MS_MGC_VAL) *flags &= ~MS_MGC_MSK;
207     switch (*flags & (MS_REMOUNT | MS_MOVE | MS_BIND)) {
208     case MS_REMOUNT:
209     case MS_MOVE:
210     case MS_BIND:
211     case 0:
212     break;
213     default:
214     printk("SAKURA-ERROR: %s%s%sare given for single mount operation.\n",
215     *flags & MS_REMOUNT ? "'remount' " : "",
216     *flags & MS_MOVE ? "'move' " : "",
217     *flags & MS_BIND ? "'bind' " : "");
218     return -EINVAL;
219     }
220     switch (*flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)) {
221     case MS_UNBINDABLE:
222     case MS_PRIVATE:
223     case MS_SLAVE:
224     case MS_SHARED:
225     case 0:
226     break;
227     default:
228     printk("SAKURA-ERROR: %s%s%s%sare given for single mount operation.\n",
229     *flags & MS_UNBINDABLE ? "'unbindable' " : "",
230     *flags & MS_PRIVATE ? "'private' " : "",
231     *flags & MS_SLAVE ? "'slave' " : "",
232     *flags & MS_SHARED ? "'shared' " : "");
233     return -EINVAL;
234     }
235     if (*flags & MS_REMOUNT) {
236     *flags &= ~MS_REMOUNT;
237     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_REMOUNT_KEYWORD, flags);
238     *flags |= MS_REMOUNT;
239     } else if (*flags & MS_MOVE) {
240     *flags &= ~MS_MOVE;
241     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MOVE_KEYWORD, flags);
242     *flags |= MS_MOVE;
243     } else if (*flags & MS_BIND) {
244     *flags &= ~MS_BIND;
245     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_BIND_KEYWORD, flags);
246     *flags |= MS_BIND;
247     } else if (*flags & MS_UNBINDABLE) {
248     *flags &= ~MS_UNBINDABLE;
249     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_UNBINDABLE_KEYWORD, flags);
250     *flags |= MS_UNBINDABLE;
251     } else if (*flags & MS_PRIVATE) {
252     *flags &= ~MS_PRIVATE;
253     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_PRIVATE_KEYWORD, flags);
254     *flags |= MS_PRIVATE;
255     } else if (*flags & MS_SLAVE) {
256     *flags &= ~MS_SLAVE;
257     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_SLAVE_KEYWORD, flags);
258     *flags |= MS_SLAVE;
259     } else if (*flags & MS_SHARED) {
260     *flags &= ~MS_SHARED;
261     error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_SHARED_KEYWORD, flags);
262     *flags |= MS_SHARED;
263     } else {
264     goto normal_mount;
265     }
266     if (error_flag) {
267     if (is_enforce) return -EPERM;
268     return 0;
269     }
270     normal_mount: ;
271     {
272 kumaneko 214 struct mount_entry *ptr;
273 kumaneko 111 struct file_system_type *fstype = NULL;
274     const char *requested_dir_name = NULL;
275     const char *requested_dev_name = NULL;
276     struct path_info rdev, rdir;
277     int need_dev = 0;
278    
279     if ((requested_dir_name = realpath(dir_name)) == NULL) goto cleanup;
280     rdir.name = requested_dir_name;
281     fill_path_info(&rdir);
282    
283     /* Compare fs name. */
284     if (strcmp(type, MOUNT_REMOUNT_KEYWORD) == 0) {
285     /* Needn't to resolve dev_name */
286     } else if (strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
287     strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
288     strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
289     strcmp(type, MOUNT_MAKE_SHARED_KEYWORD) == 0) {
290     /* Needn't to resolve dev_name */
291     } else if (strcmp(type, MOUNT_BIND_KEYWORD) == 0 || strcmp(type, MOUNT_MOVE_KEYWORD) == 0) {
292     if ((requested_dev_name = realpath(dev_name)) == NULL) goto cleanup;
293     rdev.name = requested_dev_name;
294     fill_path_info(&rdev);
295     need_dev = -1;
296     } else if ((fstype = get_fs_type(type)) != NULL) {
297     if (fstype->fs_flags & FS_REQUIRES_DEV) {
298     if ((requested_dev_name = realpath(dev_name)) == NULL) goto cleanup;
299     rdev.name = requested_dev_name;
300     fill_path_info(&rdev);
301     need_dev = 1;
302     }
303     } else {
304     goto cleanup;
305     }
306     for (ptr = mount_list; ptr; ptr = ptr->next) {
307     if (ptr->is_deleted) continue;
308    
309     /* Compare fs name. */
310     if (strcmp(type, ptr->fs_type->name)) continue;
311    
312     /* Compare mount point. */
313     if (PathMatchesToPattern(&rdir, ptr->dir_name) == 0) continue;
314    
315     /* Compare device name. */
316     if (requested_dev_name && PathMatchesToPattern(&rdev, ptr->dev_name) == 0) continue;
317    
318     /* OK. */
319     error_flag = 0;
320     *flags &= ~ptr->disabled_options;
321     *flags |= ptr->enabled_options;
322    
323     if (need_dev > 0) {
324     printk(KERN_DEBUG "SAKURA-NOTICE: 'mount -t %s %s %s' accepted.\n", type, requested_dev_name, requested_dir_name);
325     } else if (need_dev < 0) {
326     printk(KERN_DEBUG "SAKURA-NOTICE: 'mount %s %s %s' accepted.\n", type, requested_dev_name, requested_dir_name);
327     } else if (strcmp(type, MOUNT_REMOUNT_KEYWORD) == 0) {
328     printk(KERN_DEBUG "SAKURA-NOTICE: 'mount -o remount %s' accepted.\n", requested_dir_name);
329     } else if (strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
330     strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
331     strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
332     strcmp(type, MOUNT_MAKE_SHARED_KEYWORD) == 0) {
333     printk(KERN_DEBUG "SAKURA-NOTICE: 'mount %s %s' accepted.\n", type, requested_dir_name);
334     } else {
335     printk(KERN_DEBUG "SAKURA-NOTICE: 'mount %s on %s' accepted.\n", type, requested_dir_name);
336     }
337     break;
338     }
339     if (error_flag && !is_enforce && CheckCCSAccept(CCS_SAKURA_RESTRICT_MOUNT)) {
340     AddMountACL(need_dev ? requested_dev_name : dev_name, requested_dir_name, type, 0, 0, 0);
341     UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);
342     }
343     cleanup:
344     if (requested_dev_name) ccs_free(requested_dev_name);
345     if (requested_dir_name) ccs_free(requested_dir_name);
346     if (fstype) put_filesystem(fstype);
347     }
348    
349     if (error_flag) {
350     int error = -EPERM;
351     const int is_enforce = CheckCCSEnforce(CCS_SAKURA_RESTRICT_MOUNT);
352     const char *realname1 = realpath(dev_name), *realname2 = realpath(dir_name), *exename = GetEXE();
353     if (strcmp(type, MOUNT_REMOUNT_KEYWORD) == 0) {
354     printk("SAKURA-%s: mount -o remount %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), realname2 ? realname2 : dir_name, current->pid, exename);
355     if (is_enforce && CheckSupervisor("# %s is requesting\nmount -o remount %s\n", exename, realname2 ? realname2 : dir_name) == 0) error = 0;
356     } else if (strcmp(type, MOUNT_BIND_KEYWORD) == 0 || strcmp(type, MOUNT_MOVE_KEYWORD) == 0) {
357     printk("SAKURA-%s: mount %s %s %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name, current->pid, exename);
358     if (is_enforce && CheckSupervisor("# %s is requesting\nmount %s %s %s\n", exename, type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name) == 0) error = 0;
359     } else if (strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
360     strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
361     strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
362     strcmp(type, MOUNT_MAKE_SHARED_KEYWORD) == 0) {
363     printk("SAKURA-%s: mount %s %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), type, realname2 ? realname2 : dir_name, current->pid, exename);
364     if (is_enforce && CheckSupervisor("# %s is requesting\nmount %s %s", exename, type, realname2 ? realname2 : dir_name) == 0) error = 0;
365     } else {
366     printk("SAKURA-%s: mount -t %s %s %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name, current->pid, exename);
367     if (is_enforce && CheckSupervisor("# %s is requesting\nmount -t %s %s %s\n", exename, type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name) == 0) error = 0;
368     }
369     if (exename) ccs_free(exename);
370     if (realname2) ccs_free(realname2);
371     if (realname1) ccs_free(realname1);
372     if (is_enforce) return error;
373     }
374     return 0;
375     }
376 kumaneko 223 EXPORT_SYMBOL(CheckMountPermission);
377 kumaneko 111
378     int AddMountPolicy(char *data, const int is_delete)
379     {
380     char *cp, *cp2;
381     const char *fs, *dev, *dir;
382     unsigned int enable = 0, disable = 0;
383     cp2 = data; if ((cp = strchr(cp2, ' ')) == NULL) return -EINVAL; *cp = '\0'; dev = cp2;
384     cp2 = cp + 1; if ((cp = strchr(cp2, ' ')) == NULL) return -EINVAL; *cp = '\0'; dir = cp2;
385     cp2 = cp + 1;
386     if ((cp = strchr(cp2, ' ')) != NULL) {
387     *cp = '\0';
388     ParseMountOptions(cp + 1, &enable, &disable);
389     }
390     fs = cp2;
391     return AddMountACL(dev, dir, fs, enable, disable, is_delete);
392     }
393    
394 kumaneko 214 int ReadMountPolicy(struct io_buffer *head)
395 kumaneko 111 {
396 kumaneko 214 struct mount_entry *ptr = head->read_var2;
397 kumaneko 111 if (!ptr) ptr = mount_list;
398     while (ptr) {
399     char options[64];
400 kumaneko 214 head->read_var2 = ptr;
401 kumaneko 111 MakeMountOptions(options, sizeof(options), ptr->enabled_options, ptr->disabled_options);
402     if (ptr->is_deleted == 0 && io_printf(head, KEYWORD_ALLOW_MOUNT "%s %s %s %s\n", ptr->dev_name->name, ptr->dir_name->name, ptr->fs_type->name, options)) break;
403     ptr = ptr->next;
404     }
405     return ptr ? -ENOMEM : 0;
406     }
407    
408     /***** SAKURA Linux end. *****/

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