Blame view

fs/proc/proc_sysctl.c 40.8 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
2
3
4
  /*
   * /proc/sys support
   */
1e0edd3f6   Alexey Dobriyan   proc: spread __init
5
  #include <linux/init.h>
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
6
  #include <linux/sysctl.h>
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
7
  #include <linux/poll.h>
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
8
  #include <linux/proc_fs.h>
87ebdc00e   Andrew Morton   fs/proc: clean up...
9
  #include <linux/printk.h>
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
10
  #include <linux/security.h>
404015308   Al Viro   security: trim se...
11
  #include <linux/sched.h>
5b825c3af   Ingo Molnar   sched/headers: Pr...
12
  #include <linux/cred.h>
34286d666   Nick Piggin   fs: rcu-walk awar...
13
  #include <linux/namei.h>
404015308   Al Viro   security: trim se...
14
  #include <linux/mm.h>
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
15
  #include <linux/module.h>
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
16
  #include "internal.h"
d72f71eb0   Al Viro   constify dentry_o...
17
  static const struct dentry_operations proc_sys_dentry_operations;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
18
  static const struct file_operations proc_sys_file_operations;
03a44825b   Jan Engelhardt   procfs: constify ...
19
  static const struct inode_operations proc_sys_inode_operations;
9043476f7   Al Viro   [PATCH] sanitize ...
20
21
  static const struct file_operations proc_sys_dir_file_operations;
  static const struct inode_operations proc_sys_dir_operations;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
22

f9bd6733d   Eric W. Biederman   sysctl: Allow cre...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  /* Support for permanently empty directories */
  
  struct ctl_table sysctl_mount_point[] = {
  	{ }
  };
  
  static bool is_empty_dir(struct ctl_table_header *head)
  {
  	return head->ctl_table[0].child == sysctl_mount_point;
  }
  
  static void set_empty_dir(struct ctl_dir *dir)
  {
  	dir->header.ctl_table[0].child = sysctl_mount_point;
  }
  
  static void clear_empty_dir(struct ctl_dir *dir)
  
  {
  	dir->header.ctl_table[0].child = NULL;
  }
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
44
45
46
47
48
49
50
51
  void proc_sys_poll_notify(struct ctl_table_poll *poll)
  {
  	if (!poll)
  		return;
  
  	atomic_inc(&poll->event);
  	wake_up_interruptible(&poll->wait);
  }
a194558e8   Eric W. Biederman   sysctl: Normalize...
52
53
54
  static struct ctl_table root_table[] = {
  	{
  		.procname = "",
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
55
  		.mode = S_IFDIR|S_IRUGO|S_IXUGO,
a194558e8   Eric W. Biederman   sysctl: Normalize...
56
57
58
  	},
  	{ }
  };
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
59
  static struct ctl_table_root sysctl_table_root = {
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
60
  	.default_set.dir.header = {
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
61
62
  		{{.count = 1,
  		  .nreg = 1,
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
63
  		  .ctl_table = root_table }},
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
64
  		.ctl_table_arg = root_table,
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
65
66
67
  		.root = &sysctl_table_root,
  		.set = &sysctl_table_root.default_set,
  	},
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
68
  };
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
69
70
  
  static DEFINE_SPINLOCK(sysctl_lock);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
71
  static void drop_sysctl_table(struct ctl_table_header *header);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
72
  static int sysctl_follow_link(struct ctl_table_header **phead,
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
73
  	struct ctl_table **pentry);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
74
75
  static int insert_links(struct ctl_table_header *head);
  static void put_links(struct ctl_table_header *header);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
76

6980128fe   Eric W. Biederman   sysctl: Add sysct...
77
78
79
80
  static void sysctl_print_dir(struct ctl_dir *dir)
  {
  	if (dir->header.parent)
  		sysctl_print_dir(dir->header.parent);
87ebdc00e   Andrew Morton   fs/proc: clean up...
81
  	pr_cont("%s/", dir->header.ctl_table[0].procname);
6980128fe   Eric W. Biederman   sysctl: Add sysct...
82
  }
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  static int namecmp(const char *name1, int len1, const char *name2, int len2)
  {
  	int minlen;
  	int cmp;
  
  	minlen = len1;
  	if (minlen > len2)
  		minlen = len2;
  
  	cmp = memcmp(name1, name2, minlen);
  	if (cmp == 0)
  		cmp = len1 - len2;
  	return cmp;
  }
60f126d93   Eric W. Biederman   sysctl: Comments ...
97
  /* Called under sysctl_lock */
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
98
  static struct ctl_table *find_entry(struct ctl_table_header **phead,
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
99
  	struct ctl_dir *dir, const char *name, int namelen)
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
100
101
102
  {
  	struct ctl_table_header *head;
  	struct ctl_table *entry;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
103
  	struct rb_node *node = dir->root.rb_node;
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
104

ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  	while (node)
  	{
  		struct ctl_node *ctl_node;
  		const char *procname;
  		int cmp;
  
  		ctl_node = rb_entry(node, struct ctl_node, node);
  		head = ctl_node->header;
  		entry = &head->ctl_table[ctl_node - head->node];
  		procname = entry->procname;
  
  		cmp = namecmp(name, namelen, procname, strlen(procname));
  		if (cmp < 0)
  			node = node->rb_left;
  		else if (cmp > 0)
  			node = node->rb_right;
  		else {
  			*phead = head;
  			return entry;
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
124
125
126
127
  		}
  	}
  	return NULL;
  }
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  static int insert_entry(struct ctl_table_header *head, struct ctl_table *entry)
  {
  	struct rb_node *node = &head->node[entry - head->ctl_table].node;
  	struct rb_node **p = &head->parent->root.rb_node;
  	struct rb_node *parent = NULL;
  	const char *name = entry->procname;
  	int namelen = strlen(name);
  
  	while (*p) {
  		struct ctl_table_header *parent_head;
  		struct ctl_table *parent_entry;
  		struct ctl_node *parent_node;
  		const char *parent_name;
  		int cmp;
  
  		parent = *p;
  		parent_node = rb_entry(parent, struct ctl_node, node);
  		parent_head = parent_node->header;
  		parent_entry = &parent_head->ctl_table[parent_node - parent_head->node];
  		parent_name = parent_entry->procname;
  
  		cmp = namecmp(name, namelen, parent_name, strlen(parent_name));
  		if (cmp < 0)
  			p = &(*p)->rb_left;
  		else if (cmp > 0)
  			p = &(*p)->rb_right;
  		else {
87ebdc00e   Andrew Morton   fs/proc: clean up...
155
  			pr_err("sysctl duplicate entry: ");
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
156
  			sysctl_print_dir(head->parent);
87ebdc00e   Andrew Morton   fs/proc: clean up...
157
158
  			pr_cont("/%s
  ", entry->procname);
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
159
160
161
162
163
  			return -EEXIST;
  		}
  	}
  
  	rb_link_node(node, parent, p);
ea5272f5c   Michel Lespinasse   rbtree: fix incor...
164
  	rb_insert_color(node, &head->parent->root);
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
165
166
167
168
169
170
171
172
173
  	return 0;
  }
  
  static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry)
  {
  	struct rb_node *node = &head->node[entry - head->ctl_table].node;
  
  	rb_erase(node, &head->parent->root);
  }
e0d045290   Eric W. Biederman   sysctl: Factor ou...
174
175
  static void init_header(struct ctl_table_header *head,
  	struct ctl_table_root *root, struct ctl_table_set *set,
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
176
  	struct ctl_node *node, struct ctl_table *table)
e0d045290   Eric W. Biederman   sysctl: Factor ou...
177
  {
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
178
  	head->ctl_table = table;
e0d045290   Eric W. Biederman   sysctl: Factor ou...
179
  	head->ctl_table_arg = table;
e0d045290   Eric W. Biederman   sysctl: Factor ou...
180
181
182
183
184
185
186
  	head->used = 0;
  	head->count = 1;
  	head->nreg = 1;
  	head->unregistering = NULL;
  	head->root = root;
  	head->set = set;
  	head->parent = NULL;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
187
  	head->node = node;
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
188
  	INIT_HLIST_HEAD(&head->inodes);
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
189
190
  	if (node) {
  		struct ctl_table *entry;
4c199a93a   Michel Lespinasse   rbtree: empty nod...
191
  		for (entry = table; entry->procname; entry++, node++)
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
192
  			node->header = head;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
193
  	}
e0d045290   Eric W. Biederman   sysctl: Factor ou...
194
  }
8425d6aaf   Eric W. Biederman   sysctl: Factor ou...
195
196
  static void erase_header(struct ctl_table_header *head)
  {
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
197
198
199
  	struct ctl_table *entry;
  	for (entry = head->ctl_table; entry->procname; entry++)
  		erase_entry(head, entry);
8425d6aaf   Eric W. Biederman   sysctl: Factor ou...
200
  }
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
201
  static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
