Index: trunk/base/src/darwintracelib1.0/darwintrace.c
===================================================================
--- trunk/base/src/darwintracelib1.0/darwintrace.c	(revision 18701)
+++ trunk/base/src/darwintracelib1.0/darwintrace.c	(revision 18709)
@@ -1,5 +1,8 @@
 /*
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- * $Id: darwintrace.c,v 1.14 2006/07/23 00:36:42 pguyot Exp $
+ * Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
+ * All rights reserved.
+ *
+ * $Id: darwintrace.c,v 1.15 2006/07/24 05:55:43 pguyot Exp $
  *
  * @APPLE_BSD_LICENSE_HEADER_START@
@@ -56,6 +59,15 @@
  * DARWINTRACE_SHOW_PROCESS: show the process id of every access
  * DARWINTRACE_LOG_CREATE: log creation of files as well.
+ * DARWINTRACE_SANDBOX: control creation and writing to files.
  * DARWINTRACE_LOG_FULL_PATH: use F_GETPATH to log the full path.
  * DARWINTRACE_DEBUG_OUTPUT: verbose output of stuff to debug darwintrace.
+ *
+ * global variables (only checked when setup is first called)
+ * DARWINTRACE_LOG
+ *    path to the log file (no logging happens if it's unset).
+ * DARWINTRACE_SANDBOX_BOUNDS
+ *    : separated allowed paths for the creation of files.
+ *    \: -> :
+ *    \\ -> \
  */
 
@@ -64,5 +76,8 @@
 #endif
 #ifndef DARWINTRACE_LOG_CREATE
-#define DARWINTRACE_LOG_CREATE 1
+#define DARWINTRACE_LOG_CREATE 0
+#endif
+#ifndef DARWINTRACE_SANDBOX
+#define DARWINTRACE_SANDBOX 1
 #endif
 #ifndef DARWINTRACE_DEBUG_OUTPUT
@@ -80,4 +95,5 @@
  * Prototypes.
  */
+inline int __darwintrace_strbeginswith(const char* str, const char* prefix);
 inline void __darwintrace_log_op(const char* op, const char* procname, const char* path, int fd);
 inline void __darwintrace_setup();
@@ -91,4 +107,7 @@
 static pid_t __darwintrace_pid = -1;
 #endif
+#if DARWINTRACE_SANDBOX
+static char** __darwintrace_sandbox_bounds = NULL;
+#endif
 
 #if __STDC_VERSION__==199901L
@@ -105,4 +124,17 @@
 #endif
 #endif
+
+/*
+ * return 0 if str doesn't begin with prefix, 1 otherwise.
+ */
+inline int __darwintrace_strbeginswith(const char* str, const char* prefix) {
+	char theCharS;
+	char theCharP;
+	do {
+		theCharS = *str++;
+		theCharP = *prefix++;
+	} while(theCharP && (theCharP == theCharS));
+	return (theCharP == 0);
+}
 
 inline void __darwintrace_setup() {
@@ -134,4 +166,65 @@
 		if (progname && *progname) {
 			strcpy(__darwintrace_progname, *progname);
+		}
+	}
+#endif
+#if DARWINTRACE_SANDBOX
+	if (__darwintrace_sandbox_bounds == NULL) {
+		char* paths = getenv("DARWINTRACE_SANDBOX_BOUNDS");
+		if (paths != NULL) {
+			/* copy the string */
+			char* copy = strdup(paths);
+			if (copy != NULL) {
+				int nbPaths = 1;
+				int nbAllocatedPaths = 5;
+				char** paths = (char**) malloc(sizeof(char*) * nbAllocatedPaths);
+				char* crsr = copy;
+				char** pathsCrsr = paths;
+				/* first path */
+				*pathsCrsr++ = crsr;
+				/* parse the paths (modify the copy) */
+				do {
+					char theChar = *crsr;
+					if (theChar == '\0') {
+						/* the end of the paths */
+						break;
+					}
+					if (theChar == ':') {
+						/* the end of this path */
+						*crsr = 0;
+						nbPaths++;
+						if (nbPaths == nbAllocatedPaths) {
+							nbAllocatedPaths += 5;
+							paths = (char**) realloc(paths, sizeof(char*) * nbAllocatedPaths);
+							/* reset the cursor in case paths pointer was moved */
+							pathsCrsr = paths + (nbPaths - 1);
+						}
+						*pathsCrsr++ = crsr + 1;
+					}
+					if (theChar == '\\') {
+						/* escape character. test next char */
+						char nextChar = crsr[1];
+						if (nextChar == '\\') {
+							/* rewrite the string */
+							char* rewriteCrsr = crsr + 1;
+							do {
+								char theChar = *rewriteCrsr;
+								rewriteCrsr[-1] = theChar;
+								rewriteCrsr++;
+							} while (theChar != 0);
+						} else if (nextChar == ':') {
+							crsr++;
+						}
+						/* otherwise, ignore (keep the backslash) */
+					}
+					
+					/* next char */
+					crsr++;
+				} while (1);
+				/* null terminate the array */
+				*pathsCrsr = 0;
+				/* resize and save it */
+				__darwintrace_sandbox_bounds = (char**) realloc(paths, sizeof(char*) * (nbPaths + 1));
+			}
 		}
 	}
