Blame view
fs/proc/root.c
4.87 KB
b24413180
|
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c
|
2 3 4 5 6 7 8 |
/* * linux/fs/proc/root.c * * Copyright (C) 1991, 1992 Linus Torvalds * * proc root directory handling functions */ |
7c0f6ba68
|
9 |
#include <linux/uaccess.h> |
1da177e4c
|
10 11 12 13 14 |
#include <linux/errno.h> #include <linux/time.h> #include <linux/proc_fs.h> #include <linux/stat.h> |
1da177e4c
|
15 |
#include <linux/init.h> |
914e26379
|
16 |
#include <linux/sched.h> |
03441a348
|
17 |
#include <linux/sched/stat.h> |
1da177e4c
|
18 19 |
#include <linux/module.h> #include <linux/bitops.h> |
87a8ebd63
|
20 |
#include <linux/user_namespace.h> |
f6c7a1f34
|
21 |
#include <linux/mount.h> |
07543f5c7
|
22 |
#include <linux/pid_namespace.h> |
97412950b
|
23 |
#include <linux/parser.h> |
5b825c3af
|
24 |
#include <linux/cred.h> |
1da177e4c
|
25 |
|
fee781e6c
|
26 |
#include "internal.h" |
97412950b
|
27 |
enum { |
0499680a4
|
28 |
Opt_gid, Opt_hidepid, Opt_err, |
97412950b
|
29 30 31 |
}; static const match_table_t tokens = { |
0499680a4
|
32 33 |
{Opt_hidepid, "hidepid=%u"}, {Opt_gid, "gid=%u"}, |
97412950b
|
34 35 |
{Opt_err, NULL}, }; |
e94591d0d
|
36 |
int proc_parse_options(char *options, struct pid_namespace *pid) |
97412950b
|
37 38 39 |
{ char *p; substring_t args[MAX_OPT_ARGS]; |
0499680a4
|
40 |
int option; |
97412950b
|
41 42 43 44 45 46 47 48 |
if (!options) return 1; while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; |
9fb884421
|
49 |
args[0].to = args[0].from = NULL; |
97412950b
|
50 51 |
token = match_token(p, tokens, args); switch (token) { |
0499680a4
|
52 53 54 |
case Opt_gid: if (match_int(&args[0], &option)) return 0; |
dcb0f2228
|
55 |
pid->pid_gid = make_kgid(current_user_ns(), option); |
0499680a4
|
56 57 58 59 |
break; case Opt_hidepid: if (match_int(&args[0], &option)) return 0; |
796f571b0
|
60 61 |
if (option < HIDEPID_OFF || option > HIDEPID_INVISIBLE) { |
0499680a4
|
62 63 64 65 66 67 |
pr_err("proc: hidepid value must be between 0 and 2. "); return 0; } pid->hide_pid = option; break; |
97412950b
|
68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
default: pr_err("proc: unrecognized mount option \"%s\" " "or missing value ", p); return 0; } } return 1; } int proc_remount(struct super_block *sb, int *flags, char *data) { struct pid_namespace *pid = sb->s_fs_info; |
02b9984d6
|
82 83 |
sync_filesystem(sb); |
97412950b
|
84 85 |
return !proc_parse_options(data, pid); } |
aed1d84f9
|
86 87 |
static struct dentry *proc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) |
1da177e4c
|
88 |
{ |
07543f5c7
|
89 |
struct pid_namespace *ns; |
07543f5c7
|
90 |
|
1751e8a6c
|
91 |
if (flags & SB_KERNMOUNT) { |
e94591d0d
|
92 93 |
ns = data; data = NULL; |
97412950b
|
94 |
} else { |
17cf22c33
|
95 |
ns = task_active_pid_ns(current); |
07543f5c7
|
96 |
} |
e94591d0d
|
97 |
return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super); |
07543f5c7
|
98 99 100 101 102 103 104 |
} static void proc_kill_sb(struct super_block *sb) { struct pid_namespace *ns; ns = (struct pid_namespace *)sb->s_fs_info; |
021ada7df
|
105 106 |
if (ns->proc_self) dput(ns->proc_self); |
0097875bd
|
107 108 |
if (ns->proc_thread_self) dput(ns->proc_thread_self); |
07543f5c7
|
109 110 |
kill_anon_super(sb); put_pid_ns(ns); |
1da177e4c
|
111 |
} |
c2319540c
|
112 |
static struct file_system_type proc_fs_type = { |
1da177e4c
|
113 |
.name = "proc", |
aed1d84f9
|
114 |
.mount = proc_mount, |
07543f5c7
|
115 |
.kill_sb = proc_kill_sb, |
8654df4e2
|
116 |
.fs_flags = FS_USERNS_MOUNT, |
1da177e4c
|
117 |
}; |
1da177e4c
|
118 119 |
void __init proc_root_init(void) { |
195b8cf06
|
120 |
proc_init_kmemcache(); |
1270dd8d9
|
121 |
set_proc_pid_nlink(); |
e656d8a6f
|
122 |
proc_self_init(); |
0097875bd
|
123 |
proc_thread_self_init(); |
155134fef
|
124 |
proc_symlink("mounts", NULL, "self/mounts"); |
457c4cbc5
|
125 126 |
proc_net_init(); |
36a5aeb87
|
127 |
proc_mkdir("fs", NULL); |
928b4d8c8
|
128 |
proc_mkdir("driver", NULL); |
eb6d38d54
|
129 |
proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */ |
1da177e4c
|
130 131 |
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) /* just give it a mountpoint */ |
eb6d38d54
|
132 |
proc_create_mount_point("openprom"); |
1da177e4c
|
133 134 |
#endif proc_tty_init(); |
9c37066d8
|
135 |
proc_mkdir("bus", NULL); |
77b14db50
|
136 |
proc_sys_init(); |
1539d584e
|
137 138 |
register_filesystem(&proc_fs_type); |
1da177e4c
|
139 |
} |
a528d35e8
|
140 141 |
static int proc_root_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags) |
1da177e4c
|
142 |
{ |
a528d35e8
|
143 |
generic_fillattr(d_inode(path->dentry), stat); |
76b6159ba
|
144 145 146 |
stat->nlink = proc_root.nlink + nr_processes(); return 0; } |
1da177e4c
|
147 |
|
00cd8dd3b
|
148 |
static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags) |
76b6159ba
|
149 |
{ |
335eb5315
|
150 |
if (!proc_pid_lookup(dir, dentry, flags)) |
1da177e4c
|
151 |
return NULL; |
1da177e4c
|
152 |
|
335eb5315
|
153 |
return proc_lookup(dir, dentry, flags); |
1da177e4c
|
154 |
} |
f0c3b5093
|
155 |
static int proc_root_readdir(struct file *file, struct dir_context *ctx) |
1da177e4c
|
156 |
{ |
f0c3b5093
|
157 |
if (ctx->pos < FIRST_PROCESS_ENTRY) { |
94fc5d9de
|
158 159 160 |
int error = proc_readdir(file, ctx); if (unlikely(error <= 0)) return error; |
f0c3b5093
|
161 |
ctx->pos = FIRST_PROCESS_ENTRY; |
1da177e4c
|
162 |
} |
1da177e4c
|
163 |
|
f0c3b5093
|
164 |
return proc_pid_readdir(file, ctx); |
1da177e4c
|
165 166 167 168 169 170 171 |
} /* * The root /proc directory is special, as it has the * <pid> directories. Thus we don't use the generic * directory handling functions for that.. */ |
00977a59b
|
172 |
static const struct file_operations proc_root_operations = { |
1da177e4c
|
173 |
.read = generic_read_dir, |
f50752eaa
|
174 175 |
.iterate_shared = proc_root_readdir, .llseek = generic_file_llseek, |
1da177e4c
|
176 177 178 179 180 |
}; /* * proc root can do almost nothing.. */ |
c5ef1c42c
|
181 |
static const struct inode_operations proc_root_inode_operations = { |
1da177e4c
|
182 |
.lookup = proc_root_lookup, |
76b6159ba
|
183 |
.getattr = proc_root_getattr, |
1da177e4c
|
184 185 186 187 188 189 190 191 |
}; /* * This is the root "inode" in the /proc tree.. */ struct proc_dir_entry proc_root = { .low_ino = PROC_ROOT_INO, .namelen = 5, |
1da177e4c
|
192 193 |
.mode = S_IFDIR | S_IRUGO | S_IXUGO, .nlink = 2, |
9cdd83e31
|
194 |
.refcnt = REFCOUNT_INIT(1), |
1da177e4c
|
195 196 197 |
.proc_iops = &proc_root_inode_operations, .proc_fops = &proc_root_operations, .parent = &proc_root, |
4f1134370
|
198 |
.subdir = RB_ROOT, |
24074a35c
|
199 |
.name = "/proc", |
1da177e4c
|
200 |
}; |
6f4e64335
|
201 202 203 204 205 206 207 |
int pid_ns_prepare_proc(struct pid_namespace *ns) { struct vfsmount *mnt; mnt = kern_mount_data(&proc_fs_type, ns); if (IS_ERR(mnt)) return PTR_ERR(mnt); |
579441a39
|
208 |
ns->proc_mnt = mnt; |
6f4e64335
|
209 210 211 212 213 |
return 0; } void pid_ns_release_proc(struct pid_namespace *ns) { |
905ad269c
|
214 |
kern_unmount(ns->proc_mnt); |
6f4e64335
|
215 |
} |