Root/kernel/sysctl_check.c

1#include <linux/stat.h>
2#include <linux/sysctl.h>
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
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}
161

Archive Download this file



interactive