mq_sysctl.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2007 IBM Corporation
  4. *
  5. * Author: Cedric Le Goater <clg@fr.ibm.com>
  6. */
  7. #include <linux/nsproxy.h>
  8. #include <linux/ipc_namespace.h>
  9. #include <linux/sysctl.h>
  10. #include <linux/stat.h>
  11. #include <linux/capability.h>
  12. #include <linux/slab.h>
  13. #include <linux/cred.h>
  14. static int msg_max_limit_min = MIN_MSGMAX;
  15. static int msg_max_limit_max = HARD_MSGMAX;
  16. static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
  17. static int msg_maxsize_limit_max = HARD_MSGSIZEMAX;
  18. static struct ctl_table mq_sysctls[] = {
  19. {
  20. .procname = "queues_max",
  21. .data = &init_ipc_ns.mq_queues_max,
  22. .maxlen = sizeof(int),
  23. .mode = 0644,
  24. .proc_handler = proc_dointvec,
  25. },
  26. {
  27. .procname = "msg_max",
  28. .data = &init_ipc_ns.mq_msg_max,
  29. .maxlen = sizeof(int),
  30. .mode = 0644,
  31. .proc_handler = proc_dointvec_minmax,
  32. .extra1 = &msg_max_limit_min,
  33. .extra2 = &msg_max_limit_max,
  34. },
  35. {
  36. .procname = "msgsize_max",
  37. .data = &init_ipc_ns.mq_msgsize_max,
  38. .maxlen = sizeof(int),
  39. .mode = 0644,
  40. .proc_handler = proc_dointvec_minmax,
  41. .extra1 = &msg_maxsize_limit_min,
  42. .extra2 = &msg_maxsize_limit_max,
  43. },
  44. {
  45. .procname = "msg_default",
  46. .data = &init_ipc_ns.mq_msg_default,
  47. .maxlen = sizeof(int),
  48. .mode = 0644,
  49. .proc_handler = proc_dointvec_minmax,
  50. .extra1 = &msg_max_limit_min,
  51. .extra2 = &msg_max_limit_max,
  52. },
  53. {
  54. .procname = "msgsize_default",
  55. .data = &init_ipc_ns.mq_msgsize_default,
  56. .maxlen = sizeof(int),
  57. .mode = 0644,
  58. .proc_handler = proc_dointvec_minmax,
  59. .extra1 = &msg_maxsize_limit_min,
  60. .extra2 = &msg_maxsize_limit_max,
  61. },
  62. };
  63. static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
  64. {
  65. return &current->nsproxy->ipc_ns->mq_set;
  66. }
  67. static int set_is_seen(struct ctl_table_set *set)
  68. {
  69. return &current->nsproxy->ipc_ns->mq_set == set;
  70. }
  71. static void mq_set_ownership(struct ctl_table_header *head,
  72. kuid_t *uid, kgid_t *gid)
  73. {
  74. struct ipc_namespace *ns =
  75. container_of(head->set, struct ipc_namespace, mq_set);
  76. kuid_t ns_root_uid = make_kuid(ns->user_ns, 0);
  77. kgid_t ns_root_gid = make_kgid(ns->user_ns, 0);
  78. *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID;
  79. *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID;
  80. }
  81. static int mq_permissions(struct ctl_table_header *head, const struct ctl_table *table)
  82. {
  83. int mode = table->mode;
  84. kuid_t ns_root_uid;
  85. kgid_t ns_root_gid;
  86. mq_set_ownership(head, &ns_root_uid, &ns_root_gid);
  87. if (uid_eq(current_euid(), ns_root_uid))
  88. mode >>= 6;
  89. else if (in_egroup_p(ns_root_gid))
  90. mode >>= 3;
  91. mode &= 7;
  92. return (mode << 6) | (mode << 3) | mode;
  93. }
  94. static struct ctl_table_root set_root = {
  95. .lookup = set_lookup,
  96. .permissions = mq_permissions,
  97. .set_ownership = mq_set_ownership,
  98. };
  99. bool setup_mq_sysctls(struct ipc_namespace *ns)
  100. {
  101. struct ctl_table *tbl;
  102. setup_sysctl_set(&ns->mq_set, &set_root, set_is_seen);
  103. tbl = kmemdup(mq_sysctls, sizeof(mq_sysctls), GFP_KERNEL);
  104. if (tbl) {
  105. int i;
  106. for (i = 0; i < ARRAY_SIZE(mq_sysctls); i++) {
  107. if (tbl[i].data == &init_ipc_ns.mq_queues_max)
  108. tbl[i].data = &ns->mq_queues_max;
  109. else if (tbl[i].data == &init_ipc_ns.mq_msg_max)
  110. tbl[i].data = &ns->mq_msg_max;
  111. else if (tbl[i].data == &init_ipc_ns.mq_msgsize_max)
  112. tbl[i].data = &ns->mq_msgsize_max;
  113. else if (tbl[i].data == &init_ipc_ns.mq_msg_default)
  114. tbl[i].data = &ns->mq_msg_default;
  115. else if (tbl[i].data == &init_ipc_ns.mq_msgsize_default)
  116. tbl[i].data = &ns->mq_msgsize_default;
  117. else
  118. tbl[i].data = NULL;
  119. }
  120. ns->mq_sysctls = __register_sysctl_table(&ns->mq_set,
  121. "fs/mqueue", tbl,
  122. ARRAY_SIZE(mq_sysctls));
  123. }
  124. if (!ns->mq_sysctls) {
  125. kfree(tbl);
  126. retire_sysctl_set(&ns->mq_set);
  127. return false;
  128. }
  129. return true;
  130. }
  131. void retire_mq_sysctls(struct ipc_namespace *ns)
  132. {
  133. const struct ctl_table *tbl;
  134. tbl = ns->mq_sysctls->ctl_table_arg;
  135. unregister_sysctl_table(ns->mq_sysctls);
  136. retire_sysctl_set(&ns->mq_set);
  137. kfree(tbl);
  138. }