8425d6aaf   Eric W. Biederman   sysctl: Factor ou...
202
  {
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
203
  	struct ctl_table *entry;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
204
  	int err;
f9bd6733d   Eric W. Biederman   sysctl: Allow cre...
205
206
207
208
209
210
211
212
213
214
  	/* Is this a permanently empty directory? */
  	if (is_empty_dir(&dir->header))
  		return -EROFS;
  
  	/* Am I creating a permanently empty directory? */
  	if (header->ctl_table == sysctl_mount_point) {
  		if (!RB_EMPTY_ROOT(&dir->root))
  			return -EINVAL;
  		set_empty_dir(dir);
  	}
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
215
  	dir->header.nreg++;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
216
  	header->parent = dir;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
217
218
219
  	err = insert_links(header);
  	if (err)
  		goto fail_links;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
220
221
222
223
224
  	for (entry = header->ctl_table; entry->procname; entry++) {
  		err = insert_entry(header, entry);
  		if (err)
  			goto fail;
  	}
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
225
  	return 0;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
226
227
228
  fail:
  	erase_header(header);
  	put_links(header);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
229
  fail_links:
f9bd6733d   Eric W. Biederman   sysctl: Allow cre...
230
231
  	if (header->ctl_table == sysctl_mount_point)
  		clear_empty_dir(dir);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
232
233
234
  	header->parent = NULL;
  	drop_sysctl_table(&dir->header);
  	return err;
8425d6aaf   Eric W. Biederman   sysctl: Factor ou...
235
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  /* called under sysctl_lock */
  static int use_table(struct ctl_table_header *p)
  {
  	if (unlikely(p->unregistering))
  		return 0;
  	p->used++;
  	return 1;
  }
  
  /* called under sysctl_lock */
  static void unuse_table(struct ctl_table_header *p)
  {
  	if (!--p->used)
  		if (unlikely(p->unregistering))
  			complete(p->unregistering);
  }
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
252
253
  static void proc_sys_prune_dcache(struct ctl_table_header *head)
  {
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
254
  	struct inode *inode;
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
255
  	struct proc_inode *ei;
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
256
257
  	struct hlist_node *node;
  	struct super_block *sb;
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
258

ace0c791e   Eric W. Biederman   proc/sysctl: Don'...
259
  	rcu_read_lock();
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  	for (;;) {
  		node = hlist_first_rcu(&head->inodes);
  		if (!node)
  			break;
  		ei = hlist_entry(node, struct proc_inode, sysctl_inodes);
  		spin_lock(&sysctl_lock);
  		hlist_del_init_rcu(&ei->sysctl_inodes);
  		spin_unlock(&sysctl_lock);
  
  		inode = &ei->vfs_inode;
  		sb = inode->i_sb;
  		if (!atomic_inc_not_zero(&sb->s_active))
  			continue;
  		inode = igrab(inode);
  		rcu_read_unlock();
  		if (unlikely(!inode)) {
  			deactivate_super(sb);
ace0c791e   Eric W. Biederman   proc/sysctl: Don'...
277
  			rcu_read_lock();
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
278
  			continue;
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
279
  		}
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
280
281
282
283
284
285
  
  		d_prune_aliases(inode);
  		iput(inode);
  		deactivate_super(sb);
  
  		rcu_read_lock();
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
286
  	}
ace0c791e   Eric W. Biederman   proc/sysctl: Don'...
287
  	rcu_read_unlock();
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
288
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
289
290
291
292
293
294
295
296
297
298
299
300
301
  /* called under sysctl_lock, will reacquire if has to wait */
  static void start_unregistering(struct ctl_table_header *p)
  {
  	/*
  	 * if p->used is 0, nobody will ever touch that entry again;
  	 * we'll eliminate all paths to it before dropping sysctl_lock
  	 */
  	if (unlikely(p->used)) {
  		struct completion wait;
  		init_completion(&wait);
  		p->unregistering = &wait;
  		spin_unlock(&sysctl_lock);
  		wait_for_completion(&wait);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
302
303
304
  	} else {
  		/* anything non-NULL; we'll never dereference it */
  		p->unregistering = ERR_PTR(-EINVAL);
ace0c791e   Eric W. Biederman   proc/sysctl: Don'...
305
  		spin_unlock(&sysctl_lock);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
306
307
  	}
  	/*
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
308
309
310
311
312
  	 * Prune dentries for unregistered sysctls: namespaced sysctls
  	 * can have duplicate names and contaminate dcache very badly.
  	 */
  	proc_sys_prune_dcache(p);
  	/*
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
313
314
315
  	 * do not remove from the list until nobody holds it; walking the
  	 * list in do_sysctl() relies on that.
  	 */
ace0c791e   Eric W. Biederman   proc/sysctl: Don'...
316
  	spin_lock(&sysctl_lock);
8425d6aaf   Eric W. Biederman   sysctl: Factor ou...
317
  	erase_header(p);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
318
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
319
320
  static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
  {
ab4a1f247   Prasad Joshi   proc_sysctl.c: us...
321
  	BUG_ON(!head);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  	spin_lock(&sysctl_lock);
  	if (!use_table(head))
  		head = ERR_PTR(-ENOENT);
  	spin_unlock(&sysctl_lock);
  	return head;
  }
  
  static void sysctl_head_finish(struct ctl_table_header *head)
  {
  	if (!head)
  		return;
  	spin_lock(&sysctl_lock);
  	unuse_table(head);
  	spin_unlock(&sysctl_lock);
  }
  
  static struct ctl_table_set *
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
339
  lookup_header_set(struct ctl_table_root *root)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
340
341
342
  {
  	struct ctl_table_set *set = &root->default_set;
  	if (root->lookup)
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
343
  		set = root->lookup(root);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
344
345
  	return set;
  }
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
346
  static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
347
  				      struct ctl_dir *dir,
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
348
349
350
351
  				      const char *name, int namelen)
  {
  	struct ctl_table_header *head;
  	struct ctl_table *entry;
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
352
353
  
  	spin_lock(&sysctl_lock);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
354
355
356
357
358
  	entry = find_entry(&head, dir, name, namelen);
  	if (entry && use_table(head))
  		*phead = head;
  	else
  		entry = NULL;
076c3eed2   Eric W. Biederman   sysctl: Rewrite p...
359
360
361
  	spin_unlock(&sysctl_lock);
  	return entry;
  }
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
362
  static struct ctl_node *first_usable_entry(struct rb_node *node)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
363
  {
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
364
  	struct ctl_node *ctl_node;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
365

ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
366
367
368
369
  	for (;node; node = rb_next(node)) {
  		ctl_node = rb_entry(node, struct ctl_node, node);
  		if (use_table(ctl_node->header))
  			return ctl_node;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
370
  	}
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
371
372
  	return NULL;
  }
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
373
  static void first_entry(struct ctl_dir *dir,
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
374
375
  	struct ctl_table_header **phead, struct ctl_table **pentry)
  {
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
376
  	struct ctl_table_header *head = NULL;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
377
  	struct ctl_table *entry = NULL;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
378
  	struct ctl_node *ctl_node;
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
379
380
  
  	spin_lock(&sysctl_lock);
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
381
  	ctl_node = first_usable_entry(rb_first(&dir->root));
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
382
  	spin_unlock(&sysctl_lock);
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
383
384
385
386
  	if (ctl_node) {
  		head = ctl_node->header;
  		entry = &head->ctl_table[ctl_node - head->node];
  	}
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
387
388
389
  	*phead = head;
  	*pentry = entry;
  }
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
390
  static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
391
  {
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
392
393
  	struct ctl_table_header *head = *phead;
  	struct ctl_table *entry = *pentry;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
394
  	struct ctl_node *ctl_node = &head->node[entry - head->ctl_table];
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
395

ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
396
397
398
399
400
401
402
403
404
  	spin_lock(&sysctl_lock);
  	unuse_table(head);
  
  	ctl_node = first_usable_entry(rb_next(&ctl_node->node));
  	spin_unlock(&sysctl_lock);
  	head = NULL;
  	if (ctl_node) {
  		head = ctl_node->header;
  		entry = &head->ctl_table[ctl_node - head->node];
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
405
406
407
  	}
  	*phead = head;
  	*pentry = entry;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
408
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
409
410
411
412
413
414
415
  /*
   * sysctl_perm does NOT grant the superuser all rights automatically, because
   * some sysctl variables are readonly even to root.
   */
  
  static int test_perm(int mode, int op)
  {
091bd3ea4   Eric W. Biederman   userns: Convert s...
416
  	if (uid_eq(current_euid(), GLOBAL_ROOT_UID))
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
417
  		mode >>= 6;
091bd3ea4   Eric W. Biederman   userns: Convert s...
418
  	else if (in_egroup_p(GLOBAL_ROOT_GID))
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
419
420
421
422
423
  		mode >>= 3;
  	if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
  		return 0;
  	return -EACCES;
  }
73f7ef435   Eric W. Biederman   sysctl: Pass usef...
424
  static int sysctl_perm(struct ctl_table_header *head, struct ctl_table *table, int op)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
425
  {
73f7ef435   Eric W. Biederman   sysctl: Pass usef...
426
  	struct ctl_table_root *root = head->root;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
427
428
429
  	int mode;
  
  	if (root->permissions)
73f7ef435   Eric W. Biederman   sysctl: Pass usef...
430
  		mode = root->permissions(head, table);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
431
432
433
434
435
  	else
  		mode = table->mode;
  
  	return test_perm(mode, op);
  }
9043476f7   Al Viro   [PATCH] sanitize ...
436
437
  static struct inode *proc_sys_make_inode(struct super_block *sb,
  		struct ctl_table_header *head, struct ctl_table *table)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
438
  {
e79c6a4fc   Dmitry Torokhov   net: make net nam...
439
  	struct ctl_table_root *root = head->root;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
440
  	struct inode *inode;
9043476f7   Al Viro   [PATCH] sanitize ...
441
  	struct proc_inode *ei;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
442

9043476f7   Al Viro   [PATCH] sanitize ...
443
  	inode = new_inode(sb);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
444
445
  	if (!inode)
  		goto out;
85fe4025c   Christoph Hellwig   fs: do not assign...
446
  	inode->i_ino = get_next_ino();
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
447
  	ei = PROC_I(inode);
9043476f7   Al Viro   [PATCH] sanitize ...
448

d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
449
  	spin_lock(&sysctl_lock);
ace0c791e   Eric W. Biederman   proc/sysctl: Don'...
450
451
452
453
454
455
456
457
  	if (unlikely(head->unregistering)) {
  		spin_unlock(&sysctl_lock);
  		iput(inode);
  		inode = NULL;
  		goto out;
  	}
  	ei->sysctl = head;
  	ei->sysctl_entry = table;
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
458
  	hlist_add_head_rcu(&ei->sysctl_inodes, &head->inodes);
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
459
460
  	head->count++;
  	spin_unlock(&sysctl_lock);
078cd8279   Deepa Dinamani   fs: Replace CURRE...
461
  	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
9043476f7   Al Viro   [PATCH] sanitize ...
462
  	inode->i_mode = table->mode;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
463
  	if (!S_ISDIR(table->mode)) {
9043476f7   Al Viro   [PATCH] sanitize ...
464
465
466
467
468
  		inode->i_mode |= S_IFREG;
  		inode->i_op = &proc_sys_inode_operations;
  		inode->i_fop = &proc_sys_file_operations;
  	} else {
  		inode->i_mode |= S_IFDIR;
9043476f7   Al Viro   [PATCH] sanitize ...
469
470
  		inode->i_op = &proc_sys_dir_operations;
  		inode->i_fop = &proc_sys_dir_file_operations;
f9bd6733d   Eric W. Biederman   sysctl: Allow cre...
471
472
  		if (is_empty_dir(head))
  			make_empty_dir_inode(inode);
9043476f7   Al Viro   [PATCH] sanitize ...
473
  	}
e79c6a4fc   Dmitry Torokhov   net: make net nam...
474
475
476
  
  	if (root->set_ownership)
  		root->set_ownership(head, table, &inode->i_uid, &inode->i_gid);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
477
478
479
  out:
  	return inode;
  }
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
480
481
482
  void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head)
  {
  	spin_lock(&sysctl_lock);
2fd1d2c4c   Eric W. Biederman   proc: Fix proc_sy...
483
  	hlist_del_init_rcu(&PROC_I(inode)->sysctl_inodes);
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
484
485
486
487
  	if (!--head->count)
  		kfree_rcu(head, rcu);
  	spin_unlock(&sysctl_lock);
  }
81324364b   Adrian Bunk   proc: make grab_h...
488
  static struct ctl_table_header *grab_header(struct inode *inode)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
489
  {
3cc3e0463   Eric W. Biederman   sysctl: A more ob...
490
491
  	struct ctl_table_header *head = PROC_I(inode)->sysctl;
  	if (!head)
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
492
  		head = &sysctl_table_root.default_set.dir.header;
3cc3e0463   Eric W. Biederman   sysctl: A more ob...
493
  	return sysctl_head_grab(head);
9043476f7   Al Viro   [PATCH] sanitize ...
494
  }
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
495

9043476f7   Al Viro   [PATCH] sanitize ...
496
  static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
497
  					unsigned int flags)
9043476f7   Al Viro   [PATCH] sanitize ...
498
499
  {
  	struct ctl_table_header *head = grab_header(dir);
9043476f7   Al Viro   [PATCH] sanitize ...
500
  	struct ctl_table_header *h = NULL;
dc12e9094   Al Viro   qstr: constify in...
501
  	const struct qstr *name = &dentry->d_name;
9043476f7   Al Viro   [PATCH] sanitize ...
502
503
504
  	struct ctl_table *p;
  	struct inode *inode;
  	struct dentry *err = ERR_PTR(-ENOENT);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
505
  	struct ctl_dir *ctl_dir;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
506
  	int ret;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
507

9043476f7   Al Viro   [PATCH] sanitize ...
508
509
  	if (IS_ERR(head))
  		return ERR_CAST(head);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
510

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
511
  	ctl_dir = container_of(head, struct ctl_dir, header);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
512

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
513
  	p = lookup_entry(&h, ctl_dir, name->name, name->len);
9043476f7   Al Viro   [PATCH] sanitize ...
514
  	if (!p)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
515
  		goto out;
4e7573203   Eric W. Biederman   sysctl: Don't cal...
516
  	if (S_ISLNK(p->mode)) {
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
517
  		ret = sysctl_follow_link(&h, &p);
4e7573203   Eric W. Biederman   sysctl: Don't cal...
518
519
520
521
  		err = ERR_PTR(ret);
  		if (ret)
  			goto out;
  	}
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
522

77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
523
  	err = ERR_PTR(-ENOMEM);
9043476f7   Al Viro   [PATCH] sanitize ...
524
  	inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
525
526
527
528
  	if (!inode)
  		goto out;
  
  	err = NULL;
fb045adb9   Nick Piggin   fs: dcache reduce...
529
  	d_set_d_op(dentry, &proc_sys_dentry_operations);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
530
531
532
  	d_add(dentry, inode);
  
  out:
6bf610457   Francesco Ruggeri   fs/proc: fix pote...
533
534
  	if (h)
  		sysctl_head_finish(h);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
535
536
537
  	sysctl_head_finish(head);
  	return err;
  }
7708bfb1c   Pavel Emelyanov   sysctl: merge equ...
538
539
  static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
  		size_t count, loff_t *ppos, int write)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
