svn commit: r203242 - projects/capabilities8/lib/libcapability

Robert Watson rwatson at FreeBSD.org
Sat Jan 30 20:06:52 UTC 2010


Author: rwatson
Date: Sat Jan 30 20:06:52 2010
New Revision: 203242
URL: http://svn.freebsd.org/changeset/base/203242

Log:
  Merge c173834 from the p4 TrustedBSD Capabilities branch to capabilities8:
  
    Initial lc_fdlist work. No mmap'ing yet.
  
  Submitted by:	Jonathan Anderson <jonathan.anderson at cl.cam.ac.uk>

Added:
  projects/capabilities8/lib/libcapability/libcapability_fdlist.c
Modified:
  projects/capabilities8/lib/libcapability/Makefile
  projects/capabilities8/lib/libcapability/libcapability.h

Modified: projects/capabilities8/lib/libcapability/Makefile
==============================================================================
--- projects/capabilities8/lib/libcapability/Makefile	Sat Jan 30 20:04:59 2010	(r203241)
+++ projects/capabilities8/lib/libcapability/Makefile	Sat Jan 30 20:06:52 2010	(r203242)
@@ -10,7 +10,7 @@ SRCS=					\
 	libcapability_sandbox_io.c	\
 	libcapability_host.c		\
 	libcapability_host_io.c		\
-	libcapability_registry.c
+	libcapability_fdlist.c
 
 INCS=	libcapability.h
 

Modified: projects/capabilities8/lib/libcapability/libcapability.h
==============================================================================
--- projects/capabilities8/lib/libcapability/libcapability.h	Sat Jan 30 20:04:59 2010	(r203241)
+++ projects/capabilities8/lib/libcapability/libcapability.h	Sat Jan 30 20:06:52 2010	(r203242)
@@ -30,13 +30,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#26 $
+ * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability.h#27 $
  */
 
 #ifndef _LIBCAPABILITY_H_
 #define	_LIBCAPABILITY_H_
 
 #include <sys/cdefs.h>
+#include <sys/capability.h>
 
 __BEGIN_DECLS
 
@@ -52,29 +53,53 @@ struct lc_library {
 	int		 lcl_fd;
 };
 
-/*
- * A file descriptor "registry"
- */
-struct lc_fdregistry_entry;
-struct lc_fdregistry {
-	struct lc_fdregistry_entry *entries;	/* registry entries */
 
-	unsigned int count;			/* number of entries */
-	unsigned int capacity;			/* entries that we can hold */
-};
+/* 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_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);
+
 
 /*
- * Registry operations
+ * Add a file descriptor to the list.
+ *
+ * l		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
  */
-struct lc_fdregistry*	lc_fdregistry_new(void);
-struct lc_fdregistry*	lc_fdregistry_dup(const struct lc_fdregistry *orig);
-void			lc_fdregistry_free(struct lc_fdregistry *registry);
+int	lc_fdlist_add(struct lc_fdlist **l,
+	              const char *subsystem, const char *classname,
+	              const char *name, int fd);
 
-int	lc_fdregistry_add(const struct lc_fdregistry *reg,
-	                  const char *id, 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);
 
