All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir
@ 2013-01-22  0:09 Theodore Ts'o
  2013-01-22  0:09 ` [PATCH 2/3] contrib: add thread locking and readdir64_r " Theodore Ts'o
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Theodore Ts'o @ 2013-01-22  0:09 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o

This is part of a series of improvements from a 2008 version of
spd_readdir.c that somehow didn't make it into the version which we
checked into e2fsprogs git tree.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
 contrib/spd_readdir.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/contrib/spd_readdir.c b/contrib/spd_readdir.c
index f89832c..30c01b3 100644
--- a/contrib/spd_readdir.c
+++ b/contrib/spd_readdir.c
@@ -27,6 +27,10 @@
 #define MAX_DIRSIZE	0
 
 #define DEBUG
+/* Util we autoconfiscate spd_readdir... */
+#define HAVE___SECURE_GETENV	1
+#define HAVE_PRCTL		1
+#define HAVE_SYS_PRCTL_H	1
 
 #ifdef DEBUG
 #define DEBUG_DIR(x)	{if (do_debug) { x; }}
@@ -46,6 +50,11 @@
 #include <dirent.h>
 #include <errno.h>
 #include <dlfcn.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
 
 struct dirent_s {
 	unsigned long long d_ino;
@@ -83,6 +92,27 @@ static int num_open = 0;
 static int do_debug = 0;
 #endif
 
+static char *safe_getenv(const char *arg)
+{
+	if ((getuid() != geteuid()) || (getgid() != getegid()))
+		return NULL;
+#if HAVE_PRCTL
+	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+		return NULL;
+#else
+#if (defined(linux) && defined(SYS_prctl))
+	if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+		return NULL;
+#endif
+#endif
+
+#if HAVE___SECURE_GETENV
+	return __secure_getenv(arg);
+#else
+	return getenv(arg);
+#endif
+}
+
 static void setup_ptr()
 {
 	char *cp;
@@ -97,11 +127,11 @@ static void setup_ptr()
 	real_telldir = dlsym(RTLD_NEXT, "telldir");
 	real_seekdir = dlsym(RTLD_NEXT, "seekdir");
 	real_dirfd = dlsym(RTLD_NEXT, "dirfd");
-	if ((cp = getenv("SPD_READDIR_MAX_SIZE")) != NULL) {
+	if ((cp = safe_getenv("SPD_READDIR_MAX_SIZE")) != NULL) {
 		max_dirsize = atol(cp);
 	}
 #ifdef DEBUG
-	if (getenv("SPD_READDIR_DEBUG")) {
+	if (safe_getenv("SPD_READDIR_DEBUG")) {
 		printf("initialized!\n");
 		do_debug++;
 	}
-- 
1.7.12.rc0.22.gcdd159b


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] contrib: add thread locking and readdir64_r support to spd_readdir
  2013-01-22  0:09 [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Theodore Ts'o
@ 2013-01-22  0:09 ` Theodore Ts'o
  2013-01-22  0:09 ` [PATCH 3/3] contrib: fix namespace leakage in spd_readdir Theodore Ts'o
  2013-01-23 12:17 ` [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Florian Weimer
  2 siblings, 0 replies; 5+ messages in thread
From: Theodore Ts'o @ 2013-01-22  0:09 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o

This is part of a series of improvements from a 2008 version of
spd_readdir.c that somehow didn't make it into the version which we
checked into e2fsprogs git tree.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
 contrib/spd_readdir.c | 75 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 18 deletions(-)

diff --git a/contrib/spd_readdir.c b/contrib/spd_readdir.c
index 30c01b3..910b104 100644
--- a/contrib/spd_readdir.c
+++ b/contrib/spd_readdir.c
@@ -1,21 +1,22 @@
 /*
  * readdir accelerator
  *
- * (C) Copyright 2003, 2004 by Theodore Ts'o.
+ * (C) Copyright 2003, 2004, 2008 by Theodore Ts'o.
+ *
+ * 2008-06-08 Modified by Ross Boylan <RossBoylan stanfordalumni org>
+ *    Added support for readdir_r and readdir64_r calls.  Note
+ *     this has not been tested on anything other than GNU/Linux i386,
+ *     and that the regular readdir wrapper will take slightly more
+ *     space than Ted's original since it now includes a lock.
  *
  * Compile using the command:
  *
- * gcc -o spd_readdir.so -fPIC -shared spd_readdir.c -ldl
+ * gcc -o spd_readdir.so -shared -fpic spd_readdir.c -ldl
  *
  * Use it by setting the LD_PRELOAD environment variable:
  * 
  * export LD_PRELOAD=/usr/local/sbin/spd_readdir.so
  *
- * Note that this preload is not going to work for all programs.  In
- * particular, although it does supply readdir_r(), it is *not* thread
- * safe.  So I can't recommend this as something to be dropped in
- * /etc/ld.so.preload.
- *
  * %Begin-Header%
  * This file may be redistributed under the terms of the GNU Public
  * License.
@@ -55,6 +56,7 @@
 #else
 #define PR_GET_DUMPABLE 3
 #endif
+#include <pthread.h>
 
 struct dirent_s {
 	unsigned long long d_ino;
@@ -66,6 +68,7 @@ struct dirent_s {
 
 struct dir_s {
 	DIR	*dir;
+	pthread_mutex_t lock; /* Mutex lock for this structure.  */
 	int	num;
 	int	max;
 	struct dirent_s *dp;
@@ -83,6 +86,8 @@ static struct dirent *(*real_readdir)(DIR *dir) = 0;
 static int (*real_readdir_r)(DIR *dir, struct dirent *entry,
 			     struct dirent **result) = 0;
 static struct dirent64 *(*real_readdir64)(DIR *dir) = 0;
+static int (*real_readdir64_r)(DIR *dir, struct dirent64 *entry,
+			       struct dirent64 **result) = 0;
 static off_t (*real_telldir)(DIR *dir) = 0;
 static void (*real_seekdir)(DIR *dir, off_t offset) = 0;
 static int (*real_dirfd)(DIR *dir) = 0;
@@ -124,6 +129,7 @@ static void setup_ptr()
 	real_readdir = dlsym(RTLD_NEXT, "readdir");
 	real_readdir_r = dlsym(RTLD_NEXT, "readdir_r");
 	real_readdir64 = dlsym(RTLD_NEXT, "readdir64");
+	real_readdir64_r = dlsym(RTLD_NEXT, "readdir64_r");
 	real_telldir = dlsym(RTLD_NEXT, "telldir");
 	real_seekdir = dlsym(RTLD_NEXT, "seekdir");
 	real_dirfd = dlsym(RTLD_NEXT, "dirfd");
@@ -142,6 +148,8 @@ static void free_cached_dir(struct dir_s *dirstruct)
 {
 	int i;
 
+	pthread_mutex_destroy(&(dirstruct->lock));
+
 	if (!dirstruct->dp)
 		return;
 
@@ -181,11 +189,14 @@ static int ino_cmp(const void *a, const void *b)
 struct dir_s *alloc_dirstruct(DIR *dir)
 {
 	struct dir_s	*dirstruct;
+	static pthread_mutexattr_t mutexattr;
+	mutexattr.__align = PTHREAD_MUTEX_RECURSIVE;
 
 	dirstruct = malloc(sizeof(struct dir_s));
 	if (dirstruct)
 		memset(dirstruct, 0, sizeof(struct dir_s));
 	dirstruct->dir = dir;
+	pthread_mutex_init(&(dirstruct->lock), &mutexattr);
 	return dirstruct;
 }
 
@@ -268,7 +279,7 @@ DIR *fdopendir(int fd)
 	if (!real_fdopendir)
 		setup_ptr();
 
-	DEBUG_DIR(printf("fdpendir(%d) (%d open)\n", fd, num_open++));
+	DEBUG_DIR(printf("fdopendir(%d) (%d open)\n", fd, num_open++));
 	dir = (*real_fdopendir)(fd);
 	if (!dir)
 		return NULL;
@@ -336,19 +347,19 @@ int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)
 	if (dirstruct->direct)
 		return (*real_readdir_r)(dirstruct->dir, entry, result);
 
+	pthread_mutex_lock(&(dirstruct->lock));
 	if (dirstruct->pos >= dirstruct->num) {
 		*result = NULL;
-		return 0;
+	} else {
+		ds = &dirstruct->dp[dirstruct->pos++];
+		entry->d_ino = ds->d_ino;
+		entry->d_off = ds->d_off;
+		entry->d_reclen = ds->d_reclen;
+		entry->d_type = ds->d_type;
+		strncpy(entry->d_name, ds->d_name, sizeof(entry->d_name));
+		*result = entry;
 	}
-
-	ds = &dirstruct->dp[dirstruct->pos++];
-	entry->d_ino = ds->d_ino;
-	entry->d_off = ds->d_off;
-	entry->d_reclen = ds->d_reclen;
-	entry->d_type = ds->d_type;
-	strncpy(entry->d_name, ds->d_name, sizeof(entry->d_name));
-	*result = entry;
-
+	pthread_mutex_unlock(&(dirstruct->lock));
 	return 0;
 }
 
