Skip to content

Commit

Permalink
Robustify libc-side nscd database reader.
Browse files Browse the repository at this point in the history
The nscd database mapped in processes can change at any time.  We
have to be more vigilant when it comes to using that memory.  Test
the data entries are valid in their entire size, don't read data
again from memory once we verified it, and make sure the trailing
pointer is not going off the deep end.
  • Loading branch information
Jakub Jelinek authored and Ulrich Drepper committed May 16, 2009
1 parent 3b1b533 commit cfe1fc1
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 30 deletions.
27 changes: 19 additions & 8 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
2009-05-12 Jakub Jelinek <jakub@redhat.com>

* include/atomic.h: Formatting.
(catomic_compare_and_exchange_val_acq): Don't define if already
defined by bits/atomic.h.

2009-05-14 Jakub Jelinek <jakub@redhat.com>

* nscd/nscd_helper.c: Include stddef.h.
(__nscd_cache_search): Add datalen argument. Use atomic_forced_read
in a couple of places. Return NULL if trail is not less than
datasize, don't consider dataheads with length smaller than
offsetof (struct datahead, data) + datalen.
* nscd/nscd_client.h (__nscd_cache_search): Adjust prototype.
* nscd/nscd_gethst_r.c (nscd_gethst_r): Adjust callers.
* nscd/nscd_getpw_r.c (nscd_getpw_r): Likewise.
* nscd/nscd_getgr_r.c (nscd_getgr_r): Likewise.
* nscd/nscd_getai.c (__nscd_getai): Likewise.
* nscd/nscd_initgroups.c (__nscd_getgrouplist): Likewise.
* nscd/nscd_getserv_r.c (nscd_getserv_r): Likewise.

* sysdeps/unix/sysv/linux/i386/fallocate64.c (__fallocate64_l64):
Rename ...
(fallocate64): ... to this.
Expand All @@ -22,13 +29,17 @@
* sysdeps/unix/sysv/linux/sparc/sparc32/Versions (libc): Likewise.
* sysdeps/unix/sysv/linux/sh/Versions (libc): Likewise.

2009-05-14 Jakub Jelinek <jakub@redhat.com>

* nscd/selinux.c (nscd_avc_destroy): Removed.
* nscd/selinux.h (nscd_avc_destroy): Likewise.
* nscd/nscd.c (termination_handler): Don't call
nscd_avc_destroy.

2009-05-12 Jakub Jelinek <jakub@redhat.com>

* include/atomic.h: Formatting.
(catomic_compare_and_exchange_val_acq): Don't define if already
defined by bits/atomic.h.

2009-05-15 Ulrich Drepper <drepper@redhat.com>

* math/libm-test.inc (expm1_test): Add test for range error.
Expand Down
5 changes: 3 additions & 2 deletions nscd/nscd-client.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005, 2006, 2007
/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
Expand Down Expand Up @@ -329,7 +329,8 @@ static inline int __nscd_drop_map_ref (struct mapped_database *map,
extern struct datahead *__nscd_cache_search (request_type type,
const char *key,
size_t keylen,
const struct mapped_database *mapped);
const struct mapped_database *mapped,
size_t datalen);