@@ -258,5 +351,41 @@
 	mode = va_arg(args, int);
 	va_end(args);
+#if DARWINTRACE_SANDBOX
+	result = 0;
+	if (flags & (O_CREAT | O_APPEND | O_RDWR | O_WRONLY | O_TRUNC)) {
+		__darwintrace_setup();
+		if (__darwintrace_sandbox_bounds != NULL) {
+			/* check the path */
+			char** basePathsCrsr = __darwintrace_sandbox_bounds;
+			char* basepath = *basePathsCrsr++;
+			/* normalize the path */
+			char createpath[MAXPATHLEN];
+			if (realpath(path, createpath) != NULL) {
+				__darwintrace_cleanup_path(createpath);
+				/* forbid unless allowed */
+				result = -1;
+				while (basepath != NULL) {
+					if (__darwintrace_strbeginswith(createpath, basepath)) {
+						result = 0;
+						break;
+					}
+					basepath = *basePathsCrsr++;;
+				}
+			} /* otherwise, open will fail anyway */
+		}
+		if (result == 0) {
+			dprintf("darwintrace: creation/writing was allowed at %s\n", path);
+		}
+	}
+	if (result == 0) {
+		result = open(path, flags, mode);
+	} else {
+		dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
+		__darwintrace_log_op("sandbox_violation", NULL, path, result);
+		errno = EACCES;
+	}
+#else
 	result = open(path, flags, mode);
+#endif
 	if (result >= 0) {
 		/* check that it's a file */
Index: trunk/base/src/port1.0/porttrace.tcl
===================================================================
--- trunk/base/src/port1.0/porttrace.tcl	(revision 18701)
+++ trunk/base/src/port1.0/porttrace.tcl	(revision 18709)
@@ -2,7 +2,7 @@
 # porttrace.tcl
 #
-# $Id: porttrace.tcl,v 1.16 2006/07/22 09:16:10 pguyot Exp $
-#
-# Copyright (c) 2005 Paul Guyot <pguyot@kallisys.net>,
+# $Id: porttrace.tcl,v 1.17 2006/07/24 05:55:44 pguyot Exp $
+#
+# Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
 # All rights reserved.
 #
@@ -42,5 +42,5 @@
 			ui_warn "trace requires Tcl Thread package ($error)"
 		} else {
-			global env trace_fifo
+			global env trace_fifo trace_sandboxbounds
 			# Create a fifo.
 			set trace_fifo "$workpath/trace_fifo"
@@ -57,5 +57,32 @@
 			set env(DYLD_FORCE_FLAT_NAMESPACE) 1
 			set env(DARWINTRACE_LOG) "$trace_fifo"
-		}
+			# The sandbox is limited to:
+			# workpath
+			# /tmp
+			# /var/tmp
+			# $TMPDIR
+			# /dev/null
+			# /dev/tty
+			set trace_sandboxbounds "/tmp:/var/tmp:/dev/null:/dev/tty:${workpath}"
+			if {[info exists env(TMPDIR)]} {
+				set trace_sandboxbounds "${trace_sandboxbounds}:$env(TMPDIR)"
+			}
+		}
+	}
+}
+
+# Enable the fence.
+# Only done for targets that should only happen in the sandbox.
+proc trace_enable_fence {} {
+	global env trace_sandboxbounds
+	set env(DARWINTRACE_SANDBOX_BOUNDS) $trace_sandboxbounds	
+}
+
+# Disable the fence.
+# Unused yet.
+proc trace_disable_fence {} {
+	global env
+	if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
+		unset env(DARWINTRACE_SANDBOX_BOUNDS)
 	}
 }
