• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/jail/capabilities.c

  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         /* each capset is optional, set all-1 mask if absent */
 64         if (!msg)
 65                 return JAIL_CAP_ALL;
 66 
 67         blobmsg_for_each_attr(cur, msg, rem) {
 68                 capnum = find_capabilities(blobmsg_get_string(cur));
 69                 if (capnum < 0)
 70                         return JAIL_CAP_ERROR;
 71 
 72                 caps |= (1LLU << capnum);
 73         }
 74 
 75         return caps;
 76 }
 77 
 78 int parseOCIcapabilities(struct jail_capset *capset, struct blob_attr *msg)
 79 {
 80         struct blob_attr *tb[__OCI_CAPABILITIES_MAX];
 81         uint64_t caps;
 82         blobmsg_parse(oci_capabilities_policy, __OCI_CAPABILITIES_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
 83 
 84         caps = parseOCIcap(tb[OCI_CAPABILITIES_BOUNDING]);
 85         if (caps == JAIL_CAP_ERROR)
 86                 return EINVAL;
 87         else
 88                 capset->bounding = caps;
 89 
 90         caps = parseOCIcap(tb[OCI_CAPABILITIES_EFFECTIVE]);
 91         if (caps == JAIL_CAP_ERROR)
 92                 return EINVAL;
 93         else
 94                 capset->effective = caps;
 95 
 96         caps = parseOCIcap(tb[OCI_CAPABILITIES_INHERITABLE]);
 97         if (caps == JAIL_CAP_ERROR)
 98                 return EINVAL;
 99         else
100                 capset->inheritable = caps;
101 
102         caps = parseOCIcap(tb[OCI_CAPABILITIES_PERMITTED]);
103         if (caps == JAIL_CAP_ERROR)
104                 return EINVAL;
105         else
106                 capset->permitted = caps;
107 
108         caps = parseOCIcap(tb[OCI_CAPABILITIES_AMBIENT]);
109         if (caps == JAIL_CAP_ERROR)
110                 return EINVAL;
111         else
112                 capset->ambient = caps;
113 
114         capset->apply = 1;
115 
116         return 0;
117 }
118 
119 
120 int applyOCIcapabilities(struct jail_capset ocicapset, uint64_t retain)
121 {
122         struct __user_cap_header_struct uh = {};
123         struct __user_cap_data_struct ud[2];
124         int cap;
125         int is_set;
126 
127         if (!ocicapset.apply)
128                 return 0;
129 
130         /* drop from bounding set */
131         if (ocicapset.bounding != JAIL_CAP_ALL) {
132                 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
133                         if (!prctl(PR_CAPBSET_READ, cap, 0, 0, 0)) {
134                                 /* can't raise */
135                                 if (ocicapset.bounding & (1LLU << cap))
136                                         ERROR("capability %s (%d) is not in bounding set\n", capabilities_names[cap], cap);
137 
138                                 continue;
139                         }
140                         if ( ((ocicapset.bounding | retain) & (1LLU << cap)) == 0) {
141                                 DEBUG("dropping capability %s (%d) from bounding set\n", capabilities_names[cap], cap);
142                                 if (prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)) {
143                                         ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %m\n", cap);
144                                         return errno;
145                                 }
146                         } else {
147                                 DEBUG("keeping capability %s (%d)\n", capabilities_names[cap], cap);
148                         }
149                 }
150         }
151 
152         /* set effective, permitted and inheritable */
153         uh.version = _LINUX_CAPABILITY_VERSION_3;
154         uh.pid = getpid();
155 
156         if (capget(&uh, ud)) {
157                 ERROR("capget() failed\n");
158                 return -1;
159         }
160 
161         DEBUG("old capabilities: Pe=%016llx Pp=%016llx Pi=%016llx\n",
162                 0LLU | ud[0].effective | (0LLU | ud[1].effective) << 32,
163                 0LLU | ud[0].permitted | (0LLU | ud[1].permitted) << 32,
164                 0LLU | ud[0].inheritable | (0LLU | ud[1].inheritable) << 32);
165 
166         if (ocicapset.effective != JAIL_CAP_ALL) {
167                 ud[0].effective = (ocicapset.effective | retain) & 0xFFFFFFFFU;
168                 ud[1].effective = ((ocicapset.effective | retain) >> 32) & 0xFFFFFFFFU;
169         }
170 
171         if (ocicapset.permitted != JAIL_CAP_ALL) {
172                 ud[0].permitted = (ocicapset.permitted | retain) & 0xFFFFFFFFU;
173                 ud[1].permitted = ((ocicapset.permitted | retain) >> 32) & 0xFFFFFFFFU;
174         }
175 
176         if (ocicapset.inheritable != JAIL_CAP_ALL) {
177                 ud[0].inheritable = (ocicapset.inheritable | retain) & 0xFFFFFFFFU;
178                 ud[1].inheritable = ((ocicapset.inheritable | retain) >> 32) & 0xFFFFFFFFU;
179         }
180 
181         DEBUG("new capabilities: Pe=%016llx Pp=%016llx Pi=%016llx\n",
182                 0LLU | ud[0].effective | (0LLU | ud[1].effective) << 32,
183                 0LLU | ud[0].permitted | (0LLU | ud[1].permitted) << 32,
184                 0LLU | ud[0].inheritable | (0LLU | ud[1].inheritable) << 32);
185 
186         if (capset(&uh, ud)) {
187                 ERROR("capset() failed\n");
188                 return -1;
189         }
190 
191         /* edit ambient set */
192         if (ocicapset.ambient != JAIL_CAP_ALL) {
193                 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
194                         is_set = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0);
195                         if ( (ocicapset.ambient & (1LLU << cap)) == 0) {
196                                 if (is_set) {
197                                         DEBUG("dropping capability %s (%d) from ambient set\n", capabilities_names[cap], cap);
198                                         if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)) {
199                                                 ERROR("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, %d, 0, 0) failed: %m\n", cap);
200                                                 return errno;
201                                         }
202                                 }
203                         } else {
204                                 if (!is_set) {
205                                         DEBUG("raising capability %s (%d) to ambient set\n", capabilities_names[cap], cap);
206                                         if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {\
207                                                 ERROR("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %d, 0, 0) failed: %m\n", cap);
208                                                 return errno;
209                                         }
210                                 }
211                         }
212                 }
213         }
214 
215         return 0;
216 }
217 
218 int parseOCIcapabilities_from_file(struct jail_capset *capset, const char *file)
219 {
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         ret = parseOCIcapabilities(capset, b.head);
231 
232 err:
233         blob_buf_free(&b);
234         return ret;
235 }
236 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt