[124146] trunk/base/src

cal at macports.org cal at macports.org
Tue Aug 19 16:17:13 PDT 2014


Revision: 124146
          https://trac.macports.org/changeset/124146
Author:   cal at macports.org
Date:     2014-08-19 16:17:13 -0700 (Tue, 19 Aug 2014)
Log Message:
-----------
base: darwintrace: fix ignoring of /usr/local and /Library/Frameworks

In detail:
 - Add FILEMAP_DENY action that allows denying access to a specific prefix
   completely (which is required to allow blacklisting /Library/Frameworks
   without listing all 67 other directories in /Library in the sandbox)
 - Move complete sandbox specification into Tcl code for easier, and less
   confusing setup. This includes:
 - No longer implicitly allow / (i.e., everything), if developer_dir is less
   than two levels deep; code was originally added to deal with
   $xcode/Contents/Developer and now does exactly that.
 - No longer allow access to /usr in general since /usr also includes
   /usr/local. Instead, list all directories in /usr explicitly. That should
   also fix includes getting loaded from /usr/X11 -> /opt/X11, but will likely
   break stuff on systems that *do* have X headers installed by Apple in this
   location. We still have copies in MacPorts anyway, so this shouldn't be
   a big deal.

Modified Paths:
--------------
    trunk/base/src/darwintracelib1.0/darwintrace.c
    trunk/base/src/pextlib1.0/Makefile.in
    trunk/base/src/pextlib1.0/tracelib.c
    trunk/base/src/port1.0/porttrace.tcl

Added Paths:
-----------
    trunk/base/src/darwintracelib1.0/sandbox_actions.h

Modified: trunk/base/src/darwintracelib1.0/darwintrace.c
===================================================================
--- trunk/base/src/darwintracelib1.0/darwintrace.c	2014-08-19 23:09:50 UTC (rev 124145)
+++ trunk/base/src/darwintracelib1.0/darwintrace.c	2014-08-19 23:17:13 UTC (rev 124146)
@@ -37,6 +37,7 @@
 
 #define DARWINTRACE_USE_PRIVATE_API 1
 #include "darwintrace.h"
+#include "sandbox_actions.h"
 
 #ifdef HAVE_LIBKERN_OSATOMIC_H
 #include <libkern/OSAtomic.h>
@@ -127,15 +128,10 @@
  *  0: allow
  *  1: map the path to the one given in additional_data (currently unsupported)
  *  2: check for a dependency using the socket
+ *  3: deny access to the path and stop processing
  */
 static char *filemap;
 