540
  {
496ad9aa8   Al Viro   new helper: file_...
541
  	struct inode *inode = file_inode(filp);
9043476f7   Al Viro   [PATCH] sanitize ...
542
543
  	struct ctl_table_header *head = grab_header(inode);
  	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
2a2da53b1   David Howells   Fix pointer misma...
544
545
  	ssize_t error;
  	size_t res;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
546

9043476f7   Al Viro   [PATCH] sanitize ...
547
548
  	if (IS_ERR(head))
  		return PTR_ERR(head);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
549
550
551
552
553
554
  
  	/*
  	 * At this point we know that the sysctl was not unregistered
  	 * and won't be until we finish.
  	 */
  	error = -EPERM;
73f7ef435   Eric W. Biederman   sysctl: Pass usef...
555
  	if (sysctl_perm(head, table, write ? MAY_WRITE : MAY_READ))
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
556
  		goto out;
9043476f7   Al Viro   [PATCH] sanitize ...
557
558
559
560
  	/* if that can happen at all, it should be -EINVAL, not -EISDIR */
  	error = -EINVAL;
  	if (!table->proc_handler)
  		goto out;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
561
562
  	/* careful: calling conventions are nasty here */
  	res = count;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
563
  	error = table->proc_handler(table, write, buf, &res, ppos);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
564
565
566
567
568
569
570
  	if (!error)
  		error = res;
  out:
  	sysctl_head_finish(head);
  
  	return error;
  }
7708bfb1c   Pavel Emelyanov   sysctl: merge equ...
571
  static ssize_t proc_sys_read(struct file *filp, char __user *buf,
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
572
573
  				size_t count, loff_t *ppos)
  {
7708bfb1c   Pavel Emelyanov   sysctl: merge equ...
574
575
  	return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
  }
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
576

7708bfb1c   Pavel Emelyanov   sysctl: merge equ...
577
578
579
580
  static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
  				size_t count, loff_t *ppos)
  {
  	return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
581
  }
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
582
583
  static int proc_sys_open(struct inode *inode, struct file *filp)
  {
4e474a00d   Lucas De Marchi   sysctl: protect p...
584
  	struct ctl_table_header *head = grab_header(inode);
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
585
  	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
4e474a00d   Lucas De Marchi   sysctl: protect p...
586
587
588
  	/* sysctl was unregistered */
  	if (IS_ERR(head))
  		return PTR_ERR(head);
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
589
590
  	if (table->poll)
  		filp->private_data = proc_sys_poll_event(table->poll);
4e474a00d   Lucas De Marchi   sysctl: protect p...
591
  	sysctl_head_finish(head);
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
592
593
594
595
596
  	return 0;
  }
  
  static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
  {
496ad9aa8   Al Viro   new helper: file_...
597
  	struct inode *inode = file_inode(filp);
4e474a00d   Lucas De Marchi   sysctl: protect p...
598
  	struct ctl_table_header *head = grab_header(inode);
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
599
  	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
600
  	unsigned int ret = DEFAULT_POLLMASK;
4e474a00d   Lucas De Marchi   sysctl: protect p...
601
602
603
604
605
  	unsigned long event;
  
  	/* sysctl was unregistered */
  	if (IS_ERR(head))
  		return POLLERR | POLLHUP;
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
606
607
608
609
610
611
  
  	if (!table->proc_handler)
  		goto out;
  
  	if (!table->poll)
  		goto out;
4e474a00d   Lucas De Marchi   sysctl: protect p...
612
  	event = (unsigned long)filp->private_data;
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
613
614
615
616
617
618
619
620
  	poll_wait(filp, &table->poll->wait, wait);
  
  	if (event != atomic_read(&table->poll->event)) {
  		filp->private_data = proc_sys_poll_event(table->poll);
  		ret = POLLIN | POLLRDNORM | POLLERR | POLLPRI;
  	}
  
  out:
4e474a00d   Lucas De Marchi   sysctl: protect p...
621
  	sysctl_head_finish(head);
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
622
623
  	return ret;
  }
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
624