/* Wrappers around read, readv and write that only read/write less than LEN
bytes on error or EOF. */
Expand Down
5 changes: 3 additions & 2 deletions nscd/nscd_getai.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
/* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
Expand Down Expand Up @@ -75,7 +76,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
if (mapped != NO_MAPPING)
{
struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
mapped);
mapped, sizeof ai_resp);
if (found != NULL)
{
respdata = (char *) (&found->data[0].aidata + 1);
Expand Down
5 changes: 3 additions & 2 deletions nscd/nscd_getgr_r.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 1998-2000, 2002-2005, 2006, 2007
/* Copyright (C) 1998-2000, 2002-2005, 2006, 2007, 2009
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
Expand Down Expand Up @@ -107,7 +107,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,

if (mapped != NO_MAPPING)
{
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
sizeof gr_resp);
if (found != NULL)
{
len = (const uint32_t *) (&found->data[0].grdata + 1);
Expand Down
6 changes: 4 additions & 2 deletions nscd/nscd_gethst_r.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* Copyright (C) 1998-2005, 2006, 2007, 2008 Free Software Foundation, Inc.
/* Copyright (C) 1998-2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
Expand Down Expand Up @@ -137,7 +138,8 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
if (mapped != NO_MAPPING)
{
/* No const qualifier, as it can change during garbage collection. */
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
sizeof hst_resp);
if (found != NULL)
{
h_name = (char *) (&found->data[0].hstdata + 1);
Expand Down
5 changes: 3 additions & 2 deletions nscd/nscd_getpw_r.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 1998, 1999, 2003, 2004, 2005, 2007
/* Copyright (C) 1998, 1999, 2003, 2004, 2005, 2007, 2009
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
Expand Down Expand Up @@ -104,7 +104,8 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,

if (mapped != NO_MAPPING)
{
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
sizeof pw_resp);
if (found != NULL)
{
pw_name = (const char *) (&found->data[0].pwdata + 1);
Expand Down
5 changes: 3 additions & 2 deletions nscd/nscd_getserv_r.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2007 Free Software Foundation, Inc.
/* Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
Expand Down Expand Up @@ -104,7 +104,8 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,

if (mapped != NO_MAPPING)
{
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
sizeof serv_resp);

if (found != NULL)
{
Expand Down
27 changes: 19 additions & 8 deletions nscd/nscd_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
Expand Down Expand Up @@ -472,18 +473,20 @@ __nscd_get_map_ref (request_type type, const char *name,
garbage collection. */
struct datahead *
__nscd_cache_search (request_type type, const char *key, size_t keylen,
const struct mapped_database *mapped)
const struct mapped_database *mapped, size_t datalen)
{
unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
size_t datasize = mapped->datasize;

ref_t trail = mapped->head->array[hash];
trail = atomic_forced_read (trail);
ref_t work = trail;
int tick = 0;

while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
{
struct hashentry *here = (struct hashentry *) (mapped->data + work);
ref_t here_key, here_packet;

#ifndef _STRING_ARCH_unaligned
/* Although during garbage collection when moving struct hashentry
Expand All @@ -498,13 +501,14 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,

if (type == here->type
&& keylen == here->len
&& here->key + keylen <= datasize
&& memcmp (key, mapped->data + here->key, keylen) == 0
&& here->packet + sizeof (struct datahead) <= datasize)
&& (here_key = atomic_forced_read (here->key)) + keylen <= datasize
&& memcmp (key, mapped->data + here_key, keylen) == 0
&& ((here_packet = atomic_forced_read (here->packet))
+ sizeof (struct datahead) <= datasize))
{
/* We found the entry. Increment the appropriate counter. */
struct datahead *dh
= (struct datahead *) (mapped->data + here->packet);
= (struct datahead *) (mapped->data + here_packet);

#ifndef _STRING_ARCH_unaligned
if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
Expand All @@ -513,11 +517,14 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,

/* See whether we must ignore the entry or whether something
is wrong because garbage collection is in progress. */
if (dh->usable && here->packet + dh->allocsize <= datasize)
if (dh->usable
&& here_packet + dh->allocsize <= datasize
&& (here_packet + offsetof (struct datahead, data) + datalen
<= datasize))
return dh;
}

work = here->next;
work = atomic_forced_read (here->next);
/* Prevent endless loops. This should never happen but perhaps
the database got corrupted, accidentally or deliberately. */
if (work == trail)
Expand All @@ -532,7 +539,11 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1))
return NULL;
#endif
trail = trailelem->next;

if (trail + sizeof (struct hashentry) > datasize)
return NULL;

trail = atomic_forced_read (trailelem->next);
}
tick = 1 - tick;
}
Expand Down
5 changes: 3 additions & 2 deletions nscd/nscd_initgroups.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
/* Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
Expand Down Expand Up @@ -55,7 +55,8 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
if (mapped != NO_MAPPING)
{
struct datahead *found = __nscd_cache_search (INITGROUPS, user,
userlen, mapped);
userlen, mapped,
sizeof initgr_resp);
if (found != NULL)
{
respdata = (char *) (&found->data[0].initgrdata + 1);
Expand Down

0 comments on commit cfe1fc1

Please sign in to comment.