Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Feb 2010 14:51:12 +0000 (UTC)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r203346 - projects/capabilities8/lib/libcapsicum
Message-ID:  <201002011451.o11EpCJp084674@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rwatson
Date: Mon Feb  1 14:51:11 2010
New Revision: 203346
URL: http://svn.freebsd.org/changeset/base/203346

Log:
  Merge c173958, c174024, c174029, c174030, c174074, c174075, c174076,
  c174086, c174087, c174089, c174091:
  
    File descriptor reordering via lc_fdlist_reorder()
  
    Add a rough draft man page for the libcapsicum fdlist API.
  
    Fix markup nits, type nits, and argument names.
  
    Fix further nits, document return values for fdlist functions.
  
    Added ld_fdlist_append(), plus one sanity check and the ability to ignore
      names in lc_fdlist_lookup()
  
    Add lc_fdlist_append() to libcapsicum.h
  
    Added the weak symbol ld_libdirs()
  
    Avoid passing lc_fdlist by reference to utility functions by
    adopting a static lc_fdlist pointer over the life time of the list,
    with the storage pointer being rewritten instead.  The result is
    more locking friendly.  Also correct some locking bugs.
  
    Layout fixes, comment that we'll make the _size a private function.
  
    Clean up style in a few places.
  
    Properly handle lock unwinding in append.  Comment on lock
    recursion.
  
    White space tweak.
  
  Submitted by:	Jonathan Anderson <jonathan.anderson at cl.cam.ac.uk> (portions)
  Sponsored by:	Google, Inc. (portions)

Added:
  projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.3
Modified:
  projects/capabilities8/lib/libcapsicum/Makefile
  projects/capabilities8/lib/libcapsicum/libcapsicum.3
  projects/capabilities8/lib/libcapsicum/libcapsicum.h
  projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.c
  projects/capabilities8/lib/libcapsicum/libcapsicum_host.c

Modified: projects/capabilities8/lib/libcapsicum/Makefile
==============================================================================
--- projects/capabilities8/lib/libcapsicum/Makefile	Mon Feb  1 14:29:07 2010	(r203345)
+++ projects/capabilities8/lib/libcapsicum/Makefile	Mon Feb  1 14:51:11 2010	(r203346)
@@ -21,9 +21,17 @@ SHLIB_MAJOR=	1
 WARNS?=	6
 
 MAN=	libcapsicum.3
+MAN+=	libcapsicum_fdlist.3
 MAN+=	libcapsicum_host.3
 MAN+=	libcapsicum_sandbox.3
 MLINKS=	libcapsicum.3 lc_limitfd.3		\
+	libcapsicum_fdlist.3 lc_fdlist_new.3	\
+	libcapsicum_fdlist.3 lc_fdlist_global.3	\
+	libcapsicum_fdlist.3 lc_fdlist_dup.3	\
+	libcapsicum_fdlist.3 lc_fdlist_free.3	\
+	libcapsicum_fdlist.3 lc_fdlist_add.3	\
+	libcapsicum_fdlist.3 lc_fdlist_addcap.3	\
+	libcapsicum_fdlist.3 lc_fdlist_lookup.3	\
 	libcapsicum_host.3 lch_autosandbox_isenabled.3	\
 	libcapsicum_host.3 lch_start.3	\
 	libcapsicum_host.3 lch_startfd.3	\

Modified: projects/capabilities8/lib/libcapsicum/libcapsicum.3
==============================================================================
--- projects/capabilities8/lib/libcapsicum/libcapsicum.3	Mon Feb  1 14:29:07 2010	(r203345)
+++ projects/capabilities8/lib/libcapsicum/libcapsicum.3	Mon Feb  1 14:51:11 2010	(r203346)
@@ -1,5 +1,5 @@
 .\"
-.\" Copyright (c) 2009 Robert N. M. Watson
+.\" Copyright (c) 2009-2010 Robert N. M. Watson
 .\" All rights reserved.
 .\"
 .\" WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED
@@ -82,6 +82,13 @@ described in
 .Xr libcapsicum_sandbox 3 .
 Sandboxed processes themselves may launch software components in further
 sandboxes, so a single program may use both host and sandbox APIs.
+.Pp
+In addition, the
+.Nm
+file descriptor list API, described in
+.Xr libcapsicum_fdlist 3 ,
+may be used to manage the delegation of file descriptors/capabilities to
+sandboxes using a namespace.
 .Sh CAPABILITY API
 .Fn lc_limitfd
 is a wrapper around
@@ -99,6 +106,7 @@ with the requested rights mask.
 .Xr cap_new 2 ,
 .Xr close 2 ,
 .Xr dup2 2 ,
+.Xr libcapsicum_fdlist 3 ,
 .Xr libcapsicum_host 3 ,
 .Xr libcapsicum_sandbox 3 ,
 .Xr unix 4