@@ -83,15 +110,13 @@
 }
 
-# Check that no file were created outside workpath.
-# Output a warning for every created file the trace revealed.
+# Check that no violation happened.
+# Output a warning for every sandbox violation the trace revealed.
 # This method must be called after trace_start
-proc trace_check_create {} {
-	# Get the list of created files.
-	set created [slave_send slave_get_created]
+proc trace_check_violations {} {
+	# Get the list of violations.
+	set violations [slave_send slave_get_sandbox_violations]
 	
-	# Compare with portslist
-	set created [lsort $created]
-	foreach created_file $created {
-		ui_warn "A file was created outside \${workpath}: $created_file"
+	foreach violation [lsort $violations] {
+		ui_warn "A file creation/writing was attempted outside sandbox: $violation"
 	}
 }
@@ -106,4 +131,7 @@
 		unset env(DYLD_FORCE_FLAT_NAMESPACE)
 		unset env(DARWINTRACE_LOG)
+		if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
+			unset env(DARWINTRACE_SANDBOX_BOUNDS)
+		}
 
 		# Clean up.
@@ -162,5 +190,5 @@
 # Slave method to read a line from the trace.
 proc slave_read_line {chan} {
-	global ports_list trace_filemap created_list workpath
+	global ports_list trace_filemap sandbox_violation_list workpath
 	global env
 
@@ -213,15 +241,6 @@
 					}
 				}
-			} elseif {$op == "create"} {
-				# Only keep entries not under workpath, under /tmp/, under
-				# /var/tmp/, $TMPDIR and /dev/null
-				if {![string equal -length [string length "/tmp/"] "/tmp/" $path]
-					&& ![string equal -length [string length "/var/tmp/"] "/var/tmp/" $path]
-					&& (![info exists env(TMPDIR)]
-						|| ![string equal -length [string length $env(TMPDIR)] $env(TMPDIR) $path])
-					&& ![string equal "/dev/null" $path]
-					&& ![string equal -length [string length $workpath] $workpath $path]} {
-					lappend created_list $path
-				}
+			} elseif {$op == "sandbox_violation"} {
+				lappend sandbox_violation_list $path
 			}
 		}