-enum {
-    FILEMAP_ALLOW = 0,
-    // FILEMAP_REDIR = 1,
-    FILEMAP_ASK   = 2
-};
-
 /**
  * Setup method called as constructor to set up thread-local storage for the
  * thread id and the darwintrace socket.
@@ -671,6 +667,11 @@
 							}
 							return false;
 					}
+				case FILEMAP_DENY:
+					if ((flags & DT_REPORT) > 0) {
+						__darwintrace_log_op("sandbox_violation", path);
+					}
+					return false;
 				default:
 					fprintf(stderr, "darwintrace: error: unexpected byte in file map: `%x'\n", *t);
 					abort();

Added: trunk/base/src/darwintracelib1.0/sandbox_actions.h
===================================================================
--- trunk/base/src/darwintracelib1.0/sandbox_actions.h	                        (rev 0)
+++ trunk/base/src/darwintracelib1.0/sandbox_actions.h	2014-08-19 23:17:13 UTC (rev 124146)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * $Id$
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * 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.
+ * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+enum {
+    FILEMAP_ALLOW = 0,
+    // FILEMAP_REDIR = 1,
+    FILEMAP_ASK   = 2,
+    FILEMAP_DENY  = 3
+};


Property changes on: trunk/base/src/darwintracelib1.0/sandbox_actions.h
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Rev URL
Added: svn:eol-style
   + native

Modified: trunk/base/src/pextlib1.0/Makefile.in
===================================================================
--- trunk/base/src/pextlib1.0/Makefile.in	2014-08-19 23:09:50 UTC (rev 124145)
+++ trunk/base/src/pextlib1.0/Makefile.in	2014-08-19 23:17:13 UTC (rev 124146)
@@ -13,6 +13,9 @@
 OBJS+=strlcat.o
 endif
 
+# tracelib.o has an additional dependency
+tracelib.o: ../darwintracelib1.0/sandbox_actions.h
+
 SHLIB_NAME= Pextlib${SHLIB_SUFFIX}
 INSTALLDIR= ${DESTDIR}${TCL_PACKAGE_PATH}/pextlib1.0
 

Modified: trunk/base/src/pextlib1.0/tracelib.c
===================================================================
--- trunk/base/src/pextlib1.0/tracelib.c	2014-08-19 23:09:50 UTC (rev 124145)
+++ trunk/base/src/pextlib1.0/tracelib.c	2014-08-19 23:17:13 UTC (rev 124146)
@@ -59,6 +59,7 @@
 #include <cregistry/portgroup.h>
 #include <cregistry/entry.h>
 #include <registry2.0/registry.h>
+#include <darwintracelib1.0/sandbox_actions.h>
 
 #include "tracelib.h"
 
@@ -84,7 +85,7 @@
 
 static char *name;
 static char *sandbox;
-static char *filemap, *filemap_end;
+static size_t sandboxLength;
 static char *depends;
 static int sock = -1;
 static int kq = -1;
@@ -95,7 +96,6 @@
 static Tcl_Interp *interp;
 static pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER;
 static int cleanuping = 0;
-static char *sdk = NULL;
 
 static void send_file_map(int sock);
 static void dep_check(int sock, char *path);
@@ -108,6 +108,7 @@
 
 #define MAX_SOCKETS (1024)
 #define BUFSIZE     (4096)
+#define CANARY      (0xdeadbeef)
 
 /**
  * send a buffer \c buf with the given length \c size to the socket \c sock, by
@@ -179,9 +180,8 @@
  * \return a Tcl return code
  */
 static int TracelibSetSandboxCmd(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
-    int len;
     char *src, *dst;
-    enum { NORMAL, ESCAPE } state = NORMAL;
+    enum { NORMAL, ACTION, ESCAPE } state = NORMAL;
 
     if (objc != 3) {
         Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
@@ -189,8 +189,8 @@
     }
 
     src = Tcl_GetString(objv[2]);
-    len = strlen(src) + 2;
-    sandbox = malloc(len);
+    sandboxLength = strlen(src) + 2;
+    sandbox = malloc(sandboxLength);
     if (!sandbox) {
         Tcl_SetResult(interp, "memory allocation failed", TCL_STATIC);
         return TCL_ERROR;
@@ -213,18 +213,62 @@
                     /* : was escaped, keep literally */
                     *dst++ = ':';
                     state = NORMAL;
+                } else if (state == ACTION) {
+                    /* : -> \0, we're done with this entry */
+                    *dst++ = '\0';
+                    state = NORMAL;
                 } else {
-                    /* : -> \0, unless it has been escaped */
+                    /* unescaped : should never occur in normal state */
+                    free(sandbox);
+                    Tcl_SetResult(interp, "Unexpected colon before action specification.", TCL_STATIC);
+                    return TCL_ERROR;
+                }
+                break;
+            case '=':
+                if (state == ESCAPE) {
+                    /* = was escaped, keep literally */
+                    *dst++ = '=';
+                    state = NORMAL;
+                } else {
+                    /* hit =, this is the end of the path, the action follows */
                     *dst++ = '\0';
+                    state = ACTION;
                 }
                 break;
+            case '+':
+            case '-':
+            case '?':
+                if (state == ACTION) {
+                    /* control character after equals, convert to binary */
+                    switch (*src) {
+                        case '+':
+                            *dst++ = FILEMAP_ALLOW;
+                            break;
+                        case '-':
+                            *dst++ = FILEMAP_DENY;
+                            break;
+                        case '?':
+                            *dst++ = FILEMAP_ASK;
+                            break;
+                    }
+                } else {
+                    /* before equals sign, copy literally */
+                    *dst++ = *src;
+                }
+                break;
             default:
                 if (state == ESCAPE) {
                     /* unknown escape sequence, free buffer and raise an error */
                     free(sandbox);
-                    Tcl_SetResult(interp, "unknown escape sequence", TCL_STATIC);
+                    Tcl_SetResult(interp, "Unknown escape sequence.", TCL_STATIC);
                     return TCL_ERROR;
                 }
+                if (state == ACTION) {
+                    /* unknown control character, free buffer and raise an error */
+                    free(sandbox);
+                    Tcl_SetResult(interp, "Unknown control character. Possible values are +, -, and ?.", TCL_STATIC);
+                    return TCL_ERROR;
+                }
                 /* otherwise: copy the char */
                 *dst++ = *src;
                 break;
@@ -310,68 +354,12 @@
  * \param[in] sock the socket to send the sandbox bounds to
  */
 static void send_file_map(int sock) {
-    if (!filemap) {
-        char *t, * _;
-
-        size_t remaining = BUFSIZE;
-        filemap = (char *)malloc(remaining);
-        if (!filemap) {
-            ui_warn("send_file_map: memory allocation failed");
-            return;
-        }
-        t = filemap;
-
-#       define append_allow(path, resolution) do { strlcpy(t, path, remaining); \
-            if (remaining < (strlen(t)+3)) { \
-                remaining=0; \
-                fprintf(stderr, "tracelib: insufficient filemap memory\n"); \
-            } else { \
-                remaining-=strlen(t)+3; \
-            } \
-            t+=strlen(t)+1; \
-            *t++=resolution; \
-            *t++=0; \
-        } while(0);
-
-        if (enable_fence) {
-            for (_ = sandbox; *_; _ += strlen(_) + 1) {
-                append_allow(_, 0);
-            }
-
-            append_allow("/bin", 0);
-            append_allow("/sbin", 0);
-            append_allow("/dev", 0);
-            append_allow(Tcl_GetVar(interp, "prefix", TCL_GLOBAL_ONLY), 2);
-            /* If there is no SDK we will allow everything in /usr /System/Library etc, else add binaries to allow, and redirect root to SDK. */
-            if (sdk && *sdk) {
-                char buf[260];
-                buf[0] = '\0';
-                strlcat(buf, Tcl_GetVar(interp, "developer_dir", TCL_GLOBAL_ONLY), 260);
-                strlcat(buf, "/SDKs/", 260);
-                strlcat(buf, sdk, 260);
-
-                append_allow("/usr/bin", 0);
-                append_allow("/usr/sbin", 0);
-                append_allow("/usr/libexec/gcc", 0);
-                append_allow("/System/Library/Perl", 0);
-                append_allow("/", 1);
-                strlcpy(t - 1, buf, remaining);
-                t += strlen(t) + 1;
-            } else {
-                append_allow("/usr", 0);
-                append_allow("/System/Library", 0);
-                append_allow("/Library", 0);
-                append_allow(Tcl_GetVar(interp, "developer_dir", TCL_GLOBAL_ONLY), 0);
-            }
-        } else {
-            append_allow("/", 0);
-        }
-        append_allow("", 0);
-        filemap_end = t;
-#       undef append_allow
+    if (enable_fence) {
+        answer_s(sock, sandbox, sandboxLength);
+    } else {
+        char allowAllSandbox[5] = {'/', '\0', FILEMAP_ALLOW, '\0', '\0'};
+        answer_s(sock, allowAllSandbox, sizeof(allowAllSandbox));
     }
-
-    answer_s(sock, filemap, filemap_end - filemap);
 }
 
 /**
@@ -781,9 +769,6 @@
         unlink(name);
         safe_free(name);
     }
-    if (filemap) {
-        safe_free(filemap);
-    }
     if (depends) {
         safe_free(depends);
     }
@@ -838,10 +823,6 @@
 
 static int TracelibEnableFence(Tcl_Interp *interp UNUSED) {
     enable_fence = 1;
-    if (filemap) {
-        free(filemap);
-    }
-    filemap = 0;
     return TCL_OK;
 }
 #endif /* defined(HAVE_TRACEMODE_SUPPORT) */

Modified: trunk/base/src/port1.0/porttrace.tcl
===================================================================
--- trunk/base/src/port1.0/porttrace.tcl	2014-08-19 23:09:50 UTC (rev 124145)
+++ trunk/base/src/port1.0/porttrace.tcl	2014-08-19 23:17:13 UTC (rev 124146)
@@ -37,10 +37,58 @@
 package require portutil 1.0
 
 namespace eval porttrace {
+    proc appendEntry {sandbox path action} {
+        upvar 2 $sandbox sndbxlst
+
+        set mapping {}
+        # Escape backslashes with backslashes
+        lappend mapping "\\" "\\\\"
+        # Escape colons with \:
+        lappend mapping ":" "\\:"
+        # Escape equal signs with \=
+        lappend mapping "=" "\\="
+
+        set normalizedPath [file normalize $path]
+        lappend sndbxlst "[string map $mapping $path]=$action"
+        if {$normalizedPath ne $path} {
+            lappend sndbxlst "[string map $mapping $normalizedPath]=$action"
+        }
+    }
+
+    ##
+    # Append a trace sandbox entry suitable for allowing access to
+    # a directory to a given sandbox list.
+    #
+    # @param sandbox The name of the sandbox list variable
+    # @param path The path that should be permitted
+    proc allow {sandbox path} {
+        appendEntry $sandbox $path "+"
+    }
+
+    ##
+    # Append a trace sandbox entry suitable for denying access to a directory
+    # (and stopping processing of the sandbox) to a given sandbox list.
+    #
+    # @param sandbox The name of the sandbox list variable
+    # @param path The path that should be denied
+    proc deny {sandbox path} {
+        appendEntry $sandbox $path "-"
+    }
+
+    ##
+    # Append a trace sandbox entry suitable for deferring the access decision
+    # back to MacPorts to query for dependencies to a given sandbox list.
+    #
+    # @param sandbox The name of the sandbox list variable
+    # @param path The path that should be handed back to MacPorts for further
+    #             processing.
+    proc ask {sandbox path} {
+        appendEntry $sandbox $path "?"
+    }
 }
 
 proc porttrace::trace_start {workpath} {
-    global os.platform developer_dir macportsuser
+    global prefix os.platform developer_dir macportsuser
     if {${os.platform} == "darwin"} {
         if {[catch {package require Thread} error]} {
             ui_warn "trace requires Tcl Thread package ($error)"
@@ -65,56 +113,79 @@
                 set env(DYLD_INSERT_LIBRARIES) ${tracelib_path}
             }
             set env(DARWINTRACE_LOG) "$trace_fifo"
+
             # The sandbox is limited to:
-            # workpath
-            # /tmp
-            # /private/tmp
-            # /var/tmp
-            # /private/var/tmp
-            # $TMPDIR
-            # /dev/null
-            # /dev/tty
-            # /Library/Caches/com.apple.Xcode
-            # $CCACHE_DIR
-            # $HOMEDIR/.ccache
-            set trace_sandbox [list \
-            $workpath \
-            $portpath \
-            $distpath \
-            /tmp \
-            /private/tmp \
-            /var/tmp \
-            /private/var/tmp \
-            /var/folders \
-            /private/var/folders \
-            /var/empty \
-            /private/var/empty \
-            /var/run \
-            /private/var/run \
-            /var/db/xcode_select_link \
-            /private/var/db/xcode_select_link \
-            /var/db/mds \
-            /private/var/db/mds \
-            /var/db/launchd.db \
-            /private/var/db/launchd.db \
-            [file normalize ~${macportsuser}/Library/Preferences/com.apple.dt.Xcode.plist] \
-            "$env(HOME)/Library/Preferences/com.apple.dt.Xcode.plist" \
-            /Library/Caches/com.apple.Xcode \
-            /Library/LaunchDaemons \
-            /Library/LaunchAgents \
-            /dev \
-            /etc/passwd \
-            /etc/groups \
-            /etc/localtime \
-            [file normalize ${developer_dir}/../..] \
-            "$env(HOME)/.ccache"]
+            set trace_sandbox [list]
+
+            # Allow work-, port-, and distpath
+            allow trace_sandbox $workpath
+            allow trace_sandbox $portpath
+            allow trace_sandbox $distpath
+
+            # Allow standard system directories
+            allow trace_sandbox "/bin"
+            allow trace_sandbox "/sbin"
+            allow trace_sandbox "/dev"
+            allow trace_sandbox "/usr/bin"
+            allow trace_sandbox "/usr/sbin"
+            allow trace_sandbox "/usr/include"
+            allow trace_sandbox "/usr/lib"
+            allow trace_sandbox "/usr/libexec"
+            allow trace_sandbox "/usr/share"
+            allow trace_sandbox "/System/Library"
+            # Deny /Library/Frameworks, third parties install there
+            deny  trace_sandbox "/Library/Frameworks"
+            # But allow the rest of /Library
+            allow trace_sandbox "/Library"
+
+            # Allow a few configuration files
+            allow trace_sandbox "/etc/passwd"
+            allow trace_sandbox "/etc/groups"
+            allow trace_sandbox "/etc/localtime"
+
+            # Allow temporary locations
+            allow trace_sandbox "/tmp"
+            allow trace_sandbox "/var/tmp"
+            allow trace_sandbox "/var/folders"
+            allow trace_sandbox "/var/empty"
+            allow trace_sandbox "/var/run"
             if {[info exists env(TMPDIR)]} {
-                lappend trace_sandbox $env(TMPDIR)
+                set tmpdir [string trim $env(TMPDIR)]
+                if {$tmpdir ne ""} {
+                    allow trace_sandbox $tmpdir
+                }
             }
+
+            # Allow access to some Xcode specifics
+            allow trace_sandbox "/var/db/xcode_select_link"
+            allow trace_sandbox "/var/db/mds"
+            allow trace_sandbox [file normalize ~${macportsuser}/Library/Preferences/com.apple.dt.Xcode.plist]
+            allow trace_sandbox "$env(HOME)/Library/Preferences/com.apple.dt.Xcode.plist"
+
+            # Allow access to developer_dir; however, if it ends with /Contents/Developer, strip
+            # that. If it doesn't leave that in place to avoid allowing access to "/"!
+            set ddsplit [file split [file normalize [file join ${developer_dir} ".." ".."]]]
+            if {[llength $ddsplit] > 2 && [lindex $ddsplit end-1] eq "Contents" && [lindex $ddsplit end] eq "Developer"} {
+                set ddsplit [lrange $ddsplit 0 end-2]
+            }
+            allow trace_sandbox [file join {*}$ddsplit]
+
+            # Allow launchd.db access to avoid failing on port-load(1)/port-unload(1)/port-reload(1)
+            allow trace_sandbox "/var/db/launchd.db"
+
+            # Deal with ccache
+            allow trace_sandbox "$env(HOME)/.ccache"
             if {[info exists env(CCACHE_DIR)]} {
-                lappend trace_sandbox $env(CCACHE_DIR)
+                set ccachedir [string trim $env(CCACHE_DIR)]
+                if {$ccachedir ne ""} {
+                    allow trace_sandbox $ccachedir
+                }
             }
 
+            # Defer back to MacPorts for dependency checks inside $prefix. This must be at the end,
+            # or it'll be used instead of more specific rules.
+            ask trace_sandbox $prefix
+
             ui_debug "Tracelib Sandbox is:"
             foreach sandbox $trace_sandbox {
                 ui_debug "\t$sandbox"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20140819/7338dd45/attachment-0001.html>


More information about the macports-changes mailing list