xref: /unit/src/nxt_clone.c (revision 1201)
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