11579St.nateldemoura@f5.com /* 21579St.nateldemoura@f5.com * Copyright (C) NGINX, Inc. 31579St.nateldemoura@f5.com */ 41579St.nateldemoura@f5.com 51579St.nateldemoura@f5.com #include <nxt_main.h> 61579St.nateldemoura@f5.com #include <nxt_application.h> 71579St.nateldemoura@f5.com #include <nxt_process.h> 81579St.nateldemoura@f5.com #include <nxt_isolation.h> 91579St.nateldemoura@f5.com 101579St.nateldemoura@f5.com #if (NXT_HAVE_PIVOT_ROOT) 111579St.nateldemoura@f5.com #include <mntent.h> 121579St.nateldemoura@f5.com #endif 131579St.nateldemoura@f5.com 141579St.nateldemoura@f5.com 151579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set(nxt_task_t *task, 161579St.nateldemoura@f5.com nxt_conf_value_t *isolation, nxt_process_t *process); 171579St.nateldemoura@f5.com 181579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE) 191579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_namespaces(nxt_task_t *task, 201579St.nateldemoura@f5.com nxt_conf_value_t *isolation, nxt_process_t *process); 211579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_clone_flags(nxt_task_t *task, 221579St.nateldemoura@f5.com nxt_conf_value_t *namespaces, nxt_clone_t *clone); 231579St.nateldemoura@f5.com #endif 241579St.nateldemoura@f5.com 251579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 261579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_creds(nxt_task_t *task, 271579St.nateldemoura@f5.com nxt_conf_value_t *isolation, nxt_process_t *process); 281579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_credential_map(nxt_task_t *task, 291579St.nateldemoura@f5.com nxt_mp_t *mem_pool, nxt_conf_value_t *map_array, 301579St.nateldemoura@f5.com nxt_clone_credential_map_t *map); 311579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_vldt_creds(nxt_task_t *task, 321579St.nateldemoura@f5.com nxt_process_t *process); 331579St.nateldemoura@f5.com #endif 341579St.nateldemoura@f5.com 351579St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS) 361579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_rootfs(nxt_task_t *task, 371579St.nateldemoura@f5.com nxt_conf_value_t *isolation, nxt_process_t *process); 381585St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_automount(nxt_task_t *task, 391585St.nateldemoura@f5.com nxt_conf_value_t *isolation, nxt_process_t *process); 401579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_mounts(nxt_task_t *task, 411579St.nateldemoura@f5.com nxt_process_t *process, nxt_str_t *app_type); 421579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_lang_mounts(nxt_task_t *task, 431579St.nateldemoura@f5.com nxt_process_t *process, nxt_array_t *syspaths); 44*1671St.nateldemoura@f5.com static int nxt_cdecl nxt_isolation_mount_compare(const void *v1, 45*1671St.nateldemoura@f5.com const void *v2); 461579St.nateldemoura@f5.com static void nxt_isolation_unmount_all(nxt_task_t *task, nxt_process_t *process); 471579St.nateldemoura@f5.com 481579St.nateldemoura@f5.com #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) 491579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_pivot_root(nxt_task_t *task, const char *rootfs); 501579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_make_private_mount(nxt_task_t *task, 511579St.nateldemoura@f5.com const char *rootfs); 521579St.nateldemoura@f5.com nxt_inline int nxt_pivot_root(const char *new_root, const char *old_root); 531579St.nateldemoura@f5.com #endif 541579St.nateldemoura@f5.com 551579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_chroot(nxt_task_t *task, const char *path); 561579St.nateldemoura@f5.com #endif 571579St.nateldemoura@f5.com 581579St.nateldemoura@f5.com #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 591579St.nateldemoura@f5.com static nxt_int_t nxt_isolation_set_new_privs(nxt_task_t *task, 601579St.nateldemoura@f5.com nxt_conf_value_t *isolation, nxt_process_t *process); 611579St.nateldemoura@f5.com #endif 621579St.nateldemoura@f5.com 631579St.nateldemoura@f5.com 641579St.nateldemoura@f5.com nxt_int_t 651579St.nateldemoura@f5.com nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process, 661579St.nateldemoura@f5.com nxt_mp_t *mp) 671579St.nateldemoura@f5.com { 681579St.nateldemoura@f5.com nxt_int_t cap_setid; 691579St.nateldemoura@f5.com nxt_int_t ret; 701579St.nateldemoura@f5.com nxt_runtime_t *rt; 711579St.nateldemoura@f5.com nxt_common_app_conf_t *app_conf; 721579St.nateldemoura@f5.com 731579St.nateldemoura@f5.com rt = task->thread->runtime; 741579St.nateldemoura@f5.com app_conf = process->data.app; 751579St.nateldemoura@f5.com cap_setid = rt->capabilities.setid; 761579St.nateldemoura@f5.com 771579St.nateldemoura@f5.com if (app_conf->isolation != NULL) { 781579St.nateldemoura@f5.com ret = nxt_isolation_set(task, app_conf->isolation, process); 791579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 801579St.nateldemoura@f5.com return ret; 811579St.nateldemoura@f5.com } 821579St.nateldemoura@f5.com } 831579St.nateldemoura@f5.com 841579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 851579St.nateldemoura@f5.com if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { 861579St.nateldemoura@f5.com cap_setid = 1; 871579St.nateldemoura@f5.com } 881579St.nateldemoura@f5.com #endif 891579St.nateldemoura@f5.com 901579St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS) 911579St.nateldemoura@f5.com if (process->isolation.rootfs != NULL) { 921579St.nateldemoura@f5.com ret = nxt_isolation_set_mounts(task, process, &app_conf->type); 931579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 941579St.nateldemoura@f5.com return ret; 951579St.nateldemoura@f5.com } 961579St.nateldemoura@f5.com } 971579St.nateldemoura@f5.com #endif 981579St.nateldemoura@f5.com 991579St.nateldemoura@f5.com if (cap_setid) { 1001579St.nateldemoura@f5.com ret = nxt_process_creds_set(task, process, &app_conf->user, 1011579St.nateldemoura@f5.com &app_conf->group); 1021579St.nateldemoura@f5.com 1031579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 1041579St.nateldemoura@f5.com return ret; 1051579St.nateldemoura@f5.com } 1061579St.nateldemoura@f5.com 1071579St.nateldemoura@f5.com } else { 1081579St.nateldemoura@f5.com if (!nxt_str_eq(&app_conf->user, (u_char *) rt->user_cred.user, 1091579St.nateldemoura@f5.com nxt_strlen(rt->user_cred.user))) 1101579St.nateldemoura@f5.com { 1111579St.nateldemoura@f5.com nxt_alert(task, "cannot set user \"%V\" for app \"%V\": " 1121579St.nateldemoura@f5.com "missing capabilities", &app_conf->user, &app_conf->name); 1131579St.nateldemoura@f5.com 1141579St.nateldemoura@f5.com return NXT_ERROR; 1151579St.nateldemoura@f5.com } 1161579St.nateldemoura@f5.com 1171579St.nateldemoura@f5.com if (app_conf->group.length > 0 1181579St.nateldemoura@f5.com && !nxt_str_eq(&app_conf->group, (u_char *) rt->group, 1191579St.nateldemoura@f5.com nxt_strlen(rt->group))) 1201579St.nateldemoura@f5.com { 1211579St.nateldemoura@f5.com nxt_alert(task, "cannot set group \"%V\" for app \"%V\": " 1221579St.nateldemoura@f5.com "missing capabilities", &app_conf->group, 1231579St.nateldemoura@f5.com &app_conf->name); 1241579St.nateldemoura@f5.com 1251579St.nateldemoura@f5.com return NXT_ERROR; 1261579St.nateldemoura@f5.com } 1271579St.nateldemoura@f5.com } 1281579St.nateldemoura@f5.com 1291579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 1301579St.nateldemoura@f5.com ret = nxt_isolation_vldt_creds(task, process); 1311579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 1321579St.nateldemoura@f5.com return ret; 1331579St.nateldemoura@f5.com } 1341579St.nateldemoura@f5.com #endif 1351579St.nateldemoura@f5.com 1361579St.nateldemoura@f5.com return NXT_OK; 1371579St.nateldemoura@f5.com } 1381579St.nateldemoura@f5.com 1391579St.nateldemoura@f5.com 1401579St.nateldemoura@f5.com static nxt_int_t 1411579St.nateldemoura@f5.com nxt_isolation_set(nxt_task_t *task, nxt_conf_value_t *isolation, 1421579St.nateldemoura@f5.com nxt_process_t *process) 1431579St.nateldemoura@f5.com { 1441579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE) 1451579St.nateldemoura@f5.com if (nxt_slow_path(nxt_isolation_set_namespaces(task, isolation, process) 1461579St.nateldemoura@f5.com != NXT_OK)) 1471579St.nateldemoura@f5.com { 1481579St.nateldemoura@f5.com return NXT_ERROR; 1491579St.nateldemoura@f5.com } 1501579St.nateldemoura@f5.com #endif 1511579St.nateldemoura@f5.com 1521579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 1531579St.nateldemoura@f5.com if (nxt_slow_path(nxt_isolation_set_creds(task, isolation, process) 1541579St.nateldemoura@f5.com != NXT_OK)) 1551579St.nateldemoura@f5.com { 1561579St.nateldemoura@f5.com return NXT_ERROR; 1571579St.nateldemoura@f5.com } 1581579St.nateldemoura@f5.com #endif 1591579St.nateldemoura@f5.com 1601579St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS) 1611579St.nateldemoura@f5.com if (nxt_slow_path(nxt_isolation_set_rootfs(task, isolation, process) 1621579St.nateldemoura@f5.com != NXT_OK)) 1631579St.nateldemoura@f5.com { 1641579St.nateldemoura@f5.com return NXT_ERROR; 1651579St.nateldemoura@f5.com } 1661585St.nateldemoura@f5.com 1671585St.nateldemoura@f5.com if (nxt_slow_path(nxt_isolation_set_automount(task, isolation, process) 1681585St.nateldemoura@f5.com != NXT_OK)) 1691585St.nateldemoura@f5.com { 1701585St.nateldemoura@f5.com return NXT_ERROR; 1711585St.nateldemoura@f5.com } 1721579St.nateldemoura@f5.com #endif 1731579St.nateldemoura@f5.com 1741579St.nateldemoura@f5.com #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 1751579St.nateldemoura@f5.com if (nxt_slow_path(nxt_isolation_set_new_privs(task, isolation, process) 1761579St.nateldemoura@f5.com != NXT_OK)) 1771579St.nateldemoura@f5.com { 1781579St.nateldemoura@f5.com return NXT_ERROR; 1791579St.nateldemoura@f5.com } 1801579St.nateldemoura@f5.com #endif 1811579St.nateldemoura@f5.com 1821579St.nateldemoura@f5.com return NXT_OK; 1831579St.nateldemoura@f5.com } 1841579St.nateldemoura@f5.com 1851579St.nateldemoura@f5.com 1861579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE) 1871579St.nateldemoura@f5.com 1881579St.nateldemoura@f5.com static nxt_int_t 1891579St.nateldemoura@f5.com nxt_isolation_set_namespaces(nxt_task_t *task, nxt_conf_value_t *isolation, 1901579St.nateldemoura@f5.com nxt_process_t *process) 1911579St.nateldemoura@f5.com { 1921579St.nateldemoura@f5.com nxt_int_t ret; 1931579St.nateldemoura@f5.com nxt_conf_value_t *obj; 1941579St.nateldemoura@f5.com 1951579St.nateldemoura@f5.com static nxt_str_t nsname = nxt_string("namespaces"); 1961579St.nateldemoura@f5.com 1971579St.nateldemoura@f5.com obj = nxt_conf_get_object_member(isolation, &nsname, NULL); 1981579St.nateldemoura@f5.com if (obj != NULL) { 1991579St.nateldemoura@f5.com ret = nxt_isolation_clone_flags(task, obj, &process->isolation.clone); 2001579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2011579St.nateldemoura@f5.com return NXT_ERROR; 2021579St.nateldemoura@f5.com } 2031579St.nateldemoura@f5.com } 2041579St.nateldemoura@f5.com 2051579St.nateldemoura@f5.com return NXT_OK; 2061579St.nateldemoura@f5.com } 2071579St.nateldemoura@f5.com 2081579St.nateldemoura@f5.com #endif 2091579St.nateldemoura@f5.com 2101579St.nateldemoura@f5.com 2111579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 2121579St.nateldemoura@f5.com 2131579St.nateldemoura@f5.com static nxt_int_t 2141579St.nateldemoura@f5.com nxt_isolation_set_creds(nxt_task_t *task, nxt_conf_value_t *isolation, 2151579St.nateldemoura@f5.com nxt_process_t *process) 2161579St.nateldemoura@f5.com { 2171579St.nateldemoura@f5.com nxt_int_t ret; 2181579St.nateldemoura@f5.com nxt_clone_t *clone; 2191579St.nateldemoura@f5.com nxt_conf_value_t *array; 2201579St.nateldemoura@f5.com 2211579St.nateldemoura@f5.com static nxt_str_t uidname = nxt_string("uidmap"); 2221579St.nateldemoura@f5.com static nxt_str_t gidname = nxt_string("gidmap"); 2231579St.nateldemoura@f5.com 2241579St.nateldemoura@f5.com clone = &process->isolation.clone; 2251579St.nateldemoura@f5.com 2261579St.nateldemoura@f5.com array = nxt_conf_get_object_member(isolation, &uidname, NULL); 2271579St.nateldemoura@f5.com if (array != NULL) { 2281579St.nateldemoura@f5.com ret = nxt_isolation_credential_map(task, process->mem_pool, array, 2291579St.nateldemoura@f5.com &clone->uidmap); 2301579St.nateldemoura@f5.com 2311579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2321579St.nateldemoura@f5.com return NXT_ERROR; 2331579St.nateldemoura@f5.com } 2341579St.nateldemoura@f5.com } 2351579St.nateldemoura@f5.com 2361579St.nateldemoura@f5.com array = nxt_conf_get_object_member(isolation, &gidname, NULL); 2371579St.nateldemoura@f5.com if (array != NULL) { 2381579St.nateldemoura@f5.com ret = nxt_isolation_credential_map(task, process->mem_pool, array, 2391579St.nateldemoura@f5.com &clone->gidmap); 2401579St.nateldemoura@f5.com 2411579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2421579St.nateldemoura@f5.com return NXT_ERROR; 2431579St.nateldemoura@f5.com } 2441579St.nateldemoura@f5.com } 2451579St.nateldemoura@f5.com 2461579St.nateldemoura@f5.com return NXT_OK; 2471579St.nateldemoura@f5.com } 2481579St.nateldemoura@f5.com 2491579St.nateldemoura@f5.com 2501579St.nateldemoura@f5.com static nxt_int_t 2511579St.nateldemoura@f5.com nxt_isolation_credential_map(nxt_task_t *task, nxt_mp_t *mp, 2521579St.nateldemoura@f5.com nxt_conf_value_t *map_array, nxt_clone_credential_map_t *map) 2531579St.nateldemoura@f5.com { 2541579St.nateldemoura@f5.com nxt_int_t ret; 2551579St.nateldemoura@f5.com nxt_uint_t i; 2561579St.nateldemoura@f5.com nxt_conf_value_t *obj; 2571579St.nateldemoura@f5.com 2581579St.nateldemoura@f5.com static nxt_conf_map_t nxt_clone_map_entry_conf[] = { 2591579St.nateldemoura@f5.com { 2601579St.nateldemoura@f5.com nxt_string("container"), 2611579St.nateldemoura@f5.com NXT_CONF_MAP_INT, 2621579St.nateldemoura@f5.com offsetof(nxt_clone_map_entry_t, container), 2631579St.nateldemoura@f5.com }, 2641579St.nateldemoura@f5.com 2651579St.nateldemoura@f5.com { 2661579St.nateldemoura@f5.com nxt_string("host"), 2671579St.nateldemoura@f5.com NXT_CONF_MAP_INT, 2681579St.nateldemoura@f5.com offsetof(nxt_clone_map_entry_t, host), 2691579St.nateldemoura@f5.com }, 2701579St.nateldemoura@f5.com 2711579St.nateldemoura@f5.com { 2721579St.nateldemoura@f5.com nxt_string("size"), 2731579St.nateldemoura@f5.com NXT_CONF_MAP_INT, 2741579St.nateldemoura@f5.com offsetof(nxt_clone_map_entry_t, size), 2751579St.nateldemoura@f5.com }, 2761579St.nateldemoura@f5.com }; 2771579St.nateldemoura@f5.com 2781579St.nateldemoura@f5.com map->size = nxt_conf_array_elements_count(map_array); 2791579St.nateldemoura@f5.com 2801579St.nateldemoura@f5.com if (map->size == 0) { 2811579St.nateldemoura@f5.com return NXT_OK; 2821579St.nateldemoura@f5.com } 2831579St.nateldemoura@f5.com 2841579St.nateldemoura@f5.com map->map = nxt_mp_alloc(mp, map->size * sizeof(nxt_clone_map_entry_t)); 2851579St.nateldemoura@f5.com if (nxt_slow_path(map->map == NULL)) { 2861579St.nateldemoura@f5.com return NXT_ERROR; 2871579St.nateldemoura@f5.com } 2881579St.nateldemoura@f5.com 2891579St.nateldemoura@f5.com for (i = 0; i < map->size; i++) { 2901579St.nateldemoura@f5.com obj = nxt_conf_get_array_element(map_array, i); 2911579St.nateldemoura@f5.com 2921579St.nateldemoura@f5.com ret = nxt_conf_map_object(mp, obj, nxt_clone_map_entry_conf, 2931579St.nateldemoura@f5.com nxt_nitems(nxt_clone_map_entry_conf), 2941579St.nateldemoura@f5.com map->map + i); 2951579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2961579St.nateldemoura@f5.com nxt_alert(task, "clone map entry map error"); 2971579St.nateldemoura@f5.com return NXT_ERROR; 2981579St.nateldemoura@f5.com } 2991579St.nateldemoura@f5.com } 3001579St.nateldemoura@f5.com 3011579St.nateldemoura@f5.com return NXT_OK; 3021579St.nateldemoura@f5.com } 3031579St.nateldemoura@f5.com 3041579St.nateldemoura@f5.com 3051579St.nateldemoura@f5.com static nxt_int_t 3061579St.nateldemoura@f5.com nxt_isolation_vldt_creds(nxt_task_t *task, nxt_process_t *process) 3071579St.nateldemoura@f5.com { 3081579St.nateldemoura@f5.com nxt_int_t ret; 3091579St.nateldemoura@f5.com nxt_clone_t *clone; 3101579St.nateldemoura@f5.com nxt_credential_t *creds; 3111579St.nateldemoura@f5.com 3121579St.nateldemoura@f5.com clone = &process->isolation.clone; 3131579St.nateldemoura@f5.com creds = process->user_cred; 3141579St.nateldemoura@f5.com 3151579St.nateldemoura@f5.com if (clone->uidmap.size == 0 && clone->gidmap.size == 0) { 3161579St.nateldemoura@f5.com return NXT_OK; 3171579St.nateldemoura@f5.com } 3181579St.nateldemoura@f5.com 3191579St.nateldemoura@f5.com if (!nxt_is_clone_flag_set(clone->flags, NEWUSER)) { 3201579St.nateldemoura@f5.com if (nxt_slow_path(clone->uidmap.size > 0)) { 3211579St.nateldemoura@f5.com nxt_log(task, NXT_LOG_ERR, "\"uidmap\" is set but " 3221579St.nateldemoura@f5.com "\"isolation.namespaces.credential\" is false or unset"); 3231579St.nateldemoura@f5.com 3241579St.nateldemoura@f5.com return NXT_ERROR; 3251579St.nateldemoura@f5.com } 3261579St.nateldemoura@f5.com 3271579St.nateldemoura@f5.com if (nxt_slow_path(clone->gidmap.size > 0)) { 3281579St.nateldemoura@f5.com nxt_log(task, NXT_LOG_ERR, "\"gidmap\" is set but " 3291579St.nateldemoura@f5.com "\"isolation.namespaces.credential\" is false or unset"); 3301579St.nateldemoura@f5.com 3311579St.nateldemoura@f5.com return NXT_ERROR; 3321579St.nateldemoura@f5.com } 3331579St.nateldemoura@f5.com 3341579St.nateldemoura@f5.com return NXT_OK; 3351579St.nateldemoura@f5.com } 3361579St.nateldemoura@f5.com 3371579St.nateldemoura@f5.com ret = nxt_clone_vldt_credential_uidmap(task, &clone->uidmap, creds); 3381579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 3391579St.nateldemoura@f5.com return NXT_ERROR; 3401579St.nateldemoura@f5.com } 3411579St.nateldemoura@f5.com 3421579St.nateldemoura@f5.com return nxt_clone_vldt_credential_gidmap(task, &clone->gidmap, creds); 3431579St.nateldemoura@f5.com } 3441579St.nateldemoura@f5.com 3451579St.nateldemoura@f5.com #endif 3461579St.nateldemoura@f5.com 3471579St.nateldemoura@f5.com 3481579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE) 3491579St.nateldemoura@f5.com 3501579St.nateldemoura@f5.com static nxt_int_t 3511579St.nateldemoura@f5.com nxt_isolation_clone_flags(nxt_task_t *task, nxt_conf_value_t *namespaces, 3521579St.nateldemoura@f5.com nxt_clone_t *clone) 3531579St.nateldemoura@f5.com { 3541579St.nateldemoura@f5.com uint32_t index; 3551579St.nateldemoura@f5.com nxt_str_t name; 3561579St.nateldemoura@f5.com nxt_int_t flag; 3571579St.nateldemoura@f5.com nxt_conf_value_t *value; 3581579St.nateldemoura@f5.com 3591579St.nateldemoura@f5.com index = 0; 3601579St.nateldemoura@f5.com 3611579St.nateldemoura@f5.com for ( ;; ) { 3621579St.nateldemoura@f5.com value = nxt_conf_next_object_member(namespaces, &name, &index); 3631579St.nateldemoura@f5.com 3641579St.nateldemoura@f5.com if (value == NULL) { 3651579St.nateldemoura@f5.com break; 3661579St.nateldemoura@f5.com } 3671579St.nateldemoura@f5.com 3681579St.nateldemoura@f5.com flag = 0; 3691579St.nateldemoura@f5.com 3701579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 3711579St.nateldemoura@f5.com if (nxt_str_eq(&name, "credential", 10)) { 3721579St.nateldemoura@f5.com flag = CLONE_NEWUSER; 3731579St.nateldemoura@f5.com } 3741579St.nateldemoura@f5.com #endif 3751579St.nateldemoura@f5.com 3761579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWPID) 3771579St.nateldemoura@f5.com if (nxt_str_eq(&name, "pid", 3)) { 3781579St.nateldemoura@f5.com flag = CLONE_NEWPID; 3791579St.nateldemoura@f5.com } 3801579St.nateldemoura@f5.com #endif 3811579St.nateldemoura@f5.com 3821579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWNET) 3831579St.nateldemoura@f5.com if (nxt_str_eq(&name, "network", 7)) { 3841579St.nateldemoura@f5.com flag = CLONE_NEWNET; 3851579St.nateldemoura@f5.com } 3861579St.nateldemoura@f5.com #endif 3871579St.nateldemoura@f5.com 3881579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUTS) 3891579St.nateldemoura@f5.com if (nxt_str_eq(&name, "uname", 5)) { 3901579St.nateldemoura@f5.com flag = CLONE_NEWUTS; 3911579St.nateldemoura@f5.com } 3921579St.nateldemoura@f5.com #endif 3931579St.nateldemoura@f5.com 3941579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWNS) 3951579St.nateldemoura@f5.com if (nxt_str_eq(&name, "mount", 5)) { 3961579St.nateldemoura@f5.com flag = CLONE_NEWNS; 3971579St.nateldemoura@f5.com } 3981579St.nateldemoura@f5.com #endif 3991579St.nateldemoura@f5.com 4001579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWCGROUP) 4011579St.nateldemoura@f5.com if (nxt_str_eq(&name, "cgroup", 6)) { 4021579St.nateldemoura@f5.com flag = CLONE_NEWCGROUP; 4031579St.nateldemoura@f5.com } 4041579St.nateldemoura@f5.com #endif 4051579St.nateldemoura@f5.com 4061579St.nateldemoura@f5.com if (!flag) { 4071579St.nateldemoura@f5.com nxt_alert(task, "unknown namespace flag: \"%V\"", &name); 4081579St.nateldemoura@f5.com return NXT_ERROR; 4091579St.nateldemoura@f5.com } 4101579St.nateldemoura@f5.com 4111579St.nateldemoura@f5.com if (nxt_conf_get_boolean(value)) { 4121579St.nateldemoura@f5.com clone->flags |= flag; 4131579St.nateldemoura@f5.com } 4141579St.nateldemoura@f5.com } 4151579St.nateldemoura@f5.com 4161579St.nateldemoura@f5.com return NXT_OK; 4171579St.nateldemoura@f5.com } 4181579St.nateldemoura@f5.com 4191579St.nateldemoura@f5.com #endif 4201579St.nateldemoura@f5.com 4211579St.nateldemoura@f5.com 4221579St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS) 4231579St.nateldemoura@f5.com 4241579St.nateldemoura@f5.com static nxt_int_t 4251579St.nateldemoura@f5.com nxt_isolation_set_rootfs(nxt_task_t *task, nxt_conf_value_t *isolation, 4261579St.nateldemoura@f5.com nxt_process_t *process) 4271579St.nateldemoura@f5.com { 4281579St.nateldemoura@f5.com nxt_str_t str; 4291579St.nateldemoura@f5.com nxt_conf_value_t *obj; 4301579St.nateldemoura@f5.com 4311579St.nateldemoura@f5.com static nxt_str_t rootfs_name = nxt_string("rootfs"); 4321579St.nateldemoura@f5.com 4331579St.nateldemoura@f5.com obj = nxt_conf_get_object_member(isolation, &rootfs_name, NULL); 4341579St.nateldemoura@f5.com if (obj != NULL) { 4351579St.nateldemoura@f5.com nxt_conf_get_string(obj, &str); 4361579St.nateldemoura@f5.com 4371579St.nateldemoura@f5.com if (nxt_slow_path(str.length <= 1 || str.start[0] != '/')) { 4381579St.nateldemoura@f5.com nxt_log(task, NXT_LOG_ERR, "rootfs requires an absolute path other " 4391579St.nateldemoura@f5.com "than \"/\" but given \"%V\"", &str); 4401579St.nateldemoura@f5.com 4411579St.nateldemoura@f5.com return NXT_ERROR; 4421579St.nateldemoura@f5.com } 4431579St.nateldemoura@f5.com 4441579St.nateldemoura@f5.com if (str.start[str.length - 1] == '/') { 4451579St.nateldemoura@f5.com str.length--; 4461579St.nateldemoura@f5.com } 4471579St.nateldemoura@f5.com 4481579St.nateldemoura@f5.com process->isolation.rootfs = nxt_mp_alloc(process->mem_pool, 4491579St.nateldemoura@f5.com str.length + 1); 4501579St.nateldemoura@f5.com 4511579St.nateldemoura@f5.com if (nxt_slow_path(process->isolation.rootfs == NULL)) { 4521579St.nateldemoura@f5.com return NXT_ERROR; 4531579St.nateldemoura@f5.com } 4541579St.nateldemoura@f5.com 4551579St.nateldemoura@f5.com nxt_memcpy(process->isolation.rootfs, str.start, str.length); 4561579St.nateldemoura@f5.com 4571579St.nateldemoura@f5.com process->isolation.rootfs[str.length] = '\0'; 4581579St.nateldemoura@f5.com } 4591579St.nateldemoura@f5.com 4601579St.nateldemoura@f5.com return NXT_OK; 4611579St.nateldemoura@f5.com } 4621579St.nateldemoura@f5.com 4631579St.nateldemoura@f5.com 4641579St.nateldemoura@f5.com static nxt_int_t 4651585St.nateldemoura@f5.com nxt_isolation_set_automount(nxt_task_t *task, nxt_conf_value_t *isolation, 4661585St.nateldemoura@f5.com nxt_process_t *process) 4671585St.nateldemoura@f5.com { 4681585St.nateldemoura@f5.com nxt_conf_value_t *conf, *value; 4691585St.nateldemoura@f5.com nxt_process_automount_t *automount; 4701585St.nateldemoura@f5.com 4711585St.nateldemoura@f5.com static nxt_str_t automount_name = nxt_string("automount"); 4721585St.nateldemoura@f5.com static nxt_str_t langdeps_name = nxt_string("language_deps"); 4731585St.nateldemoura@f5.com 4741585St.nateldemoura@f5.com automount = &process->isolation.automount; 4751585St.nateldemoura@f5.com 4761585St.nateldemoura@f5.com automount->language_deps = 1; 4771585St.nateldemoura@f5.com 4781585St.nateldemoura@f5.com conf = nxt_conf_get_object_member(isolation, &automount_name, NULL); 4791585St.nateldemoura@f5.com if (conf != NULL) { 4801585St.nateldemoura@f5.com value = nxt_conf_get_object_member(conf, &langdeps_name, NULL); 4811585St.nateldemoura@f5.com if (value != NULL) { 4821585St.nateldemoura@f5.com automount->language_deps = nxt_conf_get_boolean(value); 4831585St.nateldemoura@f5.com } 4841585St.nateldemoura@f5.com } 4851585St.nateldemoura@f5.com 4861585St.nateldemoura@f5.com return NXT_OK; 4871585St.nateldemoura@f5.com } 4881585St.nateldemoura@f5.com 4891585St.nateldemoura@f5.com 4901585St.nateldemoura@f5.com static nxt_int_t 4911579St.nateldemoura@f5.com nxt_isolation_set_mounts(nxt_task_t *task, nxt_process_t *process, 4921579St.nateldemoura@f5.com nxt_str_t *app_type) 4931579St.nateldemoura@f5.com { 4941579St.nateldemoura@f5.com nxt_int_t ret, cap_chroot; 4951579St.nateldemoura@f5.com nxt_runtime_t *rt; 4961579St.nateldemoura@f5.com nxt_app_lang_module_t *lang; 4971579St.nateldemoura@f5.com 4981579St.nateldemoura@f5.com rt = task->thread->runtime; 4991579St.nateldemoura@f5.com cap_chroot = rt->capabilities.chroot; 5001579St.nateldemoura@f5.com lang = nxt_app_lang_module(rt, app_type); 5011579St.nateldemoura@f5.com 5021579St.nateldemoura@f5.com nxt_assert(lang != NULL); 5031579St.nateldemoura@f5.com 5041579St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER) 5051579St.nateldemoura@f5.com if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { 5061579St.nateldemoura@f5.com cap_chroot = 1; 5071579St.nateldemoura@f5.com } 5081579St.nateldemoura@f5.com #endif 5091579St.nateldemoura@f5.com 5101579St.nateldemoura@f5.com if (!cap_chroot) { 5111579St.nateldemoura@f5.com nxt_log(task, NXT_LOG_ERR, "The \"rootfs\" field requires privileges"); 5121579St.nateldemoura@f5.com return NXT_ERROR; 5131579St.nateldemoura@f5.com } 5141579St.nateldemoura@f5.com 5151580St.nateldemoura@f5.com ret = nxt_isolation_set_lang_mounts(task, process, lang->mounts); 5161580St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 5171580St.nateldemoura@f5.com return NXT_ERROR; 5181580St.nateldemoura@f5.com } 5191579St.nateldemoura@f5.com 5201580St.nateldemoura@f5.com process->isolation.cleanup = nxt_isolation_unmount_all; 5211579St.nateldemoura@f5.com 5221579St.nateldemoura@f5.com return NXT_OK; 5231579St.nateldemoura@f5.com } 5241579St.nateldemoura@f5.com 5251579St.nateldemoura@f5.com 5261579St.nateldemoura@f5.com static nxt_int_t 5271579St.nateldemoura@f5.com nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process, 5281579St.nateldemoura@f5.com nxt_array_t *lang_mounts) 5291579St.nateldemoura@f5.com { 5301579St.nateldemoura@f5.com u_char *p; 5311579St.nateldemoura@f5.com size_t i, n, rootfs_len, len; 5321579St.nateldemoura@f5.com nxt_mp_t *mp; 5331579St.nateldemoura@f5.com nxt_array_t *mounts; 5341579St.nateldemoura@f5.com const u_char *rootfs; 5351579St.nateldemoura@f5.com nxt_fs_mount_t *mnt, *lang_mnt; 5361579St.nateldemoura@f5.com 5371579St.nateldemoura@f5.com mp = process->mem_pool; 5381579St.nateldemoura@f5.com 5391579St.nateldemoura@f5.com /* copy to init mem pool */ 5401579St.nateldemoura@f5.com mounts = nxt_array_copy(mp, NULL, lang_mounts); 5411579St.nateldemoura@f5.com if (mounts == NULL) { 5421579St.nateldemoura@f5.com return NXT_ERROR; 5431579St.nateldemoura@f5.com } 5441579St.nateldemoura@f5.com 5451579St.nateldemoura@f5.com n = mounts->nelts; 5461579St.nateldemoura@f5.com mnt = mounts->elts; 5471579St.nateldemoura@f5.com lang_mnt = lang_mounts->elts; 5481579St.nateldemoura@f5.com 5491580St.nateldemoura@f5.com rootfs = process->isolation.rootfs; 5501580St.nateldemoura@f5.com rootfs_len = nxt_strlen(rootfs); 5511580St.nateldemoura@f5.com 5521579St.nateldemoura@f5.com for (i = 0; i < n; i++) { 5531579St.nateldemoura@f5.com len = nxt_strlen(lang_mnt[i].dst); 5541579St.nateldemoura@f5.com 5551579St.nateldemoura@f5.com mnt[i].dst = nxt_mp_alloc(mp, rootfs_len + len + 1); 5561580St.nateldemoura@f5.com if (nxt_slow_path(mnt[i].dst == NULL)) { 5571579St.nateldemoura@f5.com return NXT_ERROR; 5581579St.nateldemoura@f5.com } 5591579St.nateldemoura@f5.com 5601579St.nateldemoura@f5.com p = nxt_cpymem(mnt[i].dst, rootfs, rootfs_len); 5611579St.nateldemoura@f5.com p = nxt_cpymem(p, lang_mnt[i].dst, len); 5621579St.nateldemoura@f5.com *p = '\0'; 5631579St.nateldemoura@f5.com } 5641579St.nateldemoura@f5.com 5651580St.nateldemoura@f5.com mnt = nxt_array_add(mounts); 5661580St.nateldemoura@f5.com if (nxt_slow_path(mnt == NULL)) { 5671580St.nateldemoura@f5.com return NXT_ERROR; 5681580St.nateldemoura@f5.com } 5691580St.nateldemoura@f5.com 5701580St.nateldemoura@f5.com mnt->src = (u_char *) "tmpfs"; 5711580St.nateldemoura@f5.com mnt->fstype = (u_char *) "tmpfs"; 5721580St.nateldemoura@f5.com mnt->flags = NXT_MS_NOSUID | NXT_MS_NODEV | NXT_MS_NOEXEC | NXT_MS_RELATIME; 5731580St.nateldemoura@f5.com mnt->data = (u_char *) "size=1m,mode=777"; 5741585St.nateldemoura@f5.com mnt->builtin = 1; 5751580St.nateldemoura@f5.com 5761580St.nateldemoura@f5.com mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/tmp") + 1); 5771580St.nateldemoura@f5.com if (nxt_slow_path(mnt->dst == NULL)) { 5781580St.nateldemoura@f5.com return NXT_ERROR; 5791580St.nateldemoura@f5.com } 5801580St.nateldemoura@f5.com 5811580St.nateldemoura@f5.com p = nxt_cpymem(mnt->dst, rootfs, rootfs_len); 5821580St.nateldemoura@f5.com p = nxt_cpymem(p, "/tmp", 4); 5831580St.nateldemoura@f5.com *p = '\0'; 5841580St.nateldemoura@f5.com 5851580St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWPID) && (NXT_HAVE_CLONE_NEWNS) 5861580St.nateldemoura@f5.com 5871580St.nateldemoura@f5.com if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID) 5881580St.nateldemoura@f5.com && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS)) 5891580St.nateldemoura@f5.com { 5901580St.nateldemoura@f5.com mnt = nxt_array_add(mounts); 5911580St.nateldemoura@f5.com if (nxt_slow_path(mnt == NULL)) { 5921580St.nateldemoura@f5.com return NXT_ERROR; 5931580St.nateldemoura@f5.com } 5941580St.nateldemoura@f5.com 5951580St.nateldemoura@f5.com mnt->fstype = (u_char *) "proc"; 5961580St.nateldemoura@f5.com mnt->src = (u_char *) "proc"; 5971580St.nateldemoura@f5.com 5981580St.nateldemoura@f5.com mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/proc") + 1); 5991580St.nateldemoura@f5.com if (nxt_slow_path(mnt->dst == NULL)) { 6001580St.nateldemoura@f5.com return NXT_ERROR; 6011580St.nateldemoura@f5.com } 6021580St.nateldemoura@f5.com 6031580St.nateldemoura@f5.com p = nxt_cpymem(mnt->dst, rootfs, rootfs_len); 6041580St.nateldemoura@f5.com p = nxt_cpymem(p, "/proc", 5); 6051580St.nateldemoura@f5.com *p = '\0'; 6061580St.nateldemoura@f5.com 6071580St.nateldemoura@f5.com mnt->data = (u_char *) ""; 6081580St.nateldemoura@f5.com mnt->flags = 0; 6091580St.nateldemoura@f5.com } 6101580St.nateldemoura@f5.com #endif 6111580St.nateldemoura@f5.com 612*1671St.nateldemoura@f5.com qsort(mounts->elts, mounts->nelts, sizeof(nxt_fs_mount_t), 613*1671St.nateldemoura@f5.com nxt_isolation_mount_compare); 614*1671St.nateldemoura@f5.com 6151579St.nateldemoura@f5.com process->isolation.mounts = mounts; 6161579St.nateldemoura@f5.com 6171579St.nateldemoura@f5.com return NXT_OK; 6181579St.nateldemoura@f5.com } 6191579St.nateldemoura@f5.com 6201579St.nateldemoura@f5.com 621*1671St.nateldemoura@f5.com static int nxt_cdecl 622*1671St.nateldemoura@f5.com nxt_isolation_mount_compare(const void *v1, const void *v2) 623*1671St.nateldemoura@f5.com { 624*1671St.nateldemoura@f5.com const nxt_fs_mount_t *mnt1, *mnt2; 625*1671St.nateldemoura@f5.com 626*1671St.nateldemoura@f5.com mnt1 = v1; 627*1671St.nateldemoura@f5.com mnt2 = v2; 628*1671St.nateldemoura@f5.com 629*1671St.nateldemoura@f5.com return nxt_strlen(mnt1->src) > nxt_strlen(mnt2->src); 630*1671St.nateldemoura@f5.com } 631*1671St.nateldemoura@f5.com 632*1671St.nateldemoura@f5.com 6331579St.nateldemoura@f5.com void 6341579St.nateldemoura@f5.com nxt_isolation_unmount_all(nxt_task_t *task, nxt_process_t *process) 6351579St.nateldemoura@f5.com { 636*1671St.nateldemoura@f5.com size_t n; 6371585St.nateldemoura@f5.com nxt_array_t *mounts; 638*1671St.nateldemoura@f5.com nxt_runtime_t *rt; 6391585St.nateldemoura@f5.com nxt_fs_mount_t *mnt; 6401585St.nateldemoura@f5.com nxt_process_automount_t *automount; 6411579St.nateldemoura@f5.com 642*1671St.nateldemoura@f5.com rt = task->thread->runtime; 643*1671St.nateldemoura@f5.com 644*1671St.nateldemoura@f5.com if (!rt->capabilities.setid) { 645*1671St.nateldemoura@f5.com return; 646*1671St.nateldemoura@f5.com } 647*1671St.nateldemoura@f5.com 648*1671St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWNS) 649*1671St.nateldemoura@f5.com if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS)) { 650*1671St.nateldemoura@f5.com return; 651*1671St.nateldemoura@f5.com } 652*1671St.nateldemoura@f5.com #endif 653*1671St.nateldemoura@f5.com 6541579St.nateldemoura@f5.com nxt_debug(task, "unmount all (%s)", process->name); 6551579St.nateldemoura@f5.com 6561585St.nateldemoura@f5.com automount = &process->isolation.automount; 6571579St.nateldemoura@f5.com mounts = process->isolation.mounts; 6581579St.nateldemoura@f5.com n = mounts->nelts; 6591579St.nateldemoura@f5.com mnt = mounts->elts; 6601579St.nateldemoura@f5.com 661*1671St.nateldemoura@f5.com while (n > 0) { 662*1671St.nateldemoura@f5.com n--; 663*1671St.nateldemoura@f5.com 664*1671St.nateldemoura@f5.com if (mnt[n].builtin && !automount->language_deps) { 6651585St.nateldemoura@f5.com continue; 6661585St.nateldemoura@f5.com } 6671585St.nateldemoura@f5.com 668*1671St.nateldemoura@f5.com nxt_fs_unmount(mnt[n].dst); 6691579St.nateldemoura@f5.com } 6701579St.nateldemoura@f5.com } 6711579St.nateldemoura@f5.com 6721579St.nateldemoura@f5.com 6731579St.nateldemoura@f5.com nxt_int_t 6741579St.nateldemoura@f5.com nxt_isolation_prepare_rootfs(nxt_task_t *task, nxt_process_t *process) 6751579St.nateldemoura@f5.com { 6761585St.nateldemoura@f5.com size_t i, n; 6771585St.nateldemoura@f5.com nxt_int_t ret; 6781585St.nateldemoura@f5.com struct stat st; 6791585St.nateldemoura@f5.com nxt_array_t *mounts; 6801585St.nateldemoura@f5.com const u_char *dst; 6811585St.nateldemoura@f5.com nxt_fs_mount_t *mnt; 6821585St.nateldemoura@f5.com nxt_process_automount_t *automount; 6831579St.nateldemoura@f5.com 6841585St.nateldemoura@f5.com automount = &process->isolation.automount; 6851579St.nateldemoura@f5.com mounts = process->isolation.mounts; 6861579St.nateldemoura@f5.com 6871579St.nateldemoura@f5.com n = mounts->nelts; 6881579St.nateldemoura@f5.com mnt = mounts->elts; 6891579St.nateldemoura@f5.com 6901579St.nateldemoura@f5.com for (i = 0; i < n; i++) { 6911579St.nateldemoura@f5.com dst = mnt[i].dst; 6921579St.nateldemoura@f5.com 6931585St.nateldemoura@f5.com if (mnt[i].builtin && !automount->language_deps) { 6941585St.nateldemoura@f5.com continue; 6951585St.nateldemoura@f5.com } 6961585St.nateldemoura@f5.com 6971579St.nateldemoura@f5.com if (nxt_slow_path(nxt_memcmp(mnt[i].fstype, "bind", 4) == 0 6981579St.nateldemoura@f5.com && stat((const char *) mnt[i].src, &st) != 0)) 6991579St.nateldemoura@f5.com { 7001579St.nateldemoura@f5.com nxt_log(task, NXT_LOG_WARN, "host path not found: %s", mnt[i].src); 7011579St.nateldemoura@f5.com continue; 7021579St.nateldemoura@f5.com } 7031579St.nateldemoura@f5.com 7041579St.nateldemoura@f5.com ret = nxt_fs_mkdir_all(dst, S_IRWXU | S_IRWXG | S_IRWXO); 7051579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 7061579St.nateldemoura@f5.com nxt_alert(task, "mkdir(%s) %E", dst, nxt_errno); 7071579St.nateldemoura@f5.com goto undo; 7081579St.nateldemoura@f5.com } 7091579St.nateldemoura@f5.com 7101579St.nateldemoura@f5.com ret = nxt_fs_mount(task, &mnt[i]); 7111579St.nateldemoura@f5.com if (nxt_slow_path(ret != NXT_OK)) { 7121579St.nateldemoura@f5.com goto undo; 7131579St.nateldemoura@f5.com } 7141579St.nateldemoura@f5.com } 7151579St.nateldemoura@f5.com 7161579St.nateldemoura@f5.com return NXT_OK; 7171579St.nateldemoura@f5.com 7181579St.nateldemoura@f5.com undo: 7191579St.nateldemoura@f5.com 7201579St.nateldemoura@f5.com n = i + 1; 7211579St.nateldemoura@f5.com 7221579St.nateldemoura@f5.com for (i = 0; i < n; i++) { 7231579St.nateldemoura@f5.com nxt_fs_unmount(mnt[i].dst); 7241579St.nateldemoura@f5.com } 7251579St.nateldemoura@f5.com 7261579St.nateldemoura@f5.com return NXT_ERROR; 7271579St.nateldemoura@f5.com } 7281579St.nateldemoura@f5.com 7291579St.nateldemoura@f5.com 7301579St.nateldemoura@f5.com #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) 7311579St.nateldemoura@f5.com 7321579St.nateldemoura@f5.com nxt_int_t 7331579St.nateldemoura@f5.com nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process) 7341579St.nateldemoura@f5.com { 7351579St.nateldemoura@f5.com char *rootfs; 7361579St.nateldemoura@f5.com nxt_int_t ret; 7371579St.nateldemoura@f5.com 7381579St.nateldemoura@f5.com rootfs = (char *) process->isolation.rootfs; 7391579St.nateldemoura@f5.com 7401579St.nateldemoura@f5.com nxt_debug(task, "change root: %s", rootfs); 7411579St.nateldemoura@f5.com 7421595St.nateldemoura@f5.com if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS)) { 7431579St.nateldemoura@f5.com ret = nxt_isolation_pivot_root(task, rootfs); 7441579St.nateldemoura@f5.com 7451579St.nateldemoura@f5.com } else { 7461579St.nateldemoura@f5.com ret = nxt_isolation_chroot(task, rootfs); 7471579St.nateldemoura@f5.com } 7481579St.nateldemoura@f5.com 7491579St.nateldemoura@f5.com if (nxt_fast_path(ret == NXT_OK)) { 7501579St.nateldemoura@f5.com if (nxt_slow_path(chdir("/") < 0)) { 7511579St.nateldemoura@f5.com nxt_alert(task, "chdir(\"/\") %E", nxt_errno); 7521579St.nateldemoura@f5.com return NXT_ERROR; 7531579St.nateldemoura@f5.com } 7541579St.nateldemoura@f5.com } 7551579St.nateldemoura@f5.com 7561579St.nateldemoura@f5.com return ret; 7571579St.nateldemoura@f5.com } 7581579St.nateldemoura@f5.com 7591579St.nateldemoura@f5.com 7601579St.nateldemoura@f5.com /* 7611579St.nateldemoura@f5.com * pivot_root(2) can only be safely used with containers, otherwise it can 7621579St.nateldemoura@f5.com * umount(2) the global root filesystem and screw up the machine. 7631579St.nateldemoura@f5.com */ 7641579St.nateldemoura@f5.com 7651579St.nateldemoura@f5.com static nxt_int_t 7661579St.nateldemoura@f5.com nxt_isolation_pivot_root(nxt_task_t *task, const char *path) 7671579St.nateldemoura@f5.com { 7681579St.nateldemoura@f5.com /* 7691579St.nateldemoura@f5.com * This implementation makes use of a kernel trick that works for ages 7701579St.nateldemoura@f5.com * and now documented in Linux kernel 5. 7711579St.nateldemoura@f5.com * https://lore.kernel.org/linux-man/87r24piwhm.fsf@x220.int.ebiederm.org/T/ 7721579St.nateldemoura@f5.com */ 7731579St.nateldemoura@f5.com 7741579St.nateldemoura@f5.com if (nxt_slow_path(mount("", "/", "", MS_SLAVE|MS_REC, "") != 0)) { 7751602Sartem.konev@nginx.com nxt_alert(task, "mount(\"/\", MS_SLAVE|MS_REC) failed: %E", nxt_errno); 7761579St.nateldemoura@f5.com return NXT_ERROR; 7771579St.nateldemoura@f5.com } 7781579St.nateldemoura@f5.com 7791579St.nateldemoura@f5.com if (nxt_slow_path(nxt_isolation_make_private_mount(task, path) != NXT_OK)) { 7801579St.nateldemoura@f5.com return NXT_ERROR; 7811579St.nateldemoura@f5.com } 7821579St.nateldemoura@f5.com 7831579St.nateldemoura@f5.com if (nxt_slow_path(mount(path, path, "bind", MS_BIND|MS_REC, "") != 0)) { 7841579St.nateldemoura@f5.com nxt_alert(task, "error bind mounting rootfs %E", nxt_errno); 7851579St.nateldemoura@f5.com return NXT_ERROR; 7861579St.nateldemoura@f5.com } 7871579St.nateldemoura@f5.com 7881579St.nateldemoura@f5.com if (nxt_slow_path(chdir(path) != 0)) { 7891579St.nateldemoura@f5.com nxt_alert(task, "failed to chdir(%s) %E", path, nxt_errno); 7901579St.nateldemoura@f5.com return NXT_ERROR; 7911579St.nateldemoura@f5.com } 7921579St.nateldemoura@f5.com 7931579St.nateldemoura@f5.com if (nxt_slow_path(nxt_pivot_root(".", ".") != 0)) { 7941579St.nateldemoura@f5.com nxt_alert(task, "failed to pivot_root %E", nxt_errno); 7951579St.nateldemoura@f5.com return NXT_ERROR; 7961579St.nateldemoura@f5.com } 7971579St.nateldemoura@f5.com 7981579St.nateldemoura@f5.com /* 7991602Sartem.konev@nginx.com * Demote the oldroot mount to avoid unmounts getting propagated to 8001602Sartem.konev@nginx.com * the host. 8011579St.nateldemoura@f5.com */ 8021579St.nateldemoura@f5.com if (nxt_slow_path(mount("", ".", "", MS_SLAVE | MS_REC, NULL) != 0)) { 8031579St.nateldemoura@f5.com nxt_alert(task, "failed to bind mount rootfs %E", nxt_errno); 8041579St.nateldemoura@f5.com return NXT_ERROR; 8051579St.nateldemoura@f5.com } 8061579St.nateldemoura@f5.com 8071579St.nateldemoura@f5.com if (nxt_slow_path(umount2(".", MNT_DETACH) != 0)) { 8081579St.nateldemoura@f5.com nxt_alert(task, "failed to umount old root directory %E", nxt_errno); 8091579St.nateldemoura@f5.com return NXT_ERROR; 8101579St.nateldemoura@f5.com } 8111579St.nateldemoura@f5.com 8121579St.nateldemoura@f5.com return NXT_OK; 8131579St.nateldemoura@f5.com } 8141579St.nateldemoura@f5.com 8151579St.nateldemoura@f5.com 8161579St.nateldemoura@f5.com static nxt_int_t 8171579St.nateldemoura@f5.com nxt_isolation_make_private_mount(nxt_task_t *task, const char *rootfs) 8181579St.nateldemoura@f5.com { 8191579St.nateldemoura@f5.com char *parent_mnt; 8201579St.nateldemoura@f5.com FILE *procfile; 8211579St.nateldemoura@f5.com u_char **mounts; 8221579St.nateldemoura@f5.com size_t len; 8231579St.nateldemoura@f5.com uint8_t *shared; 8241579St.nateldemoura@f5.com nxt_int_t ret, index, nmounts; 8251579St.nateldemoura@f5.com struct mntent *ent; 8261579St.nateldemoura@f5.com 8271579St.nateldemoura@f5.com static const char *mount_path = "/proc/self/mounts"; 8281579St.nateldemoura@f5.com 8291579St.nateldemoura@f5.com ret = NXT_ERROR; 8301579St.nateldemoura@f5.com ent = NULL; 8311579St.nateldemoura@f5.com shared = NULL; 8321579St.nateldemoura@f5.com procfile = NULL; 8331579St.nateldemoura@f5.com parent_mnt = NULL; 8341579St.nateldemoura@f5.com 8351579St.nateldemoura@f5.com nmounts = 256; 8361579St.nateldemoura@f5.com 8371579St.nateldemoura@f5.com mounts = nxt_malloc(nmounts * sizeof(uintptr_t)); 8381579St.nateldemoura@f5.com if (nxt_slow_path(mounts == NULL)) { 8391579St.nateldemoura@f5.com goto fail; 8401579St.nateldemoura@f5.com } 8411579St.nateldemoura@f5.com 8421579St.nateldemoura@f5.com shared = nxt_malloc(nmounts); 8431579St.nateldemoura@f5.com if (nxt_slow_path(shared == NULL)) { 8441579St.nateldemoura@f5.com goto fail; 8451579St.nateldemoura@f5.com } 8461579St.nateldemoura@f5.com 8471579St.nateldemoura@f5.com procfile = setmntent(mount_path, "r"); 8481579St.nateldemoura@f5.com if (nxt_slow_path(procfile == NULL)) { 8491579St.nateldemoura@f5.com nxt_alert(task, "failed to open %s %E", mount_path, nxt_errno); 8501579St.nateldemoura@f5.com 8511579St.nateldemoura@f5.com goto fail; 8521579St.nateldemoura@f5.com } 8531579St.nateldemoura@f5.com 8541579St.nateldemoura@f5.com index = 0; 8551579St.nateldemoura@f5.com 8561579St.nateldemoura@f5.com again: 8571579St.nateldemoura@f5.com 8581579St.nateldemoura@f5.com for ( ; index < nmounts; index++) { 8591579St.nateldemoura@f5.com ent = getmntent(procfile); 8601579St.nateldemoura@f5.com if (ent == NULL) { 8611579St.nateldemoura@f5.com nmounts = index; 8621579St.nateldemoura@f5.com break; 8631579St.nateldemoura@f5.com } 8641579St.nateldemoura@f5.com 8651579St.nateldemoura@f5.com mounts[index] = (u_char *) strdup(ent->mnt_dir); 8661579St.nateldemoura@f5.com shared[index] = hasmntopt(ent, "shared") != NULL; 8671579St.nateldemoura@f5.com } 8681579St.nateldemoura@f5.com 8691579St.nateldemoura@f5.com if (ent != NULL) { 8701579St.nateldemoura@f5.com /* there are still entries to be read */ 8711579St.nateldemoura@f5.com 8721579St.nateldemoura@f5.com nmounts *= 2; 8731579St.nateldemoura@f5.com mounts = nxt_realloc(mounts, nmounts); 8741579St.nateldemoura@f5.com if (nxt_slow_path(mounts == NULL)) { 8751579St.nateldemoura@f5.com goto fail; 8761579St.nateldemoura@f5.com } 8771579St.nateldemoura@f5.com 8781579St.nateldemoura@f5.com shared = nxt_realloc(shared, nmounts); 8791579St.nateldemoura@f5.com if (nxt_slow_path(shared == NULL)) { 8801579St.nateldemoura@f5.com goto fail; 8811579St.nateldemoura@f5.com } 8821579St.nateldemoura@f5.com 8831579St.nateldemoura@f5.com goto again; 8841579St.nateldemoura@f5.com } 8851579St.nateldemoura@f5.com 8861579St.nateldemoura@f5.com for (index = 0; index < nmounts; index++) { 8871579St.nateldemoura@f5.com if (nxt_strcmp(mounts[index], rootfs) == 0) { 8881579St.nateldemoura@f5.com parent_mnt = (char *) rootfs; 8891579St.nateldemoura@f5.com break; 8901579St.nateldemoura@f5.com } 8911579St.nateldemoura@f5.com } 8921579St.nateldemoura@f5.com 8931579St.nateldemoura@f5.com if (parent_mnt == NULL) { 8941579St.nateldemoura@f5.com len = nxt_strlen(rootfs); 8951579St.nateldemoura@f5.com 8961579St.nateldemoura@f5.com parent_mnt = nxt_malloc(len + 1); 8971579St.nateldemoura@f5.com if (parent_mnt == NULL) { 8981579St.nateldemoura@f5.com goto fail; 8991579St.nateldemoura@f5.com } 9001579St.nateldemoura@f5.com 9011579St.nateldemoura@f5.com nxt_memcpy(parent_mnt, rootfs, len); 9021579St.nateldemoura@f5.com parent_mnt[len] = '\0'; 9031579St.nateldemoura@f5.com 9041579St.nateldemoura@f5.com if (parent_mnt[len - 1] == '/') { 9051579St.nateldemoura@f5.com parent_mnt[len - 1] = '\0'; 9061579St.nateldemoura@f5.com len--; 9071579St.nateldemoura@f5.com } 9081579St.nateldemoura@f5.com 9091579St.nateldemoura@f5.com for ( ;; ) { 9101579St.nateldemoura@f5.com for (index = 0; index < nmounts; index++) { 9111579St.nateldemoura@f5.com if (nxt_strcmp(mounts[index], parent_mnt) == 0) { 9121579St.nateldemoura@f5.com goto found; 9131579St.nateldemoura@f5.com } 9141579St.nateldemoura@f5.com } 9151579St.nateldemoura@f5.com 9161579St.nateldemoura@f5.com if (len == 1 && parent_mnt[0] == '/') { 9171579St.nateldemoura@f5.com nxt_alert(task, "parent mount not found"); 9181579St.nateldemoura@f5.com goto fail; 9191579St.nateldemoura@f5.com } 9201579St.nateldemoura@f5.com 9211579St.nateldemoura@f5.com /* parent dir */ 9221579St.nateldemoura@f5.com while (parent_mnt[len - 1] != '/' && len > 0) { 9231579St.nateldemoura@f5.com len--; 9241579St.nateldemoura@f5.com } 9251579St.nateldemoura@f5.com 9261579St.nateldemoura@f5.com if (nxt_slow_path(len == 0)) { 9271579St.nateldemoura@f5.com nxt_alert(task, "parent mount not found"); 9281579St.nateldemoura@f5.com goto fail; 9291579St.nateldemoura@f5.com } 9301579St.nateldemoura@f5.com 9311579St.nateldemoura@f5.com if (len == 1) { 9321579St.nateldemoura@f5.com parent_mnt[len] = '\0'; /* / */ 9331579St.nateldemoura@f5.com } else { 9341579St.nateldemoura@f5.com parent_mnt[len - 1] = '\0'; /* /<path> */ 9351579St.nateldemoura@f5.com } 9361579St.nateldemoura@f5.com } 9371579St.nateldemoura@f5.com } 9381579St.nateldemoura@f5.com 9391579St.nateldemoura@f5.com found: 9401579St.nateldemoura@f5.com 9411579St.nateldemoura@f5.com if (shared[index]) { 9421579St.nateldemoura@f5.com if (nxt_slow_path(mount("", parent_mnt, "", MS_PRIVATE, "") != 0)) { 9431579St.nateldemoura@f5.com nxt_alert(task, "mount(\"\", \"%s\", MS_PRIVATE) %E", parent_mnt, 9441579St.nateldemoura@f5.com nxt_errno); 9451579St.nateldemoura@f5.com 9461579St.nateldemoura@f5.com goto fail; 9471579St.nateldemoura@f5.com } 9481579St.nateldemoura@f5.com } 9491579St.nateldemoura@f5.com 9501579St.nateldemoura@f5.com ret = NXT_OK; 9511579St.nateldemoura@f5.com 9521579St.nateldemoura@f5.com fail: 9531579St.nateldemoura@f5.com 9541579St.nateldemoura@f5.com if (procfile != NULL) { 9551579St.nateldemoura@f5.com endmntent(procfile); 9561579St.nateldemoura@f5.com } 9571579St.nateldemoura@f5.com 9581579St.nateldemoura@f5.com if (mounts != NULL) { 9591579St.nateldemoura@f5.com for (index = 0; index < nmounts; index++) { 9601579St.nateldemoura@f5.com nxt_free(mounts[index]); 9611579St.nateldemoura@f5.com } 9621579St.nateldemoura@f5.com 9631579St.nateldemoura@f5.com nxt_free(mounts); 9641579St.nateldemoura@f5.com } 9651579St.nateldemoura@f5.com 9661579St.nateldemoura@f5.com if (shared != NULL) { 9671579St.nateldemoura@f5.com nxt_free(shared); 9681579St.nateldemoura@f5.com } 9691579St.nateldemoura@f5.com 9701579St.nateldemoura@f5.com if (parent_mnt != NULL && parent_mnt != rootfs) { 9711579St.nateldemoura@f5.com nxt_free(parent_mnt); 9721579St.nateldemoura@f5.com } 9731579St.nateldemoura@f5.com 9741579St.nateldemoura@f5.com return ret; 9751579St.nateldemoura@f5.com } 9761579St.nateldemoura@f5.com 9771579St.nateldemoura@f5.com 9781579St.nateldemoura@f5.com nxt_inline int 9791579St.nateldemoura@f5.com nxt_pivot_root(const char *new_root, const char *old_root) 9801579St.nateldemoura@f5.com { 9811579St.nateldemoura@f5.com return syscall(__NR_pivot_root, new_root, old_root); 9821579St.nateldemoura@f5.com } 9831579St.nateldemoura@f5.com 9841579St.nateldemoura@f5.com 9851579St.nateldemoura@f5.com #else /* !(NXT_HAVE_PIVOT_ROOT) || !(NXT_HAVE_CLONE_NEWNS) */ 9861579St.nateldemoura@f5.com 9871579St.nateldemoura@f5.com 9881579St.nateldemoura@f5.com nxt_int_t 9891579St.nateldemoura@f5.com nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process) 9901579St.nateldemoura@f5.com { 9911579St.nateldemoura@f5.com char *rootfs; 9921579St.nateldemoura@f5.com 9931579St.nateldemoura@f5.com rootfs = (char *) process->isolation.rootfs; 9941579St.nateldemoura@f5.com 9951579St.nateldemoura@f5.com nxt_debug(task, "change root: %s", rootfs); 9961579St.nateldemoura@f5.com 9971579St.nateldemoura@f5.com if (nxt_fast_path(nxt_isolation_chroot(task, rootfs) == NXT_OK)) { 9981579St.nateldemoura@f5.com if (nxt_slow_path(chdir("/") < 0)) { 9991579St.nateldemoura@f5.com nxt_alert(task, "chdir(\"/\") %E", nxt_errno); 10001579St.nateldemoura@f5.com return NXT_ERROR; 10011579St.nateldemoura@f5.com } 10021579St.nateldemoura@f5.com 10031579St.nateldemoura@f5.com return NXT_OK; 10041579St.nateldemoura@f5.com } 10051579St.nateldemoura@f5.com 10061579St.nateldemoura@f5.com return NXT_ERROR; 10071579St.nateldemoura@f5.com } 10081579St.nateldemoura@f5.com 10091579St.nateldemoura@f5.com #endif 10101579St.nateldemoura@f5.com 10111579St.nateldemoura@f5.com 10121579St.nateldemoura@f5.com static nxt_int_t 10131579St.nateldemoura@f5.com nxt_isolation_chroot(nxt_task_t *task, const char *path) 10141579St.nateldemoura@f5.com { 10151579St.nateldemoura@f5.com if (nxt_slow_path(chroot(path) < 0)) { 10161579St.nateldemoura@f5.com nxt_alert(task, "chroot(%s) %E", path, nxt_errno); 10171579St.nateldemoura@f5.com return NXT_ERROR; 10181579St.nateldemoura@f5.com } 10191579St.nateldemoura@f5.com 10201579St.nateldemoura@f5.com return NXT_OK; 10211579St.nateldemoura@f5.com } 10221579St.nateldemoura@f5.com 10231579St.nateldemoura@f5.com #endif /* NXT_HAVE_ISOLATION_ROOTFS */ 10241579St.nateldemoura@f5.com 10251579St.nateldemoura@f5.com 10261579St.nateldemoura@f5.com #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 10271579St.nateldemoura@f5.com 10281579St.nateldemoura@f5.com static nxt_int_t 10291579St.nateldemoura@f5.com nxt_isolation_set_new_privs(nxt_task_t *task, nxt_conf_value_t *isolation, 10301579St.nateldemoura@f5.com nxt_process_t *process) 10311579St.nateldemoura@f5.com { 10321579St.nateldemoura@f5.com nxt_conf_value_t *obj; 10331579St.nateldemoura@f5.com 10341579St.nateldemoura@f5.com static nxt_str_t new_privs_name = nxt_string("new_privs"); 10351579St.nateldemoura@f5.com 10361579St.nateldemoura@f5.com obj = nxt_conf_get_object_member(isolation, &new_privs_name, NULL); 10371579St.nateldemoura@f5.com if (obj != NULL) { 10381579St.nateldemoura@f5.com process->isolation.new_privs = nxt_conf_get_boolean(obj); 10391579St.nateldemoura@f5.com } 10401579St.nateldemoura@f5.com 10411579St.nateldemoura@f5.com return NXT_OK; 10421579St.nateldemoura@f5.com } 10431579St.nateldemoura@f5.com 10441579St.nateldemoura@f5.com #endif 1045