for (int i = 0; i < NSS_DATABASE_COUNT; ++i) if (staging->services[i] == NULL) { ok = nss_database_select_default (&cache, i, &staging->services[i]); if (!ok) break; }
staticbool nss_database_check_reload_and_get (struct nss_database_state *local, nss_action_list *result, enum nss_database database_index) { struct __stat64_t64str; /* Acquire MO is needed because the thread that sets reload_disabled may have loaded the configuration first, so synchronize with the Release MO store there. */ if (atomic_load_acquire (&local->data.reload_disabled)) { *result = local->data.services[database_index]; /* No reload, so there is no error. */ returntrue; } structfile_change_detectioninitial; if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF)) returnfalse; __libc_lock_lock (local->lock); if (__file_is_unchanged (&initial, &local->data.nsswitch_conf)) { /* Configuration is up-to-date. Read it and return it to the caller. */ *result = local->data.services[database_index]; __libc_lock_unlock (local->lock); returntrue; } int stat_rv = __stat64_time64 ("/", &str); if (local->data.services[database_index] != NULL) { /* Before we reload, verify that "/" hasn't changed. We assume that errors here are very unlikely, but the chance that we're entering a container is also very unlikely, so we err on the side of both very unlikely things not happening at the same time. */ if (stat_rv != 0 || (local->root_ino != 0 && (str.st_ino != local->root_ino || str.st_dev != local->root_dev))) { /* Change detected; disable reloading and return current state. */ atomic_store_release (&local->data.reload_disabled, 1); *result = local->data.services[database_index]; __libc_lock_unlock (local->lock); returntrue; } } if (stat_rv == 0) { local->root_ino = str.st_ino; local->root_dev = str.st_dev; } __libc_lock_unlock (local->lock); /* Avoid overwriting the global configuration until we have loaded everything successfully. Otherwise, if the file change information changes back to what is in the global configuration, the lookups would use the partially-written configuration. */ structnss_database_datastaging = { .initialized = true, }; bool ok = nss_database_reload (&staging, &initial); if (ok) { __libc_lock_lock (local->lock); /* See above for memory order. */ if (!atomic_load_acquire (&local->data.reload_disabled)) /* This may go back in time if another thread beats this thread with the update, but in this case, a reload happens on the next NSS call. */ local->data = staging; *result = local->data.services[database_index]; __libc_lock_unlock (local->lock); } return ok; }
if (atomic_load_acquire (&local->data.reload_disabled)) { *result = local->data.services[database_index]; /* No reload, so there is no error. */ returntrue; }
然后是判断/etc/nsswitch.conf文件是否修改:
1 2 3 4 5 6 7 8 9 10 11 12
structfile_change_detectioninitial; if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF)) returnfalse; __libc_lock_lock (local->lock); if (__file_is_unchanged (&initial, &local->data.nsswitch_conf)) { /* Configuration is up-to-date. Read it and return it to the caller. */ *result = local->data.services[database_index]; __libc_lock_unlock (local->lock); returntrue; }
if (local->data.services[database_index] != NULL) { /* Before we reload, verify that "/" hasn't changed. We assume that errors here are very unlikely, but the chance that we're entering a container is also very unlikely, so we err on the side of both very unlikely things not happening at the same time. */ if (stat_rv != 0 || (local->root_ino != 0 && (str.st_ino != local->root_ino || str.st_dev != local->root_dev))) { /* Change detected; disable reloading and return current state. */ atomic_store_release (&local->data.reload_disabled, 1); *result = local->data.services[database_index]; __libc_lock_unlock (local->lock); returntrue; } }
>end (gdb) i b Num Type Disp Enb Address What 3 breakpoint keep y <MULTIPLE> 3.1 y 0x00007ffff7d2b050 in pivot_root at ../sysdeps/unix/syscall-template.S:120 3.2 y 0x00007ffff7eb59b0 in pivot_root at ./pivot.c:39 4 breakpoint keep y 0x00007ffff7eb5b00 in unpivot_root at ./pivot.c:64 5 breakpoint keep y 0x00007ffff7d52300 in nss_database_check_reload_and_get at ./nss/nss_database.c:396 i r rdx c (gdb)
Breakpoint 3.2, pivot_root (new_root=0x5555555a701c "woot", state=0x7fffffffcc38) at ./pivot.c:39 39 { (gdb) c Continuing. Download failed: Invalid argument. Continuing without source file ./nss/./nss/nss_database.c.
Breakpoint 5, nss_database_check_reload_and_get (local=0x5555555a1ad0, result=0x7fffffffc510, database_index=nss_database_initgroups) at ./nss/nss_database.c:396 warning: 396 ./nss/nss_database.c: No such file or directory rdx 0x6 6
Breakpoint 5, nss_database_check_reload_and_get (local=0x5555555a1ad0, result=0x7fffffffc510, database_index=nss_database_group) at ./nss/nss_database.c:396 396 in ./nss/nss_database.c rdx 0x2 2
Breakpoint 4, unpivot_root (state=state@entry=0x7fffffffcc38) at ./pivot.c:64 64 { (gdb) c Continuing. Download failed: Invalid argument. Continuing without source file ./nss/./nss/nss_database.c.
Breakpoint 5, nss_database_check_reload_and_get (local=0x5555555a1ad0, result=0x7ffff7e10b68 <__nss_group_database>, database_index=nss_database_group) at ./nss/nss_database.c:396 warning: 396 ./nss/nss_database.c: No such file or directory rdx 0x2 2
Breakpoint 5, nss_database_check_reload_and_get (local=0x5555555a1ad0, result=0x7ffff7e10b68 <__nss_group_database>, database_index=nss_database_group) at ./nss/nss_database.c:396 396 in ./nss/nss_database.c rdx 0x2 2
Breakpoint 5, nss_database_check_reload_and_get (local=0x5555555a1ad0, result=0x7ffff7e10b00 <__nss_shadow_database>, database_index=nss_database_shadow) at ./nss/nss_database.c:396 396 in ./nss/nss_database.c rdx 0xf 15 Downloading separate debug info for libnss_/woot1337.so.2 Download failed: Invalid argument. Continuing without source file ./nss/./nss/nss_database.c.
当走到 if (local->data.services[database_index] != NULL) 判断的时候
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
if (local->data.services[database_index] != NULL) { /* Before we reload, verify that "/" hasn't changed. We assume that errors here are very unlikely, but the chance that we're entering a container is also very unlikely, so we err on the side of both very unlikely things not happening at the same time. */ if (stat_rv != 0 || (local->root_ino != 0 && (str.st_ino != local->root_ino || str.st_dev != local->root_dev))) { /* Change detected; disable reloading and return current state. */ atomic_store_release (&local->data.reload_disabled, 1); *result = local->data.services[database_index]; __libc_lock_unlock (local->lock); returntrue; } }
由于 local->data.services[database_index] 不为空, 因此会进入 if 的逻辑。 且此时
/* Internal implementation of __nss_module_load. */ staticbool module_load (struct nss_module *module) { if (strcmp (module->name, "files") == 0) return module_load_nss_files (module); if (strcmp (module->name, "dns") == 0) return module_load_nss_dns (module); void *handle; { char *shlib_name; if (__asprintf (&shlib_name, "libnss_%s.so%s", module->name, __nss_shlib_revision) < 0) /* This is definitely a temporary failure. Do not update module->state. This will trigger another attempt at the next call. */ returnfalse; handle = __libc_dlopen (shlib_name); free (shlib_name); } /* Failing to load the module can be caused by several different scenarios. One such scenario is that the module has been removed from the disk. In which case the in-memory version is all that we have, and if the module->state indidates it is loaded then we can use it. */ if (handle == NULL) { /* dlopen failure. We do not know if this a temporary or permanent error. See bug 22041. Update the state using the double-checked locking idiom. */ __libc_lock_lock (nss_module_list_lock); bool result = result; switch ((enum nss_module_state) atomic_load_acquire (&module->state)) { case nss_module_uninitialized: atomic_store_release (&module->state, nss_module_failed); result = false; break; case nss_module_loaded: result = true; break; case nss_module_failed: result = false; break; } __libc_lock_unlock (nss_module_list_lock); return result; } nss_module_functions_untyped pointers; /* Look up and store locally all the function pointers we may need later. Doing this now means the data will not change in the future. */ for (size_t idx = 0; idx < array_length (nss_function_name_array); ++idx) { char *function_name; if (__asprintf (&function_name, "_nss_%s_%s", module->name, nss_function_name_array[idx]) < 0) { /* Definitely a temporary error. */ __libc_dlclose (handle); returnfalse; } pointers[idx] = __libc_dlsym (handle, function_name); free (function_name); PTR_MANGLE (pointers[idx]); }