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

Subversion リポジトリの参照

Contents of /trunk/1.6.x/ccs-patch/fs/sakura_mount.c

Parent Directory Parent Directory | Revision Log Revision Log


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


1 /*
2 * fs/sakura_mount.c
3 *
4 * Implementation of the Domain-Free Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 *
8 * Version: 1.6.6-pre 2008/12/01
9 *
10 * This file is applicable to both 2.4.30 and 2.6.11 and later.
11 * See README.ccs for ChangeLog.
12 *
13 */
14
15 #include <linux/ccs_common.h>
16 #include <linux/sakura.h>
17 #include <linux/realpath.h>
18 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
19 #include <linux/namespace.h>
20 #endif
21
22 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
23 #define MS_UNBINDABLE (1<<17) /* change to unbindable */
24 #define MS_PRIVATE (1<<18) /* change to private */
25 #define MS_SLAVE (1<<19) /* change to slave */
26 #define MS_SHARED (1<<20) /* change to shared */
27 #endif
28
29 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
30 #include <linux/namei.h>
31 #else
32 /* For compatibility with older kernels. */
33 static inline void module_put(struct module *module)
34 {
35 if (module)
36 __MOD_DEC_USE_COUNT(module);
37 }
38 #endif
39
40 /* Keywords for mount restrictions. */
41
42 /* Allow to call 'mount --bind /source_dir /dest_dir' */
43 #define MOUNT_BIND_KEYWORD "--bind"
44 /* Allow to call 'mount --move /old_dir /new_dir ' */
45 #define MOUNT_MOVE_KEYWORD "--move"
46 /* Allow to call 'mount -o remount /dir ' */
47 #define MOUNT_REMOUNT_KEYWORD "--remount"
48 /* Allow to call 'mount --make-unbindable /dir' */
49 #define MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable"
50 /* Allow to call 'mount --make-private /dir' */
51 #define MOUNT_MAKE_PRIVATE_KEYWORD "--make-private"
52 /* Allow to call 'mount --make-slave /dir' */
53 #define MOUNT_MAKE_SLAVE_KEYWORD "--make-slave"
54 /* Allow to call 'mount --make-shared /dir' */
55 #define MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
56
57 /* Structure for "allow_mount" keyword. */
58 struct mount_entry {
59 struct list1_head list;
60 const struct path_info *dev_name;
61 const struct path_info *dir_name;
62 const struct path_info *fs_type;
63 unsigned long flags;
64 bool is_deleted;
65 };
66
67 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
68 /* For compatibility with older kernels. */
69 static void put_filesystem(struct file_system_type *fs)
70 {
71 module_put(fs->owner);
72 }
73 #endif
74
75 /* The list for "struct mount_entry". */
76 static LIST1_HEAD(mount_list);
77
78 /**
79 * update_mount_acl - Update "struct mount_entry" list.
80 *
81 * @dev_name: Name of device file.
82 * @dir_name: Name of mount point.
83 * @fs_type: Name of filesystem.
84 * @flags: Mount options.
85 * @is_delete: True if it is a delete request.
86 *
87 * Returns 0 on success, negative value otherwise.
88 */
89 static int update_mount_acl(const char *dev_name, const char *dir_name,
90 const char *fs_type, const unsigned long flags,
91 const bool is_delete)
92 {
93 struct file_system_type *type = NULL;
94 struct mount_entry *new_entry;
95 struct mount_entry *ptr;
96 const struct path_info *fs;
97 const struct path_info *dev;
98 const struct path_info *dir;
99 static DEFINE_MUTEX(lock);
100 int error = -ENOMEM;
101 fs = ccs_save_name(fs_type);
102 if (!fs)
103 return -EINVAL;
104 if (!dev_name)
105 /* Map dev_name to "<NULL>" for if no dev_name given. */
106 dev_name = "<NULL>";
107 if (!strcmp(fs->name, MOUNT_REMOUNT_KEYWORD))
108 /* Fix dev_name to "any" for remount permission. */
109 dev_name = "any";
110 if (!strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
111 !strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) ||
112 !strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) ||
113 !strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD))
114 dev_name = "any";
115 if (!ccs_is_correct_path(dev_name, 0, 0, 0, __func__) ||
116 !ccs_is_correct_path(dir_name, 0, 0, 0, __func__))
117 return -EINVAL;
118 dev = ccs_save_name(dev_name);
119 dir = ccs_save_name(dir_name);
120 if (!dev || !dir)
121 return -ENOMEM;
122 mutex_lock(&lock);
123 list1_for_each_entry(ptr, &mount_list, list) {
124 if (ptr->flags != flags ||
125 ccs_pathcmp(ptr->dev_name, dev) ||
126 ccs_pathcmp(ptr->dir_name, dir) ||
127 ccs_pathcmp(ptr->fs_type, fs))
128 continue;
129 error = 0;
130 if (is_delete) {
131 ptr->is_deleted = true;
132 goto out;
133 } else {
134 if (ptr->is_deleted) {
135 ptr->is_deleted = false;
136 goto update;
137 }
138 goto out; /* No changes. */
139 }
140 }
141 if (is_delete) {
142 error = -ENOENT;
143 goto out;
144 }
145 new_entry = ccs_alloc_element(sizeof(*new_entry));
146 if (!new_entry)
147 goto out;
148 new_entry->dev_name = dev;
149 new_entry->dir_name = dir;
150 new_entry->fs_type = fs;
151 new_entry->flags = flags;
152 list1_add_tail_mb(&new_entry->list, &mount_list);
153 error = 0;
154 ptr = new_entry;
155 update:
156 if (!strcmp(fs->name, MOUNT_REMOUNT_KEYWORD)) {
157 printk(KERN_CONT "%sAllow remount %s with options 0x%lX.\n",
158 ccs_log_level, dir->name, ptr->flags);
159 } else if (!strcmp(fs->name, MOUNT_BIND_KEYWORD)
160 || !strcmp(fs->name, MOUNT_MOVE_KEYWORD)) {
161 printk(KERN_CONT "%sAllow mount %s %s %s with options 0x%lX\n",
162 ccs_log_level, fs->name, dev->name, dir->name,
163 ptr->flags);
164 } else if (!strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
165 !strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) ||
166 !strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) ||
167 !strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD)) {
168 printk(KERN_CONT "%sAllow mount %s %s with options 0x%lX.\n",
169 ccs_log_level, fs->name, dir->name, ptr->flags);
170 } else {
171 type = get_fs_type(fs->name);
172 if (type && (type->fs_flags & FS_REQUIRES_DEV) != 0)
173 printk(KERN_CONT "%sAllow mount -t %s %s %s "
174 "with options 0x%lX.\n", ccs_log_level,
175 fs->name, dev->name, dir->name, ptr->flags);
176 else
177 printk(KERN_CONT "%sAllow mount %s on %s "
178 "with options 0x%lX.\n", ccs_log_level,
179 fs->name, dir->name, ptr->flags);
180 }
181 if (type)
182 put_filesystem(type);
183 out:
184 mutex_unlock(&lock);
185 ccs_update_counter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);
186 return error;
187 }
188
189 /**
190 * print_success - Print success messages.
191 *
192 * @dev_name: Name of device file.
193 * @dir_name: Name of mount point.
194 * @type: Name of filesystem type.
195 * @flags: Mount options.
196 * @need_dev: Type of @dev_name.
197 *
198 * Returns nothing.
199 */
200 static void print_success(const char *dev_name, const char *dir_name,
201 const char *type, const unsigned long flags,
202 const int need_dev)
203 {
204 if (need_dev > 0) {
205 printk(KERN_DEBUG "SAKURA-NOTICE: "
206 "'mount -t %s %s %s 0x%lX' accepted.\n",
207 type, dev_name, dir_name, flags);
208 } else if (need_dev < 0) {
209 printk(KERN_DEBUG "SAKURA-NOTICE: "
210 "'mount %s %s %s 0x%lX' accepted.\n",
211 type, dev_name, dir_name, flags);
212 } else if (!strcmp(type, MOUNT_REMOUNT_KEYWORD)) {
213 printk(KERN_DEBUG "SAKURA-NOTICE: "
214 "'mount -o remount %s 0x%lX' accepted.\n",
215 dir_name, flags);
216 } else if (!strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
217 !strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) ||
218 !strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) ||
219 !strcmp(type, MOUNT_MAKE_SHARED_KEYWORD)) {
220 printk(KERN_DEBUG "SAKURA-NOTICE: "
221 "'mount %s %s 0x%lX' accepted.\n",
222 type, dir_name, flags);
223 } else {
224 printk(KERN_DEBUG "SAKURA-NOTICE: "
225 "'mount %s on %s 0x%lX' accepted.\n",
226 type, dir_name, flags);
227 }
228 }
229
230 /**
231 * print_error - Print error messages.
232 *
233 * @r: Pointer to "struct ccs_request_info".
234 * @dev_name: Name of device file.
235 * @dir_name: Name of mount point.
236 * @type: Name of filesystem type.
237 * @flags: Mount options.
238 * @error: Error value.
239 *
240 * Returns 0 if permitted by the administrator's decision, negative value
241 * otherwise.
242 */
243 static int print_error(struct ccs_request_info *r,
244 const char *dev_name, const char *dir_name,
245 const char *type, const unsigned long flags,
246 int error)
247 {
248 const bool is_enforce = (r->mode == 3);
249 const char *realname1 = ccs_realpath(dev_name);
250 const char *realname2 = ccs_realpath(dir_name);
251 const char *exename = ccs_get_exe();
252 const pid_t pid = (pid_t) sys_getpid();
253 if (!strcmp(type, MOUNT_REMOUNT_KEYWORD)) {
254 printk(KERN_WARNING "SAKURA-%s: mount -o remount %s 0x%lX "
255 "(pid=%d:exe=%s): Permission denied.\n",
256 ccs_get_msg(is_enforce),
257 realname2 ? realname2 : dir_name,
258 flags, pid, exename);
259 if (is_enforce)
260 error = ccs_check_supervisor(r, "# %s is requesting\n"
261 "mount -o remount %s "
262 "0x%lX\n", exename,
263 realname2 ? realname2
264 : dir_name, flags);
265 } else if (!strcmp(type, MOUNT_BIND_KEYWORD)
266 || !strcmp(type, MOUNT_MOVE_KEYWORD)) {
267 printk(KERN_WARNING "SAKURA-%s: mount %s %s %s 0x%lX "
268 "(pid=%d:exe=%s): Permission denied.\n",
269 ccs_get_msg(is_enforce), type,
270 realname1 ? realname1 : dev_name,
271 realname2 ? realname2 : dir_name,
272 flags, pid, exename);
273 if (is_enforce)
274 error = ccs_check_supervisor(r, "# %s is requesting\n"
275 "mount %s %s %s 0x%lX\n",
276 exename, type,
277 realname1 ? realname1 :
278 dev_name,
279 realname2 ? realname2 :
280 dir_name, flags);
281 } else if (!strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
282 !strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) ||
283 !strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) ||
284 !strcmp(type, MOUNT_MAKE_SHARED_KEYWORD)) {
285 printk(KERN_WARNING "SAKURA-%s: mount %s %s 0x%lX "
286 "(pid=%d:exe=%s): Permission denied.\n",
287 ccs_get_msg(is_enforce), type,
288 realname2 ? realname2 : dir_name,
289 flags, pid, exename);
290 if (is_enforce)
291 error = ccs_check_supervisor(r, "# %s is requesting\n"
292 "mount %s %s 0x%lX",
293 exename, type,
294 realname2 ? realname2 :
295 dir_name, flags);
296 } else {
297 printk(KERN_WARNING "SAKURA-%s: mount -t %s %s %s 0x%lX "
298 "(pid=%d:exe=%s): Permission denied.\n",
299 ccs_get_msg(is_enforce), type,
300 realname1 ? realname1 : dev_name,
301 realname2 ? realname2 : dir_name,
302 flags, pid, exename);
303 if (is_enforce)
304 error = ccs_check_supervisor(r, "# %s is requesting\n"
305 "mount -t %s %s %s "
306 "0x%lX\n", exename, type,
307 realname1 ? realname1 :
308 dev_name,
309 realname2 ? realname2 :
310 dir_name, flags);
311 }
312 ccs_free(exename);
313 ccs_free(realname2);
314 ccs_free(realname1);
315 return error;
316 }
317
318 /**
319 * check_mount_permission2 - Check permission for mount() operation.
320 *
321 * @r: Pointer to "struct ccs_request_info".
322 * @dev_name: Name of device file.
323 * @dir_name: Name of mount point.
324 * @type: Name of filesystem type. May be NULL.
325 * @flags: Mount options.
326 *
327 * Returns 0 on success, negative value otherwise.
328 */
329 static int check_mount_permission2(struct ccs_request_info *r,
330 char *dev_name, char *dir_name, char *type,
331 unsigned long flags)
332 {
333 const bool is_enforce = (r->mode == 3);
334 int error;
335 retry:
336 error = -EPERM;
337 if (!type)
338 type = "<NULL>";
339 if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
340 flags &= ~MS_MGC_MSK;
341 switch (flags & (MS_REMOUNT | MS_MOVE | MS_BIND)) {
342 case MS_REMOUNT:
343 case MS_MOVE:
344 case MS_BIND:
345 case 0:
346 break;
347 default:
348 printk(KERN_WARNING "SAKURA-ERROR: "
349 "%s%s%sare given for single mount operation.\n",
350 flags & MS_REMOUNT ? "'remount' " : "",
351 flags & MS_MOVE ? "'move' " : "",
352 flags & MS_BIND ? "'bind' " : "");
353 return -EINVAL;
354 }
355 switch (flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)) {
356 case MS_UNBINDABLE:
357 case MS_PRIVATE:
358 case MS_SLAVE:
359 case MS_SHARED:
360 case 0:
361 break;
362 default:
363 printk(KERN_WARNING "SAKURA-ERROR: "
364 "%s%s%s%sare given for single mount operation.\n",
365 flags & MS_UNBINDABLE ? "'unbindable' " : "",
366 flags & MS_PRIVATE ? "'private' " : "",
367 flags & MS_SLAVE ? "'slave' " : "",
368 flags & MS_SHARED ? "'shared' " : "");
369 return -EINVAL;
370 }
371 if (flags & MS_REMOUNT) {
372 error = check_mount_permission2(r, dev_name, dir_name,
373 MOUNT_REMOUNT_KEYWORD,
374 flags & ~MS_REMOUNT);
375 } else if (flags & MS_MOVE) {
376 error = check_mount_permission2(r, dev_name, dir_name,
377 MOUNT_MOVE_KEYWORD,
378 flags & ~MS_MOVE);
379 } else if (flags & MS_BIND) {
380 error = check_mount_permission2(r, dev_name, dir_name,
381 MOUNT_BIND_KEYWORD,
382 flags & ~MS_BIND);
383 } else if (flags & MS_UNBINDABLE) {
384 error = check_mount_permission2(r, dev_name, dir_name,
385 MOUNT_MAKE_UNBINDABLE_KEYWORD,
386 flags & ~MS_UNBINDABLE);
387 } else if (flags & MS_PRIVATE) {
388 error = check_mount_permission2(r, dev_name, dir_name,
389 MOUNT_MAKE_PRIVATE_KEYWORD,
390 flags & ~MS_PRIVATE);
391 } else if (flags & MS_SLAVE) {
392 error = check_mount_permission2(r, dev_name, dir_name,
393 MOUNT_MAKE_SLAVE_KEYWORD,
394 flags & ~MS_SLAVE);
395 } else if (flags & MS_SHARED) {
396 error = check_mount_permission2(r, dev_name, dir_name,
397 MOUNT_MAKE_SHARED_KEYWORD,
398 flags & ~MS_SHARED);
399 } else {
400 struct mount_entry *ptr;
401 struct file_system_type *fstype = NULL;
402 const char *requested_dir_name = NULL;
403 const char *requested_dev_name = NULL;
404 struct path_info rdev;
405 struct path_info rdir;
406 int need_dev = 0;
407
408 requested_dir_name = ccs_realpath(dir_name);
409 if (!requested_dir_name) {
410 error = -ENOENT;
411 goto cleanup;
412 }
413 rdir.name = requested_dir_name;
414 ccs_fill_path_info(&rdir);
415
416 /* Compare fs name. */
417 if (!strcmp(type, MOUNT_REMOUNT_KEYWORD)) {
418 /* Needn't to resolve dev_name */
419 } else if (!strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
420 !strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) ||
421 !strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) ||
422 !strcmp(type, MOUNT_MAKE_SHARED_KEYWORD)) {
423 /* Needn't to resolve dev_name */
424 } else if (!strcmp(type, MOUNT_BIND_KEYWORD) ||
425 !strcmp(type, MOUNT_MOVE_KEYWORD)) {
426 requested_dev_name = ccs_realpath(dev_name);
427 if (!requested_dev_name) {
428 error = -ENOENT;
429 goto cleanup;
430 }
431 rdev.name = requested_dev_name;
432 ccs_fill_path_info(&rdev);
433 /* dev_name is a directory */
434 need_dev = -1;
435 } else {
436 fstype = get_fs_type(type);
437 if (fstype) {
438 if (fstype->fs_flags & FS_REQUIRES_DEV) {
439 requested_dev_name
440 = ccs_realpath(dev_name);
441 if (!requested_dev_name) {
442 error = -ENOENT;
443 goto cleanup;
444 }
445 rdev.name = requested_dev_name;
446 ccs_fill_path_info(&rdev);
447 /* dev_name is a block device file */
448 need_dev = 1;
449 }
450 } else {
451 error = -ENODEV;
452 goto cleanup;
453 }
454 }
455 list1_for_each_entry(ptr, &mount_list, list) {
456 if (ptr->is_deleted)
457 continue;
458
459 /* Compare options */
460 if (ptr->flags != flags)
461 continue;
462
463 /* Compare fs name. */
464 if (strcmp(type, ptr->fs_type->name))
465 continue;
466
467 /* Compare mount point. */
468 if (ccs_path_matches_pattern(&rdir, ptr->dir_name) == 0)
469 continue;
470
471 /* Compare device name. */
472 if (requested_dev_name &&
473 ccs_path_matches_pattern(&rdev, ptr->dev_name) == 0)
474 continue;
475
476 /* OK. */
477 error = 0;
478 print_success(requested_dev_name, requested_dir_name,
479 type, flags, need_dev);
480 break;
481 }
482 if (error)
483 error = print_error(r, dev_name, dir_name, type, flags,
484 error);
485 if (error && r->mode == 1)
486 update_mount_acl(need_dev ?
487 requested_dev_name : dev_name,
488 requested_dir_name, type, flags, 0);
489 cleanup:
490 ccs_free(requested_dev_name);
491 ccs_free(requested_dir_name);
492 if (fstype)
493 put_filesystem(fstype);
494 }
495 if (!is_enforce)
496 error = 0;
497 if (error == 1)
498 goto retry;
499 return error;
500 }
501
502 /**
503 * ccs_check_mount_permission - Check permission for mount() operation.
504 *
505 * @dev_name: Name of device file.
506 * @dir_name: Name of mount point.
507 * @type: Name of filesystem type. May be NULL.
508 * @flags: Mount options.
509 *
510 * Returns 0 on success, negative value otherwise.
511 */
512 int ccs_check_mount_permission(char *dev_name, char *dir_name, char *type,
513 const unsigned long *flags)
514 {
515 struct ccs_request_info r;
516 if (!ccs_can_sleep())
517 return 0;
518 ccs_init_request_info(&r, NULL, CCS_SAKURA_RESTRICT_MOUNT);
519 if (!r.mode)
520 return 0;
521 return check_mount_permission2(&r, dev_name, dir_name, type, *flags);
522 }
523
524 /**
525 * ccs_write_mount_policy - Write "struct mount_entry" list.
526 *
527 * @data: String to parse.
528 * @is_delete: True if it is a delete request.
529 *
530 * Returns 0 on success, negative value otherwise.
531 */
532 int ccs_write_mount_policy(char *data, const bool is_delete)
533 {
534 char *cp;
535 char *cp2;
536 const char *fs;
537 const char *dev;
538 const char *dir;
539 unsigned long flags = 0;
540 cp2 = data;
541 cp = strchr(cp2, ' ');
542 if (!cp)
543 return -EINVAL;
544 *cp = '\0';
545 dev = cp2;
546 cp2 = cp + 1;
547 cp = strchr(cp2, ' ');
548 if (!cp)
549 return -EINVAL;
550 *cp = '\0';
551 dir = cp2;
552 cp2 = cp + 1;
553 cp = strchr(cp2, ' ');
554 if (!cp)
555 return -EINVAL;
556 *cp = '\0';
557 fs = cp2;
558 flags = simple_strtoul(cp + 1, NULL, 0);
559 return update_mount_acl(dev, dir, fs, flags, is_delete);
560 }
561
562 /**
563 * ccs_read_mount_policy - Read "struct mount_entry" list.
564 *
565 * @head: Pointer to "struct ccs_io_buffer".
566 *
567 * Returns true on success, false otherwise.
568 */
569 bool ccs_read_mount_policy(struct ccs_io_buffer *head)
570 {
571 struct list1_head *pos;
572 list1_for_each_cookie(pos, head->read_var2, &mount_list) {
573 struct mount_entry *ptr;
574 ptr = list1_entry(pos, struct mount_entry, list);
575 if (ptr->is_deleted)
576 continue;
577 if (!ccs_io_printf(head, KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
578 ptr->dev_name->name, ptr->dir_name->name,
579 ptr->fs_type->name, ptr->flags))
580 goto out;
581 }
582 return true;
583 out:
584 return false;
585 }

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