f0c3b5093   Al Viro   [readdir] convert...
625
626
  static bool proc_sys_fill_cache(struct file *file,
  				struct dir_context *ctx,
9043476f7   Al Viro   [PATCH] sanitize ...
627
628
  				struct ctl_table_header *head,
  				struct ctl_table *table)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
629
  {
f0c3b5093   Al Viro   [readdir] convert...
630
  	struct dentry *child, *dir = file->f_path.dentry;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
631
632
633
634
  	struct inode *inode;
  	struct qstr qname;
  	ino_t ino = 0;
  	unsigned type = DT_UNKNOWN;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
635
636
637
  
  	qname.name = table->procname;
  	qname.len  = strlen(table->procname);
8387ff257   Linus Torvalds   vfs: make the str...
638
  	qname.hash = full_name_hash(dir, qname.name, qname.len);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
639

77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
640
641
  	child = d_lookup(dir, &qname);
  	if (!child) {
76aab3ab6   Al Viro   proc_sys_fill_cac...
642
643
644
645
646
  		DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
  		child = d_alloc_parallel(dir, &qname, &wq);
  		if (IS_ERR(child))
  			return false;
  		if (d_in_lookup(child)) {
9043476f7   Al Viro   [PATCH] sanitize ...
647
648
  			inode = proc_sys_make_inode(dir->d_sb, head, table);
  			if (!inode) {
76aab3ab6   Al Viro   proc_sys_fill_cac...
649
  				d_lookup_done(child);
9043476f7   Al Viro   [PATCH] sanitize ...
650
  				dput(child);
f0c3b5093   Al Viro   [readdir] convert...
651
  				return false;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
652
  			}
76aab3ab6   Al Viro   proc_sys_fill_cac...
653
654
  			d_set_d_op(child, &proc_sys_dentry_operations);
  			d_add(child, inode);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
655
656
  		}
  	}
2b0143b5c   David Howells   VFS: normal files...
657
  	inode = d_inode(child);
9043476f7   Al Viro   [PATCH] sanitize ...
658
659
  	ino  = inode->i_ino;
  	type = inode->i_mode >> 12;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
660
  	dput(child);
f0c3b5093   Al Viro   [readdir] convert...
661
  	return dir_emit(ctx, qname.name, qname.len, ino, type);
9043476f7   Al Viro   [PATCH] sanitize ...
662
  }
f0c3b5093   Al Viro   [readdir] convert...
663
664
  static bool proc_sys_link_fill_cache(struct file *file,
  				    struct dir_context *ctx,
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
665
666
667
  				    struct ctl_table_header *head,
  				    struct ctl_table *table)
  {
f0c3b5093   Al Viro   [readdir] convert...
668
  	bool ret = true;
9c9844d9c   Danilo Krummrich   fs/proc/proc_sysc...
669

0e47c99d7   Eric W. Biederman   sysctl: Replace r...
670
  	head = sysctl_head_grab(head);
9c9844d9c   Danilo Krummrich   fs/proc/proc_sysc...
671
672
  	if (IS_ERR(head))
  		return false;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
673

4e7573203   Eric W. Biederman   sysctl: Don't cal...
674
675
  	if (S_ISLNK(table->mode)) {
  		/* It is not an error if we can not follow the link ignore it */
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
676
  		int err = sysctl_follow_link(&head, &table);
4e7573203   Eric W. Biederman   sysctl: Don't cal...
677
678
679
  		if (err)
  			goto out;
  	}
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
680

f0c3b5093   Al Viro   [readdir] convert...
681
  	ret = proc_sys_fill_cache(file, ctx, head, table);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
682
683
684
685
  out:
  	sysctl_head_finish(head);
  	return ret;
  }
e5eea0981   Joe Perches   sysctl: remove ty...
686
  static int scan(struct ctl_table_header *head, struct ctl_table *table,
9043476f7   Al Viro   [PATCH] sanitize ...
687
  		unsigned long *pos, struct file *file,
f0c3b5093   Al Viro   [readdir] convert...
688
  		struct dir_context *ctx)
9043476f7   Al Viro   [PATCH] sanitize ...
689
  {
f0c3b5093   Al Viro   [readdir] convert...
690
  	bool res;
9043476f7   Al Viro   [PATCH] sanitize ...
691

f0c3b5093   Al Viro   [readdir] convert...
692
693
  	if ((*pos)++ < ctx->pos)
  		return true;
9043476f7   Al Viro   [PATCH] sanitize ...
694

0e47c99d7   Eric W. Biederman   sysctl: Replace r...
695
  	if (unlikely(S_ISLNK(table->mode)))
f0c3b5093   Al Viro   [readdir] convert...
696
  		res = proc_sys_link_fill_cache(file, ctx, head, table);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
697
  	else
f0c3b5093   Al Viro   [readdir] convert...
698
  		res = proc_sys_fill_cache(file, ctx, head, table);
9043476f7   Al Viro   [PATCH] sanitize ...
699

f0c3b5093   Al Viro   [readdir] convert...
700
701
  	if (res)
  		ctx->pos = *pos;
9043476f7   Al Viro   [PATCH] sanitize ...
702

6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
703
  	return res;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
704
  }
f0c3b5093   Al Viro   [readdir] convert...
705
  static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
706
  {
f0c3b5093   Al Viro   [readdir] convert...
707
  	struct ctl_table_header *head = grab_header(file_inode(file));
9043476f7   Al Viro   [PATCH] sanitize ...
708
  	struct ctl_table_header *h = NULL;
6a75ce167   Eric W. Biederman   sysctl: Rewrite p...
709
  	struct ctl_table *entry;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
710
  	struct ctl_dir *ctl_dir;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
711
  	unsigned long pos;
9043476f7   Al Viro   [PATCH] sanitize ...
712
713
714
  
  	if (IS_ERR(head))
  		return PTR_ERR(head);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
715

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
716
  	ctl_dir = container_of(head, struct ctl_dir, header);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
717

f0c3b5093   Al Viro   [readdir] convert...
718
  	if (!dir_emit_dots(file, ctx))
93362fa47   Zhou Chengming   sysctl: Drop refe...
719
  		goto out;
f0c3b5093   Al Viro   [readdir] convert...
720

77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
721
  	pos = 2;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
722
  	for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
f0c3b5093   Al Viro   [readdir] convert...
723
  		if (!scan(h, entry, &pos, file, ctx)) {
9043476f7   Al Viro   [PATCH] sanitize ...
724
725
  			sysctl_head_finish(h);
  			break;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
726
727
  		}
  	}
93362fa47   Zhou Chengming   sysctl: Drop refe...
728
  out:
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
729
  	sysctl_head_finish(head);
f0c3b5093   Al Viro   [readdir] convert...
730
  	return 0;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
731
  }
10556cb21   Al Viro   ->permission() sa...
732
  static int proc_sys_permission(struct inode *inode, int mask)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
733
734
735
736
737
  {
  	/*
  	 * sysctl entries that are not writeable,
  	 * are _NOT_ writeable, capabilities or not.
  	 */
f696a3659   Miklos Szeredi   [PATCH] move exec...
738
739
  	struct ctl_table_header *head;
  	struct ctl_table *table;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
740
  	int error;
f696a3659   Miklos Szeredi   [PATCH] move exec...
741
742
743
744
745
  	/* Executable files are not allowed under /proc/sys/ */
  	if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
  		return -EACCES;
  
  	head = grab_header(inode);
9043476f7   Al Viro   [PATCH] sanitize ...
746
747
  	if (IS_ERR(head))
  		return PTR_ERR(head);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
748

f696a3659   Miklos Szeredi   [PATCH] move exec...
749
  	table = PROC_I(inode)->sysctl_entry;
9043476f7   Al Viro   [PATCH] sanitize ...
750
751
752
  	if (!table) /* global root - r-xr-xr-x */
  		error = mask & MAY_WRITE ? -EACCES : 0;
  	else /* Use the permissions on the sysctl table entry */
73f7ef435   Eric W. Biederman   sysctl: Pass usef...
753
  		error = sysctl_perm(head, table, mask & ~MAY_NOT_BLOCK);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
754

77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
755
756
757
758
759
760
  	sysctl_head_finish(head);
  	return error;
  }
  
  static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
  {
2b0143b5c   David Howells   VFS: normal files...
761
  	struct inode *inode = d_inode(dentry);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
762
763
764
765
  	int error;
  
  	if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
  		return -EPERM;
31051c85b   Jan Kara   fs: Give dentry t...
766
  	error = setattr_prepare(dentry, attr);
1025774ce   Christoph Hellwig   remove inode_setattr
767
768
  	if (error)
  		return error;
1025774ce   Christoph Hellwig   remove inode_setattr
769
770
771
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
772
  }
