11182St.nateldemoura@f5.com /* 21182St.nateldemoura@f5.com * Copyright (C) Igor Sysoev 31182St.nateldemoura@f5.com * Copyright (C) NGINX, Inc. 41182St.nateldemoura@f5.com */ 51182St.nateldemoura@f5.com 61182St.nateldemoura@f5.com #include <nxt_main.h> 71182St.nateldemoura@f5.com #include <sys/types.h> 81182St.nateldemoura@f5.com #include <nxt_conf.h> 91182St.nateldemoura@f5.com #include <nxt_clone.h> 101182St.nateldemoura@f5.com 111182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE) 121182St.nateldemoura@f5.com 131182St.nateldemoura@f5.com pid_t 141182St.nateldemoura@f5.com nxt_clone(nxt_int_t flags) 151182St.nateldemoura@f5.com { 161182St.nateldemoura@f5.com #if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) 171182St.nateldemoura@f5.com return syscall(__NR_clone, NULL, flags); 181182St.nateldemoura@f5.com #else 191182St.nateldemoura@f5.com return syscall(__NR_clone, flags, NULL); 201182St.nateldemoura@f5.com #endif 211182St.nateldemoura@f5.com } 221182St.nateldemoura@f5.com 231182St.nateldemoura@f5.com #endif 241182St.nateldemoura@f5.com 251182St.nateldemoura@f5.com 261182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 271182St.nateldemoura@f5.com 281182St.nateldemoura@f5.com /* map uid 65534 to unit pid */ 291182St.nateldemoura@f5.com #define NXT_DEFAULT_UNPRIV_MAP "65534 %d 1" 301182St.nateldemoura@f5.com 311182St.nateldemoura@f5.com nxt_int_t nxt_clone_proc_setgroups(nxt_task_t *task, pid_t child_pid, 321182St.nateldemoura@f5.com const char *str); 331182St.nateldemoura@f5.com nxt_int_t nxt_clone_proc_map_set(nxt_task_t *task, const char* mapfile, 341182St.nateldemoura@f5.com pid_t pid, nxt_int_t defval, nxt_conf_value_t *mapobj); 351182St.nateldemoura@f5.com nxt_int_t nxt_clone_proc_map_write(nxt_task_t *task, const char *mapfile, 361182St.nateldemoura@f5.com pid_t pid, u_char *mapinfo); 371182St.nateldemoura@f5.com 381182St.nateldemoura@f5.com 391182St.nateldemoura@f5.com typedef struct { 401182St.nateldemoura@f5.com nxt_int_t container; 411182St.nateldemoura@f5.com nxt_int_t host; 421182St.nateldemoura@f5.com nxt_int_t size; 431182St.nateldemoura@f5.com } nxt_clone_procmap_t; 441182St.nateldemoura@f5.com 451182St.nateldemoura@f5.com 461182St.nateldemoura@f5.com nxt_int_t 471182St.nateldemoura@f5.com nxt_clone_proc_setgroups(nxt_task_t *task, pid_t child_pid, const char *str) 481182St.nateldemoura@f5.com { 491182St.nateldemoura@f5.com int fd, n; 501182St.nateldemoura@f5.com u_char *p, *end; 511182St.nateldemoura@f5.com u_char path[PATH_MAX]; 521182St.nateldemoura@f5.com 531182St.nateldemoura@f5.com end = path + PATH_MAX; 541182St.nateldemoura@f5.com p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid); 551182St.nateldemoura@f5.com *p = '\0'; 561182St.nateldemoura@f5.com 571182St.nateldemoura@f5.com if (nxt_slow_path(p == end)) { 581182St.nateldemoura@f5.com nxt_alert(task, "error write past the buffer: %s", path); 591182St.nateldemoura@f5.com return NXT_ERROR; 601182St.nateldemoura@f5.com } 611182St.nateldemoura@f5.com 621182St.nateldemoura@f5.com fd = open((char *)path, O_RDWR); 631182St.nateldemoura@f5.com 641182St.nateldemoura@f5.com if (fd == -1) { 651182St.nateldemoura@f5.com /* 661182St.nateldemoura@f5.com * If the /proc/pid/setgroups doesn't exists, we are 671182St.nateldemoura@f5.com * safe to set uid/gid maps. But if the error is anything 681182St.nateldemoura@f5.com * other than ENOENT, then we should abort and let user know. 691182St.nateldemoura@f5.com */ 701182St.nateldemoura@f5.com 711182St.nateldemoura@f5.com if (errno != ENOENT) { 721182St.nateldemoura@f5.com nxt_alert(task, "open(%s): %E", path, nxt_errno); 731182St.nateldemoura@f5.com return NXT_ERROR; 741182St.nateldemoura@f5.com } 751182St.nateldemoura@f5.com 761182St.nateldemoura@f5.com return NXT_OK; 771182St.nateldemoura@f5.com } 781182St.nateldemoura@f5.com 791182St.nateldemoura@f5.com n = write(fd, str, strlen(str)); 801182St.nateldemoura@f5.com close(fd); 811182St.nateldemoura@f5.com 821182St.nateldemoura@f5.com if (nxt_slow_path(n == -1)) { 831182St.nateldemoura@f5.com nxt_alert(task, "write(%s): %E", path, nxt_errno); 841182St.nateldemoura@f5.com return NXT_ERROR; 851182St.nateldemoura@f5.com } 861182St.nateldemoura@f5.com 871182St.nateldemoura@f5.com return NXT_OK; 881182St.nateldemoura@f5.com } 891182St.nateldemoura@f5.com 901182St.nateldemoura@f5.com 911182St.nateldemoura@f5.com nxt_int_t 921182St.nateldemoura@f5.com nxt_clone_proc_map_write(nxt_task_t *task, const char *mapfile, pid_t pid, 931182St.nateldemoura@f5.com u_char *mapinfo) 941182St.nateldemoura@f5.com { 951182St.nateldemoura@f5.com int len, mapfd; 961182St.nateldemoura@f5.com u_char *p, *end; 971182St.nateldemoura@f5.com ssize_t n; 981182St.nateldemoura@f5.com u_char buf[256]; 991182St.nateldemoura@f5.com 1001182St.nateldemoura@f5.com end = buf + sizeof(buf); 1011182St.nateldemoura@f5.com 1021182St.nateldemoura@f5.com p = nxt_sprintf(buf, end, "/proc/%d/%s", pid, mapfile); 1031182St.nateldemoura@f5.com if (nxt_slow_path(p == end)) { 1041182St.nateldemoura@f5.com nxt_alert(task, "writing past the buffer"); 1051182St.nateldemoura@f5.com return NXT_ERROR; 1061182St.nateldemoura@f5.com } 1071182St.nateldemoura@f5.com 1081182St.nateldemoura@f5.com *p = '\0'; 1091182St.nateldemoura@f5.com 1101182St.nateldemoura@f5.com mapfd = open((char*)buf, O_RDWR); 1111182St.nateldemoura@f5.com if (nxt_slow_path(mapfd == -1)) { 1121182St.nateldemoura@f5.com nxt_alert(task, "failed to open proc map (%s) %E", buf, nxt_errno); 1131182St.nateldemoura@f5.com return NXT_ERROR; 1141182St.nateldemoura@f5.com } 1151182St.nateldemoura@f5.com 1161182St.nateldemoura@f5.com len = nxt_strlen(mapinfo); 1171182St.nateldemoura@f5.com 1181182St.nateldemoura@f5.com n = write(mapfd, (char *)mapinfo, len); 1191182St.nateldemoura@f5.com if (nxt_slow_path(n != len)) { 1201182St.nateldemoura@f5.com 1211182St.nateldemoura@f5.com if (n == -1 && nxt_errno == EINVAL) { 1221182St.nateldemoura@f5.com nxt_alert(task, "failed to write %s: Check kernel maximum " \ 1231182St.nateldemoura@f5.com "allowed lines %E", buf, nxt_errno); 1241182St.nateldemoura@f5.com 1251182St.nateldemoura@f5.com } else { 1261182St.nateldemoura@f5.com nxt_alert(task, "failed to write proc map (%s) %E", buf, 1271182St.nateldemoura@f5.com nxt_errno); 1281182St.nateldemoura@f5.com } 1291182St.nateldemoura@f5.com 130*1201St.nateldemoura@f5.com close(mapfd); 131*1201St.nateldemoura@f5.com 1321182St.nateldemoura@f5.com return NXT_ERROR; 1331182St.nateldemoura@f5.com } 1341182St.nateldemoura@f5.com 135*1201St.nateldemoura@f5.com close(mapfd); 136*1201St.nateldemoura@f5.com 1371182St.nateldemoura@f5.com return NXT_OK; 1381182St.nateldemoura@f5.com } 1391182St.nateldemoura@f5.com 1401182St.nateldemoura@f5.com 1411182St.nateldemoura@f5.com nxt_int_t 1421182St.nateldemoura@f5.com nxt_clone_proc_map_set(nxt_task_t *task, const char* mapfile, pid_t pid, 1431182St.nateldemoura@f5.com nxt_int_t defval, nxt_conf_value_t *mapobj) 1441182St.nateldemoura@f5.com { 1451182St.nateldemoura@f5.com u_char *p, *end, *mapinfo; 1461182St.nateldemoura@f5.com nxt_int_t container, host, size; 1471182St.nateldemoura@f5.com nxt_int_t ret, len, count, i; 1481182St.nateldemoura@f5.com nxt_conf_value_t *obj, *value; 1491182St.nateldemoura@f5.com 1501182St.nateldemoura@f5.com static nxt_str_t str_cont = nxt_string("container"); 1511182St.nateldemoura@f5.com static nxt_str_t str_host = nxt_string("host"); 1521182St.nateldemoura@f5.com static nxt_str_t str_size = nxt_string("size"); 1531182St.nateldemoura@f5.com 1541182St.nateldemoura@f5.com /* 1551182St.nateldemoura@f5.com * uid_map one-entry size: 1561182St.nateldemoura@f5.com * alloc space for 3 numbers (32bit) plus 2 spaces and \n. 1571182St.nateldemoura@f5.com */ 1581182St.nateldemoura@f5.com len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1); 1591182St.nateldemoura@f5.com 1601182St.nateldemoura@f5.com if (mapobj != NULL) { 1611182St.nateldemoura@f5.com count = nxt_conf_array_elements_count(mapobj); 1621182St.nateldemoura@f5.com 1631182St.nateldemoura@f5.com if (count == 0) { 1641182St.nateldemoura@f5.com goto default_map; 1651182St.nateldemoura@f5.com } 1661182St.nateldemoura@f5.com 1671182St.nateldemoura@f5.com len = len * count + 1; 1681182St.nateldemoura@f5.com 1691182St.nateldemoura@f5.com mapinfo = nxt_malloc(len); 1701182St.nateldemoura@f5.com if (nxt_slow_path(mapinfo == NULL)) { 1711182St.nateldemoura@f5.com nxt_alert(task, "failed to allocate uid_map buffer"); 1721182St.nateldemoura@f5.com return NXT_ERROR; 1731182St.nateldemoura@f5.com } 1741182St.nateldemoura@f5.com 1751182St.nateldemoura@f5.com p = mapinfo; 1761182St.nateldemoura@f5.com end = mapinfo + len; 1771182St.nateldemoura@f5.com 1781182St.nateldemoura@f5.com for (i = 0; i < count; i++) { 1791182St.nateldemoura@f5.com obj = nxt_conf_get_array_element(mapobj, i); 1801182St.nateldemoura@f5.com 1811182St.nateldemoura@f5.com value = nxt_conf_get_object_member(obj, &str_cont, NULL); 1821182St.nateldemoura@f5.com container = nxt_conf_get_integer(value); 1831182St.nateldemoura@f5.com 1841182St.nateldemoura@f5.com value = nxt_conf_get_object_member(obj, &str_host, NULL); 1851182St.nateldemoura@f5.com host = nxt_conf_get_integer(value); 1861182St.nateldemoura@f5.com 1871182St.nateldemoura@f5.com value = nxt_conf_get_object_member(obj, &str_size, NULL); 1881182St.nateldemoura@f5.com size = nxt_conf_get_integer(value); 1891182St.nateldemoura@f5.com 1901182St.nateldemoura@f5.com p = nxt_sprintf(p, end, "%d %d %d", container, host, size); 1911182St.nateldemoura@f5.com if (nxt_slow_path(p == end)) { 1921182St.nateldemoura@f5.com nxt_alert(task, "write past the uid_map buffer"); 1931182St.nateldemoura@f5.com nxt_free(mapinfo); 1941182St.nateldemoura@f5.com return NXT_ERROR; 1951182St.nateldemoura@f5.com } 1961182St.nateldemoura@f5.com 1971182St.nateldemoura@f5.com if (i+1 < count) { 1981182St.nateldemoura@f5.com *p++ = '\n'; 1991182St.nateldemoura@f5.com 2001182St.nateldemoura@f5.com } else { 2011182St.nateldemoura@f5.com *p = '\0'; 2021182St.nateldemoura@f5.com } 2031182St.nateldemoura@f5.com } 2041182St.nateldemoura@f5.com 2051182St.nateldemoura@f5.com } else { 2061182St.nateldemoura@f5.com 2071182St.nateldemoura@f5.com default_map: 2081182St.nateldemoura@f5.com 2091182St.nateldemoura@f5.com mapinfo = nxt_malloc(len); 2101182St.nateldemoura@f5.com if (nxt_slow_path(mapinfo == NULL)) { 2111182St.nateldemoura@f5.com nxt_alert(task, "failed to allocate uid_map buffer"); 2121182St.nateldemoura@f5.com return NXT_ERROR; 2131182St.nateldemoura@f5.com } 2141182St.nateldemoura@f5.com 2151182St.nateldemoura@f5.com end = mapinfo + len; 2161182St.nateldemoura@f5.com p = nxt_sprintf(mapinfo, end, NXT_DEFAULT_UNPRIV_MAP, defval); 2171182St.nateldemoura@f5.com *p = '\0'; 2181182St.nateldemoura@f5.com 2191182St.nateldemoura@f5.com if (nxt_slow_path(p == end)) { 2201182St.nateldemoura@f5.com nxt_alert(task, "write past the %s buffer", mapfile); 2211182St.nateldemoura@f5.com nxt_free(mapinfo); 2221182St.nateldemoura@f5.com return NXT_ERROR; 2231182St.nateldemoura@f5.com } 2241182St.nateldemoura@f5.com } 2251182St.nateldemoura@f5.com 2261182St.nateldemoura@f5.com ret = nxt_clone_proc_map_write(task, mapfile, pid, mapinfo); 2271182St.nateldemoura@f5.com 2281182St.nateldemoura@f5.com nxt_free(mapinfo); 2291182St.nateldemoura@f5.com 2301182St.nateldemoura@f5.com return ret; 2311182St.nateldemoura@f5.com } 2321182St.nateldemoura@f5.com 2331182St.nateldemoura@f5.com 2341182St.nateldemoura@f5.com nxt_int_t 2351182St.nateldemoura@f5.com nxt_clone_proc_map(nxt_task_t *task, pid_t pid, nxt_process_clone_t *clone) 2361182St.nateldemoura@f5.com { 2371182St.nateldemoura@f5.com nxt_int_t ret; 2381182St.nateldemoura@f5.com nxt_int_t uid, gid; 2391182St.nateldemoura@f5.com const char *rule; 2401182St.nateldemoura@f5.com nxt_runtime_t *rt; 2411182St.nateldemoura@f5.com 2421182St.nateldemoura@f5.com rt = task->thread->runtime; 2431182St.nateldemoura@f5.com uid = geteuid(); 2441182St.nateldemoura@f5.com gid = getegid(); 2451182St.nateldemoura@f5.com 2461182St.nateldemoura@f5.com rule = rt->capabilities.setid ? "allow" : "deny"; 2471182St.nateldemoura@f5.com 2481182St.nateldemoura@f5.com ret = nxt_clone_proc_map_set(task, "uid_map", pid, uid, clone->uidmap); 2491182St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2501182St.nateldemoura@f5.com return NXT_ERROR; 2511182St.nateldemoura@f5.com } 2521182St.nateldemoura@f5.com 2531182St.nateldemoura@f5.com ret = nxt_clone_proc_setgroups(task, pid, rule); 2541182St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2551182St.nateldemoura@f5.com nxt_alert(task, "failed to write /proc/%d/setgroups", pid); 2561182St.nateldemoura@f5.com return NXT_ERROR; 2571182St.nateldemoura@f5.com } 2581182St.nateldemoura@f5.com 2591182St.nateldemoura@f5.com ret = nxt_clone_proc_map_set(task, "gid_map", pid, gid, clone->gidmap); 2601182St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2611182St.nateldemoura@f5.com return NXT_ERROR; 2621182St.nateldemoura@f5.com } 2631182St.nateldemoura@f5.com 2641182St.nateldemoura@f5.com return NXT_OK; 2651182St.nateldemoura@f5.com } 2661182St.nateldemoura@f5.com 2671182St.nateldemoura@f5.com #endif 268