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