@@ -374,6 +385,32 @@ struct dirent64 *readdir64(DIR *dir)
 	return (&dirstruct->ret_dir64);
 }
 
+int readdir64_r (DIR *__restrict dir,
+		 struct dirent64 *__restrict entry,
+		 struct dirent64 **__restrict result)
+{
+	struct dir_s	*dirstruct = (struct dir_s *) dir;
+	struct dirent_s *ds;
+
+	if (dirstruct->direct)
+		return (*real_readdir64_r)(dir, entry, result);
+	pthread_mutex_lock(&(dirstruct->lock));
+	if (dirstruct->pos >= dirstruct->num) {
+		*result = NULL;
+	} else {
+		ds = &dirstruct->dp[dirstruct->pos++];
+		entry->d_ino = ds->d_ino;
+		entry->d_off = ds->d_off;
+		entry->d_reclen = ds->d_reclen;
+		entry->d_type = ds->d_type;
+		strncpy(entry->d_name, ds->d_name,
+			sizeof(entry->d_name));
+		*result = entry;
+	}
+	pthread_mutex_unlock(&(dirstruct->lock));
+	return 0;
+}
+
 off_t telldir(DIR *dir)
 {
 	struct dir_s	*dirstruct = (struct dir_s *) dir;
@@ -404,9 +441,11 @@ void rewinddir(DIR *dir)
 	if (dirstruct->direct)
 		return;
 	
+	pthread_mutex_lock(&(dirstruct->lock));
 	dirstruct->pos = 0;
 	free_cached_dir(dirstruct);
 	cache_dirstruct(dirstruct);
+	pthread_mutex_unlock(&(dirstruct->lock));
 }
 
 int dirfd(DIR *dir)