@@ -111,6 +119,9 @@ WARNING: THIS IS EXPERIMENTAL SECURITY S
 PRODUCTION SYSTEMS.  IT WILL BREAK YOUR SOFTWARE IN NEW AND UNEXPECTED WAYS.
 .Sh AUTHORS
 These functions and the capability facility were created by
+.An -nosplit
 .An "Robert N. M. Watson"
+and
+.An "Jonathan Anderson"
 at the University of Cambridge Computer Laboratory with support from a grant
 from Google, Inc.

Modified: projects/capabilities8/lib/libcapsicum/libcapsicum.h
==============================================================================
--- projects/capabilities8/lib/libcapsicum/libcapsicum.h	Mon Feb  1 14:29:07 2010	(r203345)
+++ projects/capabilities8/lib/libcapsicum/libcapsicum.h	Mon Feb  1 14:51:11 2010	(r203346)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009 Robert N. M. Watson
+ * Copyright (c) 2009-2010 Robert N. M. Watson
  * All rights reserved.
  *
  * WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED
@@ -53,54 +53,76 @@ struct lc_library {
 	int		 lcl_fd;
 };
 
-
-/* A list of file descriptors, which can be passed around in shared memory */
+/*
+ * A list of file descriptors, which can be passed around in shared memory.
+ */
 struct lc_fdlist;
+struct lc_fdlist	*lc_fdlist_new(void);
+struct lc_fdlist	*lc_fdlist_global(void);
+struct lc_fdlist	*lc_fdlist_dup(struct lc_fdlist *lfp_orig);
+void			 lc_fdlist_free(struct lc_fdlist *lfp);
 
-struct lc_fdlist*	lc_fdlist_new(void);
-struct lc_fdlist*	lc_fdlist_global(void);
-struct lc_fdlist*	lc_fdlist_dup(struct lc_fdlist *orig);
-void			lc_fdlist_free(struct lc_fdlist *l);
-
-
-/* Size of an FD list in bytes, including all associated string data */
-int	lc_fdlist_size(struct lc_fdlist *l);
-
+/*
+ * Size of an FD list in bytes, including all associated string data.
+ *
+ * XXX: This will probably become library-private soon.
+ */
+u_int	lc_fdlist_size(struct lc_fdlist *lfp);
 
 /*
  * Add a file descriptor to the list.
  *
- * l		the list to add to
+ * lfp		the list to add to
  * subsystem	a software component name, e.g. "org.freebsd.rtld-elf"
  * classname	a class name, e.g. "libdir" or "library"
  * name		an instance name, e.g. "system library dir" or "libc.so.6"
  * fd		the file descriptor
  */