@@ -232,5 +251,5 @@
 # Slave init method.
 proc slave_start {fifo p_workpath} {
-	global ports_list trace_filemap created_list trace_fifo_r_chan \
+	global ports_list trace_filemap sandbox_violation_list trace_fifo_r_chan \
 		trace_fifo_w_chan workpath
 	# Save the workpath.
@@ -239,5 +258,5 @@
 	filemap create trace_filemap
 	set ports_list {}
-	set created_list {}
+	set sandbox_violation_list {}
 	set trace_fifo_r_chan [open $fifo {RDONLY NONBLOCK}]
 	# To prevent EOF when darwintrace closes the file, I also open the pipe
@@ -271,7 +290,7 @@
 
 # Private.
-# Slave created export method.
-proc slave_get_created {} {
-	global created_list
-	return $created_list
-}
+# Slave sandbox violations export method.
+proc slave_get_sandbox_violations {} {
+	global sandbox_violation_list
+	return $sandbox_violation_list
+}
Index: trunk/base/src/port1.0/portutil.tcl
===================================================================
--- trunk/base/src/port1.0/portutil.tcl	(revision 18701)
+++ trunk/base/src/port1.0/portutil.tcl	(revision 18709)
@@ -1,5 +1,5 @@
 # et:ts=4
 # portutil.tcl
-# $Id: portutil.tcl,v 1.192 2006/05/29 16:57:03 mww Exp $
+# $Id: portutil.tcl,v 1.193 2006/07/24 05:55:44 pguyot Exp $
 #
 # Copyright (c) 2004 Robert Shaw <rshaw@opendarwin.org>
@@ -636,4 +636,13 @@
 				&& $target != "clean")} {
 				trace_start $workpath
+
+				# Enable the fence to prevent any creation/modification
+				# outside the sandbox.
+				if {$target != "activate"
+					&& $target != "archive"
+					&& $target != "fetch"
+					&& $target != "install"} {
+					trace_enable_fence
+				}
 			}
 
@@ -709,13 +718,6 @@
 				}
 				trace_check_deps $target $depsPorts
+				trace_check_violations
 				
-				# Check files that were created.
-				if {$target != "activate"
-					&& $target != "archive"
-					&& $target != "fetch"
-					&& $target != "install"} {
-					trace_check_create
-				}
-
 				# End of trace.
 				trace_stop
Index: trunk/base/tests/Makefile
===================================================================
--- trunk/base/tests/Makefile	(revision 18701)
+++ trunk/base/tests/Makefile	(revision 18709)
@@ -34,5 +34,6 @@
 				PORTSRC=$(PWD)/test-ports.conf $(bindir)/port test > output 2>&1 \
 					|| (cat output; exit 1) && \
-			diff output master 2>&1 | tee difference && \
+			sed -e "s|${PWD}|PWD|g" < output > output.sed && \
+			diff output.sed master 2>&1 | tee difference && \
 			if [ -s difference ]; then \
 				exit 1; \
Index: trunk/base/tests/trace/Makefile
===================================================================
--- trunk/base/tests/trace/Makefile	(revision 18701)
+++ trunk/base/tests/trace/Makefile	(revision 18709)
@@ -10,5 +10,6 @@
 	@PORTSRC=$(PORTSRC) $(bindir)/port clean > /dev/null
 	@PORTSRC=$(PORTSRC) $(bindir)/port -t test > output 2>&1 || (cat output; exit 1)
-	@diff output master 2>&1 | tee difference
+	@sed -e "s|${PWD}|PWD|g" < output > output.sed
+	@diff output.sed master 2>&1 | tee difference
 	@if [ -s difference ]; then \
 		exit 1; \
Index: trunk/base/tests/trace/Portfile
===================================================================
--- trunk/base/tests/trace/Portfile	(revision 18701)
+++ trunk/base/tests/trace/Portfile	(revision 18709)
@@ -1,3 +1,3 @@
-# $Id: Portfile,v 1.1 2005/08/27 07:24:35 pguyot Exp $
+# $Id: Portfile,v 1.2 2006/07/24 05:55:44 pguyot Exp $
 
 PortSystem 1.0
@@ -20,6 +20,5 @@
 
 test {  
-	system "rm -f hello-trace"
-	system "touch hello-trace"
-	system "rm hello-trace"
+	catch {system "rm -f hello-trace && touch hello-trace && rm hello-trace"}
+	catch {system "rm -f /tmp/hello-trace && /tmp/hello-trace && rm /tmp/hello-trace"}
 }
Index: trunk/base/tests/trace/master
===================================================================
--- trunk/base/tests/trace/master	(revision 18701)
+++ trunk/base/tests/trace/master	(revision 18709)
@@ -5,3 +5,3 @@
 --->  Building trace with target all
 --->  Testing trace
-Warning: A file was created outside ${workpath}: /Junk/src/opendarwin/darwinports/base/tests/trace/hello-trace
+Warning: A file creation/writing was attempted outside sandbox: PWD/hello-trace
