1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00

nsswitch: do not reload if "/" changes

https://sourceware.org/bugzilla/show_bug.cgi?id=27077

Before reloading nsswitch.conf, verify that the root directory
hasn't changed - if it has, it's likely that we've entered a
container and should not trust the nsswitch inside the container
nor load any shared objects therein.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
DJ Delorie
2021-01-15 19:50:00 -05:00
parent 01cdcf783a
commit 429029a73e
9 changed files with 178 additions and 1 deletions

View File

@ -67,7 +67,7 @@ tests-container = \
tst-nss-files-hosts-long \
tst-nss-db-endpwent \
tst-nss-db-endgrent \
tst-reload1
tst-reload1 tst-reload2
# Tests which need libdl
ifeq (yes,$(build-shared))

View File

@ -33,6 +33,11 @@ struct nss_database_state
{
struct nss_database_data data;
__libc_lock_define (, lock);
/* If "/" changes, we switched into a container and do NOT want to
reload anything. This data must be persistent across
reloads. */
ino64_t root_ino;
dev_t root_dev;
};
@ -54,6 +59,8 @@ global_state_allocate (void *closure)
result->data.initialized = true;
result->data.reload_disabled = false;
__libc_lock_init (result->lock);
result->root_ino = 0;
result->root_dev = 0;
}
return result;
}
@ -356,6 +363,8 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
nss_action_list *result,
enum nss_database database_index)
{
struct stat64 str;
/* 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. */
@ -379,6 +388,24 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
__libc_lock_unlock (local->lock);
return true;
}
/* 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 (__stat64 ("/", &str) != 0
|| (local->root_ino != 0
&& (str.st_ino != local->root_ino
|| str.st_dev != local->root_dev)))
{
/* Change detected; disable reloading. */
atomic_store_release (&local->data.reload_disabled, 1);
__libc_lock_unlock (local->lock);
__nss_module_disable_loading ();
return true;
}
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

View File

@ -349,6 +349,19 @@ __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
}
#endif
/* Block attempts to dlopen any module we haven't already opened. */
void
__nss_module_disable_loading (void)
{
__libc_lock_lock (nss_module_list_lock);
for (struct nss_module *p = nss_module_list; p != NULL; p = p->next)
if (p->state == nss_module_uninitialized)
p->state = nss_module_failed;
__libc_lock_unlock (nss_module_list_lock);
}
void __libc_freeres_fn_section
__nss_module_freeres (void)
{

View File

@ -87,6 +87,9 @@ bool __nss_module_load (struct nss_module *module) attribute_hidden;
void *__nss_module_get_function (struct nss_module *module, const char *name)
attribute_hidden;
/* Block attempts to dlopen any module we haven't already opened. */
void __nss_module_disable_loading (void);
/* Called from __libc_freeres. */
void __nss_module_freeres (void) attribute_hidden;

126
nss/tst-reload2.c Normal file
View File

@ -0,0 +1,126 @@
/* Test that reloading is disabled after a chroot.
Copyright (C) 2020-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <nss.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <support/support.h>
#include <support/check.h>
#include <support/xunistd.h>
#include "nss_test.h"
static struct passwd pwd_table1[] =
{
PWD_N (1234, "test1"),
PWD_N (4321, "test2"),
PWD_LAST ()
};
static const char *group_4[] = {
"alpha", "beta", "gamma", "fred", NULL
};
static struct group group_table_data[] =
{
GRP (4),
GRP_LAST ()
};
void
_nss_test1_init_hook (test_tables *t)
{
t->pwd_table = pwd_table1;
t->grp_table = group_table_data;
}
static struct passwd pwd_table2[] =
{
PWD_N (5, "test1"),
PWD_N (2468, "test2"),
PWD_LAST ()
};
void
_nss_test2_init_hook (test_tables *t)
{
t->pwd_table = pwd_table2;
}
static int
do_test (void)
{
struct passwd *pw;
struct group *gr;
char buf1[PATH_MAX];
char buf2[PATH_MAX];
sprintf (buf1, "/subdir%s", support_slibdir_prefix);
xmkdirp (buf1, 0777);
/* Copy this DSO into the chroot so it *could* be loaded. */
sprintf (buf1, "%s/libnss_files.so.2", support_slibdir_prefix);
sprintf (buf2, "/subdir%s/libnss_files.so.2", support_slibdir_prefix);
support_copy_file (buf1, buf2);
/* Check we're using the "outer" nsswitch.conf. */
/* This uses the test1 DSO. */
pw = getpwnam ("test1");
TEST_VERIFY (pw != NULL);
if (pw)
TEST_COMPARE (pw->pw_uid, 1234);
/* This just loads the test2 DSO. */
gr = getgrnam ("name4");
/* Change the root dir. */
TEST_VERIFY (chroot ("/subdir") == 0);
chdir ("/");
/* Check we're NOT using the "inner" nsswitch.conf. */
/* Both DSOs are loaded, which is used? */
pw = getpwnam ("test2");
TEST_VERIFY (pw != NULL);
if (pw)
TEST_VERIFY (pw->pw_uid != 2468);
/* The "files" DSO should not be loaded. */
gr = getgrnam ("test3");
TEST_VERIFY (gr == NULL);
/* We should still be using the old configuration. */
pw = getpwnam ("test1");
TEST_VERIFY (pw != NULL);
if (pw)
TEST_COMPARE (pw->pw_uid, 1234);
return 0;
}
#include <support/test-driver.c>

View File

@ -0,0 +1,2 @@
passwd: test1
group: test2

View File

@ -0,0 +1 @@
test3:x:123:

View File

@ -0,0 +1,2 @@
passwd: test2
group: files

View File

@ -0,0 +1,3 @@
su
cp $B/nss/libnss_test1.so $L/libnss_test1.so.2
cp $B/nss/libnss_test2.so $L/libnss_test2.so.2