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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 323 - (show annotations) (download) (as text)
Mon Aug 6 12:38:46 2007 UTC (16 years, 9 months ago) by kumaneko
Original Path: trunk/1.4.x/ccs-patch/fs/sakura_mount.c
File MIME type: text/x-csrc
File size: 16832 byte(s)
mkdir 1.4.x in trunk
1 /*
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 * Version: 1.4.2 2007/07/13
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 /***** 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 struct mount_entry {
54 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 };
62
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 static struct mount_entry *mount_list = NULL;
112
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 struct mount_entry *new_entry, *ptr;
116 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 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
161 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 struct mount_entry *ptr;
273 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 EXPORT_SYMBOL(CheckMountPermission);
377
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 int ReadMountPolicy(struct io_buffer *head)
395 {
396 struct mount_entry *ptr = head->read_var2;
397 if (!ptr) ptr = mount_list;
398 while (ptr) {
399 char options[64];
400 head->read_var2 = ptr;
401 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