diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 3 | ||||
-rw-r--r-- | fs/proc/base.c | 98 | ||||
-rw-r--r-- | fs/proc/nommu.c | 1 |
3 files changed, 95 insertions, 7 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index d88d518d30f..d84eecacbea 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -74,6 +74,7 @@ | |||
74 | #include <linux/file.h> | 74 | #include <linux/file.h> |
75 | #include <linux/times.h> | 75 | #include <linux/times.h> |
76 | #include <linux/cpuset.h> | 76 | #include <linux/cpuset.h> |
77 | #include <linux/rcupdate.h> | ||
77 | 78 | ||
78 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
79 | #include <asm/pgtable.h> | 80 | #include <asm/pgtable.h> |
@@ -180,12 +181,14 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
180 | p->gid, p->egid, p->sgid, p->fsgid); | 181 | p->gid, p->egid, p->sgid, p->fsgid); |
181 | read_unlock(&tasklist_lock); | 182 | read_unlock(&tasklist_lock); |
182 | task_lock(p); | 183 | task_lock(p); |
184 | rcu_read_lock(); | ||
183 | if (p->files) | 185 | if (p->files) |
184 | fdt = files_fdtable(p->files); | 186 | fdt = files_fdtable(p->files); |
185 | buffer += sprintf(buffer, | 187 | buffer += sprintf(buffer, |
186 | "FDSize:\t%d\n" | 188 | "FDSize:\t%d\n" |
187 | "Groups:\t", | 189 | "Groups:\t", |
188 | fdt ? fdt->max_fds : 0); | 190 | fdt ? fdt->max_fds : 0); |
191 | rcu_read_unlock(); | ||
189 | 192 | ||
190 | group_info = p->group_info; | 193 | group_info = p->group_info; |
191 | get_group_info(group_info); | 194 | get_group_info(group_info); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 23db452ab42..a170450aadb 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -103,7 +103,9 @@ enum pid_directory_inos { | |||
103 | PROC_TGID_NUMA_MAPS, | 103 | PROC_TGID_NUMA_MAPS, |
104 | PROC_TGID_MOUNTS, | 104 | PROC_TGID_MOUNTS, |
105 | PROC_TGID_WCHAN, | 105 | PROC_TGID_WCHAN, |
106 | #ifdef CONFIG_MMU | ||
106 | PROC_TGID_SMAPS, | 107 | PROC_TGID_SMAPS, |
108 | #endif | ||
107 | #ifdef CONFIG_SCHEDSTATS | 109 | #ifdef CONFIG_SCHEDSTATS |
108 | PROC_TGID_SCHEDSTAT, | 110 | PROC_TGID_SCHEDSTAT, |
109 | #endif | 111 | #endif |
@@ -141,7 +143,9 @@ enum pid_directory_inos { | |||
141 | PROC_TID_NUMA_MAPS, | 143 | PROC_TID_NUMA_MAPS, |
142 | PROC_TID_MOUNTS, | 144 | PROC_TID_MOUNTS, |
143 | PROC_TID_WCHAN, | 145 | PROC_TID_WCHAN, |
146 | #ifdef CONFIG_MMU | ||
144 | PROC_TID_SMAPS, | 147 | PROC_TID_SMAPS, |
148 | #endif | ||
145 | #ifdef CONFIG_SCHEDSTATS | 149 | #ifdef CONFIG_SCHEDSTATS |
146 | PROC_TID_SCHEDSTAT, | 150 | PROC_TID_SCHEDSTAT, |
147 | #endif | 151 | #endif |
@@ -195,7 +199,9 @@ static struct pid_entry tgid_base_stuff[] = { | |||
195 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 199 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
196 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 200 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
197 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 201 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
202 | #ifdef CONFIG_MMU | ||
198 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), | 203 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), |
204 | #endif | ||
199 | #ifdef CONFIG_SECURITY | 205 | #ifdef CONFIG_SECURITY |
200 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 206 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
201 | #endif | 207 | #endif |
@@ -235,7 +241,9 @@ static struct pid_entry tid_base_stuff[] = { | |||
235 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 241 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
236 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 242 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
237 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 243 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
244 | #ifdef CONFIG_MMU | ||
238 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), | 245 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), |
246 | #endif | ||
239 | #ifdef CONFIG_SECURITY | 247 | #ifdef CONFIG_SECURITY |
240 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 248 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
241 | #endif | 249 | #endif |
@@ -340,6 +348,54 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf | |||
340 | return result; | 348 | return result; |
341 | } | 349 | } |
342 | 350 | ||
351 | |||
352 | /* Same as proc_root_link, but this addionally tries to get fs from other | ||
353 | * threads in the group */ | ||
354 | static int proc_task_root_link(struct inode *inode, struct dentry **dentry, | ||
355 | struct vfsmount **mnt) | ||
356 | { | ||
357 | struct fs_struct *fs; | ||
358 | int result = -ENOENT; | ||
359 | struct task_struct *leader = proc_task(inode); | ||
360 | |||
361 | task_lock(leader); | ||
362 | fs = leader->fs; | ||
363 | if (fs) { | ||
364 | atomic_inc(&fs->count); | ||
365 | task_unlock(leader); | ||
366 | } else { | ||
367 | /* Try to get fs from other threads */ | ||
368 | task_unlock(leader); | ||
369 | read_lock(&tasklist_lock); | ||
370 | if (pid_alive(leader)) { | ||
371 | struct task_struct *task = leader; | ||
372 | |||
373 | while ((task = next_thread(task)) != leader) { | ||
374 | task_lock(task); | ||
375 | fs = task->fs; | ||
376 | if (fs) { | ||
377 | atomic_inc(&fs->count); | ||
378 | task_unlock(task); | ||
379 | break; | ||
380 | } | ||
381 | task_unlock(task); | ||
382 | } | ||
383 | } | ||
384 | read_unlock(&tasklist_lock); | ||
385 | } | ||
386 | |||
387 | if (fs) { | ||
388 | read_lock(&fs->lock); | ||
389 | *mnt = mntget(fs->rootmnt); | ||
390 | *dentry = dget(fs->root); | ||
391 | read_unlock(&fs->lock); | ||
392 | result = 0; | ||
393 | put_fs_struct(fs); | ||
394 | } | ||
395 | return result; | ||
396 | } | ||
397 | |||
398 | |||
343 | #define MAY_PTRACE(task) \ | 399 | #define MAY_PTRACE(task) \ |
344 | (task == current || \ | 400 | (task == current || \ |
345 | (task->parent == current && \ | 401 | (task->parent == current && \ |
@@ -471,14 +527,14 @@ static int proc_oom_score(struct task_struct *task, char *buffer) | |||
471 | 527 | ||
472 | /* permission checks */ | 528 | /* permission checks */ |
473 | 529 | ||
474 | static int proc_check_root(struct inode *inode) | 530 | /* If the process being read is separated by chroot from the reading process, |
531 | * don't let the reader access the threads. | ||
532 | */ | ||
533 | static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) | ||
475 | { | 534 | { |
476 | struct dentry *de, *base, *root; | 535 | struct dentry *de, *base; |
477 | struct vfsmount *our_vfsmnt, *vfsmnt, *mnt; | 536 | struct vfsmount *our_vfsmnt, *mnt; |
478 | int res = 0; | 537 | int res = 0; |
479 | |||
480 | if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ | ||
481 | return -ENOENT; | ||
482 | read_lock(¤t->fs->lock); | 538 | read_lock(¤t->fs->lock); |
483 | our_vfsmnt = mntget(current->fs->rootmnt); | 539 | our_vfsmnt = mntget(current->fs->rootmnt); |
484 | base = dget(current->fs->root); | 540 | base = dget(current->fs->root); |
@@ -511,6 +567,16 @@ out: | |||
511 | goto exit; | 567 | goto exit; |
512 | } | 568 | } |
513 | 569 | ||
570 | static int proc_check_root(struct inode *inode) | ||
571 | { | ||
572 | struct dentry *root; | ||
573 | struct vfsmount *vfsmnt; | ||
574 | |||
575 | if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ | ||
576 | return -ENOENT; | ||
577 | return proc_check_chroot(root, vfsmnt); | ||
578 | } | ||
579 | |||
514 | static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) | 580 | static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) |
515 | { | 581 | { |
516 | if (generic_permission(inode, mask, NULL) != 0) | 582 | if (generic_permission(inode, mask, NULL) != 0) |
@@ -518,6 +584,20 @@ static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
518 | return proc_check_root(inode); | 584 | return proc_check_root(inode); |
519 | } | 585 | } |
520 | 586 | ||
587 | static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd) | ||
588 | { | ||
589 | struct dentry *root; | ||
590 | struct vfsmount *vfsmnt; | ||
591 | |||
592 | if (generic_permission(inode, mask, NULL) != 0) | ||
593 | return -EACCES; | ||
594 | |||
595 | if (proc_task_root_link(inode, &root, &vfsmnt)) | ||
596 | return -ENOENT; | ||
597 | |||
598 | return proc_check_chroot(root, vfsmnt); | ||
599 | } | ||
600 | |||
521 | extern struct seq_operations proc_pid_maps_op; | 601 | extern struct seq_operations proc_pid_maps_op; |
522 | static int maps_open(struct inode *inode, struct file *file) | 602 | static int maps_open(struct inode *inode, struct file *file) |
523 | { | 603 | { |
@@ -558,6 +638,7 @@ static struct file_operations proc_numa_maps_operations = { | |||
558 | }; | 638 | }; |
559 | #endif | 639 | #endif |
560 | 640 | ||
641 | #ifdef CONFIG_MMU | ||
561 | extern struct seq_operations proc_pid_smaps_op; | 642 | extern struct seq_operations proc_pid_smaps_op; |
562 | static int smaps_open(struct inode *inode, struct file *file) | 643 | static int smaps_open(struct inode *inode, struct file *file) |
563 | { | 644 | { |
@@ -576,6 +657,7 @@ static struct file_operations proc_smaps_operations = { | |||
576 | .llseek = seq_lseek, | 657 | .llseek = seq_lseek, |
577 | .release = seq_release, | 658 | .release = seq_release, |
578 | }; | 659 | }; |
660 | #endif | ||
579 | 661 | ||
580 | extern struct seq_operations mounts_op; | 662 | extern struct seq_operations mounts_op; |
581 | static int mounts_open(struct inode *inode, struct file *file) | 663 | static int mounts_open(struct inode *inode, struct file *file) |
@@ -1419,7 +1501,7 @@ static struct inode_operations proc_fd_inode_operations = { | |||
1419 | 1501 | ||
1420 | static struct inode_operations proc_task_inode_operations = { | 1502 | static struct inode_operations proc_task_inode_operations = { |
1421 | .lookup = proc_task_lookup, | 1503 | .lookup = proc_task_lookup, |
1422 | .permission = proc_permission, | 1504 | .permission = proc_task_permission, |
1423 | }; | 1505 | }; |
1424 | 1506 | ||
1425 | #ifdef CONFIG_SECURITY | 1507 | #ifdef CONFIG_SECURITY |
@@ -1609,10 +1691,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1609 | case PROC_TGID_MOUNTS: | 1691 | case PROC_TGID_MOUNTS: |
1610 | inode->i_fop = &proc_mounts_operations; | 1692 | inode->i_fop = &proc_mounts_operations; |
1611 | break; | 1693 | break; |
1694 | #ifdef CONFIG_MMU | ||
1612 | case PROC_TID_SMAPS: | 1695 | case PROC_TID_SMAPS: |
1613 | case PROC_TGID_SMAPS: | 1696 | case PROC_TGID_SMAPS: |
1614 | inode->i_fop = &proc_smaps_operations; | 1697 | inode->i_fop = &proc_smaps_operations; |
1615 | break; | 1698 | break; |
1699 | #endif | ||
1616 | #ifdef CONFIG_SECURITY | 1700 | #ifdef CONFIG_SECURITY |
1617 | case PROC_TID_ATTR: | 1701 | case PROC_TID_ATTR: |
1618 | inode->i_nlink = 2; | 1702 | inode->i_nlink = 2; |
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index f3bf016d5ee..cff10ab1af6 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c | |||
@@ -91,6 +91,7 @@ static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos) | |||
91 | next = _rb; | 91 | next = _rb; |
92 | break; | 92 | break; |
93 | } | 93 | } |
94 | pos--; | ||
94 | } | 95 | } |
95 | 96 | ||
96 | return next; | 97 | return next; |