a528d35e8   David Howells   statx: Add a syst...
773
774
  static int proc_sys_getattr(const struct path *path, struct kstat *stat,
  			    u32 request_mask, unsigned int query_flags)
9043476f7   Al Viro   [PATCH] sanitize ...
775
  {
a528d35e8   David Howells   statx: Add a syst...
776
  	struct inode *inode = d_inode(path->dentry);
9043476f7   Al Viro   [PATCH] sanitize ...
777
778
779
780
781
782
783
784
785
786
787
788
789
  	struct ctl_table_header *head = grab_header(inode);
  	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
  
  	if (IS_ERR(head))
  		return PTR_ERR(head);
  
  	generic_fillattr(inode, stat);
  	if (table)
  		stat->mode = (stat->mode & S_IFMT) | table->mode;
  
  	sysctl_head_finish(head);
  	return 0;
  }
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
790
  static const struct file_operations proc_sys_file_operations = {
f1ecf0685   Lucas De Marchi   sysctl: add suppo...
791
792
  	.open		= proc_sys_open,
  	.poll		= proc_sys_poll,
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
793
794
  	.read		= proc_sys_read,
  	.write		= proc_sys_write,
6038f373a   Arnd Bergmann   llseek: automatic...
795
  	.llseek		= default_llseek,
9043476f7   Al Viro   [PATCH] sanitize ...
796
797
798
  };
  
  static const struct file_operations proc_sys_dir_file_operations = {
887df0789   Pavel Emelyanov   procfs: report EI...
799
  	.read		= generic_read_dir,
f50752eaa   Al Viro   switch all procfs...
800
  	.iterate_shared	= proc_sys_readdir,
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
801
  	.llseek		= generic_file_llseek,
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
802
  };
03a44825b   Jan Engelhardt   procfs: constify ...
803
  static const struct inode_operations proc_sys_inode_operations = {
9043476f7   Al Viro   [PATCH] sanitize ...
804
805
806
807
808
809
  	.permission	= proc_sys_permission,
  	.setattr	= proc_sys_setattr,
  	.getattr	= proc_sys_getattr,
  };
  
  static const struct inode_operations proc_sys_dir_operations = {
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
810
811
812
  	.lookup		= proc_sys_lookup,
  	.permission	= proc_sys_permission,
  	.setattr	= proc_sys_setattr,
9043476f7   Al Viro   [PATCH] sanitize ...
813
  	.getattr	= proc_sys_getattr,
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
814
  };
0b728e191   Al Viro   stop passing name...
815
  static int proc_sys_revalidate(struct dentry *dentry, unsigned int flags)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
816
  {
0b728e191   Al Viro   stop passing name...
817
  	if (flags & LOOKUP_RCU)
34286d666   Nick Piggin   fs: rcu-walk awar...
818
  		return -ECHILD;
2b0143b5c   David Howells   VFS: normal files...
819
  	return !PROC_I(d_inode(dentry))->sysctl->unregistering;
9043476f7   Al Viro   [PATCH] sanitize ...
820
  }
fe15ce446   Nick Piggin   fs: change d_dele...
821
  static int proc_sys_delete(const struct dentry *dentry)
