Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v3.5.6.
  1#include <linux/stat.h>
  2#include <linux/sysctl.h>
  3#include "../fs/xfs/xfs_sysctl.h"
  4#include <linux/sunrpc/debug.h>
  5#include <linux/string.h>
  6#include <net/ip_vs.h>
  7
  8
  9static int sysctl_depth(struct ctl_table *table)
 10{
 11	struct ctl_table *tmp;
 12	int depth;
 13
 14	depth = 0;
 15	for (tmp = table; tmp->parent; tmp = tmp->parent)
 16		depth++;
 17
 18	return depth;
 19}
 20
 21static struct ctl_table *sysctl_parent(struct ctl_table *table, int n)
 22{
 23	int i;
 24
 25	for (i = 0; table && i < n; i++)
 26		table = table->parent;
 27
 28	return table;
 29}
 30
 31
 32static void sysctl_print_path(struct ctl_table *table)
 33{
 34	struct ctl_table *tmp;
 35	int depth, i;
 36	depth = sysctl_depth(table);
 37	if (table->procname) {
 38		for (i = depth; i >= 0; i--) {
 39			tmp = sysctl_parent(table, i);
 40			printk("/%s", tmp->procname?tmp->procname:"");
 41		}
 42	}
 43	printk(" ");
 44}
 45
 46static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
 47						struct ctl_table *table)
 48{
 49	struct ctl_table_header *head;
 50	struct ctl_table *ref, *test;
 51	int depth, cur_depth;
 52
 53	depth = sysctl_depth(table);
 54
 55	for (head = __sysctl_head_next(namespaces, NULL); head;
 56	     head = __sysctl_head_next(namespaces, head)) {
 57		cur_depth = depth;
 58		ref = head->ctl_table;
 59repeat:
 60		test = sysctl_parent(table, cur_depth);
 61		for (; ref->procname; ref++) {
 62			int match = 0;
 63			if (cur_depth && !ref->child)
 64				continue;
 65
 66			if (test->procname && ref->procname &&
 67			    (strcmp(test->procname, ref->procname) == 0))
 68					match++;
 69
 70			if (match) {
 71				if (cur_depth != 0) {
 72					cur_depth--;
 73					ref = ref->child;
 74					goto repeat;
 75				}
 76				goto out;
 77			}
 78		}
 79	}
 80	ref = NULL;
 81out:
 82	sysctl_head_finish(head);
 83	return ref;
 84}
 85
 86static void set_fail(const char **fail, struct ctl_table *table, const char *str)
 87{
 88	if (*fail) {
 89		printk(KERN_ERR "sysctl table check failed: ");
 90		sysctl_print_path(table);
 91		printk(" %s\n", *fail);
 92		dump_stack();
 93	}
 94	*fail = str;
 95}
 96
 97static void sysctl_check_leaf(struct nsproxy *namespaces,
 98				struct ctl_table *table, const char **fail)
 99{
100	struct ctl_table *ref;
101
102	ref = sysctl_check_lookup(namespaces, table);
103	if (ref && (ref != table))
104		set_fail(fail, table, "Sysctl already exists");
105}
106
107int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
108{
109	int error = 0;
110	for (; table->procname; table++) {
111		const char *fail = NULL;
112
113		if (table->parent) {
114			if (!table->parent->procname)
115				set_fail(&fail, table, "Parent without procname");
116		}
117		if (table->child) {
118			if (table->data)
119				set_fail(&fail, table, "Directory with data?");
120			if (table->maxlen)
121				set_fail(&fail, table, "Directory with maxlen?");
122			if ((table->mode & (S_IRUGO|S_IXUGO)) != table->mode)
123				set_fail(&fail, table, "Writable sysctl directory");
124			if (table->proc_handler)
125				set_fail(&fail, table, "Directory with proc_handler");
126			if (table->extra1)
127				set_fail(&fail, table, "Directory with extra1");
128			if (table->extra2)
129				set_fail(&fail, table, "Directory with extra2");
130		} else {
131			if ((table->proc_handler == proc_dostring) ||
132			    (table->proc_handler == proc_dointvec) ||
133			    (table->proc_handler == proc_dointvec_minmax) ||
134			    (table->proc_handler == proc_dointvec_jiffies) ||
135			    (table->proc_handler == proc_dointvec_userhz_jiffies) ||
136			    (table->proc_handler == proc_dointvec_ms_jiffies) ||
137			    (table->proc_handler == proc_doulongvec_minmax) ||
138			    (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
139				if (!table->data)
140					set_fail(&fail, table, "No data");
141				if (!table->maxlen)
142					set_fail(&fail, table, "No maxlen");
143			}
144#ifdef CONFIG_PROC_SYSCTL
145			if (!table->proc_handler)
146				set_fail(&fail, table, "No proc_handler");
147#endif
148			sysctl_check_leaf(namespaces, table, &fail);
149		}
150		if (table->mode > 0777)
151			set_fail(&fail, table, "bogus .mode");
152		if (fail) {
153			set_fail(&fail, table, NULL);
154			error = -EINVAL;
155		}
156		if (table->child)
157			error |= sysctl_check_table(namespaces, table->child);
158	}
159	return error;
160}