1 |
diff -ru linux-2.6.3-rc4.orig/fs/filesystems.c linux-2.6.3-rc4/fs/filesystems.c |
2 |
--- linux-2.6.3-rc4.orig/fs/filesystems.c 2003-12-18 03:59:18.000000000 +0100 |
3 |
+++ linux-2.6.3-rc4/fs/filesystems.c 2004-02-17 10:08:04.000000000 +0100 |
4 |
@@ -222,7 +222,8 @@ |
5 |
if (fs && !try_module_get(fs->owner)) |
6 |
fs = NULL; |
7 |
read_unlock(&file_systems_lock); |
8 |
- if (!fs && (request_module("%s", name) == 0)) { |
9 |
+ if (!fs && capable(CAP_SYS_ADMIN) && |
10 |
+ (request_module("%s", name) == 0)) { |
11 |
read_lock(&file_systems_lock); |
12 |
fs = *(find_filesystem(name)); |
13 |
if (fs && !try_module_get(fs->owner)) |
14 |
diff -ru linux-2.6.3-rc4.orig/fs/namespace.c linux-2.6.3-rc4/fs/namespace.c |
15 |
--- linux-2.6.3-rc4.orig/fs/namespace.c 2004-02-17 10:20:40.000000000 +0100 |
16 |
+++ linux-2.6.3-rc4/fs/namespace.c 2004-02-17 10:08:04.000000000 +0100 |
17 |
@@ -25,13 +25,16 @@ |
18 |
|
19 |
extern int __init init_rootfs(void); |
20 |
extern int __init sysfs_init(void); |
21 |
+extern void put_filesystem(struct file_system_type *fs); |
22 |
+ |
23 |
+#define MAX_MOUNTS 256 |
24 |
|
25 |
/* spinlock for vfsmount related operations, inplace of dcache_lock */ |
26 |
spinlock_t vfsmount_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; |
27 |
static struct list_head *mount_hashtable; |
28 |
static int hash_mask, hash_bits; |
29 |
static kmem_cache_t *mnt_cache; |
30 |
- |
31 |
+struct mounts_stat_struct mounts_stat = { .max_mounts = MAX_MOUNTS }; |
32 |
static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) |
33 |
{ |
34 |
unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES); |
35 |
@@ -40,10 +43,38 @@ |
36 |
return tmp & hash_mask; |
37 |
} |
38 |
|
39 |
+static inline int inc_nr_mounts(void) |
40 |
+{ |
41 |
+ int err = 0; |
42 |
+ spin_lock(&vfsmount_lock); |
43 |
+ if (capable(CAP_SYS_ADMIN) || |
44 |
+ mounts_stat.nr_mounts < mounts_stat.max_mounts) |
45 |
+ mounts_stat.nr_mounts++; |
46 |
+ else |
47 |
+ err = mounts_stat.max_mounts ? -EMFILE : -EPERM; |
48 |
+ spin_unlock(&vfsmount_lock); |
49 |
+ return err; |
50 |
+} |
51 |
+ |
52 |
+static inline void dec_nr_mounts(void) |
53 |
+{ |
54 |
+ spin_lock(&vfsmount_lock); |
55 |
+ mounts_stat.nr_mounts--; |
56 |
+ spin_unlock(&vfsmount_lock); |
57 |
+} |
58 |
+ |
59 |
struct vfsmount *alloc_vfsmnt(const char *name) |
60 |
{ |
61 |
- struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); |
62 |
- if (mnt) { |
63 |
+ struct vfsmount *mnt; |
64 |
+ int err = inc_nr_mounts(); |
65 |
+ if (err) |
66 |
+ return ERR_PTR(err); |
67 |
+ |
68 |
+ mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); |
69 |
+ if (!mnt) { |
70 |
+ dec_nr_mounts(); |
71 |
+ return ERR_PTR(-ENOMEM); |
72 |
+ } else { |
73 |
memset(mnt, 0, sizeof(struct vfsmount)); |
74 |
atomic_set(&mnt->mnt_count,1); |
75 |
INIT_LIST_HEAD(&mnt->mnt_hash); |
76 |
@@ -66,6 +97,7 @@ |
77 |
{ |
78 |
kfree(mnt->mnt_devname); |
79 |
kmem_cache_free(mnt_cache, mnt); |
80 |
+ dec_nr_mounts(); |
81 |
} |
82 |
|
83 |
/* |
84 |
@@ -147,13 +179,14 @@ |
85 |
struct super_block *sb = old->mnt_sb; |
86 |
struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); |
87 |
|
88 |
- if (mnt) { |
89 |
+ if (!IS_ERR(mnt)) { |
90 |
mnt->mnt_flags = old->mnt_flags; |
91 |
atomic_inc(&sb->s_active); |
92 |
mnt->mnt_sb = sb; |
93 |
mnt->mnt_root = dget(root); |
94 |
mnt->mnt_mountpoint = mnt->mnt_root; |
95 |
mnt->mnt_parent = mnt; |
96 |
+ mnt->user = capable(CAP_SYS_ADMIN) ? 0 : current->fsuid; |
97 |
} |
98 |
return mnt; |
99 |
} |
100 |
@@ -238,6 +271,8 @@ |
101 |
if (mnt->mnt_flags & fs_infop->flag) |
102 |
seq_puts(m, fs_infop->str); |
103 |
} |
104 |
+ if (mnt->user) |
105 |
+ seq_printf(m, ",user=%i", mnt->user); |
106 |
if (mnt->mnt_sb->s_op->show_options) |
107 |
err = mnt->mnt_sb->s_op->show_options(m, mnt); |
108 |
seq_puts(m, " 0 0\n"); |
109 |
@@ -388,8 +423,10 @@ |
110 |
goto dput_and_out; |
111 |
|
112 |
retval = -EPERM; |
113 |
- if (!capable(CAP_SYS_ADMIN)) |
114 |
- goto dput_and_out; |
115 |
+ if (!capable(CAP_SYS_ADMIN)) { |
116 |
+ if(nd.mnt->user != current->fsuid || (flags & MNT_FORCE)) |
117 |
+ goto dput_and_out; |
118 |
+ } |
119 |
|
120 |
retval = do_umount(nd.mnt, flags); |
121 |
dput_and_out: |
122 |
@@ -409,20 +446,15 @@ |
123 |
|
124 |
static int mount_is_safe(struct nameidata *nd) |
125 |
{ |
126 |
- if (capable(CAP_SYS_ADMIN)) |
127 |
- return 0; |
128 |
- return -EPERM; |
129 |
-#ifdef notyet |
130 |
- if (S_ISLNK(nd->dentry->d_inode->i_mode)) |
131 |
- return -EPERM; |
132 |
- if (nd->dentry->d_inode->i_mode & S_ISVTX) { |
133 |
- if (current->uid != nd->dentry->d_inode->i_uid) |
134 |
+ if (!capable(CAP_SYS_ADMIN)) { |
135 |
+ if (!S_ISDIR(nd->dentry->d_inode->i_mode) && |
136 |
+ !S_ISREG(nd->dentry->d_inode->i_mode)) |
137 |
+ return -EPERM; |
138 |
+ if (current->fsuid != nd->dentry->d_inode->i_uid || |
139 |
+ permission(nd->dentry->d_inode, MAY_WRITE, nd)) |
140 |
return -EPERM; |
141 |
} |
142 |
- if (permission(nd->dentry->d_inode, MAY_WRITE, nd)) |
143 |
- return -EPERM; |
144 |
return 0; |
145 |
-#endif |
146 |
} |
147 |
|
148 |
static int |
149 |
@@ -444,8 +476,8 @@ |
150 |
struct nameidata nd; |
151 |
|
152 |
res = q = clone_mnt(mnt, dentry); |
153 |
- if (!q) |
154 |
- goto Enomem; |
155 |
+ if (IS_ERR(q)) |
156 |
+ goto out_error; |
157 |
q->mnt_mountpoint = mnt->mnt_mountpoint; |
158 |
|
159 |
p = mnt; |
160 |
@@ -463,8 +495,8 @@ |
161 |
nd.mnt = q; |
162 |
nd.dentry = p->mnt_mountpoint; |
163 |
q = clone_mnt(p, p->mnt_root); |
164 |
- if (!q) |
165 |
- goto Enomem; |
166 |
+ if (IS_ERR(q)) |
167 |
+ goto out_error; |
168 |
spin_lock(&vfsmount_lock); |
169 |
list_add_tail(&q->mnt_list, &res->mnt_list); |
170 |
attach_mnt(q, &nd); |
171 |
@@ -472,13 +504,13 @@ |
172 |
} |
173 |
} |
174 |
return res; |
175 |
- Enomem: |
176 |
+ out_error: |
177 |
if (res) { |
178 |
spin_lock(&vfsmount_lock); |
179 |
umount_tree(res); |
180 |
spin_unlock(&vfsmount_lock); |
181 |
} |
182 |
- return NULL; |
183 |
+ return q; |
184 |
} |
185 |
|
186 |
static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) |
187 |
@@ -538,11 +570,14 @@ |
188 |
down_write(¤t->namespace->sem); |
189 |
err = -EINVAL; |
190 |
if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) { |
191 |
- err = -ENOMEM; |
192 |
if (recurse) |
193 |
mnt = copy_tree(old_nd.mnt, old_nd.dentry); |
194 |
else |
195 |
mnt = clone_mnt(old_nd.mnt, old_nd.dentry); |
196 |
+ if (IS_ERR(mnt)) { |
197 |
+ err = PTR_ERR(mnt); |
198 |
+ goto out; |
199 |
+ } |
200 |
} |
201 |
|
202 |
if (mnt) { |
203 |
@@ -555,6 +590,7 @@ |
204 |
mntput(mnt); |
205 |
} |
206 |
|
207 |
+ out: |
208 |
up_write(¤t->namespace->sem); |
209 |
path_release(&old_nd); |
210 |
return err; |
211 |
@@ -654,14 +690,28 @@ |
212 |
int mnt_flags, char *name, void *data) |
213 |
{ |
214 |
struct vfsmount *mnt; |
215 |
- int err; |
216 |
+ int err = mount_is_safe(nd); |
217 |
+ if(err) |
218 |
+ return err; |
219 |
|
220 |
if (!type || !memchr(type, 0, PAGE_SIZE)) |
221 |
return -EINVAL; |
222 |
|
223 |
/* we need capabilities... */ |
224 |
- if (!capable(CAP_SYS_ADMIN)) |
225 |
- return -EPERM; |
226 |
+ if (!capable(CAP_SYS_ADMIN)) { |
227 |
+ /* but allow "safe" filesystems anyway */ |
228 |
+ int issafe = 0; |
229 |
+ struct file_system_type *t = get_fs_type(type); |
230 |
+ if(t) { |
231 |
+ issafe = t->fs_flags & FS_SAFE; |
232 |
+ put_filesystem(t); |
233 |
+ } |
234 |
+ if(!issafe) |
235 |
+ return -EPERM; |
236 |
+ |
237 |
+ /* users should not have suid or dev files */ |
238 |
+ mnt_flags |= (MNT_NOSUID | MNT_NODEV); |
239 |
+ } |
240 |
|
241 |
mnt = do_kern_mount(type, flags, name, data); |
242 |
err = PTR_ERR(mnt); |
243 |
@@ -797,6 +847,7 @@ |
244 |
struct namespace *new_ns; |
245 |
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; |
246 |
struct fs_struct *fs = tsk->fs; |
247 |
+ int err; |
248 |
|
249 |
if (!namespace) |
250 |
return 0; |
251 |
@@ -806,11 +857,7 @@ |
252 |
if (!(flags & CLONE_NEWNS)) |
253 |
return 0; |
254 |
|
255 |
- if (!capable(CAP_SYS_ADMIN)) { |
256 |
- put_namespace(namespace); |
257 |
- return -EPERM; |
258 |
- } |
259 |
- |
260 |
+ err = -ENOMEM; |
261 |
new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); |
262 |
if (!new_ns) |
263 |
goto out; |
264 |
@@ -822,7 +869,8 @@ |
265 |
down_write(&tsk->namespace->sem); |
266 |
/* First pass: copy the tree topology */ |
267 |
new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root); |
268 |
- if (!new_ns->root) { |
269 |
+ if (IS_ERR(new_ns->root)) { |
270 |
+ err = PTR_ERR(new_ns->root); |
271 |
up_write(&tsk->namespace->sem); |
272 |
kfree(new_ns); |
273 |
goto out; |
274 |
@@ -872,7 +920,7 @@ |
275 |
|
276 |
out: |
277 |
put_namespace(namespace); |
278 |
- return -ENOMEM; |
279 |
+ return err; |
280 |
} |
281 |
|
282 |
asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, |
283 |
diff -ru linux-2.6.3-rc4.orig/fs/super.c linux-2.6.3-rc4/fs/super.c |
284 |
--- linux-2.6.3-rc4.orig/fs/super.c 2004-02-17 10:20:40.000000000 +0100 |
285 |
+++ linux-2.6.3-rc4/fs/super.c 2004-02-17 10:17:38.000000000 +0100 |
286 |
@@ -705,7 +705,7 @@ |
287 |
do_kern_mount(const char *fstype, int flags, const char *name, void *data) |
288 |
{ |
289 |
struct file_system_type *type = get_fs_type(fstype); |
290 |
- struct super_block *sb = ERR_PTR(-ENOMEM); |
291 |
+ struct super_block *sb; |
292 |
struct vfsmount *mnt; |
293 |
int error; |
294 |
char *secdata = NULL; |
295 |
@@ -714,24 +714,23 @@ |
296 |
return ERR_PTR(-ENODEV); |
297 |
|
298 |
mnt = alloc_vfsmnt(name); |
299 |
- if (!mnt) |
300 |
+ error = PTR_ERR(mnt); |
301 |
+ if (IS_ERR(mnt)) |
302 |
goto out; |
303 |
|
304 |
if (data) { |
305 |
secdata = alloc_secdata(); |
306 |
- if (!secdata) { |
307 |
- sb = ERR_PTR(-ENOMEM); |
308 |
+ error = -ENOMEM; |
309 |
+ if (!secdata) |
310 |
goto out_mnt; |
311 |
- } |
312 |
|
313 |
error = security_sb_copy_data(fstype, data, secdata); |
314 |
- if (error) { |
315 |
- sb = ERR_PTR(error); |
316 |
+ if (error) |
317 |
goto out_free_secdata; |
318 |
- } |
319 |
} |
320 |
|
321 |
sb = type->get_sb(type, flags, name, data); |
322 |
+ error = PTR_ERR(sb); |
323 |
if (IS_ERR(sb)) |
324 |
goto out_free_secdata; |
325 |
error = security_sb_kern_mount(sb, secdata); |
326 |
@@ -741,20 +740,20 @@ |
327 |
mnt->mnt_root = dget(sb->s_root); |
328 |
mnt->mnt_mountpoint = sb->s_root; |
329 |
mnt->mnt_parent = mnt; |
330 |
+ mnt->user = capable(CAP_SYS_ADMIN) ? 0 : current->fsuid; |
331 |
up_write(&sb->s_umount); |
332 |
put_filesystem(type); |
333 |
return mnt; |
334 |
out_sb: |
335 |
up_write(&sb->s_umount); |
336 |
deactivate_super(sb); |
337 |
- sb = ERR_PTR(error); |
338 |
out_free_secdata: |
339 |
free_secdata(secdata); |
340 |
out_mnt: |
341 |
free_vfsmnt(mnt); |
342 |
out: |
343 |
put_filesystem(type); |
344 |
- return (struct vfsmount *)sb; |
345 |
+ return ERR_PTR(error); |
346 |
} |
347 |
|
348 |
struct vfsmount *kern_mount(struct file_system_type *type) |
349 |
diff -ru linux-2.6.3-rc4.orig/include/linux/fs.h linux-2.6.3-rc4/include/linux/fs.h |
350 |
--- linux-2.6.3-rc4.orig/include/linux/fs.h 2004-02-17 10:20:42.000000000 +0100 |
351 |
+++ linux-2.6.3-rc4/include/linux/fs.h 2004-02-17 10:08:04.000000000 +0100 |
352 |
@@ -55,6 +55,12 @@ |
353 |
}; |
354 |
extern struct files_stat_struct files_stat; |
355 |
|
356 |
+struct mounts_stat_struct { |
357 |
+ int nr_mounts; |
358 |
+ int max_mounts; |
359 |
+}; |
360 |
+extern struct mounts_stat_struct mounts_stat; |
361 |
+ |
362 |
struct inodes_stat_t { |
363 |
int nr_inodes; |
364 |
int nr_unused; |
365 |
@@ -89,6 +95,7 @@ |
366 |
|
367 |
/* public flags for file_system_type */ |
368 |
#define FS_REQUIRES_DEV 1 |
369 |
+#define FS_SAFE 2 /* Safe to mount by user */ |
370 |
#define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */ |
371 |
#define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon |
372 |
* as nfs_rename() will be cleaned up |
373 |
diff -ru linux-2.6.3-rc4.orig/include/linux/mount.h linux-2.6.3-rc4/include/linux/mount.h |
374 |
--- linux-2.6.3-rc4.orig/include/linux/mount.h 2003-12-18 03:58:08.000000000 +0100 |
375 |
+++ linux-2.6.3-rc4/include/linux/mount.h 2004-02-17 10:08:04.000000000 +0100 |
376 |
@@ -30,6 +30,7 @@ |
377 |
atomic_t mnt_count; |
378 |
int mnt_flags; |
379 |
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ |
380 |
+ uid_t user; |
381 |
struct list_head mnt_list; |
382 |
}; |
383 |
|
384 |
diff -ru linux-2.6.3-rc4.orig/include/linux/sysctl.h linux-2.6.3-rc4/include/linux/sysctl.h |
385 |
--- linux-2.6.3-rc4.orig/include/linux/sysctl.h 2004-02-17 10:20:42.000000000 +0100 |
386 |
+++ linux-2.6.3-rc4/include/linux/sysctl.h 2004-02-17 10:08:04.000000000 +0100 |
387 |
@@ -608,8 +608,8 @@ |
388 |
FS_NRFILE=6, /* int:current number of allocated filedescriptors */ |
389 |
FS_MAXFILE=7, /* int:maximum number of filedescriptors that can be allocated */ |
390 |
FS_DENTRY=8, |
391 |
- FS_NRSUPER=9, /* int:current number of allocated super_blocks */ |
392 |
- FS_MAXSUPER=10, /* int:maximum number of super_blocks that can be allocated */ |
393 |
+ FS_NRMOUNT=9, /* int:current number of mounts */ |
394 |
+ FS_MAXMOUNT=10, /* int:maximum number of mounts allowed */ |
395 |
FS_OVERFLOWUID=11, /* int: overflow UID */ |
396 |
FS_OVERFLOWGID=12, /* int: overflow GID */ |
397 |
FS_LEASES=13, /* int: leases enabled */ |
398 |
diff -ru linux-2.6.3-rc4.orig/kernel/sysctl.c linux-2.6.3-rc4/kernel/sysctl.c |
399 |
--- linux-2.6.3-rc4.orig/kernel/sysctl.c 2004-02-17 10:20:43.000000000 +0100 |
400 |
+++ linux-2.6.3-rc4/kernel/sysctl.c 2004-02-17 10:08:04.000000000 +0100 |
401 |
@@ -763,6 +763,22 @@ |
402 |
.proc_handler = &proc_dointvec, |
403 |
}, |
404 |
{ |
405 |
+ .ctl_name = FS_NRMOUNT, |
406 |
+ .procname = "mount-nr", |
407 |
+ .data = &mounts_stat.nr_mounts, |
408 |
+ .maxlen = sizeof(int), |
409 |
+ .mode = 0444, |
410 |
+ .proc_handler = &proc_dointvec, |
411 |
+ }, |
412 |
+ { |
413 |
+ .ctl_name = FS_MAXMOUNT, |
414 |
+ .procname = "mount-max", |
415 |
+ .data = &mounts_stat.max_mounts, |
416 |
+ .maxlen = sizeof(int), |
417 |
+ .mode = 0644, |
418 |
+ .proc_handler = &proc_dointvec, |
419 |
+ }, |
420 |
+ { |
421 |
.ctl_name = FS_OVERFLOWUID, |
422 |
.procname = "overflowuid", |
423 |
.data = &fs_overflowuid, |