2
0

capabilities.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright (C) 2015 Etienne CHAMPETIER <champetier.etienne@gmail.com>
  3. * Copyright (C) 2020 Daniel Golle <daniel@makrotopia.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License version 2.1
  7. * as published by the Free Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #define _GNU_SOURCE 1
  15. #include <syslog.h>
  16. #include <sys/prctl.h>
  17. #include <libubox/blobmsg.h>
  18. #include <libubox/blobmsg_json.h>
  19. #include "log.h"
  20. #include "../capabilities-names.h"
  21. #include "capabilities.h"
  22. #define JAIL_CAP_ERROR (1LLU << (CAP_LAST_CAP+1))
  23. #define JAIL_CAP_ALL (0xffffffffffffffffLLU)
  24. static int find_capabilities(const char *name)
  25. {
  26. int i;
  27. for (i = 0; i <= CAP_LAST_CAP; i++)
  28. if (capabilities_names[i] && !strcasecmp(capabilities_names[i], name))
  29. return i;
  30. return -1;
  31. }
  32. enum {
  33. OCI_CAPABILITIES_BOUNDING,
  34. OCI_CAPABILITIES_EFFECTIVE,
  35. OCI_CAPABILITIES_INHERITABLE,
  36. OCI_CAPABILITIES_PERMITTED,
  37. OCI_CAPABILITIES_AMBIENT,
  38. __OCI_CAPABILITIES_MAX
  39. };
  40. static const struct blobmsg_policy oci_capabilities_policy[] = {
  41. [OCI_CAPABILITIES_BOUNDING] = { "bounding", BLOBMSG_TYPE_ARRAY },
  42. [OCI_CAPABILITIES_EFFECTIVE] = { "effective", BLOBMSG_TYPE_ARRAY },
  43. [OCI_CAPABILITIES_INHERITABLE] = { "inheritable", BLOBMSG_TYPE_ARRAY },
  44. [OCI_CAPABILITIES_PERMITTED] = { "permitted", BLOBMSG_TYPE_ARRAY },
  45. [OCI_CAPABILITIES_AMBIENT] = { "ambient", BLOBMSG_TYPE_ARRAY },
  46. };
  47. static uint64_t parseOCIcap(struct blob_attr *msg)
  48. {
  49. struct blob_attr *cur;
  50. int rem;
  51. uint64_t caps = 0;
  52. int capnum;
  53. /* each capset is optional, set all-1 mask if absent */
  54. if (!msg)
  55. return JAIL_CAP_ALL;
  56. blobmsg_for_each_attr(cur, msg, rem) {
  57. capnum = find_capabilities(blobmsg_get_string(cur));
  58. if (capnum < 0)
  59. return JAIL_CAP_ERROR;
  60. caps |= (1LLU << capnum);
  61. }
  62. return caps;
  63. }
  64. int parseOCIcapabilities(struct jail_capset *capset, struct blob_attr *msg)
  65. {
  66. struct blob_attr *tb[__OCI_CAPABILITIES_MAX];
  67. uint64_t caps;
  68. blobmsg_parse(oci_capabilities_policy, __OCI_CAPABILITIES_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
  69. caps = parseOCIcap(tb[OCI_CAPABILITIES_BOUNDING]);
  70. if (caps == JAIL_CAP_ERROR)
  71. return EINVAL;
  72. else
  73. capset->bounding = caps;
  74. caps = parseOCIcap(tb[OCI_CAPABILITIES_EFFECTIVE]);
  75. if (caps == JAIL_CAP_ERROR)
  76. return EINVAL;
  77. else
  78. capset->effective = caps;
  79. caps = parseOCIcap(tb[OCI_CAPABILITIES_INHERITABLE]);
  80. if (caps == JAIL_CAP_ERROR)
  81. return EINVAL;
  82. else
  83. capset->inheritable = caps;
  84. caps = parseOCIcap(tb[OCI_CAPABILITIES_PERMITTED]);
  85. if (caps == JAIL_CAP_ERROR)
  86. return EINVAL;
  87. else
  88. capset->permitted = caps;
  89. caps = parseOCIcap(tb[OCI_CAPABILITIES_AMBIENT]);
  90. if (caps == JAIL_CAP_ERROR)
  91. return EINVAL;
  92. else
  93. capset->ambient = caps;
  94. capset->apply = 1;
  95. return 0;
  96. }
  97. int applyOCIcapabilities(struct jail_capset ocicapset, uint64_t retain)
  98. {
  99. struct __user_cap_header_struct uh = {};
  100. struct __user_cap_data_struct ud[2];
  101. int cap;
  102. int is_set;
  103. if (!ocicapset.apply)
  104. return 0;
  105. /* drop from bounding set */
  106. if (ocicapset.bounding != JAIL_CAP_ALL) {
  107. for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
  108. if (!prctl(PR_CAPBSET_READ, cap, 0, 0, 0)) {
  109. /* can't raise */
  110. if (ocicapset.bounding & (1LLU << cap))
  111. ERROR("capability %s (%d) is not in bounding set\n", capabilities_names[cap], cap);
  112. continue;
  113. }
  114. if ( ((ocicapset.bounding | retain) & (1LLU << cap)) == 0) {
  115. DEBUG("dropping capability %s (%d) from bounding set\n", capabilities_names[cap], cap);
  116. if (prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)) {
  117. ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %m\n", cap);
  118. return errno;
  119. }
  120. } else {
  121. DEBUG("keeping capability %s (%d)\n", capabilities_names[cap], cap);
  122. }
  123. }
  124. }
  125. /* set effective, permitted and inheritable */
  126. uh.version = _LINUX_CAPABILITY_VERSION_3;
  127. uh.pid = getpid();
  128. if (capget(&uh, ud)) {
  129. ERROR("capget() failed\n");
  130. return -1;
  131. }
  132. DEBUG("old capabilities: Pe=%016llx Pp=%016llx Pi=%016llx\n",
  133. 0LLU | ud[0].effective | (0LLU | ud[1].effective) << 32,
  134. 0LLU | ud[0].permitted | (0LLU | ud[1].permitted) << 32,
  135. 0LLU | ud[0].inheritable | (0LLU | ud[1].inheritable) << 32);
  136. if (ocicapset.effective != JAIL_CAP_ALL) {
  137. ud[0].effective = (ocicapset.effective | retain) & 0xFFFFFFFFU;
  138. ud[1].effective = ((ocicapset.effective | retain) >> 32) & 0xFFFFFFFFU;
  139. }
  140. if (ocicapset.permitted != JAIL_CAP_ALL) {
  141. ud[0].permitted = (ocicapset.permitted | retain) & 0xFFFFFFFFU;
  142. ud[1].permitted = ((ocicapset.permitted | retain) >> 32) & 0xFFFFFFFFU;
  143. }
  144. if (ocicapset.inheritable != JAIL_CAP_ALL) {
  145. ud[0].inheritable = (ocicapset.inheritable | retain) & 0xFFFFFFFFU;
  146. ud[1].inheritable = ((ocicapset.inheritable | retain) >> 32) & 0xFFFFFFFFU;
  147. }
  148. DEBUG("new capabilities: Pe=%016llx Pp=%016llx Pi=%016llx\n",
  149. 0LLU | ud[0].effective | (0LLU | ud[1].effective) << 32,
  150. 0LLU | ud[0].permitted | (0LLU | ud[1].permitted) << 32,
  151. 0LLU | ud[0].inheritable | (0LLU | ud[1].inheritable) << 32);
  152. if (capset(&uh, ud)) {
  153. ERROR("capset() failed\n");
  154. return -1;
  155. }
  156. /* edit ambient set */
  157. if (ocicapset.ambient != JAIL_CAP_ALL) {
  158. for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
  159. is_set = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0);
  160. if ( (ocicapset.ambient & (1LLU << cap)) == 0) {
  161. if (is_set) {
  162. DEBUG("dropping capability %s (%d) from ambient set\n", capabilities_names[cap], cap);
  163. if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)) {
  164. ERROR("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, %d, 0, 0) failed: %m\n", cap);
  165. return errno;
  166. }
  167. }
  168. } else {
  169. if (!is_set) {
  170. DEBUG("raising capability %s (%d) to ambient set\n", capabilities_names[cap], cap);
  171. if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {\
  172. ERROR("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %d, 0, 0) failed: %m\n", cap);
  173. return errno;
  174. }
  175. }
  176. }
  177. }
  178. }
  179. return 0;
  180. }
  181. int parseOCIcapabilities_from_file(struct jail_capset *capset, const char *file)
  182. {
  183. struct blob_buf b = { 0 };
  184. int ret;
  185. blob_buf_init(&b, 0);
  186. ret = !blobmsg_add_json_from_file(&b, file);
  187. if (ret) {
  188. ERROR("failed to load %s\n", file);
  189. goto err;
  190. }
  191. ret = parseOCIcapabilities(capset, b.head);
  192. err:
  193. blob_buf_free(&b);
  194. return ret;
  195. }