Deleted
Added
nxt_clone.c (1201:563e00547881) | nxt_clone.c (1306:3604d05e48be) |
---|---|
1/* 2 * Copyright (C) Igor Sysoev 3 * Copyright (C) NGINX, Inc. 4 */ 5 6#include <nxt_main.h> 7#include <sys/types.h> 8#include <nxt_conf.h> --- 11 unchanged lines hidden (view full) --- 20#endif 21} 22 23#endif 24 25 26#if (NXT_HAVE_CLONE_NEWUSER) 27 | 1/* 2 * Copyright (C) Igor Sysoev 3 * Copyright (C) NGINX, Inc. 4 */ 5 6#include <nxt_main.h> 7#include <sys/types.h> 8#include <nxt_conf.h> --- 11 unchanged lines hidden (view full) --- 20#endif 21} 22 23#endif 24 25 26#if (NXT_HAVE_CLONE_NEWUSER) 27 |
28/* map uid 65534 to unit pid */ 29#define NXT_DEFAULT_UNPRIV_MAP "65534 %d 1" 30 31nxt_int_t nxt_clone_proc_setgroups(nxt_task_t *task, pid_t child_pid, | 28nxt_int_t nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid, |
32 const char *str); | 29 const char *str); |
33nxt_int_t nxt_clone_proc_map_set(nxt_task_t *task, const char* mapfile, 34 pid_t pid, nxt_int_t defval, nxt_conf_value_t *mapobj); 35nxt_int_t nxt_clone_proc_map_write(nxt_task_t *task, const char *mapfile, | 30nxt_int_t nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, 31 pid_t pid, nxt_int_t default_container, nxt_int_t default_host, 32 nxt_clone_credential_map_t *map); 33nxt_int_t nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile, |
36 pid_t pid, u_char *mapinfo); 37 38 | 34 pid_t pid, u_char *mapinfo); 35 36 |
39typedef struct { 40 nxt_int_t container; 41 nxt_int_t host; 42 nxt_int_t size; 43} nxt_clone_procmap_t; 44 45 | |
46nxt_int_t | 37nxt_int_t |
47nxt_clone_proc_setgroups(nxt_task_t *task, pid_t child_pid, const char *str) | 38nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid, 39 const char *str) |
48{ 49 int fd, n; 50 u_char *p, *end; 51 u_char path[PATH_MAX]; 52 53 end = path + PATH_MAX; 54 p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid); 55 *p = '\0'; --- 28 unchanged lines hidden (view full) --- 84 return NXT_ERROR; 85 } 86 87 return NXT_OK; 88} 89 90 91nxt_int_t | 40{ 41 int fd, n; 42 u_char *p, *end; 43 u_char path[PATH_MAX]; 44 45 end = path + PATH_MAX; 46 p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid); 47 *p = '\0'; --- 28 unchanged lines hidden (view full) --- 76 return NXT_ERROR; 77 } 78 79 return NXT_OK; 80} 81 82 83nxt_int_t |
92nxt_clone_proc_map_write(nxt_task_t *task, const char *mapfile, pid_t pid, 93 u_char *mapinfo) | 84nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile, 85 pid_t pid, u_char *mapinfo) |
94{ 95 int len, mapfd; 96 u_char *p, *end; 97 ssize_t n; 98 u_char buf[256]; 99 100 end = buf + sizeof(buf); 101 --- 32 unchanged lines hidden (view full) --- 134 135 close(mapfd); 136 137 return NXT_OK; 138} 139 140 141nxt_int_t | 86{ 87 int len, mapfd; 88 u_char *p, *end; 89 ssize_t n; 90 u_char buf[256]; 91 92 end = buf + sizeof(buf); 93 --- 32 unchanged lines hidden (view full) --- 126 127 close(mapfd); 128 129 return NXT_OK; 130} 131 132 133nxt_int_t |
142nxt_clone_proc_map_set(nxt_task_t *task, const char* mapfile, pid_t pid, 143 nxt_int_t defval, nxt_conf_value_t *mapobj) | 134nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid, 135 nxt_int_t default_container, nxt_int_t default_host, 136 nxt_clone_credential_map_t *map) |
144{ | 137{ |
145 u_char *p, *end, *mapinfo; 146 nxt_int_t container, host, size; 147 nxt_int_t ret, len, count, i; 148 nxt_conf_value_t *obj, *value; | 138 u_char *p, *end, *mapinfo; 139 nxt_int_t ret, len; 140 nxt_uint_t i; |
149 | 141 |
150 static nxt_str_t str_cont = nxt_string("container"); 151 static nxt_str_t str_host = nxt_string("host"); 152 static nxt_str_t str_size = nxt_string("size"); 153 | |
154 /* 155 * uid_map one-entry size: 156 * alloc space for 3 numbers (32bit) plus 2 spaces and \n. 157 */ 158 len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1); 159 | 142 /* 143 * uid_map one-entry size: 144 * alloc space for 3 numbers (32bit) plus 2 spaces and \n. 145 */ 146 len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1); 147 |
160 if (mapobj != NULL) { 161 count = nxt_conf_array_elements_count(mapobj); | 148 if (map->size > 0) { 149 len = len * map->size + 1; |
162 | 150 |
163 if (count == 0) { 164 goto default_map; 165 } 166 167 len = len * count + 1; 168 | |
169 mapinfo = nxt_malloc(len); 170 if (nxt_slow_path(mapinfo == NULL)) { | 151 mapinfo = nxt_malloc(len); 152 if (nxt_slow_path(mapinfo == NULL)) { |
171 nxt_alert(task, "failed to allocate uid_map buffer"); | |
172 return NXT_ERROR; 173 } 174 175 p = mapinfo; 176 end = mapinfo + len; 177 | 153 return NXT_ERROR; 154 } 155 156 p = mapinfo; 157 end = mapinfo + len; 158 |
178 for (i = 0; i < count; i++) { 179 obj = nxt_conf_get_array_element(mapobj, i); | 159 for (i = 0; i < map->size; i++) { 160 p = nxt_sprintf(p, end, "%d %d %d", map->map[i].container, 161 map->map[i].host, map->map[i].size); |
180 | 162 |
181 value = nxt_conf_get_object_member(obj, &str_cont, NULL); 182 container = nxt_conf_get_integer(value); 183 184 value = nxt_conf_get_object_member(obj, &str_host, NULL); 185 host = nxt_conf_get_integer(value); 186 187 value = nxt_conf_get_object_member(obj, &str_size, NULL); 188 size = nxt_conf_get_integer(value); 189 190 p = nxt_sprintf(p, end, "%d %d %d", container, host, size); | |
191 if (nxt_slow_path(p == end)) { | 163 if (nxt_slow_path(p == end)) { |
192 nxt_alert(task, "write past the uid_map buffer"); | 164 nxt_alert(task, "write past the mapinfo buffer"); |
193 nxt_free(mapinfo); 194 return NXT_ERROR; 195 } 196 | 165 nxt_free(mapinfo); 166 return NXT_ERROR; 167 } 168 |
197 if (i+1 < count) { | 169 if (i+1 < map->size) { |
198 *p++ = '\n'; 199 200 } else { 201 *p = '\0'; 202 } 203 } 204 205 } else { | 170 *p++ = '\n'; 171 172 } else { 173 *p = '\0'; 174 } 175 } 176 177 } else { |
206 207default_map: 208 | |
209 mapinfo = nxt_malloc(len); 210 if (nxt_slow_path(mapinfo == NULL)) { | 178 mapinfo = nxt_malloc(len); 179 if (nxt_slow_path(mapinfo == NULL)) { |
211 nxt_alert(task, "failed to allocate uid_map buffer"); | |
212 return NXT_ERROR; 213 } 214 215 end = mapinfo + len; | 180 return NXT_ERROR; 181 } 182 183 end = mapinfo + len; |
216 p = nxt_sprintf(mapinfo, end, NXT_DEFAULT_UNPRIV_MAP, defval); | 184 p = nxt_sprintf(mapinfo, end, "%d %d 1", 185 default_container, default_host); |
217 *p = '\0'; 218 219 if (nxt_slow_path(p == end)) { | 186 *p = '\0'; 187 188 if (nxt_slow_path(p == end)) { |
220 nxt_alert(task, "write past the %s buffer", mapfile); | 189 nxt_alert(task, "write past mapinfo buffer"); |
221 nxt_free(mapinfo); 222 return NXT_ERROR; 223 } 224 } 225 | 190 nxt_free(mapinfo); 191 return NXT_ERROR; 192 } 193 } 194 |
226 ret = nxt_clone_proc_map_write(task, mapfile, pid, mapinfo); | 195 ret = nxt_clone_credential_map_write(task, mapfile, pid, mapinfo); |
227 228 nxt_free(mapinfo); 229 230 return ret; 231} 232 233 234nxt_int_t | 196 197 nxt_free(mapinfo); 198 199 return ret; 200} 201 202 203nxt_int_t |
235nxt_clone_proc_map(nxt_task_t *task, pid_t pid, nxt_process_clone_t *clone) | 204nxt_clone_credential_map(nxt_task_t *task, pid_t pid, 205 nxt_credential_t *app_creds, nxt_clone_t *clone) |
236{ 237 nxt_int_t ret; | 206{ 207 nxt_int_t ret; |
238 nxt_int_t uid, gid; | 208 nxt_int_t default_host_uid; 209 nxt_int_t default_host_gid; |
239 const char *rule; 240 nxt_runtime_t *rt; 241 242 rt = task->thread->runtime; | 210 const char *rule; 211 nxt_runtime_t *rt; 212 213 rt = task->thread->runtime; |
243 uid = geteuid(); 244 gid = getegid(); | |
245 | 214 |
246 rule = rt->capabilities.setid ? "allow" : "deny"; | 215 if (rt->capabilities.setid) { 216 rule = "allow"; |
247 | 217 |
248 ret = nxt_clone_proc_map_set(task, "uid_map", pid, uid, clone->uidmap); | 218 /* 219 * By default we don't map a privileged user 220 */ 221 default_host_uid = app_creds->uid; 222 default_host_gid = app_creds->base_gid; 223 } else { 224 rule = "deny"; 225 226 default_host_uid = nxt_euid; 227 default_host_gid = nxt_egid; 228 } 229 230 ret = nxt_clone_credential_map_set(task, "uid_map", pid, app_creds->uid, 231 default_host_uid, 232 &clone->uidmap); 233 |
249 if (nxt_slow_path(ret != NXT_OK)) { 250 return NXT_ERROR; 251 } 252 | 234 if (nxt_slow_path(ret != NXT_OK)) { 235 return NXT_ERROR; 236 } 237 |
253 ret = nxt_clone_proc_setgroups(task, pid, rule); | 238 ret = nxt_clone_credential_setgroups(task, pid, rule); |
254 if (nxt_slow_path(ret != NXT_OK)) { 255 nxt_alert(task, "failed to write /proc/%d/setgroups", pid); 256 return NXT_ERROR; 257 } 258 | 239 if (nxt_slow_path(ret != NXT_OK)) { 240 nxt_alert(task, "failed to write /proc/%d/setgroups", pid); 241 return NXT_ERROR; 242 } 243 |
259 ret = nxt_clone_proc_map_set(task, "gid_map", pid, gid, clone->gidmap); | 244 ret = nxt_clone_credential_map_set(task, "gid_map", pid, app_creds->base_gid, 245 default_host_gid, 246 &clone->gidmap); 247 |
260 if (nxt_slow_path(ret != NXT_OK)) { 261 return NXT_ERROR; 262 } 263 264 return NXT_OK; 265} 266 | 248 if (nxt_slow_path(ret != NXT_OK)) { 249 return NXT_ERROR; 250 } 251 252 return NXT_OK; 253} 254 |
255 256nxt_int_t 257nxt_clone_vldt_credential_uidmap(nxt_task_t *task, 258 nxt_clone_credential_map_t *map, nxt_credential_t *creds) 259{ 260 nxt_int_t id; 261 nxt_uint_t i; 262 nxt_runtime_t *rt; 263 nxt_clone_map_entry_t m; 264 265 if (map->size == 0) { 266 return NXT_OK; 267 } 268 269 rt = task->thread->runtime; 270 271 if (!rt->capabilities.setid) { 272 if (nxt_slow_path(map->size > 1)) { 273 nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has %d entries " 274 "but unprivileged unit has a maximum of 1 map.", 275 map->size); 276 277 return NXT_ERROR; 278 } 279 280 id = map->map[0].host; 281 282 if (nxt_slow_path((nxt_uid_t) id != nxt_euid)) { 283 nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has an entry for " 284 "host uid %d but unprivileged unit can only map itself " 285 "(uid %d) into child namespaces.", id, nxt_euid); 286 287 return NXT_ERROR; 288 } 289 290 return NXT_OK; 291 } 292 293 for (i = 0; i < map->size; i++) { 294 m = map->map[i]; 295 296 if (creds->uid >= (nxt_uid_t) m.container 297 && creds->uid < (nxt_uid_t) (m.container + m.size)) 298 { 299 return NXT_OK; 300 } 301 } 302 303 nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has no \"container\" " 304 "entry for user \"%s\" (uid %d)", creds->user, creds->uid); 305 306 return NXT_ERROR; 307} 308 309 310nxt_int_t 311nxt_clone_vldt_credential_gidmap(nxt_task_t *task, 312 nxt_clone_credential_map_t *map, nxt_credential_t *creds) 313{ 314 nxt_uint_t base_ok, gid_ok, gids_ok; 315 nxt_uint_t i, j; 316 nxt_runtime_t *rt; 317 nxt_clone_map_entry_t m; 318 319 rt = task->thread->runtime; 320 321 if (!rt->capabilities.setid) { 322 if (creds->ngroups > 0 323 && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) { 324 nxt_log(task, NXT_LOG_NOTICE, 325 "unprivileged unit disallow supplementary groups for " 326 "new namespace (user \"%s\" has %d group%s).", 327 creds->user, creds->ngroups, 328 creds->ngroups > 1 ? "s" : ""); 329 330 return NXT_ERROR; 331 } 332 333 if (map->size == 0) { 334 return NXT_OK; 335 } 336 337 if (nxt_slow_path(map->size > 1)) { 338 nxt_log(task, NXT_LOG_NOTICE, "\"gidmap\" field has %d entries " 339 "but unprivileged unit has a maximum of 1 map.", 340 map->size); 341 342 return NXT_ERROR; 343 } 344 345 m = map->map[0]; 346 347 if (nxt_slow_path((nxt_gid_t) m.host != nxt_egid)) { 348 nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry for " 349 "host gid %d but unprivileged unit can only map itself " 350 "(gid %d) into child namespaces.", m.host, nxt_egid); 351 352 return NXT_ERROR; 353 } 354 355 if (nxt_slow_path(m.size > 1)) { 356 nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry with " 357 "\"size\": %d, but for unprivileged unit it must be 1.", 358 m.size); 359 360 return NXT_ERROR; 361 } 362 363 if (nxt_slow_path((nxt_gid_t) m.container != creds->base_gid)) { 364 nxt_log(task, NXT_LOG_ERR, 365 "\"gidmap\" field has no \"container\" entry for gid %d.", 366 creds->base_gid); 367 368 return NXT_ERROR; 369 } 370 371 return NXT_OK; 372 } 373 374 if (map->size == 0) { 375 if (creds->ngroups > 0 376 && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) 377 { 378 nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no entries " 379 "but user \"%s\" has %d suplementary group%s.", 380 creds->user, creds->ngroups, 381 creds->ngroups > 1 ? "s" : ""); 382 383 return NXT_ERROR; 384 } 385 386 return NXT_OK; 387 } 388 389 base_ok = 0; 390 gids_ok = 0; 391 392 for (i = 0; i < creds->ngroups; i++) { 393 gid_ok = 0; 394 395 for (j = 0; j < map->size; j++) { 396 m = map->map[j]; 397 398 if (!base_ok && creds->base_gid >= (nxt_gid_t) m.container 399 && creds->base_gid < (nxt_gid_t) (m.container+m.size)) 400 { 401 base_ok = 1; 402 } 403 404 if (creds->gids[i] >= (nxt_gid_t) m.container 405 && creds->gids[i] < (nxt_gid_t) (m.container+m.size)) 406 { 407 gid_ok = 1; 408 break; 409 } 410 } 411 412 if (nxt_fast_path(gid_ok)) { 413 gids_ok++; 414 } 415 } 416 417 if (!base_ok) { 418 for (i = 0; i < map->size; i++) { 419 m = map->map[i]; 420 421 if (creds->base_gid >= (nxt_gid_t) m.container 422 && creds->base_gid < (nxt_gid_t) (m.container+m.size)) 423 { 424 base_ok = 1; 425 break; 426 } 427 } 428 } 429 430 if (nxt_slow_path(!base_ok)) { 431 nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no \"container\" " 432 "entry for gid %d.", creds->base_gid); 433 434 return NXT_ERROR; 435 } 436 437 if (nxt_slow_path(gids_ok < creds->ngroups)) { 438 nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has missing " 439 "suplementary gid mappings (found %d out of %d).", gids_ok, 440 creds->ngroups); 441 442 return NXT_ERROR; 443 } 444 445 return NXT_OK; 446} 447 |
|
267#endif | 448#endif |