diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/Makefile | 1 | ||||
-rw-r--r-- | fs/proc/array.c | 2 | ||||
-rw-r--r-- | fs/proc/base.c | 169 | ||||
-rw-r--r-- | fs/proc/generic.c | 26 | ||||
-rw-r--r-- | fs/proc/inode.c | 6 | ||||
-rw-r--r-- | fs/proc/internal.h | 1 | ||||
-rw-r--r-- | fs/proc/namespaces.c | 185 | ||||
-rw-r--r-- | fs/proc/root.c | 17 | ||||
-rw-r--r-- | fs/proc/self.c | 59 |
9 files changed, 249 insertions, 217 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 99349efbbc2b..981b05601931 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
@@ -21,6 +21,7 @@ proc-y += uptime.o | |||
21 | proc-y += version.o | 21 | proc-y += version.o |
22 | proc-y += softirqs.o | 22 | proc-y += softirqs.o |
23 | proc-y += namespaces.o | 23 | proc-y += namespaces.o |
24 | proc-y += self.o | ||
24 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o | 25 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o |
25 | proc-$(CONFIG_NET) += proc_net.o | 26 | proc-$(CONFIG_NET) += proc_net.o |
26 | proc-$(CONFIG_PROC_KCORE) += kcore.o | 27 | proc-$(CONFIG_PROC_KCORE) += kcore.o |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 060a56a91278..6a91e6ffbcbd 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -162,7 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk) | |||
162 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | 162 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, |
163 | struct pid *pid, struct task_struct *p) | 163 | struct pid *pid, struct task_struct *p) |
164 | { | 164 | { |
165 | struct user_namespace *user_ns = current_user_ns(); | 165 | struct user_namespace *user_ns = seq_user_ns(m); |
166 | struct group_info *group_info; | 166 | struct group_info *group_info; |
167 | int g; | 167 | int g; |
168 | struct fdtable *fdt = NULL; | 168 | struct fdtable *fdt = NULL; |
diff --git a/fs/proc/base.c b/fs/proc/base.c index aa63d25157b8..5a5a0be40e40 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -2345,146 +2345,6 @@ static const struct file_operations proc_coredump_filter_operations = { | |||
2345 | }; | 2345 | }; |
2346 | #endif | 2346 | #endif |
2347 | 2347 | ||
2348 | /* | ||
2349 | * /proc/self: | ||
2350 | */ | ||
2351 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | ||
2352 | int buflen) | ||
2353 | { | ||
2354 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
2355 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
2356 | char tmp[PROC_NUMBUF]; | ||
2357 | if (!tgid) | ||
2358 | return -ENOENT; | ||
2359 | sprintf(tmp, "%d", tgid); | ||
2360 | return vfs_readlink(dentry,buffer,buflen,tmp); | ||
2361 | } | ||
2362 | |||
2363 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
2364 | { | ||
2365 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
2366 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
2367 | char *name = ERR_PTR(-ENOENT); | ||
2368 | if (tgid) { | ||
2369 | /* 11 for max length of signed int in decimal + NULL term */ | ||
2370 | name = kmalloc(12, GFP_KERNEL); | ||
2371 | if (!name) | ||
2372 | name = ERR_PTR(-ENOMEM); | ||
2373 | else | ||
2374 | sprintf(name, "%d", tgid); | ||
2375 | } | ||
2376 | nd_set_link(nd, name); | ||
2377 | return NULL; | ||
2378 | } | ||
2379 | |||
2380 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | ||
2381 | void *cookie) | ||
2382 | { | ||
2383 | char *s = nd_get_link(nd); | ||
2384 | if (!IS_ERR(s)) | ||
2385 | kfree(s); | ||
2386 | } | ||
2387 | |||
2388 | static const struct inode_operations proc_self_inode_operations = { | ||
2389 | .readlink = proc_self_readlink, | ||
2390 | .follow_link = proc_self_follow_link, | ||
2391 | .put_link = proc_self_put_link, | ||
2392 | }; | ||
2393 | |||
2394 | /* | ||
2395 | * proc base | ||
2396 | * | ||
2397 | * These are the directory entries in the root directory of /proc | ||
2398 | * that properly belong to the /proc filesystem, as they describe | ||
2399 | * describe something that is process related. | ||
2400 | */ | ||
2401 | static const struct pid_entry proc_base_stuff[] = { | ||
2402 | NOD("self", S_IFLNK|S_IRWXUGO, | ||
2403 | &proc_self_inode_operations, NULL, {}), | ||
2404 | }; | ||
2405 | |||
2406 | static struct dentry *proc_base_instantiate(struct inode *dir, | ||
2407 | struct dentry *dentry, struct task_struct *task, const void *ptr) | ||
2408 | { | ||
2409 | const struct pid_entry *p = ptr; | ||
2410 | struct inode *inode; | ||
2411 | struct proc_inode *ei; | ||
2412 | struct dentry *error; | ||
2413 | |||
2414 | /* Allocate the inode */ | ||
2415 | error = ERR_PTR(-ENOMEM); | ||
2416 | inode = new_inode(dir->i_sb); | ||
2417 | if (!inode) | ||
2418 | goto out; | ||
2419 | |||
2420 | /* Initialize the inode */ | ||
2421 | ei = PROC_I(inode); | ||
2422 | inode->i_ino = get_next_ino(); | ||
2423 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
2424 | |||
2425 | /* | ||
2426 | * grab the reference to the task. | ||
2427 | */ | ||
2428 | ei->pid = get_task_pid(task, PIDTYPE_PID); | ||
2429 | if (!ei->pid) | ||
2430 | goto out_iput; | ||
2431 | |||
2432 | inode->i_mode = p->mode; | ||
2433 | if (S_ISDIR(inode->i_mode)) | ||
2434 | set_nlink(inode, 2); | ||
2435 | if (S_ISLNK(inode->i_mode)) | ||
2436 | inode->i_size = 64; | ||
2437 | if (p->iop) | ||
2438 | inode->i_op = p->iop; | ||
2439 | if (p->fop) | ||
2440 | inode->i_fop = p->fop; | ||
2441 | ei->op = p->op; | ||
2442 | d_add(dentry, inode); | ||
2443 | error = NULL; | ||
2444 | out: | ||
2445 | return error; | ||
2446 | out_iput: | ||
2447 | iput(inode); | ||
2448 | goto out; | ||
2449 | } | ||
2450 | |||
2451 | static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) | ||
2452 | { | ||
2453 | struct dentry *error; | ||
2454 | struct task_struct *task = get_proc_task(dir); | ||
2455 | const struct pid_entry *p, *last; | ||
2456 | |||
2457 | error = ERR_PTR(-ENOENT); | ||
2458 | |||
2459 | if (!task) | ||
2460 | goto out_no_task; | ||
2461 | |||
2462 | /* Lookup the directory entry */ | ||
2463 | last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1]; | ||
2464 | for (p = proc_base_stuff; p <= last; p++) { | ||
2465 | if (p->len != dentry->d_name.len) | ||
2466 | continue; | ||
2467 | if (!memcmp(dentry->d_name.name, p->name, p->len)) | ||
2468 | break; | ||
2469 | } | ||
2470 | if (p > last) | ||
2471 | goto out; | ||
2472 | |||
2473 | error = proc_base_instantiate(dir, dentry, task, p); | ||
2474 | |||
2475 | out: | ||
2476 | put_task_struct(task); | ||
2477 | out_no_task: | ||
2478 | return error; | ||
2479 | } | ||
2480 | |||
2481 | static int proc_base_fill_cache(struct file *filp, void *dirent, | ||
2482 | filldir_t filldir, struct task_struct *task, const struct pid_entry *p) | ||
2483 | { | ||
2484 | return proc_fill_cache(filp, dirent, filldir, p->name, p->len, | ||
2485 | proc_base_instantiate, task, p); | ||
2486 | } | ||
2487 | |||
2488 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2348 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
2489 | static int do_io_accounting(struct task_struct *task, char *buffer, int whole) | 2349 | static int do_io_accounting(struct task_struct *task, char *buffer, int whole) |
2490 | { | 2350 | { |
@@ -2839,10 +2699,6 @@ void proc_flush_task(struct task_struct *task) | |||
2839 | proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, | 2699 | proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, |
2840 | tgid->numbers[i].nr); | 2700 | tgid->numbers[i].nr); |
2841 | } | 2701 | } |
2842 | |||
2843 | upid = &pid->numbers[pid->level]; | ||
2844 | if (upid->nr == 1) | ||
2845 | pid_ns_release_proc(upid->ns); | ||
2846 | } | 2702 | } |
2847 | 2703 | ||
2848 | static struct dentry *proc_pid_instantiate(struct inode *dir, | 2704 | static struct dentry *proc_pid_instantiate(struct inode *dir, |
@@ -2876,15 +2732,11 @@ out: | |||
2876 | 2732 | ||
2877 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) | 2733 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) |
2878 | { | 2734 | { |
2879 | struct dentry *result; | 2735 | struct dentry *result = NULL; |
2880 | struct task_struct *task; | 2736 | struct task_struct *task; |
2881 | unsigned tgid; | 2737 | unsigned tgid; |
2882 | struct pid_namespace *ns; | 2738 | struct pid_namespace *ns; |
2883 | 2739 | ||
2884 | result = proc_base_lookup(dir, dentry); | ||
2885 | if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) | ||
2886 | goto out; | ||
2887 | |||
2888 | tgid = name_to_int(dentry); | 2740 | tgid = name_to_int(dentry); |
2889 | if (tgid == ~0U) | 2741 | if (tgid == ~0U) |
2890 | goto out; | 2742 | goto out; |
@@ -2947,7 +2799,7 @@ retry: | |||
2947 | return iter; | 2799 | return iter; |
2948 | } | 2800 | } |
2949 | 2801 | ||
2950 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff)) | 2802 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY) |
2951 | 2803 | ||
2952 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 2804 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
2953 | struct tgid_iter iter) | 2805 | struct tgid_iter iter) |
@@ -2967,25 +2819,12 @@ static int fake_filldir(void *buf, const char *name, int namelen, | |||
2967 | /* for the /proc/ directory itself, after non-process stuff has been done */ | 2819 | /* for the /proc/ directory itself, after non-process stuff has been done */ |
2968 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | 2820 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) |
2969 | { | 2821 | { |
2970 | unsigned int nr; | ||
2971 | struct task_struct *reaper; | ||
2972 | struct tgid_iter iter; | 2822 | struct tgid_iter iter; |
2973 | struct pid_namespace *ns; | 2823 | struct pid_namespace *ns; |
2974 | filldir_t __filldir; | 2824 | filldir_t __filldir; |
2975 | 2825 | ||
2976 | if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) | 2826 | if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) |
2977 | goto out_no_task; | 2827 | goto out; |
2978 | nr = filp->f_pos - FIRST_PROCESS_ENTRY; | ||
2979 | |||
2980 | reaper = get_proc_task(filp->f_path.dentry->d_inode); | ||
2981 | if (!reaper) | ||
2982 | goto out_no_task; | ||
2983 | |||
2984 | for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { | ||
2985 | const struct pid_entry *p = &proc_base_stuff[nr]; | ||
2986 | if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) | ||
2987 | goto out; | ||
2988 | } | ||
2989 | 2828 | ||
2990 | ns = filp->f_dentry->d_sb->s_fs_info; | 2829 | ns = filp->f_dentry->d_sb->s_fs_info; |
2991 | iter.task = NULL; | 2830 | iter.task = NULL; |
@@ -3006,8 +2845,6 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
3006 | } | 2845 | } |
3007 | filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; | 2846 | filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; |
3008 | out: | 2847 | out: |
3009 | put_task_struct(reaper); | ||
3010 | out_no_task: | ||
3011 | return 0; | 2848 | return 0; |
3012 | } | 2849 | } |
3013 | 2850 | ||
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 0d80cef4cfb9..7b3ae3cc0ef9 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -350,14 +350,14 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | |||
350 | * Return an inode number between PROC_DYNAMIC_FIRST and | 350 | * Return an inode number between PROC_DYNAMIC_FIRST and |
351 | * 0xffffffff, or zero on failure. | 351 | * 0xffffffff, or zero on failure. |
352 | */ | 352 | */ |
353 | static unsigned int get_inode_number(void) | 353 | int proc_alloc_inum(unsigned int *inum) |
354 | { | 354 | { |
355 | unsigned int i; | 355 | unsigned int i; |
356 | int error; | 356 | int error; |
357 | 357 | ||
358 | retry: | 358 | retry: |
359 | if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0) | 359 | if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) |
360 | return 0; | 360 | return -ENOMEM; |
361 | 361 | ||
362 | spin_lock(&proc_inum_lock); | 362 | spin_lock(&proc_inum_lock); |
363 | error = ida_get_new(&proc_inum_ida, &i); | 363 | error = ida_get_new(&proc_inum_ida, &i); |
@@ -365,18 +365,19 @@ retry: | |||
365 | if (error == -EAGAIN) | 365 | if (error == -EAGAIN) |
366 | goto retry; | 366 | goto retry; |
367 | else if (error) | 367 | else if (error) |
368 | return 0; | 368 | return error; |
369 | 369 | ||
370 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { | 370 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { |
371 | spin_lock(&proc_inum_lock); | 371 | spin_lock(&proc_inum_lock); |
372 | ida_remove(&proc_inum_ida, i); | 372 | ida_remove(&proc_inum_ida, i); |
373 | spin_unlock(&proc_inum_lock); | 373 | spin_unlock(&proc_inum_lock); |
374 | return 0; | 374 | return -ENOSPC; |
375 | } | 375 | } |
376 | return PROC_DYNAMIC_FIRST + i; | 376 | *inum = PROC_DYNAMIC_FIRST + i; |
377 | return 0; | ||
377 | } | 378 | } |
378 | 379 | ||
379 | static void release_inode_number(unsigned int inum) | 380 | void proc_free_inum(unsigned int inum) |
380 | { | 381 | { |
381 | spin_lock(&proc_inum_lock); | 382 | spin_lock(&proc_inum_lock); |
382 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); | 383 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
@@ -554,13 +555,12 @@ static const struct inode_operations proc_dir_inode_operations = { | |||
554 | 555 | ||
555 | static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) | 556 | static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) |
556 | { | 557 | { |
557 | unsigned int i; | ||
558 | struct proc_dir_entry *tmp; | 558 | struct proc_dir_entry *tmp; |
559 | int ret; | ||
559 | 560 | ||
560 | i = get_inode_number(); | 561 | ret = proc_alloc_inum(&dp->low_ino); |
561 | if (i == 0) | 562 | if (ret) |
562 | return -EAGAIN; | 563 | return ret; |
563 | dp->low_ino = i; | ||
564 | 564 | ||
565 | if (S_ISDIR(dp->mode)) { | 565 | if (S_ISDIR(dp->mode)) { |
566 | if (dp->proc_iops == NULL) { | 566 | if (dp->proc_iops == NULL) { |
@@ -764,7 +764,7 @@ EXPORT_SYMBOL(proc_create_data); | |||
764 | 764 | ||
765 | static void free_proc_entry(struct proc_dir_entry *de) | 765 | static void free_proc_entry(struct proc_dir_entry *de) |
766 | { | 766 | { |
767 | release_inode_number(de->low_ino); | 767 | proc_free_inum(de->low_ino); |
768 | 768 | ||
769 | if (S_ISLNK(de->mode)) | 769 | if (S_ISLNK(de->mode)) |
770 | kfree(de->data); | 770 | kfree(de->data); |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 3b22bbdee9ec..439ae6886507 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -31,6 +31,7 @@ static void proc_evict_inode(struct inode *inode) | |||
31 | struct proc_dir_entry *de; | 31 | struct proc_dir_entry *de; |
32 | struct ctl_table_header *head; | 32 | struct ctl_table_header *head; |
33 | const struct proc_ns_operations *ns_ops; | 33 | const struct proc_ns_operations *ns_ops; |
34 | void *ns; | ||
34 | 35 | ||
35 | truncate_inode_pages(&inode->i_data, 0); | 36 | truncate_inode_pages(&inode->i_data, 0); |
36 | clear_inode(inode); | 37 | clear_inode(inode); |
@@ -49,8 +50,9 @@ static void proc_evict_inode(struct inode *inode) | |||
49 | } | 50 | } |
50 | /* Release any associated namespace */ | 51 | /* Release any associated namespace */ |
51 | ns_ops = PROC_I(inode)->ns_ops; | 52 | ns_ops = PROC_I(inode)->ns_ops; |
52 | if (ns_ops && ns_ops->put) | 53 | ns = PROC_I(inode)->ns; |
53 | ns_ops->put(PROC_I(inode)->ns); | 54 | if (ns_ops && ns) |
55 | ns_ops->put(ns); | ||
54 | } | 56 | } |
55 | 57 | ||
56 | static struct kmem_cache * proc_inode_cachep; | 58 | static struct kmem_cache * proc_inode_cachep; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 43973b084abf..252544c05207 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -15,6 +15,7 @@ struct ctl_table_header; | |||
15 | struct mempolicy; | 15 | struct mempolicy; |
16 | 16 | ||
17 | extern struct proc_dir_entry proc_root; | 17 | extern struct proc_dir_entry proc_root; |
18 | extern void proc_self_init(void); | ||
18 | #ifdef CONFIG_PROC_SYSCTL | 19 | #ifdef CONFIG_PROC_SYSCTL |
19 | extern int proc_sys_init(void); | 20 | extern int proc_sys_init(void); |
20 | extern void sysctl_head_put(struct ctl_table_header *head); | 21 | extern void sysctl_head_put(struct ctl_table_header *head); |
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index b178ed733c36..b7a47196c8c3 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <net/net_namespace.h> | 11 | #include <net/net_namespace.h> |
12 | #include <linux/ipc_namespace.h> | 12 | #include <linux/ipc_namespace.h> |
13 | #include <linux/pid_namespace.h> | 13 | #include <linux/pid_namespace.h> |
14 | #include <linux/user_namespace.h> | ||
14 | #include "internal.h" | 15 | #include "internal.h" |
15 | 16 | ||
16 | 17 | ||
@@ -24,12 +25,168 @@ static const struct proc_ns_operations *ns_entries[] = { | |||
24 | #ifdef CONFIG_IPC_NS | 25 | #ifdef CONFIG_IPC_NS |
25 | &ipcns_operations, | 26 | &ipcns_operations, |
26 | #endif | 27 | #endif |
28 | #ifdef CONFIG_PID_NS | ||
29 | &pidns_operations, | ||
30 | #endif | ||
31 | #ifdef CONFIG_USER_NS | ||
32 | &userns_operations, | ||
33 | #endif | ||
34 | &mntns_operations, | ||
27 | }; | 35 | }; |
28 | 36 | ||
29 | static const struct file_operations ns_file_operations = { | 37 | static const struct file_operations ns_file_operations = { |
30 | .llseek = no_llseek, | 38 | .llseek = no_llseek, |
31 | }; | 39 | }; |
32 | 40 | ||
41 | static const struct inode_operations ns_inode_operations = { | ||
42 | .setattr = proc_setattr, | ||
43 | }; | ||
44 | |||
45 | static int ns_delete_dentry(const struct dentry *dentry) | ||
46 | { | ||
47 | /* Don't cache namespace inodes when not in use */ | ||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) | ||
52 | { | ||
53 | struct inode *inode = dentry->d_inode; | ||
54 | const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; | ||
55 | |||
56 | return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", | ||
57 | ns_ops->name, inode->i_ino); | ||
58 | } | ||
59 | |||
60 | const struct dentry_operations ns_dentry_operations = | ||
61 | { | ||
62 | .d_delete = ns_delete_dentry, | ||
63 | .d_dname = ns_dname, | ||
64 | }; | ||
65 | |||
66 | static struct dentry *proc_ns_get_dentry(struct super_block *sb, | ||
67 | struct task_struct *task, const struct proc_ns_operations *ns_ops) | ||
68 | { | ||
69 | struct dentry *dentry, *result; | ||
70 | struct inode *inode; | ||
71 | struct proc_inode *ei; | ||
72 | struct qstr qname = { .name = "", }; | ||
73 | void *ns; | ||
74 | |||
75 | ns = ns_ops->get(task); | ||
76 | if (!ns) | ||
77 | return ERR_PTR(-ENOENT); | ||
78 | |||
79 | dentry = d_alloc_pseudo(sb, &qname); | ||
80 | if (!dentry) { | ||
81 | ns_ops->put(ns); | ||
82 | return ERR_PTR(-ENOMEM); | ||
83 | } | ||
84 | |||
85 | inode = iget_locked(sb, ns_ops->inum(ns)); | ||
86 | if (!inode) { | ||
87 | dput(dentry); | ||
88 | ns_ops->put(ns); | ||
89 | return ERR_PTR(-ENOMEM); | ||
90 | } | ||
91 | |||
92 | ei = PROC_I(inode); | ||
93 | if (inode->i_state & I_NEW) { | ||
94 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
95 | inode->i_op = &ns_inode_operations; | ||
96 | inode->i_mode = S_IFREG | S_IRUGO; | ||
97 | inode->i_fop = &ns_file_operations; | ||
98 | ei->ns_ops = ns_ops; | ||
99 | ei->ns = ns; | ||
100 | unlock_new_inode(inode); | ||
101 | } else { | ||
102 | ns_ops->put(ns); | ||
103 | } | ||
104 | |||
105 | d_set_d_op(dentry, &ns_dentry_operations); | ||
106 | result = d_instantiate_unique(dentry, inode); | ||
107 | if (result) { | ||
108 | dput(dentry); | ||
109 | dentry = result; | ||
110 | } | ||
111 | |||
112 | return dentry; | ||
113 | } | ||
114 | |||
115 | static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
116 | { | ||
117 | struct inode *inode = dentry->d_inode; | ||
118 | struct super_block *sb = inode->i_sb; | ||
119 | struct proc_inode *ei = PROC_I(inode); | ||
120 | struct task_struct *task; | ||
121 | struct dentry *ns_dentry; | ||
122 | void *error = ERR_PTR(-EACCES); | ||
123 | |||
124 | task = get_proc_task(inode); | ||
125 | if (!task) | ||
126 | goto out; | ||
127 | |||
128 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
129 | goto out_put_task; | ||
130 | |||
131 | ns_dentry = proc_ns_get_dentry(sb, task, ei->ns_ops); | ||
132 | if (IS_ERR(ns_dentry)) { | ||
133 | error = ERR_CAST(ns_dentry); | ||
134 | goto out_put_task; | ||
135 | } | ||
136 | |||
137 | dput(nd->path.dentry); | ||
138 | nd->path.dentry = ns_dentry; | ||
139 | error = NULL; | ||
140 | |||
141 | out_put_task: | ||
142 | put_task_struct(task); | ||
143 | out: | ||
144 | return error; | ||
145 | } | ||
146 | |||
147 | static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) | ||
148 | { | ||
149 | struct inode *inode = dentry->d_inode; | ||
150 | struct proc_inode *ei = PROC_I(inode); | ||
151 | const struct proc_ns_operations *ns_ops = ei->ns_ops; | ||
152 | struct task_struct *task; | ||
153 | void *ns; | ||
154 | char name[50]; | ||
155 | int len = -EACCES; | ||
156 | |||
157 | task = get_proc_task(inode); | ||
158 | if (!task) | ||
159 | goto out; | ||
160 | |||
161 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
162 | goto out_put_task; | ||
163 | |||
164 | len = -ENOENT; | ||
165 | ns = ns_ops->get(task); | ||
166 | if (!ns) | ||
167 | goto out_put_task; | ||
168 | |||
169 | snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns)); | ||
170 | len = strlen(name); | ||
171 | |||
172 | if (len > buflen) | ||
173 | len = buflen; | ||
174 | if (copy_to_user(buffer, name, len)) | ||
175 | len = -EFAULT; | ||
176 | |||
177 | ns_ops->put(ns); | ||
178 | out_put_task: | ||
179 | put_task_struct(task); | ||
180 | out: | ||
181 | return len; | ||
182 | } | ||
183 | |||
184 | static const struct inode_operations proc_ns_link_inode_operations = { | ||
185 | .readlink = proc_ns_readlink, | ||
186 | .follow_link = proc_ns_follow_link, | ||
187 | .setattr = proc_setattr, | ||
188 | }; | ||
189 | |||
33 | static struct dentry *proc_ns_instantiate(struct inode *dir, | 190 | static struct dentry *proc_ns_instantiate(struct inode *dir, |
34 | struct dentry *dentry, struct task_struct *task, const void *ptr) | 191 | struct dentry *dentry, struct task_struct *task, const void *ptr) |
35 | { | 192 | { |
@@ -37,21 +194,15 @@ static struct dentry *proc_ns_instantiate(struct inode *dir, | |||
37 | struct inode *inode; | 194 | struct inode *inode; |
38 | struct proc_inode *ei; | 195 | struct proc_inode *ei; |
39 | struct dentry *error = ERR_PTR(-ENOENT); | 196 | struct dentry *error = ERR_PTR(-ENOENT); |
40 | void *ns; | ||
41 | 197 | ||
42 | inode = proc_pid_make_inode(dir->i_sb, task); | 198 | inode = proc_pid_make_inode(dir->i_sb, task); |
43 | if (!inode) | 199 | if (!inode) |
44 | goto out; | 200 | goto out; |
45 | 201 | ||
46 | ns = ns_ops->get(task); | ||
47 | if (!ns) | ||
48 | goto out_iput; | ||
49 | |||
50 | ei = PROC_I(inode); | 202 | ei = PROC_I(inode); |
51 | inode->i_mode = S_IFREG|S_IRUSR; | 203 | inode->i_mode = S_IFLNK|S_IRWXUGO; |
52 | inode->i_fop = &ns_file_operations; | 204 | inode->i_op = &proc_ns_link_inode_operations; |
53 | ei->ns_ops = ns_ops; | 205 | ei->ns_ops = ns_ops; |
54 | ei->ns = ns; | ||
55 | 206 | ||
56 | d_set_d_op(dentry, &pid_dentry_operations); | 207 | d_set_d_op(dentry, &pid_dentry_operations); |
57 | d_add(dentry, inode); | 208 | d_add(dentry, inode); |
@@ -60,9 +211,6 @@ static struct dentry *proc_ns_instantiate(struct inode *dir, | |||
60 | error = NULL; | 211 | error = NULL; |
61 | out: | 212 | out: |
62 | return error; | 213 | return error; |
63 | out_iput: | ||
64 | iput(inode); | ||
65 | goto out; | ||
66 | } | 214 | } |
67 | 215 | ||
68 | static int proc_ns_fill_cache(struct file *filp, void *dirent, | 216 | static int proc_ns_fill_cache(struct file *filp, void *dirent, |
@@ -89,10 +237,6 @@ static int proc_ns_dir_readdir(struct file *filp, void *dirent, | |||
89 | if (!task) | 237 | if (!task) |
90 | goto out_no_task; | 238 | goto out_no_task; |
91 | 239 | ||
92 | ret = -EPERM; | ||
93 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
94 | goto out; | ||
95 | |||
96 | ret = 0; | 240 | ret = 0; |
97 | i = filp->f_pos; | 241 | i = filp->f_pos; |
98 | switch (i) { | 242 | switch (i) { |
@@ -152,10 +296,6 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir, | |||
152 | if (!task) | 296 | if (!task) |
153 | goto out_no_task; | 297 | goto out_no_task; |
154 | 298 | ||
155 | error = ERR_PTR(-EPERM); | ||
156 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
157 | goto out; | ||
158 | |||
159 | last = &ns_entries[ARRAY_SIZE(ns_entries)]; | 299 | last = &ns_entries[ARRAY_SIZE(ns_entries)]; |
160 | for (entry = ns_entries; entry < last; entry++) { | 300 | for (entry = ns_entries; entry < last; entry++) { |
161 | if (strlen((*entry)->name) != len) | 301 | if (strlen((*entry)->name) != len) |
@@ -163,7 +303,6 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir, | |||
163 | if (!memcmp(dentry->d_name.name, (*entry)->name, len)) | 303 | if (!memcmp(dentry->d_name.name, (*entry)->name, len)) |
164 | break; | 304 | break; |
165 | } | 305 | } |
166 | error = ERR_PTR(-ENOENT); | ||
167 | if (entry == last) | 306 | if (entry == last) |
168 | goto out; | 307 | goto out; |
169 | 308 | ||
@@ -198,3 +337,7 @@ out_invalid: | |||
198 | return ERR_PTR(-EINVAL); | 337 | return ERR_PTR(-EINVAL); |
199 | } | 338 | } |
200 | 339 | ||
340 | bool proc_ns_inode(struct inode *inode) | ||
341 | { | ||
342 | return inode->i_fop == &ns_file_operations; | ||
343 | } | ||
diff --git a/fs/proc/root.c b/fs/proc/root.c index 9889a92d2e01..c6e9fac26bac 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -100,14 +100,13 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
100 | int err; | 100 | int err; |
101 | struct super_block *sb; | 101 | struct super_block *sb; |
102 | struct pid_namespace *ns; | 102 | struct pid_namespace *ns; |
103 | struct proc_inode *ei; | ||
104 | char *options; | 103 | char *options; |
105 | 104 | ||
106 | if (flags & MS_KERNMOUNT) { | 105 | if (flags & MS_KERNMOUNT) { |
107 | ns = (struct pid_namespace *)data; | 106 | ns = (struct pid_namespace *)data; |
108 | options = NULL; | 107 | options = NULL; |
109 | } else { | 108 | } else { |
110 | ns = current->nsproxy->pid_ns; | 109 | ns = task_active_pid_ns(current); |
111 | options = data; | 110 | options = data; |
112 | } | 111 | } |
113 | 112 | ||
@@ -130,13 +129,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
130 | sb->s_flags |= MS_ACTIVE; | 129 | sb->s_flags |= MS_ACTIVE; |
131 | } | 130 | } |
132 | 131 | ||
133 | ei = PROC_I(sb->s_root->d_inode); | ||
134 | if (!ei->pid) { | ||
135 | rcu_read_lock(); | ||
136 | ei->pid = get_pid(find_pid_ns(1, ns)); | ||
137 | rcu_read_unlock(); | ||
138 | } | ||
139 | |||
140 | return dget(sb->s_root); | 132 | return dget(sb->s_root); |
141 | } | 133 | } |
142 | 134 | ||
@@ -153,6 +145,7 @@ static struct file_system_type proc_fs_type = { | |||
153 | .name = "proc", | 145 | .name = "proc", |
154 | .mount = proc_mount, | 146 | .mount = proc_mount, |
155 | .kill_sb = proc_kill_sb, | 147 | .kill_sb = proc_kill_sb, |
148 | .fs_flags = FS_USERNS_MOUNT, | ||
156 | }; | 149 | }; |
157 | 150 | ||
158 | void __init proc_root_init(void) | 151 | void __init proc_root_init(void) |
@@ -163,12 +156,8 @@ void __init proc_root_init(void) | |||
163 | err = register_filesystem(&proc_fs_type); | 156 | err = register_filesystem(&proc_fs_type); |
164 | if (err) | 157 | if (err) |
165 | return; | 158 | return; |
166 | err = pid_ns_prepare_proc(&init_pid_ns); | ||
167 | if (err) { | ||
168 | unregister_filesystem(&proc_fs_type); | ||
169 | return; | ||
170 | } | ||
171 | 159 | ||
160 | proc_self_init(); | ||
172 | proc_symlink("mounts", NULL, "self/mounts"); | 161 | proc_symlink("mounts", NULL, "self/mounts"); |
173 | 162 | ||
174 | proc_net_init(); | 163 | proc_net_init(); |
diff --git a/fs/proc/self.c b/fs/proc/self.c new file mode 100644 index 000000000000..aa5cc3bff140 --- /dev/null +++ b/fs/proc/self.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include <linux/proc_fs.h> | ||
2 | #include <linux/sched.h> | ||
3 | #include <linux/namei.h> | ||
4 | |||
5 | /* | ||
6 | * /proc/self: | ||
7 | */ | ||
8 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | ||
9 | int buflen) | ||
10 | { | ||
11 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
12 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
13 | char tmp[PROC_NUMBUF]; | ||
14 | if (!tgid) | ||
15 | return -ENOENT; | ||
16 | sprintf(tmp, "%d", tgid); | ||
17 | return vfs_readlink(dentry,buffer,buflen,tmp); | ||
18 | } | ||
19 | |||
20 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
21 | { | ||
22 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
23 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
24 | char *name = ERR_PTR(-ENOENT); | ||
25 | if (tgid) { | ||
26 | /* 11 for max length of signed int in decimal + NULL term */ | ||
27 | name = kmalloc(12, GFP_KERNEL); | ||
28 | if (!name) | ||
29 | name = ERR_PTR(-ENOMEM); | ||
30 | else | ||
31 | sprintf(name, "%d", tgid); | ||
32 | } | ||
33 | nd_set_link(nd, name); | ||
34 | return NULL; | ||
35 | } | ||
36 | |||
37 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | ||
38 | void *cookie) | ||
39 | { | ||
40 | char *s = nd_get_link(nd); | ||
41 | if (!IS_ERR(s)) | ||
42 | kfree(s); | ||
43 | } | ||
44 | |||
45 | static const struct inode_operations proc_self_inode_operations = { | ||
46 | .readlink = proc_self_readlink, | ||
47 | .follow_link = proc_self_follow_link, | ||
48 | .put_link = proc_self_put_link, | ||
49 | }; | ||
50 | |||
51 | void __init proc_self_init(void) | ||
52 | { | ||
53 | struct proc_dir_entry *proc_self_symlink; | ||
54 | mode_t mode; | ||
55 | |||
56 | mode = S_IFLNK | S_IRWXUGO; | ||
57 | proc_self_symlink = proc_create("self", mode, NULL, NULL ); | ||
58 | proc_self_symlink->proc_iops = &proc_self_inode_operations; | ||
59 | } | ||