blob: 10b90d8a03c48678258c6aaf3de353af7b06ed36 [file] [log] [blame]
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -07001#include <linux/stat.h>
2#include <linux/sysctl.h>
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -07003#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
4#include <linux/sunrpc/debug.h>
5#include <linux/string.h>
6#include <net/ip_vs.h>
7
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -07008
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
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070031
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(" ");
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070044}
45
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +110046static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
47 struct ctl_table *table)
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070048{
49 struct ctl_table_header *head;
50 struct ctl_table *ref, *test;
51 int depth, cur_depth;
52
53 depth = sysctl_depth(table);
54
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +110055 for (head = __sysctl_head_next(namespaces, NULL); head;
56 head = __sysctl_head_next(namespaces, head)) {
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070057 cur_depth = depth;
58 ref = head->ctl_table;
59repeat:
60 test = sysctl_parent(table, cur_depth);
Eric W. Biederman83ac2012009-04-03 02:22:26 -070061 for (; ref->procname; ref++) {
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070062 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
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070070 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);
Alexey Dobriyan5db6a4d2007-11-05 14:50:52 -080092 dump_stack();
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070093 }
94 *fail = str;
95}
96
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +110097static void sysctl_check_leaf(struct nsproxy *namespaces,
98 struct ctl_table *table, const char **fail)
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -070099{
100 struct ctl_table *ref;
101
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +1100102 ref = sysctl_check_lookup(namespaces, table);
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700103 if (ref && (ref != table))
104 set_fail(fail, table, "Sysctl already exists");
105}
106
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +1100107int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700108{
109 int error = 0;
Eric W. Biederman83ac2012009-04-03 02:22:26 -0700110 for (; table->procname; table++) {
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700111 const char *fail = NULL;
112
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700113 if (table->parent) {
114 if (table->procname && !table->parent->procname)
115 set_fail(&fail, table, "Parent without procname");
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700116 }
117 if (!table->procname)
118 set_fail(&fail, table, "No procname");
119 if (table->child) {
120 if (table->data)
121 set_fail(&fail, table, "Directory with data?");
122 if (table->maxlen)
123 set_fail(&fail, table, "Directory with maxlen?");
124 if ((table->mode & (S_IRUGO|S_IXUGO)) != table->mode)
125 set_fail(&fail, table, "Writable sysctl directory");
126 if (table->proc_handler)
127 set_fail(&fail, table, "Directory with proc_handler");
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700128 if (table->extra1)
129 set_fail(&fail, table, "Directory with extra1");
130 if (table->extra2)
131 set_fail(&fail, table, "Directory with extra2");
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700132 } else {
Eric W. Biederman83ac2012009-04-03 02:22:26 -0700133 if ((table->proc_handler == proc_dostring) ||
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700134 (table->proc_handler == proc_dointvec) ||
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700135 (table->proc_handler == proc_dointvec_minmax) ||
136 (table->proc_handler == proc_dointvec_jiffies) ||
137 (table->proc_handler == proc_dointvec_userhz_jiffies) ||
138 (table->proc_handler == proc_dointvec_ms_jiffies) ||
139 (table->proc_handler == proc_doulongvec_minmax) ||
140 (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
141 if (!table->data)
142 set_fail(&fail, table, "No data");
143 if (!table->maxlen)
144 set_fail(&fail, table, "No maxlen");
145 }
Alexey Dobriyan8c85dd82009-10-26 16:50:07 -0700146#ifdef CONFIG_PROC_SYSCTL
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700147 if (table->procname && !table->proc_handler)
148 set_fail(&fail, table, "No proc_handler");
Eric W. Biederman49ffcf82007-10-18 03:05:57 -0700149#endif
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700150#if 0
151 if (!table->procname && table->proc_handler)
152 set_fail(&fail, table, "proc_handler without procname");
153#endif
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +1100154 sysctl_check_leaf(namespaces, table, &fail);
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700155 }
Alexey Dobriyan99541c22008-07-25 01:48:31 -0700156 if (table->mode > 0777)
157 set_fail(&fail, table, "bogus .mode");
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700158 if (fail) {
159 set_fail(&fail, table, NULL);
160 error = -EINVAL;
161 }
162 if (table->child)
Eric W. Biedermane51b6ba2007-11-30 23:54:00 +1100163 error |= sysctl_check_table(namespaces, table->child);
Eric W. Biedermanfc6cd252007-10-18 03:05:54 -0700164 }
165 return error;
166}