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