1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * proc/fs/generic.c --- generic routines for the proc-fs |
4 | * |
5 | * This file contains generic proc-fs routines for handling |
6 | * directories and files. |
7 | * |
8 | * Copyright (C) 1991, 1992 Linus Torvalds. |
9 | * Copyright (C) 1997 Theodore Ts'o |
10 | */ |
11 | |
12 | #include <linux/cache.h> |
13 | #include <linux/errno.h> |
14 | #include <linux/time.h> |
15 | #include <linux/proc_fs.h> |
16 | #include <linux/stat.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/module.h> |
19 | #include <linux/namei.h> |
20 | #include <linux/slab.h> |
21 | #include <linux/printk.h> |
22 | #include <linux/mount.h> |
23 | #include <linux/init.h> |
24 | #include <linux/idr.h> |
25 | #include <linux/bitops.h> |
26 | #include <linux/spinlock.h> |
27 | #include <linux/completion.h> |
28 | #include <linux/uaccess.h> |
29 | #include <linux/seq_file.h> |
30 | |
31 | #include "internal.h" |
32 | |
33 | static DEFINE_RWLOCK(proc_subdir_lock); |
34 | |
35 | struct kmem_cache *proc_dir_entry_cache __ro_after_init; |
36 | |
37 | void pde_free(struct proc_dir_entry *pde) |
38 | { |
39 | if (S_ISLNK(pde->mode)) |
40 | kfree(objp: pde->data); |
41 | if (pde->name != pde->inline_name) |
42 | kfree(objp: pde->name); |
43 | kmem_cache_free(s: proc_dir_entry_cache, objp: pde); |
44 | } |
45 | |
46 | static int proc_match(const char *name, struct proc_dir_entry *de, unsigned int len) |
47 | { |
48 | if (len < de->namelen) |
49 | return -1; |
50 | if (len > de->namelen) |
51 | return 1; |
52 | |
53 | return memcmp(p: name, q: de->name, size: len); |
54 | } |
55 | |
56 | static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir) |
57 | { |
58 | return rb_entry_safe(rb_first(&dir->subdir), struct proc_dir_entry, |
59 | subdir_node); |
60 | } |
61 | |
62 | static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir) |
63 | { |
64 | return rb_entry_safe(rb_next(&dir->subdir_node), struct proc_dir_entry, |
65 | subdir_node); |
66 | } |
67 | |
68 | static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir, |
69 | const char *name, |
70 | unsigned int len) |
71 | { |
72 | struct rb_node *node = dir->subdir.rb_node; |
73 | |
74 | while (node) { |
75 | struct proc_dir_entry *de = rb_entry(node, |
76 | struct proc_dir_entry, |
77 | subdir_node); |
78 | int result = proc_match(name, de, len); |
79 | |
80 | if (result < 0) |
81 | node = node->rb_left; |
82 | else if (result > 0) |
83 | node = node->rb_right; |
84 | else |
85 | return de; |
86 | } |
87 | return NULL; |
88 | } |
89 | |
90 | static bool pde_subdir_insert(struct proc_dir_entry *dir, |
91 | struct proc_dir_entry *de) |
92 | { |
93 | struct rb_root *root = &dir->subdir; |
94 | struct rb_node **new = &root->rb_node, *parent = NULL; |
95 | |
96 | /* Figure out where to put new node */ |
97 | while (*new) { |
98 | struct proc_dir_entry *this = rb_entry(*new, |
99 | struct proc_dir_entry, |
100 | subdir_node); |
101 | int result = proc_match(name: de->name, de: this, len: de->namelen); |
102 | |
103 | parent = *new; |
104 | if (result < 0) |
105 | new = &(*new)->rb_left; |
106 | else if (result > 0) |
107 | new = &(*new)->rb_right; |
108 | else |
109 | return false; |
110 | } |
111 | |
112 | /* Add new node and rebalance tree. */ |
113 | rb_link_node(node: &de->subdir_node, parent, rb_link: new); |
114 | rb_insert_color(&de->subdir_node, root); |
115 | return true; |
116 | } |
117 | |
118 | static int proc_notify_change(struct mnt_idmap *idmap, |
119 | struct dentry *dentry, struct iattr *iattr) |
120 | { |
121 | struct inode *inode = d_inode(dentry); |
122 | struct proc_dir_entry *de = PDE(inode); |
123 | int error; |
124 | |
125 | error = setattr_prepare(&nop_mnt_idmap, dentry, iattr); |
126 | if (error) |
127 | return error; |
128 | |
129 | setattr_copy(&nop_mnt_idmap, inode, attr: iattr); |
130 | |
131 | proc_set_user(de, inode->i_uid, inode->i_gid); |
132 | de->mode = inode->i_mode; |
133 | return 0; |
134 | } |
135 | |
136 | static int proc_getattr(struct mnt_idmap *idmap, |
137 | const struct path *path, struct kstat *stat, |
138 | u32 request_mask, unsigned int query_flags) |
139 | { |
140 | struct inode *inode = d_inode(dentry: path->dentry); |
141 | struct proc_dir_entry *de = PDE(inode); |
142 | if (de) { |
143 | nlink_t nlink = READ_ONCE(de->nlink); |
144 | if (nlink > 0) { |
145 | set_nlink(inode, nlink); |
146 | } |
147 | } |
148 | |
149 | generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); |
150 | return 0; |
151 | } |
152 | |
153 | static const struct inode_operations proc_file_inode_operations = { |
154 | .setattr = proc_notify_change, |
155 | }; |
156 | |
157 | /* |
158 | * This function parses a name such as "tty/driver/serial", and |
159 | * returns the struct proc_dir_entry for "/proc/tty/driver", and |
160 | * returns "serial" in residual. |
161 | */ |
162 | static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret, |
163 | const char **residual) |
164 | { |
165 | const char *cp = name, *next; |
166 | struct proc_dir_entry *de; |
167 | |
168 | de = *ret ?: &proc_root; |
169 | while ((next = strchr(cp, '/')) != NULL) { |
170 | de = pde_subdir_find(dir: de, name: cp, len: next - cp); |
171 | if (!de) { |
172 | WARN(1, "name '%s'\n" , name); |
173 | return -ENOENT; |
174 | } |
175 | cp = next + 1; |
176 | } |
177 | *residual = cp; |
178 | *ret = de; |
179 | return 0; |
180 | } |
181 | |
182 | static int xlate_proc_name(const char *name, struct proc_dir_entry **ret, |
183 | const char **residual) |
184 | { |
185 | int rv; |
186 | |
187 | read_lock(&proc_subdir_lock); |
188 | rv = __xlate_proc_name(name, ret, residual); |
189 | read_unlock(&proc_subdir_lock); |
190 | return rv; |
191 | } |
192 | |
193 | static DEFINE_IDA(proc_inum_ida); |
194 | |
195 | #define PROC_DYNAMIC_FIRST 0xF0000000U |
196 | |
197 | /* |
198 | * Return an inode number between PROC_DYNAMIC_FIRST and |
199 | * 0xffffffff, or zero on failure. |
200 | */ |
201 | int proc_alloc_inum(unsigned int *inum) |
202 | { |
203 | int i; |
204 | |
205 | i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, |
206 | GFP_KERNEL); |
207 | if (i < 0) |
208 | return i; |
209 | |
210 | *inum = PROC_DYNAMIC_FIRST + (unsigned int)i; |
211 | return 0; |
212 | } |
213 | |
214 | void proc_free_inum(unsigned int inum) |
215 | { |
216 | ida_simple_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
217 | } |
218 | |
219 | static int proc_misc_d_revalidate(struct dentry *dentry, unsigned int flags) |
220 | { |
221 | if (flags & LOOKUP_RCU) |
222 | return -ECHILD; |
223 | |
224 | if (atomic_read(v: &PDE(inode: d_inode(dentry))->in_use) < 0) |
225 | return 0; /* revalidate */ |
226 | return 1; |
227 | } |
228 | |
229 | static int proc_misc_d_delete(const struct dentry *dentry) |
230 | { |
231 | return atomic_read(v: &PDE(inode: d_inode(dentry))->in_use) < 0; |
232 | } |
233 | |
234 | static const struct dentry_operations proc_misc_dentry_ops = { |
235 | .d_revalidate = proc_misc_d_revalidate, |
236 | .d_delete = proc_misc_d_delete, |
237 | }; |
238 | |
239 | /* |
240 | * Don't create negative dentries here, return -ENOENT by hand |
241 | * instead. |
242 | */ |
243 | struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, |
244 | struct proc_dir_entry *de) |
245 | { |
246 | struct inode *inode; |
247 | |
248 | read_lock(&proc_subdir_lock); |
249 | de = pde_subdir_find(dir: de, name: dentry->d_name.name, len: dentry->d_name.len); |
250 | if (de) { |
251 | pde_get(pde: de); |
252 | read_unlock(&proc_subdir_lock); |
253 | inode = proc_get_inode(dir->i_sb, de); |
254 | if (!inode) |
255 | return ERR_PTR(error: -ENOMEM); |
256 | d_set_d_op(dentry, op: de->proc_dops); |
257 | return d_splice_alias(inode, dentry); |
258 | } |
259 | read_unlock(&proc_subdir_lock); |
260 | return ERR_PTR(error: -ENOENT); |
261 | } |
262 | |
263 | struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, |
264 | unsigned int flags) |
265 | { |
266 | struct proc_fs_info *fs_info = proc_sb_info(sb: dir->i_sb); |
267 | |
268 | if (fs_info->pidonly == PROC_PIDONLY_ON) |
269 | return ERR_PTR(error: -ENOENT); |
270 | |
271 | return proc_lookup_de(dir, dentry, de: PDE(inode: dir)); |
272 | } |
273 | |
274 | /* |
275 | * This returns non-zero if at EOF, so that the /proc |
276 | * root directory can use this and check if it should |
277 | * continue with the <pid> entries.. |
278 | * |
279 | * Note that the VFS-layer doesn't care about the return |
280 | * value of the readdir() call, as long as it's non-negative |
281 | * for success.. |
282 | */ |
283 | int proc_readdir_de(struct file *file, struct dir_context *ctx, |
284 | struct proc_dir_entry *de) |
285 | { |
286 | int i; |
287 | |
288 | if (!dir_emit_dots(file, ctx)) |
289 | return 0; |
290 | |
291 | i = ctx->pos - 2; |
292 | read_lock(&proc_subdir_lock); |
293 | de = pde_subdir_first(dir: de); |
294 | for (;;) { |
295 | if (!de) { |
296 | read_unlock(&proc_subdir_lock); |
297 | return 0; |
298 | } |
299 | if (!i) |
300 | break; |
301 | de = pde_subdir_next(dir: de); |
302 | i--; |
303 | } |
304 | |
305 | do { |
306 | struct proc_dir_entry *next; |
307 | pde_get(pde: de); |
308 | read_unlock(&proc_subdir_lock); |
309 | if (!dir_emit(ctx, name: de->name, namelen: de->namelen, |
310 | ino: de->low_ino, type: de->mode >> 12)) { |
311 | pde_put(de); |
312 | return 0; |
313 | } |
314 | ctx->pos++; |
315 | read_lock(&proc_subdir_lock); |
316 | next = pde_subdir_next(dir: de); |
317 | pde_put(de); |
318 | de = next; |
319 | } while (de); |
320 | read_unlock(&proc_subdir_lock); |
321 | return 1; |
322 | } |
323 | |
324 | int proc_readdir(struct file *file, struct dir_context *ctx) |
325 | { |
326 | struct inode *inode = file_inode(f: file); |
327 | struct proc_fs_info *fs_info = proc_sb_info(sb: inode->i_sb); |
328 | |
329 | if (fs_info->pidonly == PROC_PIDONLY_ON) |
330 | return 1; |
331 | |
332 | return proc_readdir_de(file, ctx, de: PDE(inode)); |
333 | } |
334 | |
335 | /* |
336 | * These are the generic /proc directory operations. They |
337 | * use the in-memory "struct proc_dir_entry" tree to parse |
338 | * the /proc directory. |
339 | */ |
340 | static const struct file_operations proc_dir_operations = { |
341 | .llseek = generic_file_llseek, |
342 | .read = generic_read_dir, |
343 | .iterate_shared = proc_readdir, |
344 | }; |
345 | |
346 | static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) |
347 | { |
348 | return 0; |
349 | } |
350 | |
351 | const struct dentry_operations proc_net_dentry_ops = { |
352 | .d_revalidate = proc_net_d_revalidate, |
353 | .d_delete = always_delete_dentry, |
354 | }; |
355 | |
356 | /* |
357 | * proc directories can do almost nothing.. |
358 | */ |
359 | static const struct inode_operations proc_dir_inode_operations = { |
360 | .lookup = proc_lookup, |
361 | .getattr = proc_getattr, |
362 | .setattr = proc_notify_change, |
363 | }; |
364 | |
365 | /* returns the registered entry, or frees dp and returns NULL on failure */ |
366 | struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, |
367 | struct proc_dir_entry *dp) |
368 | { |
369 | if (proc_alloc_inum(inum: &dp->low_ino)) |
370 | goto out_free_entry; |
371 | |
372 | write_lock(&proc_subdir_lock); |
373 | dp->parent = dir; |
374 | if (pde_subdir_insert(dir, de: dp) == false) { |
375 | WARN(1, "proc_dir_entry '%s/%s' already registered\n" , |
376 | dir->name, dp->name); |
377 | write_unlock(&proc_subdir_lock); |
378 | goto out_free_inum; |
379 | } |
380 | dir->nlink++; |
381 | write_unlock(&proc_subdir_lock); |
382 | |
383 | return dp; |
384 | out_free_inum: |
385 | proc_free_inum(inum: dp->low_ino); |
386 | out_free_entry: |
387 | pde_free(pde: dp); |
388 | return NULL; |
389 | } |
390 | |
391 | static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, |
392 | const char *name, |
393 | umode_t mode, |
394 | nlink_t nlink) |
395 | { |
396 | struct proc_dir_entry *ent = NULL; |
397 | const char *fn; |
398 | struct qstr qstr; |
399 | |
400 | if (xlate_proc_name(name, ret: parent, residual: &fn) != 0) |
401 | goto out; |
402 | qstr.name = fn; |
403 | qstr.len = strlen(fn); |
404 | if (qstr.len == 0 || qstr.len >= 256) { |
405 | WARN(1, "name len %u\n" , qstr.len); |
406 | return NULL; |
407 | } |
408 | if (qstr.len == 1 && fn[0] == '.') { |
409 | WARN(1, "name '.'\n" ); |
410 | return NULL; |
411 | } |
412 | if (qstr.len == 2 && fn[0] == '.' && fn[1] == '.') { |
413 | WARN(1, "name '..'\n" ); |
414 | return NULL; |
415 | } |
416 | if (*parent == &proc_root && name_to_int(qstr: &qstr) != ~0U) { |
417 | WARN(1, "create '/proc/%s' by hand\n" , qstr.name); |
418 | return NULL; |
419 | } |
420 | if (is_empty_pde(pde: *parent)) { |
421 | WARN(1, "attempt to add to permanently empty directory" ); |
422 | return NULL; |
423 | } |
424 | |
425 | ent = kmem_cache_zalloc(k: proc_dir_entry_cache, GFP_KERNEL); |
426 | if (!ent) |
427 | goto out; |
428 | |
429 | if (qstr.len + 1 <= SIZEOF_PDE_INLINE_NAME) { |
430 | ent->name = ent->inline_name; |
431 | } else { |
432 | ent->name = kmalloc(size: qstr.len + 1, GFP_KERNEL); |
433 | if (!ent->name) { |
434 | pde_free(pde: ent); |
435 | return NULL; |
436 | } |
437 | } |
438 | |
439 | memcpy(ent->name, fn, qstr.len + 1); |
440 | ent->namelen = qstr.len; |
441 | ent->mode = mode; |
442 | ent->nlink = nlink; |
443 | ent->subdir = RB_ROOT; |
444 | refcount_set(r: &ent->refcnt, n: 1); |
445 | spin_lock_init(&ent->pde_unload_lock); |
446 | INIT_LIST_HEAD(list: &ent->pde_openers); |
447 | proc_set_user(ent, (*parent)->uid, (*parent)->gid); |
448 | |
449 | ent->proc_dops = &proc_misc_dentry_ops; |
450 | /* Revalidate everything under /proc/${pid}/net */ |
451 | if ((*parent)->proc_dops == &proc_net_dentry_ops) |
452 | pde_force_lookup(pde: ent); |
453 | |
454 | out: |
455 | return ent; |
456 | } |
457 | |
458 | struct proc_dir_entry *proc_symlink(const char *name, |
459 | struct proc_dir_entry *parent, const char *dest) |
460 | { |
461 | struct proc_dir_entry *ent; |
462 | |
463 | ent = __proc_create(parent: &parent, name, |
464 | mode: (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),nlink: 1); |
465 | |
466 | if (ent) { |
467 | ent->data = kmalloc(size: (ent->size=strlen(dest))+1, GFP_KERNEL); |
468 | if (ent->data) { |
469 | strcpy(p: (char*)ent->data,q: dest); |
470 | ent->proc_iops = &proc_link_inode_operations; |
471 | ent = proc_register(dir: parent, dp: ent); |
472 | } else { |
473 | pde_free(pde: ent); |
474 | ent = NULL; |
475 | } |
476 | } |
477 | return ent; |
478 | } |
479 | EXPORT_SYMBOL(proc_symlink); |
480 | |
481 | struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, |
482 | struct proc_dir_entry *parent, void *data, bool force_lookup) |
483 | { |
484 | struct proc_dir_entry *ent; |
485 | |
486 | if (mode == 0) |
487 | mode = S_IRUGO | S_IXUGO; |
488 | |
489 | ent = __proc_create(parent: &parent, name, S_IFDIR | mode, nlink: 2); |
490 | if (ent) { |
491 | ent->data = data; |
492 | ent->proc_dir_ops = &proc_dir_operations; |
493 | ent->proc_iops = &proc_dir_inode_operations; |
494 | if (force_lookup) { |
495 | pde_force_lookup(pde: ent); |
496 | } |
497 | ent = proc_register(dir: parent, dp: ent); |
498 | } |
499 | return ent; |
500 | } |
501 | EXPORT_SYMBOL_GPL(_proc_mkdir); |
502 | |
503 | struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, |
504 | struct proc_dir_entry *parent, void *data) |
505 | { |
506 | return _proc_mkdir(name, mode, parent, data, false); |
507 | } |
508 | EXPORT_SYMBOL_GPL(proc_mkdir_data); |
509 | |
510 | struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, |
511 | struct proc_dir_entry *parent) |
512 | { |
513 | return proc_mkdir_data(name, mode, parent, NULL); |
514 | } |
515 | EXPORT_SYMBOL(proc_mkdir_mode); |
516 | |
517 | struct proc_dir_entry *proc_mkdir(const char *name, |
518 | struct proc_dir_entry *parent) |
519 | { |
520 | return proc_mkdir_data(name, 0, parent, NULL); |
521 | } |
522 | EXPORT_SYMBOL(proc_mkdir); |
523 | |
524 | struct proc_dir_entry *proc_create_mount_point(const char *name) |
525 | { |
526 | umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO; |
527 | struct proc_dir_entry *ent, *parent = NULL; |
528 | |
529 | ent = __proc_create(parent: &parent, name, mode, nlink: 2); |
530 | if (ent) { |
531 | ent->data = NULL; |
532 | ent->proc_dir_ops = NULL; |
533 | ent->proc_iops = NULL; |
534 | ent = proc_register(dir: parent, dp: ent); |
535 | } |
536 | return ent; |
537 | } |
538 | EXPORT_SYMBOL(proc_create_mount_point); |
539 | |
540 | struct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, |
541 | struct proc_dir_entry **parent, void *data) |
542 | { |
543 | struct proc_dir_entry *p; |
544 | |
545 | if ((mode & S_IFMT) == 0) |
546 | mode |= S_IFREG; |
547 | if ((mode & S_IALLUGO) == 0) |
548 | mode |= S_IRUGO; |
549 | if (WARN_ON_ONCE(!S_ISREG(mode))) |
550 | return NULL; |
551 | |
552 | p = __proc_create(parent, name, mode, nlink: 1); |
553 | if (p) { |
554 | p->proc_iops = &proc_file_inode_operations; |
555 | p->data = data; |
556 | } |
557 | return p; |
558 | } |
559 | |
560 | static inline void pde_set_flags(struct proc_dir_entry *pde) |
561 | { |
562 | if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT) |
563 | pde->flags |= PROC_ENTRY_PERMANENT; |
564 | } |
565 | |
566 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, |
567 | struct proc_dir_entry *parent, |
568 | const struct proc_ops *proc_ops, void *data) |
569 | { |
570 | struct proc_dir_entry *p; |
571 | |
572 | p = proc_create_reg(name, mode, parent: &parent, data); |
573 | if (!p) |
574 | return NULL; |
575 | p->proc_ops = proc_ops; |
576 | pde_set_flags(pde: p); |
577 | return proc_register(dir: parent, dp: p); |
578 | } |
579 | EXPORT_SYMBOL(proc_create_data); |
580 | |
581 | struct proc_dir_entry *proc_create(const char *name, umode_t mode, |
582 | struct proc_dir_entry *parent, |
583 | const struct proc_ops *proc_ops) |
584 | { |
585 | return proc_create_data(name, mode, parent, proc_ops, NULL); |
586 | } |
587 | EXPORT_SYMBOL(proc_create); |
588 | |
589 | static int proc_seq_open(struct inode *inode, struct file *file) |
590 | { |
591 | struct proc_dir_entry *de = PDE(inode); |
592 | |
593 | if (de->state_size) |
594 | return seq_open_private(file, de->seq_ops, de->state_size); |
595 | return seq_open(file, de->seq_ops); |
596 | } |
597 | |
598 | static int proc_seq_release(struct inode *inode, struct file *file) |
599 | { |
600 | struct proc_dir_entry *de = PDE(inode); |
601 | |
602 | if (de->state_size) |
603 | return seq_release_private(inode, file); |
604 | return seq_release(inode, file); |
605 | } |
606 | |
607 | static const struct proc_ops proc_seq_ops = { |
608 | /* not permanent -- can call into arbitrary seq_operations */ |
609 | .proc_open = proc_seq_open, |
610 | .proc_read_iter = seq_read_iter, |
611 | .proc_lseek = seq_lseek, |
612 | .proc_release = proc_seq_release, |
613 | }; |
614 | |
615 | struct proc_dir_entry *proc_create_seq_private(const char *name, umode_t mode, |
616 | struct proc_dir_entry *parent, const struct seq_operations *ops, |
617 | unsigned int state_size, void *data) |
618 | { |
619 | struct proc_dir_entry *p; |
620 | |
621 | p = proc_create_reg(name, mode, parent: &parent, data); |
622 | if (!p) |
623 | return NULL; |
624 | p->proc_ops = &proc_seq_ops; |
625 | p->seq_ops = ops; |
626 | p->state_size = state_size; |
627 | return proc_register(dir: parent, dp: p); |
628 | } |
629 | EXPORT_SYMBOL(proc_create_seq_private); |
630 | |
631 | static int proc_single_open(struct inode *inode, struct file *file) |
632 | { |
633 | struct proc_dir_entry *de = PDE(inode); |
634 | |
635 | return single_open(file, de->single_show, de->data); |
636 | } |
637 | |
638 | static const struct proc_ops proc_single_ops = { |
639 | /* not permanent -- can call into arbitrary ->single_show */ |
640 | .proc_open = proc_single_open, |
641 | .proc_read_iter = seq_read_iter, |
642 | .proc_lseek = seq_lseek, |
643 | .proc_release = single_release, |
644 | }; |
645 | |
646 | struct proc_dir_entry *proc_create_single_data(const char *name, umode_t mode, |
647 | struct proc_dir_entry *parent, |
648 | int (*show)(struct seq_file *, void *), void *data) |
649 | { |
650 | struct proc_dir_entry *p; |
651 | |
652 | p = proc_create_reg(name, mode, parent: &parent, data); |
653 | if (!p) |
654 | return NULL; |
655 | p->proc_ops = &proc_single_ops; |
656 | p->single_show = show; |
657 | return proc_register(dir: parent, dp: p); |
658 | } |
659 | EXPORT_SYMBOL(proc_create_single_data); |
660 | |
661 | void proc_set_size(struct proc_dir_entry *de, loff_t size) |
662 | { |
663 | de->size = size; |
664 | } |
665 | EXPORT_SYMBOL(proc_set_size); |
666 | |
667 | void proc_set_user(struct proc_dir_entry *de, kuid_t uid, kgid_t gid) |
668 | { |
669 | de->uid = uid; |
670 | de->gid = gid; |
671 | } |
672 | EXPORT_SYMBOL(proc_set_user); |
673 | |
674 | void pde_put(struct proc_dir_entry *pde) |
675 | { |
676 | if (refcount_dec_and_test(r: &pde->refcnt)) { |
677 | proc_free_inum(inum: pde->low_ino); |
678 | pde_free(pde); |
679 | } |
680 | } |
681 | |
682 | /* |
683 | * Remove a /proc entry and free it if it's not currently in use. |
684 | */ |
685 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) |
686 | { |
687 | struct proc_dir_entry *de = NULL; |
688 | const char *fn = name; |
689 | unsigned int len; |
690 | |
691 | write_lock(&proc_subdir_lock); |
692 | if (__xlate_proc_name(name, ret: &parent, residual: &fn) != 0) { |
693 | write_unlock(&proc_subdir_lock); |
694 | return; |
695 | } |
696 | len = strlen(fn); |
697 | |
698 | de = pde_subdir_find(dir: parent, name: fn, len); |
699 | if (de) { |
700 | if (unlikely(pde_is_permanent(de))) { |
701 | WARN(1, "removing permanent /proc entry '%s'" , de->name); |
702 | de = NULL; |
703 | } else { |
704 | rb_erase(&de->subdir_node, &parent->subdir); |
705 | if (S_ISDIR(de->mode)) |
706 | parent->nlink--; |
707 | } |
708 | } |
709 | write_unlock(&proc_subdir_lock); |
710 | if (!de) { |
711 | WARN(1, "name '%s'\n" , name); |
712 | return; |
713 | } |
714 | |
715 | proc_entry_rundown(de); |
716 | |
717 | WARN(pde_subdir_first(de), |
718 | "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n" , |
719 | __func__, de->parent->name, de->name, pde_subdir_first(de)->name); |
720 | pde_put(pde: de); |
721 | } |
722 | EXPORT_SYMBOL(remove_proc_entry); |
723 | |
724 | int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) |
725 | { |
726 | struct proc_dir_entry *root = NULL, *de, *next; |
727 | const char *fn = name; |
728 | unsigned int len; |
729 | |
730 | write_lock(&proc_subdir_lock); |
731 | if (__xlate_proc_name(name, ret: &parent, residual: &fn) != 0) { |
732 | write_unlock(&proc_subdir_lock); |
733 | return -ENOENT; |
734 | } |
735 | len = strlen(fn); |
736 | |
737 | root = pde_subdir_find(dir: parent, name: fn, len); |
738 | if (!root) { |
739 | write_unlock(&proc_subdir_lock); |
740 | return -ENOENT; |
741 | } |
742 | if (unlikely(pde_is_permanent(root))) { |
743 | write_unlock(&proc_subdir_lock); |
744 | WARN(1, "removing permanent /proc entry '%s/%s'" , |
745 | root->parent->name, root->name); |
746 | return -EINVAL; |
747 | } |
748 | rb_erase(&root->subdir_node, &parent->subdir); |
749 | |
750 | de = root; |
751 | while (1) { |
752 | next = pde_subdir_first(dir: de); |
753 | if (next) { |
754 | if (unlikely(pde_is_permanent(next))) { |
755 | write_unlock(&proc_subdir_lock); |
756 | WARN(1, "removing permanent /proc entry '%s/%s'" , |
757 | next->parent->name, next->name); |
758 | return -EINVAL; |
759 | } |
760 | rb_erase(&next->subdir_node, &de->subdir); |
761 | de = next; |
762 | continue; |
763 | } |
764 | next = de->parent; |
765 | if (S_ISDIR(de->mode)) |
766 | next->nlink--; |
767 | write_unlock(&proc_subdir_lock); |
768 | |
769 | proc_entry_rundown(de); |
770 | if (de == root) |
771 | break; |
772 | pde_put(pde: de); |
773 | |
774 | write_lock(&proc_subdir_lock); |
775 | de = next; |
776 | } |
777 | pde_put(pde: root); |
778 | return 0; |
779 | } |
780 | EXPORT_SYMBOL(remove_proc_subtree); |
781 | |
782 | void *proc_get_parent_data(const struct inode *inode) |
783 | { |
784 | struct proc_dir_entry *de = PDE(inode); |
785 | return de->parent->data; |
786 | } |
787 | EXPORT_SYMBOL_GPL(proc_get_parent_data); |
788 | |
789 | void proc_remove(struct proc_dir_entry *de) |
790 | { |
791 | if (de) |
792 | remove_proc_subtree(de->name, de->parent); |
793 | } |
794 | EXPORT_SYMBOL(proc_remove); |
795 | |
796 | /* |
797 | * Pull a user buffer into memory and pass it to the file's write handler if |
798 | * one is supplied. The ->write() method is permitted to modify the |
799 | * kernel-side buffer. |
800 | */ |
801 | ssize_t proc_simple_write(struct file *f, const char __user *ubuf, size_t size, |
802 | loff_t *_pos) |
803 | { |
804 | struct proc_dir_entry *pde = PDE(inode: file_inode(f)); |
805 | char *buf; |
806 | int ret; |
807 | |
808 | if (!pde->write) |
809 | return -EACCES; |
810 | if (size == 0 || size > PAGE_SIZE - 1) |
811 | return -EINVAL; |
812 | buf = memdup_user_nul(ubuf, size); |
813 | if (IS_ERR(ptr: buf)) |
814 | return PTR_ERR(ptr: buf); |
815 | ret = pde->write(f, buf, size); |
816 | kfree(objp: buf); |
817 | return ret == 0 ? size : ret; |
818 | } |
819 | |