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. *****/ |