brintos

brintos / linux-shallow public Read only

0
0
Text · 10.4 KiB · 52f0b75 Raw
419 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  linux/fs/proc/net.c4 *5 *  Copyright (C) 20076 *7 *  Author: Eric Biederman <ebiederm@xmission.com>8 *9 *  proc net directory handling functions10 */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 27#include "internal.h"28 29static inline struct net *PDE_NET(struct proc_dir_entry *pde)30{31	return pde->parent->data;32}33 34static struct net *get_proc_net(const struct inode *inode)35{36	return maybe_get_net(PDE_NET(PDE(inode)));37}38 39static int seq_open_net(struct inode *inode, struct file *file)40{41	unsigned int state_size = PDE(inode)->state_size;42	struct seq_net_private *p;43	struct net *net;44 45	WARN_ON_ONCE(state_size < sizeof(*p));46 47	if (file->f_mode & FMODE_WRITE && !PDE(inode)->write)48		return -EACCES;49 50	net = get_proc_net(inode);51	if (!net)52		return -ENXIO;53 54	p = __seq_open_private(file, PDE(inode)->seq_ops, state_size);55	if (!p) {56		put_net(net);57		return -ENOMEM;58	}59#ifdef CONFIG_NET_NS60	p->net = net;61	netns_tracker_alloc(net, &p->ns_tracker, GFP_KERNEL);62#endif63	return 0;64}65 66static void seq_file_net_put_net(struct seq_file *seq)67{68#ifdef CONFIG_NET_NS69	struct seq_net_private *priv = seq->private;70 71	put_net_track(priv->net, &priv->ns_tracker);72#else73	put_net(&init_net);74#endif75}76 77static int seq_release_net(struct inode *ino, struct file *f)78{79	struct seq_file *seq = f->private_data;80 81	seq_file_net_put_net(seq);82	seq_release_private(ino, f);83	return 0;84}85 86static const struct proc_ops proc_net_seq_ops = {87	.proc_open	= seq_open_net,88	.proc_read	= seq_read,89	.proc_write	= proc_simple_write,90	.proc_lseek	= seq_lseek,91	.proc_release	= seq_release_net,92};93 94int bpf_iter_init_seq_net(void *priv_data, struct bpf_iter_aux_info *aux)95{96#ifdef CONFIG_NET_NS97	struct seq_net_private *p = priv_data;98 99	p->net = get_net_track(current->nsproxy->net_ns, &p->ns_tracker,100			       GFP_KERNEL);101#endif102	return 0;103}104 105void bpf_iter_fini_seq_net(void *priv_data)106{107#ifdef CONFIG_NET_NS108	struct seq_net_private *p = priv_data;109 110	put_net_track(p->net, &p->ns_tracker);111#endif112}113 114struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,115		struct proc_dir_entry *parent, const struct seq_operations *ops,116		unsigned int state_size, void *data)117{118	struct proc_dir_entry *p;119 120	p = proc_create_reg(name, mode, &parent, data);121	if (!p)122		return NULL;123	pde_force_lookup(p);124	p->proc_ops = &proc_net_seq_ops;125	p->seq_ops = ops;126	p->state_size = state_size;127	return proc_register(parent, p);128}129EXPORT_SYMBOL_GPL(proc_create_net_data);130 131/**132 * proc_create_net_data_write - Create a writable net_ns-specific proc file133 * @name: The name of the file.134 * @mode: The file's access mode.135 * @parent: The parent directory in which to create.136 * @ops: The seq_file ops with which to read the file.137 * @write: The write method with which to 'modify' the file.138 * @state_size: The size of the per-file private state to allocate.139 * @data: Data for retrieval by pde_data().140 *141 * Create a network namespaced proc file in the @parent directory with the142 * specified @name and @mode that allows reading of a file that displays a143 * series of elements and also provides for the file accepting writes that have144 * some arbitrary effect.145 *146 * The functions in the @ops table are used to iterate over items to be147 * presented and extract the readable content using the seq_file interface.148 *149 * The @write function is called with the data copied into a kernel space150 * scratch buffer and has a NUL appended for convenience.  The buffer may be151 * modified by the @write function.  @write should return 0 on success.152 *153 * The @data value is accessible from the @show and @write functions by calling154 * pde_data() on the file inode.  The network namespace must be accessed by155 * calling seq_file_net() on the seq_file struct.156 */157struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,158						  struct proc_dir_entry *parent,159						  const struct seq_operations *ops,160						  proc_write_t write,161						  unsigned int state_size, void *data)162{163	struct proc_dir_entry *p;164 165	p = proc_create_reg(name, mode, &parent, data);166	if (!p)167		return NULL;168	pde_force_lookup(p);169	p->proc_ops = &proc_net_seq_ops;170	p->seq_ops = ops;171	p->state_size = state_size;172	p->write = write;173	return proc_register(parent, p);174}175EXPORT_SYMBOL_GPL(proc_create_net_data_write);176 177static int single_open_net(struct inode *inode, struct file *file)178{179	struct proc_dir_entry *de = PDE(inode);180	struct net *net;181	int err;182 183	net = get_proc_net(inode);184	if (!net)185		return -ENXIO;186 187	err = single_open(file, de->single_show, net);188	if (err)189		put_net(net);190	return err;191}192 193static int single_release_net(struct inode *ino, struct file *f)194{195	struct seq_file *seq = f->private_data;196	put_net(seq->private);197	return single_release(ino, f);198}199 200static const struct proc_ops proc_net_single_ops = {201	.proc_open	= single_open_net,202	.proc_read	= seq_read,203	.proc_write	= proc_simple_write,204	.proc_lseek	= seq_lseek,205	.proc_release	= single_release_net,206};207 208struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,209		struct proc_dir_entry *parent,210		int (*show)(struct seq_file *, void *), void *data)211{212	struct proc_dir_entry *p;213 214	p = proc_create_reg(name, mode, &parent, data);215	if (!p)216		return NULL;217	pde_force_lookup(p);218	p->proc_ops = &proc_net_single_ops;219	p->single_show = show;220	return proc_register(parent, p);221}222EXPORT_SYMBOL_GPL(proc_create_net_single);223 224/**225 * proc_create_net_single_write - Create a writable net_ns-specific proc file226 * @name: The name of the file.227 * @mode: The file's access mode.228 * @parent: The parent directory in which to create.229 * @show: The seqfile show method with which to read the file.230 * @write: The write method with which to 'modify' the file.231 * @data: Data for retrieval by pde_data().232 *233 * Create a network-namespaced proc file in the @parent directory with the234 * specified @name and @mode that allows reading of a file that displays a235 * single element rather than a series and also provides for the file accepting236 * writes that have some arbitrary effect.237 *238 * The @show function is called to extract the readable content via the239 * seq_file interface.240 *241 * The @write function is called with the data copied into a kernel space242 * scratch buffer and has a NUL appended for convenience.  The buffer may be243 * modified by the @write function.  @write should return 0 on success.244 *245 * The @data value is accessible from the @show and @write functions by calling246 * pde_data() on the file inode.  The network namespace must be accessed by247 * calling seq_file_single_net() on the seq_file struct.248 */249struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,250						    struct proc_dir_entry *parent,251						    int (*show)(struct seq_file *, void *),252						    proc_write_t write,253						    void *data)254{255	struct proc_dir_entry *p;256 257	p = proc_create_reg(name, mode, &parent, data);258	if (!p)259		return NULL;260	pde_force_lookup(p);261	p->proc_ops = &proc_net_single_ops;262	p->single_show = show;263	p->write = write;264	return proc_register(parent, p);265}266EXPORT_SYMBOL_GPL(proc_create_net_single_write);267 268static struct net *get_proc_task_net(struct inode *dir)269{270	struct task_struct *task;271	struct nsproxy *ns;272	struct net *net = NULL;273 274	rcu_read_lock();275	task = pid_task(proc_pid(dir), PIDTYPE_PID);276	if (task != NULL) {277		task_lock(task);278		ns = task->nsproxy;279		if (ns != NULL)280			net = get_net(ns->net_ns);281		task_unlock(task);282	}283	rcu_read_unlock();284 285	return net;286}287 288static struct dentry *proc_tgid_net_lookup(struct inode *dir,289		struct dentry *dentry, unsigned int flags)290{291	struct dentry *de;292	struct net *net;293 294	de = ERR_PTR(-ENOENT);295	net = get_proc_task_net(dir);296	if (net != NULL) {297		de = proc_lookup_de(dir, dentry, net->proc_net);298		put_net(net);299	}300	return de;301}302 303static int proc_tgid_net_getattr(struct mnt_idmap *idmap,304				 const struct path *path, struct kstat *stat,305				 u32 request_mask, unsigned int query_flags)306{307	struct inode *inode = d_inode(path->dentry);308	struct net *net;309 310	net = get_proc_task_net(inode);311 312	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);313 314	if (net != NULL) {315		stat->nlink = net->proc_net->nlink;316		put_net(net);317	}318 319	return 0;320}321 322const struct inode_operations proc_net_inode_operations = {323	.lookup		= proc_tgid_net_lookup,324	.getattr	= proc_tgid_net_getattr,325	.setattr        = proc_setattr,326};327 328static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx)329{330	int ret;331	struct net *net;332 333	ret = -EINVAL;334	net = get_proc_task_net(file_inode(file));335	if (net != NULL) {336		ret = proc_readdir_de(file, ctx, net->proc_net);337		put_net(net);338	}339	return ret;340}341 342const struct file_operations proc_net_operations = {343	.llseek		= generic_file_llseek,344	.read		= generic_read_dir,345	.iterate_shared	= proc_tgid_net_readdir,346};347 348static __net_init int proc_net_ns_init(struct net *net)349{350	struct proc_dir_entry *netd, *net_statd;351	kuid_t uid;352	kgid_t gid;353	int err;354 355	/*356	 * This PDE acts only as an anchor for /proc/${pid}/net hierarchy.357	 * Corresponding inode (PDE(inode) == net->proc_net) is never358	 * instantiated therefore blanket zeroing is fine.359	 * net->proc_net_stat inode is instantiated normally.360	 */361	err = -ENOMEM;362	netd = kmem_cache_zalloc(proc_dir_entry_cache, GFP_KERNEL);363	if (!netd)364		goto out;365 366	netd->subdir = RB_ROOT;367	netd->data = net;368	netd->nlink = 2;369	netd->namelen = 3;370	netd->parent = &proc_root;371	netd->name = netd->inline_name;372	memcpy(netd->name, "net", 4);373 374	uid = make_kuid(net->user_ns, 0);375	if (!uid_valid(uid))376		uid = netd->uid;377 378	gid = make_kgid(net->user_ns, 0);379	if (!gid_valid(gid))380		gid = netd->gid;381 382	proc_set_user(netd, uid, gid);383 384	/* Seed dentry revalidation for /proc/${pid}/net */385	pde_force_lookup(netd);386 387	err = -EEXIST;388	net_statd = proc_net_mkdir(net, "stat", netd);389	if (!net_statd)390		goto free_net;391 392	net->proc_net = netd;393	net->proc_net_stat = net_statd;394	return 0;395 396free_net:397	pde_free(netd);398out:399	return err;400}401 402static __net_exit void proc_net_ns_exit(struct net *net)403{404	remove_proc_entry("stat", net->proc_net);405	pde_free(net->proc_net);406}407 408static struct pernet_operations __net_initdata proc_net_ns_ops = {409	.init = proc_net_ns_init,410	.exit = proc_net_ns_exit,411};412 413int __init proc_net_init(void)414{415	proc_symlink("net", NULL, "self/net");416 417	return register_pernet_subsys(&proc_net_ns_ops);418}419