• 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         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