]>
Commit | Line | Data |
---|---|---|
fc6cd25b EB |
1 | #include <linux/stat.h> |
2 | #include <linux/sysctl.h> | |
fc6cd25b EB |
3 | #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 | ||
fc6cd25b EB |
8 | |
9 | static 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 | ||
21 | static 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 | ||
fc6cd25b EB |
31 | |
32 | static 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(" "); | |
fc6cd25b EB |
44 | } |
45 | ||
e51b6ba0 EB |
46 | static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces, |
47 | struct ctl_table *table) | |
fc6cd25b EB |
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 | ||
e51b6ba0 EB |
55 | for (head = __sysctl_head_next(namespaces, NULL); head; |
56 | head = __sysctl_head_next(namespaces, head)) { | |
fc6cd25b EB |
57 | cur_depth = depth; |
58 | ref = head->ctl_table; | |
59 | repeat: | |
60 | test = sysctl_parent(table, cur_depth); | |
83ac201b | 61 | for (; ref->procname; ref++) { |
fc6cd25b EB |
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 | ||
fc6cd25b EB |
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; | |
81 | out: | |
82 | sysctl_head_finish(head); | |
83 | return ref; | |
84 | } | |
85 | ||
86 | static 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); | |
5db6a4da | 92 | dump_stack(); |
fc6cd25b EB |
93 | } |
94 | *fail = str; | |
95 | } | |
96 | ||
e51b6ba0 EB |
97 | static void sysctl_check_leaf(struct nsproxy *namespaces, |
98 | struct ctl_table *table, const char **fail) | |
fc6cd25b EB |
99 | { |
100 | struct ctl_table *ref; | |
101 | ||
e51b6ba0 | 102 | ref = sysctl_check_lookup(namespaces, table); |
fc6cd25b EB |
103 | if (ref && (ref != table)) |
104 | set_fail(fail, table, "Sysctl already exists"); | |
105 | } | |
106 | ||
e51b6ba0 | 107 | int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table) |
fc6cd25b EB |
108 | { |
109 | int error = 0; | |
83ac201b | 110 | for (; table->procname; table++) { |
fc6cd25b EB |
111 | const char *fail = NULL; |
112 | ||
fc6cd25b EB |
113 | if (table->parent) { |
114 | if (table->procname && !table->parent->procname) | |
115 | set_fail(&fail, table, "Parent without procname"); | |
fc6cd25b EB |
116 | } |
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"); | |
fc6cd25b EB |
128 | if (table->extra1) |
129 | set_fail(&fail, table, "Directory with extra1"); | |
130 | if (table->extra2) | |
131 | set_fail(&fail, table, "Directory with extra2"); | |
fc6cd25b | 132 | } else { |
83ac201b | 133 | if ((table->proc_handler == proc_dostring) || |
fc6cd25b | 134 | (table->proc_handler == proc_dointvec) || |
fc6cd25b EB |
135 | (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 | } | |
8c85dd87 | 146 | #ifdef CONFIG_PROC_SYSCTL |
fc6cd25b EB |
147 | if (table->procname && !table->proc_handler) |
148 | set_fail(&fail, table, "No proc_handler"); | |
49ffcf8f | 149 | #endif |
fc6cd25b EB |
150 | #if 0 |
151 | if (!table->procname && table->proc_handler) | |
152 | set_fail(&fail, table, "proc_handler without procname"); | |
153 | #endif | |
e51b6ba0 | 154 | sysctl_check_leaf(namespaces, table, &fail); |
fc6cd25b | 155 | } |
99541c23 AD |
156 | if (table->mode > 0777) |
157 | set_fail(&fail, table, "bogus .mode"); | |
fc6cd25b EB |
158 | if (fail) { |
159 | set_fail(&fail, table, NULL); | |
160 | error = -EINVAL; | |
161 | } | |
162 | if (table->child) | |
e51b6ba0 | 163 | error |= sysctl_check_table(namespaces, table->child); |
fc6cd25b EB |
164 | } |
165 | return error; | |
166 | } |