9043476f7   Al Viro   [PATCH] sanitize ...
822
  {
2b0143b5c   David Howells   VFS: normal files...
823
  	return !!PROC_I(d_inode(dentry))->sysctl->unregistering;
9043476f7   Al Viro   [PATCH] sanitize ...
824
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  static int sysctl_is_seen(struct ctl_table_header *p)
  {
  	struct ctl_table_set *set = p->set;
  	int res;
  	spin_lock(&sysctl_lock);
  	if (p->unregistering)
  		res = 0;
  	else if (!set->is_seen)
  		res = 1;
  	else
  		res = set->is_seen(set);
  	spin_unlock(&sysctl_lock);
  	return res;
  }
6fa67e707   Al Viro   get rid of 'paren...
839
  static int proc_sys_compare(const struct dentry *dentry,
621e155a3   Nick Piggin   fs: change d_comp...
840
  		unsigned int len, const char *str, const struct qstr *name)
9043476f7   Al Viro   [PATCH] sanitize ...
841
  {
dfef6dcd3   Al Viro   unfuck proc_sysct...
842
  	struct ctl_table_header *head;
da53be12b   Linus Torvalds   Don't pass inode ...
843
  	struct inode *inode;
31e6b01f4   Nick Piggin   fs: rcu-walk for ...
844
845
  	/* Although proc doesn't have negative dentries, rcu-walk means
  	 * that inode here can be NULL */
dfef6dcd3   Al Viro   unfuck proc_sysct...
846
  	/* AV: can it, indeed? */
2b0143b5c   David Howells   VFS: normal files...
847
  	inode = d_inode_rcu(dentry);
31e6b01f4   Nick Piggin   fs: rcu-walk for ...
848
  	if (!inode)
dfef6dcd3   Al Viro   unfuck proc_sysct...
849
  		return 1;
621e155a3   Nick Piggin   fs: change d_comp...
850
  	if (name->len != len)
9043476f7   Al Viro   [PATCH] sanitize ...
851
  		return 1;
621e155a3   Nick Piggin   fs: change d_comp...
852
  	if (memcmp(name->name, str, len))
9043476f7   Al Viro   [PATCH] sanitize ...
853
  		return 1;
dfef6dcd3   Al Viro   unfuck proc_sysct...
854
855
  	head = rcu_dereference(PROC_I(inode)->sysctl);
  	return !head || !sysctl_is_seen(head);
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
856
  }
d72f71eb0   Al Viro   constify dentry_o...
857
  static const struct dentry_operations proc_sys_dentry_operations = {
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
858
  	.d_revalidate	= proc_sys_revalidate,
9043476f7   Al Viro   [PATCH] sanitize ...
859
860
  	.d_delete	= proc_sys_delete,
  	.d_compare	= proc_sys_compare,
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
861
  };
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
862
863
  static struct ctl_dir *find_subdir(struct ctl_dir *dir,
  				   const char *name, int namelen)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
864
  {
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
865
866
  	struct ctl_table_header *head;
  	struct ctl_table *entry;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
867

0e47c99d7   Eric W. Biederman   sysctl: Replace r...
868
  	entry = find_entry(&head, dir, name, namelen);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
869
870
  	if (!entry)
  		return ERR_PTR(-ENOENT);
51f72f4a0   Eric W. Biederman   sysctl: An easier...
871
872
873
  	if (!S_ISDIR(entry->mode))
  		return ERR_PTR(-ENOTDIR);
  	return container_of(head, struct ctl_dir, header);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
874
875
876
  }
  
  static struct ctl_dir *new_dir(struct ctl_table_set *set,
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
877
  			       const char *name, int namelen)
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
878
879
880
  {
  	struct ctl_table *table;
  	struct ctl_dir *new;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
881
  	struct ctl_node *node;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
882
  	char *new_name;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
883

ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
884
885
886
  	new = kzalloc(sizeof(*new) + sizeof(struct ctl_node) +
  		      sizeof(struct ctl_table)*2 +  namelen + 1,
  		      GFP_KERNEL);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
887
  	if (!new)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
888
  		return NULL;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
889
890
  	node = (struct ctl_node *)(new + 1);
  	table = (struct ctl_table *)(node + 1);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
891
892
893
894
895
  	new_name = (char *)(table + 2);
  	memcpy(new_name, name, namelen);
  	new_name[namelen] = '\0';
  	table[0].procname = new_name;
  	table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
896
  	init_header(&new->header, set->dir.header.root, set, node, table);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
897
898
  
  	return new;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
899
  }
60f126d93   Eric W. Biederman   sysctl: Comments ...
900
901
902
903
904
905
906
907
908
909
910
911
  /**
   * get_subdir - find or create a subdir with the specified name.
   * @dir:  Directory to create the subdirectory in
   * @name: The name of the subdirectory to find or create
   * @namelen: The length of name
   *
   * Takes a directory with an elevated reference count so we know that
   * if we drop the lock the directory will not go away.  Upon success
   * the reference is moved from @dir to the returned subdirectory.
   * Upon error an error code is returned and the reference on @dir is
   * simply dropped.
   */
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
912
913
  static struct ctl_dir *get_subdir(struct ctl_dir *dir,
  				  const char *name, int namelen)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
914
  {
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
915
  	struct ctl_table_set *set = dir->header.set;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
916
  	struct ctl_dir *subdir, *new = NULL;
0eb97f38d   Eric W. Biederman   sysctl: Correct e...
917
  	int err;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
918

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
919
  	spin_lock(&sysctl_lock);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
920
  	subdir = find_subdir(dir, name, namelen);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
921
922
923
924
925
926
927
928
929
930
931
  	if (!IS_ERR(subdir))
  		goto found;
  	if (PTR_ERR(subdir) != -ENOENT)
  		goto failed;
  
  	spin_unlock(&sysctl_lock);
  	new = new_dir(set, name, namelen);
  	spin_lock(&sysctl_lock);
  	subdir = ERR_PTR(-ENOMEM);
  	if (!new)
  		goto failed;
60f126d93   Eric W. Biederman   sysctl: Comments ...
932
  	/* Was the subdir added while we dropped the lock? */
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
933
  	subdir = find_subdir(dir, name, namelen);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
934
935
936
937
  	if (!IS_ERR(subdir))
  		goto found;
  	if (PTR_ERR(subdir) != -ENOENT)
  		goto failed;
60f126d93   Eric W. Biederman   sysctl: Comments ...
938
  	/* Nope.  Use the our freshly made directory entry. */
0eb97f38d   Eric W. Biederman   sysctl: Correct e...
939
940
941
  	err = insert_header(dir, &new->header);
  	subdir = ERR_PTR(err);
  	if (err)
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
942
  		goto failed;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
943
944
945
946
  	subdir = new;
  found:
  	subdir->header.nreg++;
  failed:
a1c83681d   Viresh Kumar   fs: Drop unlikely...
947
  	if (IS_ERR(subdir)) {
87ebdc00e   Andrew Morton   fs/proc: clean up...
948
  		pr_err("sysctl could not get directory: ");
6980128fe   Eric W. Biederman   sysctl: Add sysct...
949
  		sysctl_print_dir(dir);
87ebdc00e   Andrew Morton   fs/proc: clean up...
950
951
  		pr_cont("/%*.*s %ld
  ",
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
952
  			namelen, namelen, name, PTR_ERR(subdir));
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
953
  	}
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
954
955
956
957
958
  	drop_sysctl_table(&dir->header);
  	if (new)
  		drop_sysctl_table(&new->header);
  	spin_unlock(&sysctl_lock);
  	return subdir;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
959
  }
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
960
961
962
963
964
965
966
967
968
969
970
971
972
973
  static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
  {
  	struct ctl_dir *parent;
  	const char *procname;
  	if (!dir->header.parent)
  		return &set->dir;
  	parent = xlate_dir(set, dir->header.parent);
  	if (IS_ERR(parent))
  		return parent;
  	procname = dir->header.ctl_table[0].procname;
  	return find_subdir(parent, procname, strlen(procname));
  }
  
  static int sysctl_follow_link(struct ctl_table_header **phead,
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
974
  	struct ctl_table **pentry)
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
975
976
977
978
979
980
981
  {
  	struct ctl_table_header *head;
  	struct ctl_table_root *root;
  	struct ctl_table_set *set;
  	struct ctl_table *entry;
  	struct ctl_dir *dir;
  	int ret;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
982
983
984
  	ret = 0;
  	spin_lock(&sysctl_lock);
  	root = (*pentry)->data;
13bcc6a28   Eric W. Biederman   sysctl: Stop impl...
985
  	set = lookup_header_set(root);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  	dir = xlate_dir(set, (*phead)->parent);
  	if (IS_ERR(dir))
  		ret = PTR_ERR(dir);
  	else {
  		const char *procname = (*pentry)->procname;
  		head = NULL;
  		entry = find_entry(&head, dir, procname, strlen(procname));
  		ret = -ENOENT;
  		if (entry && use_table(head)) {
  			unuse_table(*phead);
  			*phead = head;
  			*pentry = entry;
  			ret = 0;
  		}
  	}
  
  	spin_unlock(&sysctl_lock);
  	return ret;
  }
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1005
  static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1006
  {
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1007
1008
  	struct va_format vaf;
  	va_list args;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1009

7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1010
1011
1012
  	va_start(args, fmt);
  	vaf.fmt = fmt;
  	vaf.va = &args;
87ebdc00e   Andrew Morton   fs/proc: clean up...
1013
1014
1015
  	pr_err("sysctl table check failed: %s/%s %pV
  ",
  	       path, table->procname, &vaf);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1016

7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1017
1018
  	va_end(args);
  	return -EINVAL;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1019
  }
4f2fec00a   Luis R. Rodriguez   sysctl: simplify ...
1020
1021
1022
  static int sysctl_check_table_array(const char *path, struct ctl_table *table)
  {
  	int err = 0;
61d9b56a8   Luis R. Rodriguez   sysctl: add unsig...
1023
1024
  	if ((table->proc_handler == proc_douintvec) ||
  	    (table->proc_handler == proc_douintvec_minmax)) {
4f2fec00a   Luis R. Rodriguez   sysctl: simplify ...
1025
1026
1027
1028
1029
1030
  		if (table->maxlen != sizeof(unsigned int))
  			err |= sysctl_err(path, table, "array now allowed");
  	}
  
  	return err;
  }
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1031
  static int sysctl_check_table(const char *path, struct ctl_table *table)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1032
  {
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1033
  	int err = 0;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1034
  	for (; table->procname; table++) {
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1035
  		if (table->child)
89c5b53b1   Luis R. Rodriguez   sysctl: fix lax s...
1036
  			err |= sysctl_err(path, table, "Not a file");
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1037
1038
1039
  
  		if ((table->proc_handler == proc_dostring) ||
  		    (table->proc_handler == proc_dointvec) ||
1680a3868   Liping Zhang   sysctl: add sanit...
1040
  		    (table->proc_handler == proc_douintvec) ||
61d9b56a8   Luis R. Rodriguez   sysctl: add unsig...
1041
  		    (table->proc_handler == proc_douintvec_minmax) ||
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1042
1043
1044
1045
1046
1047
1048
  		    (table->proc_handler == proc_dointvec_minmax) ||
  		    (table->proc_handler == proc_dointvec_jiffies) ||
  		    (table->proc_handler == proc_dointvec_userhz_jiffies) ||
  		    (table->proc_handler == proc_dointvec_ms_jiffies) ||
  		    (table->proc_handler == proc_doulongvec_minmax) ||
  		    (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
  			if (!table->data)
89c5b53b1   Luis R. Rodriguez   sysctl: fix lax s...
1049
  				err |= sysctl_err(path, table, "No data");
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1050
  			if (!table->maxlen)
89c5b53b1   Luis R. Rodriguez   sysctl: fix lax s...
1051
  				err |= sysctl_err(path, table, "No maxlen");
4f2fec00a   Luis R. Rodriguez   sysctl: simplify ...
1052
1053
  			else
  				err |= sysctl_check_table_array(path, table);
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1054
1055
  		}
  		if (!table->proc_handler)
89c5b53b1   Luis R. Rodriguez   sysctl: fix lax s...
1056
  			err |= sysctl_err(path, table, "No proc_handler");
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1057
1058
  
  		if ((table->mode & (S_IRUGO|S_IWUGO)) != table->mode)
89c5b53b1   Luis R. Rodriguez   sysctl: fix lax s...
1059
  			err |= sysctl_err(path, table, "bogus .mode 0%o",
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1060
  				table->mode);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1061
  	}
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1062
  	return err;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1063
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1064

0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1065
1066
1067
1068
1069
  static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
  	struct ctl_table_root *link_root)
  {
  	struct ctl_table *link_table, *entry, *link;
  	struct ctl_table_header *links;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1070
  	struct ctl_node *node;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  	char *link_name;
  	int nr_entries, name_bytes;
  
  	name_bytes = 0;
  	nr_entries = 0;
  	for (entry = table; entry->procname; entry++) {
  		nr_entries++;
  		name_bytes += strlen(entry->procname) + 1;
  	}
  
  	links = kzalloc(sizeof(struct ctl_table_header) +
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1082
  			sizeof(struct ctl_node)*nr_entries +
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1083
1084
1085
1086
1087
1088
  			sizeof(struct ctl_table)*(nr_entries + 1) +
  			name_bytes,
  			GFP_KERNEL);
  
  	if (!links)
  		return NULL;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1089
1090
  	node = (struct ctl_node *)(links + 1);
  	link_table = (struct ctl_table *)(node + nr_entries);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  	link_name = (char *)&link_table[nr_entries + 1];
  
  	for (link = link_table, entry = table; entry->procname; link++, entry++) {
  		int len = strlen(entry->procname) + 1;
  		memcpy(link_name, entry->procname, len);
  		link->procname = link_name;
  		link->mode = S_IFLNK|S_IRWXUGO;
  		link->data = link_root;
  		link_name += len;
  	}
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1101
  	init_header(links, dir->header.root, dir->header.set, node, link_table);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
  	links->nreg = nr_entries;
  
  	return links;
  }
  
  static bool get_links(struct ctl_dir *dir,
  	struct ctl_table *table, struct ctl_table_root *link_root)
  {
  	struct ctl_table_header *head;
  	struct ctl_table *entry, *link;
  
  	/* Are there links available for every entry in table? */
  	for (entry = table; entry->procname; entry++) {
  		const char *procname = entry->procname;
  		link = find_entry(&head, dir, procname, strlen(procname));
  		if (!link)
  			return false;
  		if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
  			continue;
  		if (S_ISLNK(link->mode) && (link->data == link_root))
  			continue;
  		return false;
  	}
  
  	/* The checks passed.  Increase the registration count on the links */
  	for (entry = table; entry->procname; entry++) {
  		const char *procname = entry->procname;
  		link = find_entry(&head, dir, procname, strlen(procname));
  		head->nreg++;
  	}
  	return true;
  }
  
  static int insert_links(struct ctl_table_header *head)
  {
  	struct ctl_table_set *root_set = &sysctl_table_root.default_set;
  	struct ctl_dir *core_parent = NULL;
  	struct ctl_table_header *links;
  	int err;
  
  	if (head->set == root_set)
  		return 0;
  
  	core_parent = xlate_dir(root_set, head->parent);
  	if (IS_ERR(core_parent))
  		return 0;
  
  	if (get_links(core_parent, head->ctl_table, head->root))
  		return 0;
  
  	core_parent->header.nreg++;
  	spin_unlock(&sysctl_lock);
  
  	links = new_links(core_parent, head->ctl_table, head->root);
  
  	spin_lock(&sysctl_lock);
  	err = -ENOMEM;
  	if (!links)
  		goto out;
  
  	err = 0;
  	if (get_links(core_parent, head->ctl_table, head->root)) {
  		kfree(links);
  		goto out;
  	}
  
  	err = insert_header(core_parent, links);
  	if (err)
  		kfree(links);
  out:
  	drop_sysctl_table(&core_parent->header);
  	return err;
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1175
  /**
f728019bb   Eric W. Biederman   sysctl: register ...
1176
   * __register_sysctl_table - register a leaf sysctl table
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1177
   * @set: Sysctl tree to register on
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
   * @path: The path to the directory the sysctl table is in.
   * @table: the top-level table structure
   *
   * Register a sysctl table hierarchy. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   *
   * The members of the &struct ctl_table structure are used as follows:
   *
   * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
   *            enter a sysctl file
   *
   * data - a pointer to data for use by proc_handler
   *
   * maxlen - the maximum size in bytes of the data
   *
f728019bb   Eric W. Biederman   sysctl: register ...
1193
   * mode - the file permissions for the /proc/sys file
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1194
   *
f728019bb   Eric W. Biederman   sysctl: register ...
1195
   * child - must be %NULL.
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1196
1197
1198
   *
   * proc_handler - the text handler routine (described below)
   *
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1199
1200
1201
1202
1203
   * extra1, extra2 - extra pointers usable by the proc handler routines
   *
   * Leaf nodes in the sysctl tree will be represented by a single file
   * under /proc; non-leaf nodes will be represented by directories.
   *
f728019bb   Eric W. Biederman   sysctl: register ...
1204
1205
   * There must be a proc_handler routine for any terminal nodes.
   * Several default handlers are available to cover common cases -
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
   *
   * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
   * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(),
   * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax()
   *
   * It is the handler's job to read the input buffer from user memory
   * and process it. The handler should return 0 on success.
   *
   * This routine returns %NULL on a failure to register, and a pointer
   * to the table header on success.
   */
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1217
  struct ctl_table_header *__register_sysctl_table(
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1218
  	struct ctl_table_set *set,
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1219
  	const char *path, struct ctl_table *table)
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1220
  {
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1221
  	struct ctl_table_root *root = set->dir.header.root;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1222
  	struct ctl_table_header *header;
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1223
  	const char *name, *nextname;
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1224
  	struct ctl_dir *dir;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1225
1226
1227
1228
1229
1230
  	struct ctl_table *entry;
  	struct ctl_node *node;
  	int nr_entries = 0;
  
  	for (entry = table; entry->procname; entry++)
  		nr_entries++;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1231

ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1232
1233
  	header = kzalloc(sizeof(struct ctl_table_header) +
  			 sizeof(struct ctl_node)*nr_entries, GFP_KERNEL);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1234
1235
  	if (!header)
  		return NULL;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1236
1237
  	node = (struct ctl_node *)(header + 1);
  	init_header(header, root, set, node, table);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1238
1239
1240
1241
  	if (sysctl_check_table(path, table))
  		goto fail;
  
  	spin_lock(&sysctl_lock);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1242
  	dir = &set->dir;
60f126d93   Eric W. Biederman   sysctl: Comments ...
1243
  	/* Reference moved down the diretory tree get_subdir */
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1244
1245
  	dir->header.nreg++;
  	spin_unlock(&sysctl_lock);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1246

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1247
  	/* Find the directory for the ctl_table */
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
  	for (name = path; name; name = nextname) {
  		int namelen;
  		nextname = strchr(name, '/');
  		if (nextname) {
  			namelen = nextname - name;
  			nextname++;
  		} else {
  			namelen = strlen(name);
  		}
  		if (namelen == 0)
  			continue;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1259

0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1260
  		dir = get_subdir(dir, name, namelen);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1261
1262
  		if (IS_ERR(dir))
  			goto fail;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1263
  	}
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1264

1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1265
  	spin_lock(&sysctl_lock);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1266
  	if (insert_header(dir, header))
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1267
  		goto fail_put_dir_locked;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1268

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1269
  	drop_sysctl_table(&dir->header);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1270
1271
1272
  	spin_unlock(&sysctl_lock);
  
  	return header;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1273

7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1274
1275
  fail_put_dir_locked:
  	drop_sysctl_table(&dir->header);
7c60c48f5   Eric W. Biederman   sysctl: Improve t...
1276
1277
1278
1279
1280
  	spin_unlock(&sysctl_lock);
  fail:
  	kfree(header);
  	dump_stack();
  	return NULL;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1281
  }
fea478d41   Eric W. Biederman   sysctl: Add regis...
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
  /**
   * register_sysctl - register a sysctl table
   * @path: The path to the directory the sysctl table is in.
   * @table: the table structure
   *
   * Register a sysctl table. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   *
   * See __register_sysctl_table for more details.
   */
  struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
  {
  	return __register_sysctl_table(&sysctl_table_root.default_set,
  					path, table);
  }
  EXPORT_SYMBOL(register_sysctl);
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
  static char *append_path(const char *path, char *pos, const char *name)
  {
  	int namelen;
  	namelen = strlen(name);
  	if (((pos - path) + namelen + 2) >= PATH_MAX)
  		return NULL;
  	memcpy(pos, name, namelen);
  	pos[namelen] = '/';
  	pos[namelen + 1] = '\0';
  	pos += namelen + 1;
  	return pos;
  }
f728019bb   Eric W. Biederman   sysctl: register ...
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
  static int count_subheaders(struct ctl_table *table)
  {
  	int has_files = 0;
  	int nr_subheaders = 0;
  	struct ctl_table *entry;
  
  	/* special case: no directory and empty directory */
  	if (!table || !table->procname)
  		return 1;
  
  	for (entry = table; entry->procname; entry++) {
  		if (entry->child)
  			nr_subheaders += count_subheaders(entry->child);
  		else
  			has_files = 1;
  	}
  	return nr_subheaders + has_files;
  }
  
  static int register_leaf_sysctl_tables(const char *path, char *pos,
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1330
  	struct ctl_table_header ***subheader, struct ctl_table_set *set,
f728019bb   Eric W. Biederman   sysctl: register ...
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
  	struct ctl_table *table)
  {
  	struct ctl_table *ctl_table_arg = NULL;
  	struct ctl_table *entry, *files;
  	int nr_files = 0;
  	int nr_dirs = 0;
  	int err = -ENOMEM;
  
  	for (entry = table; entry->procname; entry++) {
  		if (entry->child)
  			nr_dirs++;
  		else
  			nr_files++;
  	}
  
  	files = table;
  	/* If there are mixed files and directories we need a new table */
  	if (nr_dirs && nr_files) {
  		struct ctl_table *new;
  		files = kzalloc(sizeof(struct ctl_table) * (nr_files + 1),
  				GFP_KERNEL);
  		if (!files)
  			goto out;
  
  		ctl_table_arg = files;
  		for (new = files, entry = table; entry->procname; entry++) {
  			if (entry->child)
  				continue;
  			*new = *entry;
  			new++;
  		}
  	}
  
  	/* Register everything except a directory full of subdirectories */
  	if (nr_files || !nr_dirs) {
  		struct ctl_table_header *header;
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1367
  		header = __register_sysctl_table(set, path, files);
f728019bb   Eric W. Biederman   sysctl: register ...
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
  		if (!header) {
  			kfree(ctl_table_arg);
  			goto out;
  		}
  
  		/* Remember if we need to free the file table */
  		header->ctl_table_arg = ctl_table_arg;
  		**subheader = header;
  		(*subheader)++;
  	}
  
  	/* Recurse into the subdirectories. */
  	for (entry = table; entry->procname; entry++) {
  		char *child_pos;
  
  		if (!entry->child)
  			continue;
  
  		err = -ENAMETOOLONG;
  		child_pos = append_path(path, pos, entry->procname);
  		if (!child_pos)
  			goto out;
  
  		err = register_leaf_sysctl_tables(path, child_pos, subheader,
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1392
  						  set, entry->child);
f728019bb   Eric W. Biederman   sysctl: register ...
1393
1394
1395
1396
1397
1398
1399
1400
1401
  		pos[0] = '\0';
  		if (err)
  			goto out;
  	}
  	err = 0;
  out:
  	/* On failure our caller will unregister all registered subheaders */
  	return err;
  }
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1402
1403
  /**
   * __register_sysctl_paths - register a sysctl table hierarchy
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1404
   * @set: Sysctl tree to register on
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1405
1406
1407
1408
1409
1410
1411
1412
1413
   * @path: The path to the directory the sysctl table is in.
   * @table: the top-level table structure
   *
   * Register a sysctl table hierarchy. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   *
   * See __register_sysctl_table for more details.
   */
  struct ctl_table_header *__register_sysctl_paths(
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1414
  	struct ctl_table_set *set,
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1415
1416
  	const struct ctl_path *path, struct ctl_table *table)
  {
ec6a52668   Eric W. Biederman   sysctl: Add ctl_t...
1417
  	struct ctl_table *ctl_table_arg = table;
f728019bb   Eric W. Biederman   sysctl: register ...
1418
1419
  	int nr_subheaders = count_subheaders(table);
  	struct ctl_table_header *header = NULL, **subheaders, **subheader;
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
  	const struct ctl_path *component;
  	char *new_path, *pos;
  
  	pos = new_path = kmalloc(PATH_MAX, GFP_KERNEL);
  	if (!new_path)
  		return NULL;
  
  	pos[0] = '\0';
  	for (component = path; component->procname; component++) {
  		pos = append_path(new_path, pos, component->procname);
  		if (!pos)
  			goto out;
  	}
ec6a52668   Eric W. Biederman   sysctl: Add ctl_t...
1433
1434
1435
1436
1437
1438
  	while (table->procname && table->child && !table[1].procname) {
  		pos = append_path(new_path, pos, table->procname);
  		if (!pos)
  			goto out;
  		table = table->child;
  	}
f728019bb   Eric W. Biederman   sysctl: register ...
1439
  	if (nr_subheaders == 1) {
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1440
  		header = __register_sysctl_table(set, new_path, table);
f728019bb   Eric W. Biederman   sysctl: register ...
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  		if (header)
  			header->ctl_table_arg = ctl_table_arg;
  	} else {
  		header = kzalloc(sizeof(*header) +
  				 sizeof(*subheaders)*nr_subheaders, GFP_KERNEL);
  		if (!header)
  			goto out;
  
  		subheaders = (struct ctl_table_header **) (header + 1);
  		subheader = subheaders;
ec6a52668   Eric W. Biederman   sysctl: Add ctl_t...
1451
  		header->ctl_table_arg = ctl_table_arg;
f728019bb   Eric W. Biederman   sysctl: register ...
1452
1453
  
  		if (register_leaf_sysctl_tables(new_path, pos, &subheader,
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1454
  						set, table))
f728019bb   Eric W. Biederman   sysctl: register ...
1455
1456
  			goto err_register_leaves;
  	}
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1457
1458
1459
  out:
  	kfree(new_path);
  	return header;
f728019bb   Eric W. Biederman   sysctl: register ...
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
  
  err_register_leaves:
  	while (subheader > subheaders) {
  		struct ctl_table_header *subh = *(--subheader);
  		struct ctl_table *table = subh->ctl_table_arg;
  		unregister_sysctl_table(subh);
  		kfree(table);
  	}
  	kfree(header);
  	header = NULL;
  	goto out;
6e9d51641   Eric W. Biederman   sysctl: Add suppo...
1471
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
  /**
   * register_sysctl_table_path - register a sysctl table hierarchy
   * @path: The path to the directory the sysctl table is in.
   * @table: the top-level table structure
   *
   * Register a sysctl table hierarchy. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   *
   * See __register_sysctl_paths for more details.
   */
  struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
  						struct ctl_table *table)
  {
60a47a2e8   Eric W. Biederman   sysctl: Modify __...
1485
  	return __register_sysctl_paths(&sysctl_table_root.default_set,
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
  					path, table);
  }
  EXPORT_SYMBOL(register_sysctl_paths);
  
  /**
   * register_sysctl_table - register a sysctl table hierarchy
   * @table: the top-level table structure
   *
   * Register a sysctl table hierarchy. @table should be a filled in ctl_table
   * array. A completely 0 filled entry terminates the table.
   *
   * See register_sysctl_paths for more details.
   */
  struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
  {
  	static const struct ctl_path null_path[] = { {} };
  
  	return register_sysctl_paths(null_path, table);
  }
  EXPORT_SYMBOL(register_sysctl_table);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
  static void put_links(struct ctl_table_header *header)
  {
  	struct ctl_table_set *root_set = &sysctl_table_root.default_set;
  	struct ctl_table_root *root = header->root;
  	struct ctl_dir *parent = header->parent;
  	struct ctl_dir *core_parent;
  	struct ctl_table *entry;
  
  	if (header->set == root_set)
  		return;
  
  	core_parent = xlate_dir(root_set, parent);
  	if (IS_ERR(core_parent))
  		return;
  
  	for (entry = header->ctl_table; entry->procname; entry++) {
  		struct ctl_table_header *link_head;
  		struct ctl_table *link;
  		const char *name = entry->procname;
  
  		link = find_entry(&link_head, core_parent, name, strlen(name));
  		if (link &&
  		    ((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
  		     (S_ISLNK(link->mode) && (link->data == root)))) {
  			drop_sysctl_table(link_head);
  		}
  		else {
87ebdc00e   Andrew Morton   fs/proc: clean up...
1533
  			pr_err("sysctl link missing during unregister: ");
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1534
  			sysctl_print_dir(parent);
87ebdc00e   Andrew Morton   fs/proc: clean up...
1535
1536
  			pr_cont("/%s
  ", name);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1537
1538
1539
  		}
  	}
  }
938aaa4f9   Eric W. Biederman   sysctl: Initial s...
1540
1541
  static void drop_sysctl_table(struct ctl_table_header *header)
  {
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1542
  	struct ctl_dir *parent = header->parent;
938aaa4f9   Eric W. Biederman   sysctl: Initial s...
1543
1544
  	if (--header->nreg)
  		return;
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1545
  	put_links(header);
938aaa4f9   Eric W. Biederman   sysctl: Initial s...
1546
  	start_unregistering(header);
938aaa4f9   Eric W. Biederman   sysctl: Initial s...
1547
1548
  	if (!--header->count)
  		kfree_rcu(header, rcu);
7ec66d063   Eric W. Biederman   sysctl: Stop requ...
1549
1550
1551
  
  	if (parent)
  		drop_sysctl_table(&parent->header);
938aaa4f9   Eric W. Biederman   sysctl: Initial s...
1552
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1553
1554
1555
1556
1557
1558
1559
1560
1561
  /**
   * unregister_sysctl_table - unregister a sysctl table hierarchy
   * @header: the header returned from register_sysctl_table
   *
   * Unregisters the sysctl table and all children. proc entries may not
   * actually be removed until they are no longer used by anyone.
   */
  void unregister_sysctl_table(struct ctl_table_header * header)
  {
f728019bb   Eric W. Biederman   sysctl: register ...
1562
  	int nr_subheaders;
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1563
1564
1565
1566
  	might_sleep();
  
  	if (header == NULL)
  		return;
f728019bb   Eric W. Biederman   sysctl: register ...
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
  	nr_subheaders = count_subheaders(header->ctl_table_arg);
  	if (unlikely(nr_subheaders > 1)) {
  		struct ctl_table_header **subheaders;
  		int i;
  
  		subheaders = (struct ctl_table_header **)(header + 1);
  		for (i = nr_subheaders -1; i >= 0; i--) {
  			struct ctl_table_header *subh = subheaders[i];
  			struct ctl_table *table = subh->ctl_table_arg;
  			unregister_sysctl_table(subh);
  			kfree(table);
  		}
  		kfree(header);
  		return;
  	}
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1582
  	spin_lock(&sysctl_lock);
938aaa4f9   Eric W. Biederman   sysctl: Initial s...
1583
  	drop_sysctl_table(header);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1584
1585
1586
  	spin_unlock(&sysctl_lock);
  }
  EXPORT_SYMBOL(unregister_sysctl_table);
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1587
  void setup_sysctl_set(struct ctl_table_set *set,
9eb47c26f   Eric W. Biederman   sysctl: Add a roo...
1588
  	struct ctl_table_root *root,
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1589
1590
  	int (*is_seen)(struct ctl_table_set *))
  {
1347440db   Dan Carpenter   sysctl: fix memse...
1591
  	memset(set, 0, sizeof(*set));
0e47c99d7   Eric W. Biederman   sysctl: Replace r...
1592
  	set->is_seen = is_seen;
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1593
  	init_header(&set->dir.header, root, set, NULL, root_table);
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1594
  }
97324cd80   Eric W. Biederman   sysctl: Implement...
1595
1596
  void retire_sysctl_set(struct ctl_table_set *set)
  {
ac13ac6f4   Eric W. Biederman   sysctl: Index sys...
1597
  	WARN_ON(!RB_EMPTY_ROOT(&set->dir.root));
97324cd80   Eric W. Biederman   sysctl: Implement...
1598
  }
1f87f0b52   Eric W. Biederman   sysctl: Move the ...
1599

1e0edd3f6   Alexey Dobriyan   proc: spread __init
1600
  int __init proc_sys_init(void)
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
1601
  {
e1675231c   Alexey Dobriyan   proc: proc_sys_ro...
1602
  	struct proc_dir_entry *proc_sys_root;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
1603
  	proc_sys_root = proc_mkdir("sys", NULL);
9043476f7   Al Viro   [PATCH] sanitize ...
1604
1605
  	proc_sys_root->proc_iops = &proc_sys_dir_operations;
  	proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
1606
  	proc_sys_root->nlink = 0;
de4e83bd6   Eric W. Biederman   sysctl: Register ...
1607
1608
  
  	return sysctl_init();
77b14db50   Eric W. Biederman   [PATCH] sysctl: r...
1609
  }