/fs/proc/proc_net.c

https://github.com/gby/linux · C · 247 lines · 193 code · 45 blank · 9 comment · 21 complexity · b2aacad5efe359232a80c69c066d8b80 MD5 · raw file

  1. /*
  2. * linux/fs/proc/net.c
  3. *
  4. * Copyright (C) 2007
  5. *
  6. * Author: Eric Biederman <ebiederm@xmission.com>
  7. *
  8. * proc net directory handling functions
  9. */
  10. #include <linux/uaccess.h>
  11. #include <linux/errno.h>
  12. #include <linux/time.h>
  13. #include <linux/proc_fs.h>
  14. #include <linux/stat.h>
  15. #include <linux/slab.h>
  16. #include <linux/init.h>
  17. #include <linux/sched.h>
  18. #include <linux/sched/task.h>
  19. #include <linux/module.h>
  20. #include <linux/bitops.h>
  21. #include <linux/mount.h>
  22. #include <linux/nsproxy.h>
  23. #include <linux/uidgid.h>
  24. #include <net/net_namespace.h>
  25. #include <linux/seq_file.h>
  26. #include "internal.h"
  27. static inline struct net *PDE_NET(struct proc_dir_entry *pde)
  28. {
  29. return pde->parent->data;
  30. }
  31. static struct net *get_proc_net(const struct inode *inode)
  32. {
  33. return maybe_get_net(PDE_NET(PDE(inode)));
  34. }
  35. int seq_open_net(struct inode *ino, struct file *f,
  36. const struct seq_operations *ops, int size)
  37. {
  38. struct net *net;
  39. struct seq_net_private *p;
  40. BUG_ON(size < sizeof(*p));
  41. net = get_proc_net(ino);
  42. if (net == NULL)
  43. return -ENXIO;
  44. p = __seq_open_private(f, ops, size);
  45. if (p == NULL) {
  46. put_net(net);
  47. return -ENOMEM;
  48. }
  49. #ifdef CONFIG_NET_NS
  50. p->net = net;
  51. #endif
  52. return 0;
  53. }
  54. EXPORT_SYMBOL_GPL(seq_open_net);
  55. int single_open_net(struct inode *inode, struct file *file,
  56. int (*show)(struct seq_file *, void *))
  57. {
  58. int err;
  59. struct net *net;
  60. err = -ENXIO;
  61. net = get_proc_net(inode);
  62. if (net == NULL)
  63. goto err_net;
  64. err = single_open(file, show, net);
  65. if (err < 0)
  66. goto err_open;
  67. return 0;
  68. err_open:
  69. put_net(net);
  70. err_net:
  71. return err;
  72. }
  73. EXPORT_SYMBOL_GPL(single_open_net);
  74. int seq_release_net(struct inode *ino, struct file *f)
  75. {
  76. struct seq_file *seq;
  77. seq = f->private_data;
  78. put_net(seq_file_net(seq));
  79. seq_release_private(ino, f);
  80. return 0;
  81. }
  82. EXPORT_SYMBOL_GPL(seq_release_net);
  83. int single_release_net(struct inode *ino, struct file *f)
  84. {
  85. struct seq_file *seq = f->private_data;
  86. put_net(seq->private);
  87. return single_release(ino, f);
  88. }
  89. EXPORT_SYMBOL_GPL(single_release_net);
  90. static struct net *get_proc_task_net(struct inode *dir)
  91. {
  92. struct task_struct *task;
  93. struct nsproxy *ns;
  94. struct net *net = NULL;
  95. rcu_read_lock();
  96. task = pid_task(proc_pid(dir), PIDTYPE_PID);
  97. if (task != NULL) {
  98. task_lock(task);
  99. ns = task->nsproxy;
  100. if (ns != NULL)
  101. net = get_net(ns->net_ns);
  102. task_unlock(task);
  103. }
  104. rcu_read_unlock();
  105. return net;
  106. }
  107. static struct dentry *proc_tgid_net_lookup(struct inode *dir,
  108. struct dentry *dentry, unsigned int flags)
  109. {
  110. struct dentry *de;
  111. struct net *net;
  112. de = ERR_PTR(-ENOENT);
  113. net = get_proc_task_net(dir);
  114. if (net != NULL) {
  115. de = proc_lookup_de(net->proc_net, dir, dentry);
  116. put_net(net);
  117. }
  118. return de;
  119. }
  120. static int proc_tgid_net_getattr(const struct path *path, struct kstat *stat,
  121. u32 request_mask, unsigned int query_flags)
  122. {
  123. struct inode *inode = d_inode(path->dentry);
  124. struct net *net;
  125. net = get_proc_task_net(inode);
  126. generic_fillattr(inode, stat);
  127. if (net != NULL) {
  128. stat->nlink = net->proc_net->nlink;
  129. put_net(net);
  130. }
  131. return 0;
  132. }
  133. const struct inode_operations proc_net_inode_operations = {
  134. .lookup = proc_tgid_net_lookup,
  135. .getattr = proc_tgid_net_getattr,
  136. };
  137. static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)
  138. {
  139. int ret;
  140. struct net *net;
  141. ret = -EINVAL;
  142. net = get_proc_task_net(file_inode(file));
  143. if (net != NULL) {
  144. ret = proc_readdir_de(net->proc_net, file, ctx);
  145. put_net(net);
  146. }
  147. return ret;
  148. }
  149. const struct file_operations proc_net_operations = {
  150. .llseek = generic_file_llseek,
  151. .read = generic_read_dir,
  152. .iterate_shared = proc_tgid_net_readdir,
  153. };
  154. static __net_init int proc_net_ns_init(struct net *net)
  155. {
  156. struct proc_dir_entry *netd, *net_statd;
  157. kuid_t uid;
  158. kgid_t gid;
  159. int err;
  160. err = -ENOMEM;
  161. netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL);
  162. if (!netd)
  163. goto out;
  164. netd->subdir = RB_ROOT;
  165. netd->data = net;
  166. netd->nlink = 2;
  167. netd->namelen = 3;
  168. netd->parent = &proc_root;
  169. memcpy(netd->name, "net", 4);
  170. uid = make_kuid(net->user_ns, 0);
  171. if (!uid_valid(uid))
  172. uid = netd->uid;
  173. gid = make_kgid(net->user_ns, 0);
  174. if (!gid_valid(gid))
  175. gid = netd->gid;
  176. proc_set_user(netd, uid, gid);
  177. err = -EEXIST;
  178. net_statd = proc_net_mkdir(net, "stat", netd);
  179. if (!net_statd)
  180. goto free_net;
  181. net->proc_net = netd;
  182. net->proc_net_stat = net_statd;
  183. return 0;
  184. free_net:
  185. kfree(netd);
  186. out:
  187. return err;
  188. }
  189. static __net_exit void proc_net_ns_exit(struct net *net)
  190. {
  191. remove_proc_entry("stat", net->proc_net);
  192. kfree(net->proc_net);
  193. }
  194. static struct pernet_operations __net_initdata proc_net_ns_ops = {
  195. .init = proc_net_ns_init,
  196. .exit = proc_net_ns_exit,
  197. };
  198. int __init proc_net_init(void)
  199. {
  200. proc_symlink("net", NULL, "self/net");
  201. return register_pernet_subsys(&proc_net_ns_ops);
  202. }