ipc_sysctl.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright (C) 2007
  3. *
  4. * Author: Eric Biederman <ebiederm@xmision.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation, version 2 of the
  9. * License.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/ipc.h>
  13. #include <linux/nsproxy.h>
  14. #include <linux/sysctl.h>
  15. #include <linux/uaccess.h>
  16. #include <linux/ipc_namespace.h>
  17. static void *get_ipc(ctl_table *table)
  18. {
  19. char *which = table->data;
  20. struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
  21. which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
  22. return which;
  23. }
  24. #ifdef CONFIG_PROC_FS
  25. static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
  26. void __user *buffer, size_t *lenp, loff_t *ppos)
  27. {
  28. struct ctl_table ipc_table;
  29. memcpy(&ipc_table, table, sizeof(ipc_table));
  30. ipc_table.data = get_ipc(table);
  31. return proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos);
  32. }
  33. static int proc_ipc_callback_dointvec(ctl_table *table, int write,
  34. struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
  35. {
  36. size_t lenp_bef = *lenp;
  37. int rc;
  38. rc = proc_ipc_dointvec(table, write, filp, buffer, lenp, ppos);
  39. if (write && !rc && lenp_bef == *lenp)
  40. /*
  41. * Tunable has successfully been changed from userland:
  42. * disable its automatic recomputing.
  43. */
  44. unregister_ipcns_notifier(current->nsproxy->ipc_ns);
  45. return rc;
  46. }
  47. static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
  48. struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
  49. {
  50. struct ctl_table ipc_table;
  51. memcpy(&ipc_table, table, sizeof(ipc_table));
  52. ipc_table.data = get_ipc(table);
  53. return proc_doulongvec_minmax(&ipc_table, write, filp, buffer,
  54. lenp, ppos);
  55. }
  56. #else
  57. #define proc_ipc_doulongvec_minmax NULL
  58. #define proc_ipc_dointvec NULL
  59. #define proc_ipc_callback_dointvec NULL
  60. #endif
  61. #ifdef CONFIG_SYSCTL_SYSCALL
  62. /* The generic sysctl ipc data routine. */
  63. static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
  64. void __user *oldval, size_t __user *oldlenp,
  65. void __user *newval, size_t newlen)
  66. {
  67. size_t len;
  68. void *data;
  69. /* Get out of I don't have a variable */
  70. if (!table->data || !table->maxlen)
  71. return -ENOTDIR;
  72. data = get_ipc(table);
  73. if (!data)
  74. return -ENOTDIR;
  75. if (oldval && oldlenp) {
  76. if (get_user(len, oldlenp))
  77. return -EFAULT;
  78. if (len) {
  79. if (len > table->maxlen)
  80. len = table->maxlen;
  81. if (copy_to_user(oldval, data, len))
  82. return -EFAULT;
  83. if (put_user(len, oldlenp))
  84. return -EFAULT;
  85. }
  86. }
  87. if (newval && newlen) {
  88. if (newlen > table->maxlen)
  89. newlen = table->maxlen;
  90. if (copy_from_user(data, newval, newlen))
  91. return -EFAULT;
  92. }
  93. return 1;
  94. }
  95. static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
  96. int nlen, void __user *oldval, size_t __user *oldlenp,
  97. void __user *newval, size_t newlen)
  98. {
  99. int rc;
  100. rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval,
  101. newlen);
  102. if (newval && newlen && rc > 0)
  103. /*
  104. * Tunable has successfully been changed from userland:
  105. * disable its automatic recomputing.
  106. */
  107. unregister_ipcns_notifier(current->nsproxy->ipc_ns);
  108. return rc;
  109. }
  110. #else
  111. #define sysctl_ipc_data NULL
  112. #define sysctl_ipc_registered_data NULL
  113. #endif
  114. static struct ctl_table ipc_kern_table[] = {
  115. {
  116. .ctl_name = KERN_SHMMAX,
  117. .procname = "shmmax",
  118. .data = &init_ipc_ns.shm_ctlmax,
  119. .maxlen = sizeof (init_ipc_ns.shm_ctlmax),
  120. .mode = 0644,
  121. .proc_handler = proc_ipc_doulongvec_minmax,
  122. .strategy = sysctl_ipc_data,
  123. },
  124. {
  125. .ctl_name = KERN_SHMALL,
  126. .procname = "shmall",
  127. .data = &init_ipc_ns.shm_ctlall,
  128. .maxlen = sizeof (init_ipc_ns.shm_ctlall),
  129. .mode = 0644,
  130. .proc_handler = proc_ipc_doulongvec_minmax,
  131. .strategy = sysctl_ipc_data,
  132. },
  133. {
  134. .ctl_name = KERN_SHMMNI,
  135. .procname = "shmmni",
  136. .data = &init_ipc_ns.shm_ctlmni,
  137. .maxlen = sizeof (init_ipc_ns.shm_ctlmni),
  138. .mode = 0644,
  139. .proc_handler = proc_ipc_dointvec,
  140. .strategy = sysctl_ipc_data,
  141. },
  142. {
  143. .ctl_name = KERN_MSGMAX,
  144. .procname = "msgmax",
  145. .data = &init_ipc_ns.msg_ctlmax,
  146. .maxlen = sizeof (init_ipc_ns.msg_ctlmax),
  147. .mode = 0644,
  148. .proc_handler = proc_ipc_dointvec,
  149. .strategy = sysctl_ipc_data,
  150. },
  151. {
  152. .ctl_name = KERN_MSGMNI,
  153. .procname = "msgmni",
  154. .data = &init_ipc_ns.msg_ctlmni,
  155. .maxlen = sizeof (init_ipc_ns.msg_ctlmni),
  156. .mode = 0644,
  157. .proc_handler = proc_ipc_callback_dointvec,
  158. .strategy = sysctl_ipc_registered_data,
  159. },
  160. {
  161. .ctl_name = KERN_MSGMNB,
  162. .procname = "msgmnb",
  163. .data = &init_ipc_ns.msg_ctlmnb,
  164. .maxlen = sizeof (init_ipc_ns.msg_ctlmnb),
  165. .mode = 0644,
  166. .proc_handler = proc_ipc_dointvec,
  167. .strategy = sysctl_ipc_data,
  168. },
  169. {
  170. .ctl_name = KERN_SEM,
  171. .procname = "sem",
  172. .data = &init_ipc_ns.sem_ctls,
  173. .maxlen = 4*sizeof (int),
  174. .mode = 0644,
  175. .proc_handler = proc_ipc_dointvec,
  176. .strategy = sysctl_ipc_data,
  177. },
  178. {}
  179. };
  180. static struct ctl_table ipc_root_table[] = {
  181. {
  182. .ctl_name = CTL_KERN,
  183. .procname = "kernel",
  184. .mode = 0555,
  185. .child = ipc_kern_table,
  186. },
  187. {}
  188. };
  189. static int __init ipc_sysctl_init(void)
  190. {
  191. register_sysctl_table(ipc_root_table);
  192. return 0;
  193. }
  194. __initcall(ipc_sysctl_init);