-int	lc_fdlist_add(struct lc_fdlist **l,
-	              const char *subsystem, const char *classname,
-	              const char *name, int fd);
+int	lc_fdlist_add(struct lc_fdlist *lfp, const char *subsystem,
+	    const char *classname, const char *name, int fd);
 
 /*
- * Like lc_fdlist_add(), but allows capability rights to be specified. The file
- * descriptor will be wrapped in a capability with the given rights (so if the
- * descriptor *is* a capability, its rights will be constrained according to this
- * rights mask)
- */
-int	lc_fdlist_addcap(struct lc_fdlist **l,
-	                 const char *subsystem, const char *classname,
-	                 const char *name, int fd, cap_rights_t rights);
+ * Append the contents of one list to another.
+ */
+int	lc_fdlist_append(struct lc_fdlist *to, struct lc_fdlist *from);
+
+
+/*
+ * Like lc_fdlist_add(), but allows capability rights to be specified.  The
+ * file descriptor will be wrapped in a capability with the given rights (so
+ * if the descriptor *is* a capability, its rights will be constrained
+ * according to this rights mask.)
+ */
+int	lc_fdlist_addcap(struct lc_fdlist *l, const char *subsystem,
+	    const char *classname, const char *name, int fd,
+	    cap_rights_t rights);
 
 /*
  * Look up a file descriptor.
  *
  * Multiple entries with the same classname are allowed, so iterating through
- * all instances of a class is done by supplying an integer 'pos' which is used
- * internally to skip entries which have already been seen. If 'pos' is 0 or NULL,
- * the first matching entry will be returned.
- */
-int	lc_fdlist_lookup(struct lc_fdlist *l,
-	                 const char *subsystem, const char *classname,
-	                 char **name, int *fdp, int *pos);
+ * all instances of a class is done by supplying an integer 'pos' which is
+ * used internally to skip entries which have already been seen.  If 'pos' is
+ * 0 or NULL, the first matching entry will be returned.
+ */
+int	lc_fdlist_lookup(struct lc_fdlist *lfp, const char *subsystem,
+	    const char *classname, char **name, int *fdp, int *pos);
+
+/*
+ * Look up a file descriptor without a name.  Repeated calls to this function
+ * will iterate through all descriptors in the list.
+ */
+int	lc_fdlist_getentry(struct lc_fdlist *lfp, char **subsystem,
+	    char **classname, char **name, int *fdp, int *pos);
+
+/*
+ * Reorder FD list (WARNING: this could be dangerous!).
+ *
+ * This call takes all of the file descriptors in the FD list, and moves them
+ * into a continuous array, starting at the FD given by 'start'.  Any file
+ * descriptors above 'start' which are not in the FD list are closed.
+ */
+int	lc_fdlist_reorder(struct lc_fdlist *lfp);
 
 /*
  * Capability interfaces.
@@ -201,6 +223,9 @@ int	lcs_sendrpc_rights(struct lc_host *l
 int	ld_libcache_lookup(const char *libname, int *fdp);
 int	ld_insandbox(void);
 
+/* If this call is successful, the caller is responsible for freeing 'fds'. */
+int	ld_libdirs(int **fds);
+
 /*
  * Applications may declare an alternative entry point to the default ELF
  * entry point for their binary, which will be used in preference to 'main'

Added: projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.3
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.3	Mon Feb  1 14:51:11 2010	(r203346)
@@ -0,0 +1,182 @@
+.\"
+.\" Copyright (c) 2010 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED
+.\" ON IN PRODUCTION SYSTEMS.  IT WILL BREAK YOUR SOFTWARE IN NEW AND
+.\" UNEXPECTED WAYS.
+.\"
+.\" This software was developed at the University of Cambridge Computer
+.\" Laboratory with support from a grant from Google, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 31, 2010
+.Os
+.Dt LIBCAPABILITY_FDLIST 3
+.Sh NAME
+.Nm libcapsicum
+.Nd "library interface to file descriptor lists"
+.Sh LIBRARY
+.Lb libcapsicum
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/capability.h
+.In libcapsicum.h
+.Ft struct lc_fdlist *
+.Fn lc_fdlist_new "void"
+.Ft struct lc_fdlist *
+.Fn lc_fdlist_global "void"
+.Ft struct lc_fdlist *
+.Fn lc_fdlist_dup "struct lc_fdlist *lfp"
+.Ft void
+.Fn lc_fdlist_free "struct lc_fdlist *lfp"
+.Ft int
+.Fn lc_fdlist_add "struct lc_fdlist *lfp" "const char *subsystem" "const char *classname" "const char *name" "int fd"
+.Ft int
+.Fn lc_fdlist_addcap "struct lc_fdlist *lfp" "const char *subsystem" "const char *classname" "const char *name" "int fd" "cap_rights_t rights"
+.Ft int
+.Fn lc_fdlist_lookup "struct lc_fdlist *lfp" "const char *subsystem" "const char **name" "int *fdp" "int *pos"
+.Sh DESCRIPTION
+These
+.Nm
+library routines create, manage, and destroy file descriptor lists.
+File descriptor lists are used by
+.Nm
+to describe sets of rights that should be delegated to newly created
+sandboxes, as well as binding them to names so that sandboxed code can look
+up file descriptors provided by code in the host without using hard-coded
+file descriptor numbers.
+This is necessary because file descriptors may not be the same in the host
+and sandbox environments.
+.Nm
+will arrange for all necessary name and descriptor information to be
+available in the sandbox, and file descriptor numbers returned in the sandbox
+are with respect to the sandbox's file descriptor assignments.
+.Pp
+Note that the file descriptor list code is not aware of any changes in file
+descriptor status that may happen as a result of application behavior, such
+as calls to
+.Xr open 2 ,
+.Xr dup 2,
+or
+.Xr close 2.
+As such, applications must update any file descriptor lists referring to
+manipulated descriptors if the descriptor list will later be queried for
+them, or used in creating a new sandbox.
+.Ss File descriptor list creation and destruction
+These functions create, duplicate, and free file descriptor lists:
+.Pp
+.Fn lc_fdlist_new
+allocates a new file descriptor list containing no file descriptor
+registrations.
+Sandboxed code may also use
+.Fn lc_fdlist_global
+to query the global file descriptor list passed in when the sandbox was
+created.
+.Pp
+.Fn lc_fdlist_dup
+duplicates an existing file descriptor list, creating a new list with
+identical entries.
+Once duplicated, the lists may diverge; this allows the creation of a
+template list for a class of sandbox, followed by duplication and
+customization for a specific sandbox instance.
+.Pp
+.Fn lc_fdlist_free
+frees an existing file descriptor list; note that this does not close or
+otherwise modify file descriptors described by the list.
+.Ss File descriptor list entries
+Each file descriptor list entry is described by a three-part character string
+namespace:
+.Bl -tag -width "subsystem"
+.It Fa subsystem
+Application or library name, globally unique in order to prevent collisions
+between software components in the same host/sandbox pair.
+.It Fa classname
+An application-specific or library-specific name, intended to reflect a
+specific software component within that application or library.
+.It Fa name
+A per-subsystem, per-class namespace, which might contain file names or other
+specific object instance description.
+.El
+.Pp
+These functions insert and look up file descriptor list entries:
+.Pp
+.Fn lc_fdlist_add
+adds a file descriptor,
+.Fa fd ,
+with the three-part name
+.Fa subsystem ,
+.Fa classname ,
+and
+.Fa name
+to the file descriptor list
+.Fa lfp .
+.Fn lc_fdlist_add
+is identical except that it further registers a capability mask to apply to
+the descriptor during sandbox creation, avoiding the need for separate calls
+to .Xr cap_new
+in application code.
+.Pp
+.Fn lc_fdlist_lookup
+looks up a file descriptor using the three-part name
+.Fa subsystem ,
+.Fa classname ,
+and
+.Fa name
+from the file descriptor list
+.Fa lfp .
+.Sh RETURN VALUES
+The
+.Fn lc_fdlist_new ,
+.Fn lc_flist_global ,
+and
+.Fn lc_fdlist_dup
+functions return a pointer to the desired file descriptor list if successful;
+otherwise the value
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+.Rv -std lc_fdlist_add lc_fdlist_addcap lc_fdlist_lookup
+.Sh SEE ALSO
+.Xr cap_new 2 ,
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr open 2 ,
+.Xr libcapsicum 3 ,
+.Xr libcapsicum_host 3 ,
+.Xr libcapsicum_sandbox 3 ,
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh BUGS
+WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED ON IN
+PRODUCTION SYSTEMS.  IT WILL BREAK YOUR SOFTWARE IN NEW AND UNEXPECTED WAYS.
+.Sh AUTHORS
+These functions were created by
+.An "Jonathan Anderson"
+at the University of Cambridge Computer Laboratory.

Modified: projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.c
==============================================================================
--- projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.c	Mon Feb  1 14:29:07 2010	(r203345)
+++ projects/capabilities8/lib/libcapsicum/libcapsicum_fdlist.c	Mon Feb  1 14:51:11 2010	(r203346)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2009 Jonathan Anderson
+ * Copyright (c) 2010 Robert N. M. Watson
  * All rights reserved.
  *
  * WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED
@@ -46,345 +47,492 @@
 
 #include "libcapsicum_sandbox_api.h"
 
-
 struct lc_fdlist_entry {
-
-	unsigned int sysoff;	/* offset of e.g. "org.freebsd.rtld-elf-cap" */
-	unsigned int syslen;	/* length of above */
-
-	unsigned int idoff;	/* offset of variable ID e.g. "libs" */
-	unsigned int idlen;	/* length of above */
-
-	unsigned int nameoff;	/* offset of entry name (e.g. "libc.so.7") */
-	unsigned int namelen;	/* length of above */
-
+	u_int sysoff;		/* offset of e.g. "org.freebsd.rtld-elf-cap" */
+	u_int syslen;		/* length of above */
+	u_int classoff;		/* offset of variable ID e.g. "libs" */
+	u_int classnamelen;	/* length of above */
+	u_int nameoff;		/* offset of entry name (e.g. "libc.so.7") */
+	u_int namelen;		/* length of above */
 	int fd;			/* the file descriptor */
 };
 
