diff options
author | Jakub Jelinek <jakub@redhat.com> | 2005-08-08 21:34:25 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2005-08-08 21:34:25 +0000 |
commit | a6d1003497d92df2575894474fa1d2c0ee3f39f4 (patch) | |
tree | 6665a936728da87053845bdff9ff812ee58981ec /nscd | |
parent | c633e822b473e8135a36e413c5b79d7ce5a5d1fc (diff) |
Updated to fedora-glibc-20050808T2126
Diffstat (limited to 'nscd')
-rw-r--r-- | nscd/cache.c | 8 | ||||
-rw-r--r-- | nscd/connections.c | 223 | ||||
-rw-r--r-- | nscd/mem.c | 14 | ||||
-rw-r--r-- | nscd/nscd.h | 7 |
4 files changed, 236 insertions, 16 deletions
diff --git a/nscd/cache.c b/nscd/cache.c index efac4b3bcc..800b7ecf27 100644 --- a/nscd/cache.c +++ b/nscd/cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1998, 1999, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1998, 1999, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. @@ -169,6 +169,12 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet, if (nentries > table->head->maxnentries) table->head->maxnentries = nentries; + if (table->persistent) + // XXX async OK? + msync ((void *) table->head, + (char *) &table->head->array[hash] - (char *) table->head + + sizeof (ref_t), MS_ASYNC); + return 0; } diff --git a/nscd/connections.c b/nscd/connections.c index d18851f828..42a36d39c0 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -199,6 +199,210 @@ writeall (int fd, const void *buf, size_t len) } +enum usekey + { + use_not = 0, + /* The following three are not really used, they are symbolic constants. */ + use_first = 16, + use_begin = 32, + use_end = 64, + + use_he = 1, + use_he_begin = use_he | use_begin, + use_he_end = use_he | use_end, +#if SEPARATE_KEY + use_key = 2, + use_key_begin = use_key | use_begin, + use_key_end = use_key | use_end, + use_key_first = use_key_begin | use_first, +#endif + use_data = 3, + use_data_begin = use_data | use_begin, + use_data_end = use_data | use_end, + use_data_first = use_data_begin | use_first + }; + + +static int +check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap, + enum usekey use, ref_t start, size_t len) +{ + assert (len >= 2); + + if (start > first_free || start + len > first_free + || (start & BLOCK_ALIGN_M1)) + return 0; + + if (usemap[start] == use_not) + { + /* Add the start marker. */ + usemap[start] = use | use_begin; + use &= ~use_first; + + while (--len > 0) + if (usemap[++start] != use_not) + return 0; + else + usemap[start] = use; + + /* Add the end marker. */ + usemap[start] = use | use_end; + } + else if ((usemap[start] & ~use_first) == ((use | use_begin) & ~use_first)) + { + /* Hash entries can't be shared. */ + if (use == use_he) + return 0; + + usemap[start] |= (use & use_first); + use &= ~use_first; + + while (--len > 1) + if (usemap[++start] != use) + return 0; + + if (usemap[++start] != (use | use_end)) + return 0; + } + else + /* Points to a wrong object or somewhere in the middle. */ + return 0; + + return 1; +} + + +/* Verify data in persistent database. */ +static int +verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr) +{ + assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb); + + time_t now = time (NULL); + + struct database_pers_head *head = mem; + struct database_pers_head head_copy = *head; + + /* Check that the header that was read matches the head in the database. */ + if (readhead != NULL && memcmp (head, readhead, sizeof (*head)) != 0) + return 0; + + /* First some easy tests: make sure the database header is sane. */ + if (head->version != DB_VERSION + || head->header_size != sizeof (*head) + /* We allow a timestamp to be one hour ahead of the current time. + This should cover daylight saving time changes. */ + || head->timestamp > now + 60 * 60 + 60 + || (head->gc_cycle & 1) + || (size_t) head->module > INT32_MAX / sizeof (ref_t) + || (size_t) head->data_size > INT32_MAX - head->module * sizeof (ref_t) + || head->first_free < 0 + || head->first_free > head->data_size + || (head->first_free & BLOCK_ALIGN_M1) != 0 + || head->maxnentries < 0 + || head->maxnsearched < 0) + return 0; + + uint8_t *usemap = calloc (head->first_free, 1); + if (usemap == NULL) + return 0; + + const char *data = (char *) &head->array[roundup (head->module, + ALIGN / sizeof (ref_t))]; + + nscd_ssize_t he_cnt = 0; + for (nscd_ssize_t cnt = 0; cnt < head->module; ++cnt) + { + ref_t work = head->array[cnt]; + + while (work != ENDREF) + { + if (! check_use (data, head->first_free, usemap, use_he, work, + sizeof (struct hashentry))) + goto fail; + + /* Now we know we can dereference the record. */ + struct hashentry *here = (struct hashentry *) (data + work); + + ++he_cnt; + + /* Make sure the record is for this type of service. */ + if (here->type >= LASTREQ + || serv2db[here->type] != &dbs[dbnr]) + goto fail; + + /* Validate boolean field value. */ + if (here->first != false && here->first != true) + goto fail; + + if (here->len < 0) + goto fail; + + /* Now the data. */ + if (here->packet < 0 + || here->packet > head->first_free + || here->packet + sizeof (struct datahead) > head->first_free) + goto fail; + + struct datahead *dh = (struct datahead *) (data + here->packet); + + if (! check_use (data, head->first_free, usemap, + use_data | (here->first ? use_first : 0), + here->packet, dh->allocsize)) + goto fail; + + if (dh->allocsize < sizeof (struct datahead) + || dh->recsize > dh->allocsize + || (dh->notfound != false && dh->notfound != true) + || (dh->usable != false && dh->usable != true)) + goto fail; + + if (here->key < here->packet + sizeof (struct datahead) + || here->key > here->packet + dh->allocsize + || here->key + here->len > here->packet + dh->allocsize) + { +#if SEPARATE_KEY + /* If keys can appear outside of data, this should be done + instead. But gc doesn't mark the data in that case. */ + if (! check_use (data, head->first_free, usemap, + use_key | (here->first ? use_first : 0), + here->key, here->len)) +#endif + goto fail; + } + + work = here->next; + } + } + + if (he_cnt != head->nentries) + goto fail; + + /* See if all data and keys had at least one reference from + he->first == true hashentry. */ + for (ref_t idx = 0; idx < head->first_free; ++idx) + { +#if SEPARATE_KEY + if (usemap[idx] == use_key_begin) + goto fail; +#endif + if (usemap[idx] == use_data_begin) + goto fail; + } + + /* Finally, make sure the database hasn't changed since the first test. */ + if (memcmp (mem, &head_copy, sizeof (*head)) != 0) + goto fail; + + free (usemap); + return 1; + +fail: + free (usemap); + return 0; +} + + /* Initialize database information structures. */ void nscd_init (void) @@ -242,7 +446,7 @@ nscd_init (void) fail_db: dbg_log (_("invalid persistent database file \"%s\": %s"), dbs[cnt].db_filename, strerror (errno)); - dbs[cnt].persistent = 0; + unlink (dbs[cnt].db_filename); } else if (head.module == 0 && head.data_size == 0) { @@ -255,22 +459,31 @@ nscd_init (void) dbg_log (_("invalid persistent database file \"%s\": %s"), dbs[cnt].db_filename, _("header size does not match")); - dbs[cnt].persistent = 0; + unlink (dbs[cnt].db_filename); } else if ((total = (sizeof (head) + roundup (head.module * sizeof (ref_t), ALIGN) + head.data_size)) - > st.st_size) + > st.st_size + || total < sizeof (head)) { dbg_log (_("invalid persistent database file \"%s\": %s"), dbs[cnt].db_filename, _("file size does not match")); - dbs[cnt].persistent = 0; + unlink (dbs[cnt].db_filename); } else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) goto fail_db; + else if (!verify_persistent_db (mem, &head, cnt)) + { + munmap (mem, total); + dbg_log (_("invalid persistent database file \"%s\": %s"), + dbs[cnt].db_filename, + _("verification failed")); + unlink (dbs[cnt].db_filename); + } else { /* Success. We have the database. */ @@ -425,7 +638,7 @@ cannot create read-only descriptor for \"%s\"; no mmap"), if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head))) != sizeof (head)) - || ftruncate (fd, total) != 0 + || posix_fallocate (fd, 0, total) != 0 || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { diff --git a/nscd/mem.c b/nscd/mem.c index c3a0f96702..823eda1019 100644 --- a/nscd/mem.c +++ b/nscd/mem.c @@ -1,5 +1,5 @@ /* Cache memory handling. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. @@ -21,6 +21,7 @@ #include <assert.h> #include <errno.h> #include <error.h> +#include <fcntl.h> #include <inttypes.h> #include <libintl.h> #include <limits.h> @@ -34,12 +35,6 @@ #include "nscd.h" -/* Maximum alignment requirement we will encounter. */ -#define BLOCK_ALIGN_LOG 3 -#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG) -#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1) - - static int sort_he (const void *p1, const void *p2) { @@ -194,7 +189,7 @@ gc (struct database_dyn *db) highref -= BLOCK_ALIGN; } - /* No we can iterate over the MARK array and find bits which are not + /* Now we can iterate over the MARK array and find bits which are not set. These represent memory which can be recovered. */ size_t byte = 0; /* Find the first gap. */ @@ -494,7 +489,8 @@ mempool_alloc (struct database_dyn *db, size_t len) + db->head->module * sizeof (ref_t) + new_data_size); - if ((!db->mmap_used || ftruncate (db->wr_fd, newtotal) != 0) + if ((!db->mmap_used + || posix_fallocate (db->wr_fd, oldtotal, newtotal) != 0) /* Try to resize the mapping. Note: no MREMAP_MAYMOVE. */ && mremap (db->head, oldtotal, newtotal, 0) == 0) { diff --git a/nscd/nscd.h b/nscd/nscd.h index d5dc613d22..25a4b38eb4 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -1,4 +1,4 @@ -/* Copyright (c) 1998, 1999, 2000, 2001, 2003, 2004 +/* Copyright (c) 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. @@ -94,6 +94,11 @@ struct database_dyn /* Path used when not using persistent storage. */ #define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX" +/* Maximum alignment requirement we will encounter. */ +#define BLOCK_ALIGN_LOG 3 +#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG) +#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1) + /* Global variables. */ extern struct database_dyn dbs[lastdb]; |