-int	lc_fdregistry_lookup(const struct lc_fdregistry *reg,
-	                     const char *id, char **name, int *fdp);
+/*
+ * 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);
 
 /*
  * Capability interfaces.

Added: projects/capabilities8/lib/libcapability/libcapability_fdlist.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/capabilities8/lib/libcapability/libcapability_fdlist.c	Sat Jan 30 20:06:52 2010	(r203242)
@@ -0,0 +1,332 @@
+/*-
+ * Copyright (c) 2009 Jonathan Anderson
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $P4: //depot/projects/trustedbsd/capabilities/src/lib/libcapability/libcapability_fdlist.c#1 $
+ */
+
+#include <errno.h>
+#include <libcapability.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.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 */
+
+	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 */
+
+	/* followed by bytes of name data */
+};
+
+
+
+
+#define LOCK(l)		pthread_mutex_lock(&((l)->lock));
+#define UNLOCK(l)		pthread_mutex_unlock(&((l)->lock));
+
+/* Where an FD list's name byte array starts */
+char*	lc_fdlist_names(struct lc_fdlist *l);
+
+
+
+#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;
+	}
+
+	return fdlist;
+}
+
+
+struct lc_fdlist*
+lc_fdlist_dup(struct lc_fdlist *orig) {
+
+	LOCK(orig);
+
+	int size = lc_fdlist_size(orig);
+
+	struct lc_fdlist *copy = malloc(size);
+	if (copy == NULL) return (NULL);
+
+	UNLOCK(orig);
+
+	return copy;
+}
+
+
+void
+lc_fdlist_free(struct lc_fdlist *l) {
+
+	LOCK(l);
+
+	pthread_mutex_destroy(&l->lock);
+	free(l);
+}
+
+
+
+int
+lc_fdlist_add(struct lc_fdlist **fdlist,
+              const char *subsystem, const char *id,
+              const char *name, int fd) {
+
+	struct lc_fdlist *l = *fdlist;
+
+	LOCK(l);
+
+	/* do we need more entry space? */
+	if (l->count == l->capacity) {
+
+		/* move name data out of the way */
+		char *tmp = NULL;
+		if (l->namelen > 0) {
+			tmp = malloc(l->namelen);
+			if (tmp == NULL) {
+				UNLOCK(l);
+				return (-1);
+			}
+
+			memcpy(tmp, lc_fdlist_names(l), l->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) {
+			free(tmp);
+			UNLOCK(l);
+			return (-1);
+		}
+
+		copy->capacity		*= 2;
+		copy->namecapacity	+= newnamebytes;
+
+		/* copy name bytes back */
+		if (copy->namelen > 0)
+			memcpy(lc_fdlist_names(copy), tmp, copy->namelen);
+
+		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);
+			return (-1);
+		}
+
+		enlarged->namecapacity *= 2;
+		*fdlist = enlarged;
+		l = *fdlist;
+	}
+
+
+	/* create the new entry */
+	struct lc_fdlist_entry *entry = l->entries + l->count;
+
+	entry->fd = fd;
+
+	char *names = lc_fdlist_names(l);
+	char *head = names + l->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;
+
+	strncpy(head, name, namelen + 1);
+	entry->nameoff	= (head - names);
+	entry->namelen	= namelen + 1;
+	head		+= namelen + 1;
+
+	l->count++;
+	l->namelen = (head - names);
+
+	UNLOCK(l);
+
+	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);
+
+	return lc_fdlist_add(fdlist, subsystem, id, name, cap);
+}
+
+
+int
+lc_fdlist_lookup(struct lc_fdlist *l,
+                 const char *subsystem, const char *id, char **name, int *fdp,
+                 int *pos) {
+
+	LOCK(l);
+
+	int successful = 0;
+	const char *names = lc_fdlist_names(l);
+
+	for (unsigned int i = (pos ? *pos + 1 : 0); i < l->count; i++) {
+
+		struct lc_fdlist_entry *entry = l->entries + i;
+
+		if (!strncmp(subsystem, names + entry->sysoff, entry->syslen + 1)
+		    && !strncmp(id, names + entry->idoff, entry->idlen + 1)) {
+
+			/* found a matching entry! */
+			*name = malloc(entry->namelen + 1);
+			strncpy(*name, names + entry->nameoff, entry->namelen + 1);
+
+			*fdp = entry->fd;
+
+			if (pos) *pos = i;
+			successful = 1;
+
+			break;
+		}
+	}
+
+	UNLOCK(l);
+
+	if (successful) return 0;
+	else {
+		errno = ENOENT;
+		return (-1);
+	}
+}
+
+
+int
+lc_fdlist_size(struct lc_fdlist* l) {
+
+	LOCK(l);
+
+	if (l == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	int size = sizeof(struct lc_fdlist)
+		+ l->capacity * sizeof(struct lc_fdlist_entry)
+		+ l->namecapacity;
+
+	UNLOCK(l);
+
+	return size;
+}
+
+
+char*
+lc_fdlist_names(struct lc_fdlist *l) {
+
+	LOCK(l);
+
+	if (l == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	char *names = ((char*) l) + lc_fdlist_size(l) - l->namecapacity;
+
+	UNLOCK(l);
+
+	return names;
+}
+


More information about the svn-src-projects mailing list