-
-struct lc_fdlist {
-
-	unsigned int count;		/* number of entries */
-	unsigned int capacity;		/* entries that we can hold */
-
-	unsigned int namelen;		/* bytes of name data */
-	unsigned int namecapacity;	/* bytes of name data we can hold */
-
-	pthread_mutex_t lock;		/* for thread safety */
-
-	struct lc_fdlist_entry entries[];	/* entries in the descriptor list */
+struct lc_fdlist_storage {
+	u_int count;		/* number of entries */
+	u_int capacity;		/* entries that we can hold */
+	u_int namelen;		/* bytes of name data */
+	u_int namecapacity;	/* bytes of name data we can hold */
+	struct lc_fdlist_entry entries[]; /* entries in the descriptor list */
 
 	/* followed by bytes of name data */
 };
 
+struct lc_fdlist {
+	pthread_mutex_t			 lf_lock;	/* for thread safety */
+	struct lc_fdlist_storage	*lf_storage;
+};
 
-
-
-#define LOCK(l)		pthread_mutex_lock(&((l)->lock));
-#define UNLOCK(l)		pthread_mutex_unlock(&((l)->lock));
+#define LOCK(lfp)	pthread_mutex_lock(&((lfp)->lf_lock));
+#define UNLOCK(lfp)	pthread_mutex_unlock(&((lfp)->lf_lock));
 
 /* Where an FD list's name byte array starts */
-char*	lc_fdlist_names(struct lc_fdlist *l);
-
-
-
-struct lc_fdlist *global_fdlist = NULL;
-
-
-struct lc_fdlist*
-lc_fdlist_global(void) {
-
-	if (global_fdlist == NULL) {
-
-		char *env = getenv(LIBCAPABILITY_SANDBOX_FDLIST);
-
-		if ((env != NULL) && (strnlen(env, 8) < 7)) {
-
-			for (int i = 0; (i < 7) && env[i]; i++)
-				if ((env[i] < '0') || (env[i] > '9'))
-					return NULL;
-
-			int fd = -1;
-			if (sscanf(env, "%d", &fd) != 1)
-				return NULL;
+static char	*lc_fdlist_storage_names(struct lc_fdlist_storage *lfsp);
+static u_int	 lc_fdlist_storage_size(struct lc_fdlist_storage *lfsp);
 
-			if (fd < 0)
-				return NULL;
-
-			struct stat stats;
-			if (fstat(fd, &stats) < 0)
-				return NULL;
+static struct lc_fdlist global_fdlist = {
+	.lf_lock = PTHREAD_MUTEX_INITIALIZER,
+};
 
-			global_fdlist = mmap(NULL, stats.st_size,
-			                     PROT_READ | PROT_WRITE,
-			                     MAP_NOSYNC | MAP_SHARED, fd, 0);
+struct lc_fdlist *
+lc_fdlist_global(void)
+{
+	char *env;
+
+	/*
+	 * global_fdlist.lf_storage is set to a non-NULL value after the
+	 * first call, and will never change; global_fdlist is only valid
+	 * once it has non-NULL storage.
+	 */
+	LOCK(&global_fdlist);
+	if (global_fdlist.lf_storage != NULL) {
+		UNLOCK(&global_fdlist);
+		return (&global_fdlist);
+	}
+
+	env = getenv(LIBCAPABILITY_SANDBOX_FDLIST);
+	if ((env != NULL) && (strnlen(env, 8) < 7)) {
+		struct lc_fdlist_storage *lfsp;
+		struct stat sb;
+		int fd = -1;
+
+		/* XXX: Should use strtol(3). */
+		for (int i = 0; (i < 7) && env[i]; i++) {
+			if ((env[i] < '0') || (env[i] > '9'))
+				goto fail;
 		}
-	}
-
-	return global_fdlist;
+		if (sscanf(env, "%d", &fd) != 1)
+			goto fail;
+		if (fd < 0)
+			goto fail;
+		if (fstat(fd, &sb) < 0)
+			goto fail;
+		lfsp = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
+		    MAP_NOSYNC | MAP_SHARED, fd, 0);
+		if (lfsp == NULL)
+			goto fail;
+
+		/*
+		 * XXX: Should perform additional validation of shared memory
+		 * to make sure sizes/etc are internally consistent.
+		 */
+		global_fdlist.lf_storage = lfsp;
+	}
+	return (&global_fdlist);
+
+fail:
+	/* XXX: We don't always set errno before returning. */
+	UNLOCK(&global_fdlist);
+	return (NULL);
 }
 
-
 #define INITIAL_ENTRIES		16
 #define INITIAL_NAMEBYTES	(64 * INITIAL_ENTRIES)
 
-
-struct lc_fdlist*
-lc_fdlist_new(void) {
-
-	int bytes = sizeof(struct lc_fdlist)
-		+ INITIAL_ENTRIES * sizeof(struct lc_fdlist_entry)
-		+ INITIAL_NAMEBYTES;
-
-	struct lc_fdlist *fdlist = malloc(bytes);
-	if (fdlist == NULL) return (NULL);
-
-	fdlist->count = 0;
-	fdlist->capacity = INITIAL_ENTRIES;
-	fdlist->namelen = 0;
-	fdlist->namecapacity = INITIAL_NAMEBYTES;
-
-	if (pthread_mutex_init(&fdlist->lock, NULL)) {
-		free(fdlist);
-		return NULL;
+struct lc_fdlist *
+lc_fdlist_new(void)
+{
+	struct lc_fdlist_storage *lfsp;
+	struct lc_fdlist *lfp;
+	u_int bytes;
+
+	lfp = malloc(sizeof(*lfp));
+	bytes = sizeof(*lfsp) +
+	    INITIAL_ENTRIES * sizeof(struct lc_fdlist_entry) +
+	    INITIAL_NAMEBYTES;
+	lfsp = lfp->lf_storage = malloc(bytes);
+	if (lfsp == NULL) {
+		free(lfp);
+		return (NULL);
+	}
+	lfsp->count = 0;
+	lfsp->capacity = INITIAL_ENTRIES;
+	lfsp->namelen = 0;
+	lfsp->namecapacity = INITIAL_NAMEBYTES;
+	if (pthread_mutex_init(&lfp->lf_lock, NULL) != 0) {
+		free(lfp->lf_storage);
+		free(lfp);
+		return (NULL);
 	}
-
-	return fdlist;
+	return (lfp);
 }
 
-
-struct lc_fdlist*
-lc_fdlist_dup(struct lc_fdlist *orig) {
-
-	LOCK(orig);
-
-	int size = lc_fdlist_size(orig);
-	struct lc_fdlist *copy = NULL;
-
-	if (size > 0) {
-		copy = malloc(size);
-		if (copy != NULL) memcpy(copy, orig, size);
-	}
-
-	UNLOCK(orig);
-
-	return copy;
+struct lc_fdlist *
+lc_fdlist_dup(struct lc_fdlist *lfp_orig)
+{
+	struct lc_fdlist *lfp_new;
+	u_int size;
+
+	lfp_new = malloc(sizeof(*lfp_new));
+	if (lfp_new == NULL)
+		return (NULL);
+	if (pthread_mutex_init(&lfp_new->lf_lock, NULL) != 0) {
+		free(lfp_new);
+		return (NULL);
+	}
+	LOCK(lfp_orig);
+	size = lc_fdlist_storage_size(lfp_orig->lf_storage);
+	lfp_new->lf_storage = malloc(size);
+	if (lfp_new->lf_storage == NULL) {
+		UNLOCK(lfp_orig);
+		pthread_mutex_destroy(&lfp_new->lf_lock);
+		free(lfp_new);
+		return (NULL);
+	}
+	memcpy(lfp_new->lf_storage, lfp_orig->lf_storage, size);
+	UNLOCK(lfp_orig);
+	return (lfp_new);
 }
 
-
 void
-lc_fdlist_free(struct lc_fdlist *l) {
+lc_fdlist_free(struct lc_fdlist *lfp)
+{
 
-	LOCK(l);
-
-	pthread_mutex_destroy(&l->lock);
-	free(l);
+	free(lfp->lf_storage);
+	pthread_mutex_destroy(&lfp->lf_lock);
+	free(lfp);
 }
 
-
-
 int
-lc_fdlist_add(struct lc_fdlist **fdlist,
-              const char *subsystem, const char *id,
-              const char *name, int fd) {
-
-	struct lc_fdlist *l = *fdlist;
-
-	if (l == NULL) {
-
-		errno = EINVAL;
-		return -1;
-	}
-
-	LOCK(l);
-
-	/* do we need more entry space? */
-	if (l->count == l->capacity) {
-
-		/* move name data out of the way */
+lc_fdlist_add(struct lc_fdlist *lfp, const char *subsystem,
+    const char *classname, const char *name, int fd)
+{
+	struct lc_fdlist_storage *lfsp;
+
+	LOCK(lfp);
+	lfsp = lfp->lf_storage;
+
+	/* Do we need more entry space? */
+	if (lfsp->count == lfsp->capacity) {
+		u_int namebytes_per_entry, newnamebytes, newsize;
+		struct lc_fdlist_storage *lfsp_copy;
 		char *tmp = NULL;
-		if (l->namelen > 0) {
-			tmp = malloc(l->namelen);
+
+		/* Copy name data out of the way. */
+		if (lfsp->namelen > 0) {
+			tmp = malloc(lfsp->namelen);
 			if (tmp == NULL) {
-				UNLOCK(l);
+				UNLOCK(lfp);
 				return (-1);
 			}
-
-			memcpy(tmp, lc_fdlist_names(l), l->namelen);
+			memcpy(tmp, lc_fdlist_storage_names(lfsp),
+			    lfsp->namelen);
 		}
 
-		/* double the number of available entries */
-		int namebytes_per_entry = l->namecapacity / l->capacity;
-		int newnamebytes = l->capacity * namebytes_per_entry;
-
-		int newsize = lc_fdlist_size(l) + newnamebytes
-		               + l->capacity * sizeof(struct lc_fdlist_entry);
-
-		struct lc_fdlist *copy = realloc(l, newsize);
-		if (copy == NULL) {
+		/* Double the number of available entries. */
+		namebytes_per_entry = lfsp->namecapacity / lfsp->capacity;
+		newnamebytes = lfsp->capacity * namebytes_per_entry;
+		newsize = lc_fdlist_storage_size(lfsp) + newnamebytes
+		    + lfsp->capacity * sizeof(struct lc_fdlist_entry);
+		lfsp_copy = realloc(lfsp, newsize);
+		if (lfsp_copy == NULL) {
 			free(tmp);
-			UNLOCK(l);
+			UNLOCK(lfp);
 			return (-1);
 		}
 
-		copy->capacity		*= 2;
-		copy->namecapacity	+= newnamebytes;
+		lfsp_copy->capacity *= 2;
+		lfsp_copy->namecapacity += newnamebytes;
 
-		/* copy name bytes back */
-		if (copy->namelen > 0)
-			memcpy(lc_fdlist_names(copy), tmp, copy->namelen);
+		/* Copy name bytes back. */
+		if (lfsp_copy->namelen > 0)
+			memcpy(lc_fdlist_storage_names(lfsp_copy), tmp,
+			    lfsp_copy->namelen);
 
+		free(lfsp);
+		lfsp = lfp->lf_storage = lfsp_copy;
 		free(tmp);
-
-		*fdlist = copy;
-		l = *fdlist;
 	}
 
-
-	/* do we need more name space? */
-	int subsyslen	= strlen(subsystem);
-	int idlen	= strlen(id);
-	int namelen	= strlen(name);
-
-	if ((l->namelen + subsyslen + idlen + namelen) >= l->namecapacity) {
-
-		/* double the name capacity */
-		struct lc_fdlist* enlarged
-			= realloc(l, lc_fdlist_size(l) + l->namecapacity);
-
-		if (enlarged == NULL) {
-			UNLOCK(l);
+	/* Do we need more name space? */
+	u_int subsyslen = strlen(subsystem);
+	u_int classnamelen = strlen(classname);
+	u_int namelen = strlen(name);
+
+	if ((lfsp->namelen + subsyslen + classnamelen + namelen) >=
+	    lfsp->namecapacity) {
+
+		/* Double the name capacity. */
+		struct lc_fdlist_storage *lfsp_enlarged;
+
+		lfsp_enlarged = realloc(lfsp, lc_fdlist_storage_size(lfsp) +
+		    lfsp->namecapacity);
+		if (lfsp_enlarged == NULL) {
+			UNLOCK(lfp);
 			return (-1);
 		}
 
-		enlarged->namecapacity *= 2;
-		*fdlist = enlarged;
-		l = *fdlist;
+		lfsp_enlarged->namecapacity *= 2;
+		lfsp = lfp->lf_storage = lfsp_enlarged;
 	}
 
-
-	/* create the new entry */
-	struct lc_fdlist_entry *entry = l->entries + l->count;
+	/* Create the new entry. */
+	struct lc_fdlist_entry *entry = lfsp->entries + lfsp->count;
 
 	entry->fd = fd;
 
-	char *names = lc_fdlist_names(l);
-	char *head = names + l->namelen;
+	char *names = lc_fdlist_storage_names(lfsp);
+	char *head = names + lfsp->namelen;
 
 	strncpy(head, subsystem, subsyslen + 1);
-	entry->sysoff	= (head - names);
-	entry->syslen	= subsyslen;
-	head		+= subsyslen + 1;
-
-	strncpy(head, id, idlen + 1);
-	entry->idoff	= (head - names);
-	entry->idlen	= idlen;
-	head		+= idlen + 1;
+	entry->sysoff = (head - names);
+	entry->syslen = subsyslen;
+	head += subsyslen + 1;
+
+	strncpy(head, classname, classnamelen + 1);
+	entry->classoff	= (head - names);
+	entry->classnamelen = classnamelen;
+	head += classnamelen + 1;
 
 	strncpy(head, name, namelen + 1);
-	entry->nameoff	= (head - names);
-	entry->namelen	= namelen + 1;
-	head		+= namelen + 1;
-
-	l->count++;
-	l->namelen = (head - names);
+	entry->nameoff = (head - names);
+	entry->namelen = namelen + 1;
+	head += namelen + 1;
 
-	UNLOCK(l);
+	lfsp->count++;
+	lfsp->namelen = (head - names);
 
-	return 0;
+	UNLOCK(lfp);
+	return (0);
 }
 
-
 int
-lc_fdlist_addcap(struct lc_fdlist **fdlist,
-                 const char *subsystem, const char *id,
-                 const char *name, int fd, cap_rights_t rights) {
-
-	int cap = cap_new(fd, rights);
+lc_fdlist_append(struct lc_fdlist *to, struct lc_fdlist *from)
+{
+	int pos = 0;
+
+	/* Use address to order lc_fdlist locks. */
+	if ((uintptr_t)to < (uintptr_t)from) {
+		LOCK(to);
+		LOCK(from);
+	} else {
+		LOCK(from);
+		LOCK(to);
+	}
+
+	for (u_int i = 0; i < from->lf_storage->count; i++) {
+		char *subsystem;
+		char *classname;
+		char *name;
+		int fd;
+
+		/*
+		 * XXXRW: This recurses the from lock.
+		 */
+		if (lc_fdlist_getentry(from, &subsystem, &classname, &name,
+		    &fd, &pos) < 0)
+			goto fail;
+
+		/*
+		 * XXXRW: This recurses the to lock.
+		 */
+		if (lc_fdlist_add(to, subsystem, classname, name, fd) < 0) {
+			free(subsystem);
+			goto fail;
+		}
+		free(subsystem);
+	}
+	return (0);
 
-	return lc_fdlist_add(fdlist, subsystem, id, name, cap);
+fail:
+	UNLOCK(from);
+	UNLOCK(to);
+	return (-1);
 }
 
-
 int
-lc_fdlist_lookup(struct lc_fdlist *l,
-                 const char *subsystem, const char *id, char **name, int *fdp,
-                 int *pos) {
+lc_fdlist_addcap(struct lc_fdlist *fdlist, const char *subsystem,
+    const char *classname, const char *name, int fd, cap_rights_t rights)
+{
+	int capfd;
+
+	/*
+	 * XXXRW: This API isn't particularly caller-friendly, in that it
+	 * allocates a descriptor that the caller is responsible for freeing,
+	 * but doesn't tell the caller what fd that is.  Not yet clear what
+	 * the preferred API is.
+	 */
+	capfd = cap_new(fd, rights);
+	if (capfd < 0)
+		return (-1);
+	return (lc_fdlist_add(fdlist, subsystem, classname, name, capfd));
+}
 
-	if (l == NULL) {
+int
+lc_fdlist_lookup(struct lc_fdlist *lfp, const char *subsystem,
+    const char *classname, char **name, int *fdp, int *pos)
+{
+	struct lc_fdlist_storage *lfsp;
+
+	LOCK(lfp);
+	lfsp = lfp->lf_storage;
+	if ((pos != NULL) && (*pos >= (int)lfsp->count)) {
+		UNLOCK(lfp);
 		errno = EINVAL;
-		return -1;
+		return (-1);
 	}
 
-	LOCK(l);
-
 	int successful = 0;
-	const char *names = lc_fdlist_names(l);
-
-	for (unsigned int i = (pos ? *pos + 1 : 0); i < l->count; i++) {
+	const char *names = lc_fdlist_storage_names(lfsp);
 
-		struct lc_fdlist_entry *entry = l->entries + i;
+	for (u_int i = (pos ? *pos : 0); i < lfsp->count; i++) {
+		struct lc_fdlist_entry *entry = lfsp->entries + i;
 
-		if (!strncmp(subsystem, names + entry->sysoff, entry->syslen + 1)
-		    && !strncmp(id, names + entry->idoff, entry->idlen + 1)) {
+		if ((!subsystem ||
+		    !strncmp(subsystem, names + entry->sysoff,
+		    entry->syslen + 1))
+		    && (!classname || !strncmp(classname, names +
+		    entry->classoff, entry->classnamelen + 1))) {
 
 			/* found a matching entry! */
-			*name = malloc(entry->namelen + 1);
-			strncpy(*name, names + entry->nameoff, entry->namelen + 1);
+			if (name) {
+				*name = malloc(entry->namelen + 1);
+				strncpy(*name, names + entry->nameoff,
+				        entry->namelen + 1);
+			}
 
 			*fdp = entry->fd;
-
-			if (pos) *pos = i;
+			if (pos) *pos = i + 1;
 			successful = 1;
-
 			break;
 		}
 	}
-
-	UNLOCK(l);
-
-	if (successful) return 0;
-	else {
-		errno = ENOENT;
-		return (-1);
-	}
+	UNLOCK(lfp);
+	if (successful)
+		return (0);
+	errno = ENOENT;
+	return (-1);
 }
 
-
 int
-lc_fdlist_size(struct lc_fdlist* l) {
-
-	LOCK(l);
-
-	if (l == NULL) {
+lc_fdlist_getentry(struct lc_fdlist *lfp, char **subsystem, char **classname,
+    char **name, int *fdp, int *pos)
+{
+	struct lc_fdlist_storage *lfsp;
+
+	LOCK(lfp);
+	lfsp = lfp->lf_storage;
+	if ((pos == NULL) || (*pos < 0) || (*pos >= (int) lfsp->count)
+	    || (subsystem == NULL) || (classname == NULL)
+	    || (name == NULL) || (fdp == NULL)) {
 		errno = EINVAL;
 		return (-1);
 	}
 
-	int size = sizeof(struct lc_fdlist)
-		+ l->capacity * sizeof(struct lc_fdlist_entry)
-		+ l->namecapacity;
+	struct lc_fdlist_entry *entry = lfsp->entries + *pos;
+	char *names = lc_fdlist_storage_names(lfsp);
+	int size = entry->syslen + entry->classnamelen + entry->namelen;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002011451.o11EpCJp084674>