xref: /kernel/linux/linux-5.10/net/sysctl_net.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- linux-c -*-
38c2ecf20Sopenharmony_ci * sysctl_net.c: sysctl interface to net subsystem.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Begun April 1, 1996, Mike Shaver.
68c2ecf20Sopenharmony_ci * Added /proc/sys/net directories for each protocol family. [MS]
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Revision 1.2  1996/05/08  20:24:40  shaver
98c2ecf20Sopenharmony_ci * Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and
108c2ecf20Sopenharmony_ci * NET_IPV4_IP_FORWARD.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/mm.h>
168c2ecf20Sopenharmony_ci#include <linux/export.h>
178c2ecf20Sopenharmony_ci#include <linux/sysctl.h>
188c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <net/sock.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#ifdef CONFIG_INET
238c2ecf20Sopenharmony_ci#include <net/ip.h>
248c2ecf20Sopenharmony_ci#endif
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#ifdef CONFIG_NET
278c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic struct ctl_table_set *
318c2ecf20Sopenharmony_cinet_ctl_header_lookup(struct ctl_table_root *root)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	return &current->nsproxy->net_ns->sysctls;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int is_seen(struct ctl_table_set *set)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return &current->nsproxy->net_ns->sysctls == set;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* Return standard mode bits for table entry. */
428c2ecf20Sopenharmony_cistatic int net_ctl_permissions(struct ctl_table_header *head,
438c2ecf20Sopenharmony_ci			       struct ctl_table *table)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct net *net = container_of(head->set, struct net, sysctls);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* Allow network administrator to have same access as root. */
488c2ecf20Sopenharmony_ci	if (ns_capable_noaudit(net->user_ns, CAP_NET_ADMIN)) {
498c2ecf20Sopenharmony_ci		int mode = (table->mode >> 6) & 7;
508c2ecf20Sopenharmony_ci		return (mode << 6) | (mode << 3) | mode;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return table->mode;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void net_ctl_set_ownership(struct ctl_table_header *head,
578c2ecf20Sopenharmony_ci				  struct ctl_table *table,
588c2ecf20Sopenharmony_ci				  kuid_t *uid, kgid_t *gid)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct net *net = container_of(head->set, struct net, sysctls);
618c2ecf20Sopenharmony_ci	kuid_t ns_root_uid;
628c2ecf20Sopenharmony_ci	kgid_t ns_root_gid;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	ns_root_uid = make_kuid(net->user_ns, 0);
658c2ecf20Sopenharmony_ci	if (uid_valid(ns_root_uid))
668c2ecf20Sopenharmony_ci		*uid = ns_root_uid;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	ns_root_gid = make_kgid(net->user_ns, 0);
698c2ecf20Sopenharmony_ci	if (gid_valid(ns_root_gid))
708c2ecf20Sopenharmony_ci		*gid = ns_root_gid;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic struct ctl_table_root net_sysctl_root = {
748c2ecf20Sopenharmony_ci	.lookup = net_ctl_header_lookup,
758c2ecf20Sopenharmony_ci	.permissions = net_ctl_permissions,
768c2ecf20Sopenharmony_ci	.set_ownership = net_ctl_set_ownership,
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int __net_init sysctl_net_init(struct net *net)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen);
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void __net_exit sysctl_net_exit(struct net *net)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	retire_sysctl_set(&net->sysctls);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic struct pernet_operations sysctl_pernet_ops = {
918c2ecf20Sopenharmony_ci	.init = sysctl_net_init,
928c2ecf20Sopenharmony_ci	.exit = sysctl_net_exit,
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic struct ctl_table_header *net_header;
968c2ecf20Sopenharmony_ci__init int net_sysctl_init(void)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	static struct ctl_table empty[1];
998c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
1008c2ecf20Sopenharmony_ci	/* Avoid limitations in the sysctl implementation by
1018c2ecf20Sopenharmony_ci	 * registering "/proc/sys/net" as an empty directory not in a
1028c2ecf20Sopenharmony_ci	 * network namespace.
1038c2ecf20Sopenharmony_ci	 */
1048c2ecf20Sopenharmony_ci	net_header = register_sysctl("net", empty);
1058c2ecf20Sopenharmony_ci	if (!net_header)
1068c2ecf20Sopenharmony_ci		goto out;
1078c2ecf20Sopenharmony_ci	ret = register_pernet_subsys(&sysctl_pernet_ops);
1088c2ecf20Sopenharmony_ci	if (ret)
1098c2ecf20Sopenharmony_ci		goto out1;
1108c2ecf20Sopenharmony_ciout:
1118c2ecf20Sopenharmony_ci	return ret;
1128c2ecf20Sopenharmony_ciout1:
1138c2ecf20Sopenharmony_ci	unregister_sysctl_table(net_header);
1148c2ecf20Sopenharmony_ci	net_header = NULL;
1158c2ecf20Sopenharmony_ci	goto out;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistruct ctl_table_header *register_net_sysctl(struct net *net,
1198c2ecf20Sopenharmony_ci	const char *path, struct ctl_table *table)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	return __register_sysctl_table(&net->sysctls, path, table);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_net_sysctl);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_civoid unregister_net_sysctl_table(struct ctl_table_header *header)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	unregister_sysctl_table(header);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_net_sysctl_table);
130