sysctl_check.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. static int sysctl_depth(struct ctl_table *table)
  8. {
  9. struct ctl_table *tmp;
  10. int depth;
  11. depth = 0;
  12. for (tmp = table; tmp->parent; tmp = tmp->parent)
  13. depth++;
  14. return depth;
  15. }
  16. static struct ctl_table *sysctl_parent(struct ctl_table *table, int n)
  17. {
  18. int i;
  19. for (i = 0; table && i < n; i++)
  20. table = table->parent;
  21. return table;
  22. }
  23. static void sysctl_print_path(struct ctl_table *table)
  24. {
  25. struct ctl_table *tmp;
  26. int depth, i;
  27. depth = sysctl_depth(table);
  28. if (table->procname) {
  29. for (i = depth; i >= 0; i--) {
  30. tmp = sysctl_parent(table, i);
  31. printk("/%s", tmp->procname?tmp->procname:"");
  32. }
  33. }
  34. printk(" ");
  35. }
  36. static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
  37. struct ctl_table *table)
  38. {
  39. struct ctl_table_header *head;
  40. struct ctl_table *ref, *test;
  41. int depth, cur_depth;
  42. depth = sysctl_depth(table);
  43. for (head = __sysctl_head_next(namespaces, NULL); head;
  44. head = __sysctl_head_next(namespaces, head)) {
  45. cur_depth = depth;
  46. ref = head->ctl_table;
  47. repeat:
  48. test = sysctl_parent(table, cur_depth);
  49. for (; ref->procname; ref++) {
  50. int match = 0;
  51. if (cur_depth && !ref->child)
  52. continue;
  53. if (test->procname && ref->procname &&
  54. (strcmp(test->procname, ref->procname) == 0))
  55. match++;
  56. if (match) {
  57. if (cur_depth != 0) {
  58. cur_depth--;
  59. ref = ref->child;
  60. goto repeat;
  61. }
  62. goto out;
  63. }
  64. }
  65. }
  66. ref = NULL;
  67. out:
  68. sysctl_head_finish(head);
  69. return ref;
  70. }
  71. static void set_fail(const char **fail, struct ctl_table *table, const char *str)
  72. {
  73. if (*fail) {
  74. printk(KERN_ERR "sysctl table check failed: ");
  75. sysctl_print_path(table);
  76. printk(" %s\n", *fail);
  77. dump_stack();
  78. }
  79. *fail = str;
  80. }
  81. static void sysctl_check_leaf(struct nsproxy *namespaces,
  82. struct ctl_table *table, const char **fail)
  83. {
  84. struct ctl_table *ref;
  85. ref = sysctl_check_lookup(namespaces, table);
  86. if (ref && (ref != table))
  87. set_fail(fail, table, "Sysctl already exists");
  88. }
  89. int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
  90. {
  91. int error = 0;
  92. for (; table->procname; table++) {
  93. const char *fail = NULL;
  94. if (table->parent) {
  95. if (!table->parent->procname)
  96. set_fail(&fail, table, "Parent without procname");
  97. }
  98. if (table->child) {
  99. if (table->data)
  100. set_fail(&fail, table, "Directory with data?");
  101. if (table->maxlen)
  102. set_fail(&fail, table, "Directory with maxlen?");
  103. if ((table->mode & (S_IRUGO|S_IXUGO)) != table->mode)
  104. set_fail(&fail, table, "Writable sysctl directory");
  105. if (table->proc_handler)
  106. set_fail(&fail, table, "Directory with proc_handler");
  107. if (table->extra1)
  108. set_fail(&fail, table, "Directory with extra1");
  109. if (table->extra2)
  110. set_fail(&fail, table, "Directory with extra2");
  111. } else {
  112. if ((table->proc_handler == proc_dostring) ||
  113. (table->proc_handler == proc_dointvec) ||
  114. (table->proc_handler == proc_dointvec_minmax) ||
  115. (table->proc_handler == proc_dointvec_jiffies) ||
  116. (table->proc_handler == proc_dointvec_userhz_jiffies) ||
  117. (table->proc_handler == proc_dointvec_ms_jiffies) ||
  118. (table->proc_handler == proc_doulongvec_minmax) ||
  119. (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
  120. if (!table->data)
  121. set_fail(&fail, table, "No data");
  122. if (!table->maxlen)
  123. set_fail(&fail, table, "No maxlen");
  124. }
  125. #ifdef CONFIG_PROC_SYSCTL
  126. if (!table->proc_handler)
  127. set_fail(&fail, table, "No proc_handler");
  128. #endif
  129. sysctl_check_leaf(namespaces, table, &fail);
  130. }
  131. if (table->mode > 0777)
  132. set_fail(&fail, table, "bogus .mode");
  133. if (fail) {
  134. set_fail(&fail, table, NULL);
  135. error = -EINVAL;
  136. }
  137. if (table->child)
  138. error |= sysctl_check_table(namespaces, table->child);
  139. }
  140. return error;
  141. }