Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 1 | #include <linux/stat.h> |
| 2 | #include <linux/sysctl.h> |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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 | |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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 | |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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(" "); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 44 | } |
| 45 | |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 46 | static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces, |
| 47 | struct ctl_table *table) |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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 | |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 55 | for (head = __sysctl_head_next(namespaces, NULL); head; |
| 56 | head = __sysctl_head_next(namespaces, head)) { |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 57 | cur_depth = depth; |
| 58 | ref = head->ctl_table; |
| 59 | repeat: |
| 60 | test = sysctl_parent(table, cur_depth); |
Eric W. Biederman | 83ac201 | 2009-04-03 02:22:26 -0700 | [diff] [blame] | 61 | for (; ref->procname; ref++) { |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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 | |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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); |
Alexey Dobriyan | 5db6a4d | 2007-11-05 14:50:52 -0800 | [diff] [blame] | 92 | dump_stack(); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 93 | } |
| 94 | *fail = str; |
| 95 | } |
| 96 | |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 97 | static void sysctl_check_leaf(struct nsproxy *namespaces, |
| 98 | struct ctl_table *table, const char **fail) |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 99 | { |
| 100 | struct ctl_table *ref; |
| 101 | |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 102 | ref = sysctl_check_lookup(namespaces, table); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 103 | if (ref && (ref != table)) |
| 104 | set_fail(fail, table, "Sysctl already exists"); |
| 105 | } |
| 106 | |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 107 | int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table) |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 108 | { |
| 109 | int error = 0; |
Eric W. Biederman | 83ac201 | 2009-04-03 02:22:26 -0700 | [diff] [blame] | 110 | for (; table->procname; table++) { |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 111 | const char *fail = NULL; |
| 112 | |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 113 | if (table->parent) { |
| 114 | if (table->procname && !table->parent->procname) |
| 115 | set_fail(&fail, table, "Parent without procname"); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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"); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 128 | 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. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 132 | } else { |
Eric W. Biederman | 83ac201 | 2009-04-03 02:22:26 -0700 | [diff] [blame] | 133 | if ((table->proc_handler == proc_dostring) || |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 134 | (table->proc_handler == proc_dointvec) || |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 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 | } |
Alexey Dobriyan | 8c85dd8 | 2009-10-26 16:50:07 -0700 | [diff] [blame] | 146 | #ifdef CONFIG_PROC_SYSCTL |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 147 | if (table->procname && !table->proc_handler) |
| 148 | set_fail(&fail, table, "No proc_handler"); |
Eric W. Biederman | 49ffcf8 | 2007-10-18 03:05:57 -0700 | [diff] [blame] | 149 | #endif |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 150 | #if 0 |
| 151 | if (!table->procname && table->proc_handler) |
| 152 | set_fail(&fail, table, "proc_handler without procname"); |
| 153 | #endif |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 154 | sysctl_check_leaf(namespaces, table, &fail); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 155 | } |
Alexey Dobriyan | 99541c2 | 2008-07-25 01:48:31 -0700 | [diff] [blame] | 156 | if (table->mode > 0777) |
| 157 | set_fail(&fail, table, "bogus .mode"); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 158 | if (fail) { |
| 159 | set_fail(&fail, table, NULL); |
| 160 | error = -EINVAL; |
| 161 | } |
| 162 | if (table->child) |
Eric W. Biederman | e51b6ba | 2007-11-30 23:54:00 +1100 | [diff] [blame] | 163 | error |= sysctl_check_table(namespaces, table->child); |
Eric W. Biederman | fc6cd25 | 2007-10-18 03:05:54 -0700 | [diff] [blame] | 164 | } |
| 165 | return error; |
| 166 | } |