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 15 #define _GNU_SOURCE 1 16 #include <syslog.h> 17 #include <sys/prctl.h> 18 #include <libubox/blobmsg.h> 19 #include <libubox/blobmsg_json.h> 20 21 #include "log.h" 22 #include "../capabilities-names.h" 23 #include "capabilities.h" 24 25 #define JAIL_CAP_ERROR (1LLU << (CAP_LAST_CAP+1)) 26 #define JAIL_CAP_ALL (0xffffffffffffffffLLU) 27 28 static int find_capabilities(const char *name) 29 { 30 int i; 31 32 for (i = 0; i <= CAP_LAST_CAP; i++) 33 if (capabilities_names[i] && !strcasecmp(capabilities_names[i], name)) 34 return i; 35 36 return -1; 37 } 38 39 enum { 40 OCI_CAPABILITIES_BOUNDING, 41 OCI_CAPABILITIES_EFFECTIVE, 42 OCI_CAPABILITIES_INHERITABLE, 43 OCI_CAPABILITIES_PERMITTED, 44 OCI_CAPABILITIES_AMBIENT, 45 __OCI_CAPABILITIES_MAX 46 }; 47 48 static const struct blobmsg_policy oci_capabilities_policy[] = { 49 [OCI_CAPABILITIES_BOUNDING] = { "bounding", BLOBMSG_TYPE_ARRAY }, 50 [OCI_CAPABILITIES_EFFECTIVE] = { "effective", BLOBMSG_TYPE_ARRAY }, 51 [OCI_CAPABILITIES_INHERITABLE] = { "inheritable", BLOBMSG_TYPE_ARRAY }, 52 [OCI_CAPABILITIES_PERMITTED] = { "permitted", BLOBMSG_TYPE_ARRAY }, 53 [OCI_CAPABILITIES_AMBIENT] = { "ambient", BLOBMSG_TYPE_ARRAY }, 54 }; 55 56 static uint64_t parseOCIcap(struct blob_attr *msg) 57 { 58 struct blob_attr *cur; 59 int rem; 60 uint64_t caps = 0; 61 int capnum; 62 63 if (!msg) 64 return 0; 65 66 blobmsg_for_each_attr(cur, msg, rem) { 67 capnum = find_capabilities(blobmsg_get_string(cur)); 68 if (capnum < 0) 69 return JAIL_CAP_ERROR; 70 71 caps |= (1LLU << capnum); 72 } 73 74 return caps; 75 } 76 77 int parseOCIcapabilities(struct jail_capset *capset, struct blob_attr *msg) 78 { 79 struct blob_attr *tb[__OCI_CAPABILITIES_MAX]; 80 uint64_t caps; 81 blobmsg_parse(oci_capabilities_policy, __OCI_CAPABILITIES_MAX, tb, blobmsg_data(msg), blobmsg_len(msg)); 82 83 caps = parseOCIcap(tb[OCI_CAPABILITIES_BOUNDING]); 84 if (caps == JAIL_CAP_ERROR) 85 return EINVAL; 86 else 87 capset->bounding = caps; 88 89 caps = parseOCIcap(tb[OCI_CAPABILITIES_EFFECTIVE]); 90 if (caps == JAIL_CAP_ERROR) 91 return EINVAL; 92 else 93 capset->effective = caps; 94 95 caps = parseOCIcap(tb[OCI_CAPABILITIES_INHERITABLE]); 96 if (caps == JAIL_CAP_ERROR) 97 return EINVAL; 98 else 99 capset->inheritable = caps; 100 101 caps = parseOCIcap(tb[OCI_CAPABILITIES_PERMITTED]); 102 if (caps == JAIL_CAP_ERROR) 103 return EINVAL; 104 else 105 capset->permitted = caps; 106 107 caps = parseOCIcap(tb[OCI_CAPABILITIES_AMBIENT]); 108 if (caps == JAIL_CAP_ERROR) 109 return EINVAL; 110 else 111 capset->ambient = caps; 112 113 capset->apply = 1; 114 115 return 0; 116 } 117 118 119 int applyOCIcapabilities(struct jail_capset ocicapset, uint64_t retain) 120 { 121 struct __user_cap_header_struct uh = {}; 122 struct __user_cap_data_struct ud[2]; 123 int cap; 124 int is_set; 125 126 if (!ocicapset.apply) 127 return 0; 128 129 /* drop from bounding set */ 130 if (ocicapset.bounding != JAIL_CAP_ALL) { 131 for (cap = 0; cap <= CAP_LAST_CAP; cap++) { 132 if (!prctl(PR_CAPBSET_READ, cap, 0, 0, 0)) { 133 /* can't raise */ 134 if (ocicapset.bounding & (1LLU << cap)) 135 ERROR("capability %s (%d) is not in bounding set\n", capabilities_names[cap], cap); 136 137 continue; 138 } 139 if ( ((ocicapset.bounding | retain) & (1LLU << cap)) == 0) { 140 DEBUG("dropping capability %s (%d) from bounding set\n", capabilities_names[cap], cap); 141 if (prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)) { 142 ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %m\n", cap); 143 return errno; 144 } 145 } else { 146 DEBUG("keeping capability %s (%d)\n", capabilities_names[cap], cap); 147 } 148 } 149 } 150 151 /* set effective, permitted and inheritable */ 152 uh.version = _LINUX_CAPABILITY_VERSION_3; 153 uh.pid = getpid(); 154 155 if (capget(&uh, ud)) { 156 ERROR("capget() failed\n"); 157 return -1; 158 } 159 160 DEBUG("old capabilities: Pe=%016llx Pp=%016llx Pi=%016llx\n", 161 0LLU | ud[0].effective | (0LLU | ud[1].effective) << 32, 162 0LLU | ud[0].permitted | (0LLU | ud[1].permitted) << 32, 163 0LLU | ud[0].inheritable | (0LLU | ud[1].inheritable) << 32); 164 165 if (ocicapset.effective != JAIL_CAP_ALL) { 166 ud[0].effective = (ocicapset.effective | retain) & 0xFFFFFFFFU; 167 ud[1].effective = ((ocicapset.effective | retain) >> 32) & 0xFFFFFFFFU; 168 } 169 170 if (ocicapset.permitted != JAIL_CAP_ALL) { 171 ud[0].permitted = (ocicapset.permitted | retain) & 0xFFFFFFFFU; 172 ud[1].permitted = ((ocicapset.permitted | retain) >> 32) & 0xFFFFFFFFU; 173 } 174 175 if (ocicapset.inheritable != JAIL_CAP_ALL) { 176 ud[0].inheritable = (ocicapset.inheritable | retain) & 0xFFFFFFFFU; 177 ud[1].inheritable = ((ocicapset.inheritable | retain) >> 32) & 0xFFFFFFFFU; 178 } 179 180 DEBUG("new capabilities: Pe=%016llx Pp=%016llx Pi=%016llx\n", 181 0LLU | ud[0].effective | (0LLU | ud[1].effective) << 32, 182 0LLU | ud[0].permitted | (0LLU | ud[1].permitted) << 32, 183 0LLU | ud[0].inheritable | (0LLU | ud[1].inheritable) << 32); 184 185 if (capset(&uh, ud)) { 186 ERROR("capset() failed\n"); 187 return -1; 188 } 189 190 /* edit ambient set */ 191 if (ocicapset.ambient != JAIL_CAP_ALL) { 192 for (cap = 0; cap <= CAP_LAST_CAP; cap++) { 193 is_set = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0); 194 if ( (ocicapset.ambient & (1LLU << cap)) == 0) { 195 if (is_set) { 196 DEBUG("dropping capability %s (%d) from ambient set\n", capabilities_names[cap], cap); 197 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)) { 198 ERROR("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, %d, 0, 0) failed: %m\n", cap); 199 return errno; 200 } 201 } 202 } else { 203 if (!is_set) { 204 DEBUG("raising capability %s (%d) to ambient set\n", capabilities_names[cap], cap); 205 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {\ 206 ERROR("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %d, 0, 0) failed: %m\n", cap); 207 return errno; 208 } 209 } 210 } 211 } 212 } 213 214 return 0; 215 } 216 217 int parseOCIcapabilities_from_file(struct jail_capset *capset, const char *file) 218 { 219 const struct blob_attr *prev_root = jail_oci_root_get(); 220 struct blob_buf b = { 0 }; 221 int ret; 222 223 blob_buf_init(&b, 0); 224 ret = !blobmsg_add_json_from_file(&b, file); 225 if (ret) { 226 ERROR("failed to load %s\n", file); 227 goto err; 228 } 229 230 jail_oci_root_restore(b.head); 231 ret = parseOCIcapabilities(capset, b.head); 232 233 err: 234 jail_oci_root_restore(prev_root); 235 blob_buf_free(&b); 236 return ret; 237 } 238
This page was automatically generated by LXR 0.3.1. • OpenWrt