-- 
1.7.12.rc0.22.gcdd159b


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] contrib: fix namespace leakage in spd_readdir
  2013-01-22  0:09 [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Theodore Ts'o
  2013-01-22  0:09 ` [PATCH 2/3] contrib: add thread locking and readdir64_r " Theodore Ts'o
@ 2013-01-22  0:09 ` Theodore Ts'o
  2013-01-23 12:17 ` [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Florian Weimer
  2 siblings, 0 replies; 5+ messages in thread
From: Theodore Ts'o @ 2013-01-22  0:09 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o

Declare the internal symbols alloc_dirstruct() and cache_dirstruct()
as static so they don't leak out into the global namespace.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
 contrib/spd_readdir.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/contrib/spd_readdir.c b/contrib/spd_readdir.c
index 910b104..8345fa1 100644
--- a/contrib/spd_readdir.c
+++ b/contrib/spd_readdir.c
@@ -186,7 +186,7 @@ static int ino_cmp(const void *a, const void *b)
 	return (i_a - i_b);
 }
 
-struct dir_s *alloc_dirstruct(DIR *dir)
+static struct dir_s *alloc_dirstruct(DIR *dir)
 {
 	struct dir_s	*dirstruct;
 	static pthread_mutexattr_t mutexattr;
@@ -200,7 +200,7 @@ struct dir_s *alloc_dirstruct(DIR *dir)
 	return dirstruct;
 }
 
-void cache_dirstruct(struct dir_s *dirstruct)
+static void cache_dirstruct(struct dir_s *dirstruct)
 {
 	struct dirent_s *ds, *dnew;
 	struct dirent64 *d;
-- 
1.7.12.rc0.22.gcdd159b


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir
  2013-01-22  0:09 [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Theodore Ts'o
  2013-01-22  0:09 ` [PATCH 2/3] contrib: add thread locking and readdir64_r " Theodore Ts'o
  2013-01-22  0:09 ` [PATCH 3/3] contrib: fix namespace leakage in spd_readdir Theodore Ts'o
@ 2013-01-23 12:17 ` Florian Weimer
  2013-01-23 16:22   ` Theodore Ts'o
  2 siblings, 1 reply; 5+ messages in thread
From: Florian Weimer @ 2013-01-23 12:17 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Ext4 Developers List

* Theodore Ts'o:

> +#if HAVE___SECURE_GETENV
> +	return __secure_getenv(arg);
> +#else
> +	return getenv(arg);
> +#endif

glibc 2.17 has secure_getenv, but not __secure_getenv.  Unfortuantely,
this was the only way to turn this into an official interface.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir
  2013-01-23 12:17 ` [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Florian Weimer
@ 2013-01-23 16:22   ` Theodore Ts'o
  0 siblings, 0 replies; 5+ messages in thread
From: Theodore Ts'o @ 2013-01-23 16:22 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Ext4 Developers List

On Wed, Jan 23, 2013 at 01:17:25PM +0100, Florian Weimer wrote:
> 
> glibc 2.17 has secure_getenv, but not __secure_getenv.  Unfortuantely,
> this was the only way to turn this into an official interface.

Thanks for pointing this out.  I'm using Debian testing which is still
using glibc 2.13.  The bigger issue is that it's not just
spd_readdir.c (which is in contrib and so it's not compiled from the
makefile), but we are using __secure_getenv() in libext2fs and other
libraries in e2fprogs.

Use of __secure_getenv() is protected with a configure.in test, so we
won't break when we compile under glibc 2.17, but we won't have the
full benefit of using secure_getenv(), either.  We use a similar
safe_getenv() code which will skip the getenv if the process is
running setuid, or PR_GET_DUMPABLE returns 0, so hopefully that
prevents us against the worst of the security exposure, but as [1]
states, "such emulation is necessarily brittle".

[1] http://sourceware.org/glibc/wiki/Tips_and_Tricks/secure_getenv

Can someone send me a patch, please?   Or I'll put it on my todo list....

    	    	      	     	       	       - Ted


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-01-23 16:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-22  0:09 [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Theodore Ts'o
2013-01-22  0:09 ` [PATCH 2/3] contrib: add thread locking and readdir64_r " Theodore Ts'o
2013-01-22  0:09 ` [PATCH 3/3] contrib: fix namespace leakage in spd_readdir Theodore Ts'o
2013-01-23 12:17 ` [PATCH 1/3] contrib: add safe_getenv() support to spd_readdir Florian Weimer
2013-01-23 16:22   ` Theodore Ts'o

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.