Changeset 124146


Ignore:
Timestamp:
Aug 19, 2014, 11:17:13 PM (6 years ago)
Author:
cal@…
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.
Location:
trunk/base/src
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/darwintracelib1.0/darwintrace.c

    r117959 r124146  
    3838#define DARWINTRACE_USE_PRIVATE_API 1
    3939#include "darwintrace.h"
     40#include "sandbox_actions.h"
    4041
    4142#ifdef HAVE_LIBKERN_OSATOMIC_H
     
    128129 *  1: map the path to the one given in additional_data (currently unsupported)
    129130 *  2: check for a dependency using the socket
     131 *  3: deny access to the path and stop processing
    130132 */
    131133static char *filemap;
    132 
    133 enum {
    134     FILEMAP_ALLOW = 0,
    135     // FILEMAP_REDIR = 1,
    136     FILEMAP_ASK   = 2
    137 };
    138134
    139135/**
     
    672668                                                        return false;
    673669                                        }
     670                                case FILEMAP_DENY:
     671                                        if ((flags & DT_REPORT) > 0) {
     672                                                __darwintrace_log_op("sandbox_violation", path);
     673                                        }
     674                                        return false;
    674675                                default:
    675676                                        fprintf(stderr, "darwintrace: error: unexpected byte in file map: `%x'\n", *t);
  • trunk/base/src/pextlib1.0/Makefile.in

    r123002 r124146  
    1313OBJS+=strlcat.o
    1414endif
     15
     16# tracelib.o has an additional dependency
     17tracelib.o: ../darwintracelib1.0/sandbox_actions.h
    1518
    1619SHLIB_NAME= Pextlib${SHLIB_SUFFIX}
  • trunk/base/src/pextlib1.0/tracelib.c

    r120059 r124146  
    6060#include <cregistry/entry.h>
    6161#include <registry2.0/registry.h>
     62#include <darwintracelib1.0/sandbox_actions.h>
    6263
    6364#include "tracelib.h"
     
    8586static char *name;
    8687static char *sandbox;
    87 static char *filemap, *filemap_end;
     88static size_t sandboxLength;
    8889static char *depends;
    8990static int sock = -1;
     
    9697static pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER;
    9798static int cleanuping = 0;
    98 static char *sdk = NULL;
    9999
    100100static void send_file_map(int sock);
     
    109109#define MAX_SOCKETS (1024)
    110110#define BUFSIZE     (4096)
     111#define CANARY      (0xdeadbeef)
    111112
    112113/**
     
    180181 */
    181182static int TracelibSetSandboxCmd(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
    182     int len;
    183183    char *src, *dst;
    184     enum { NORMAL, ESCAPE } state = NORMAL;
     184    enum { NORMAL, ACTION, ESCAPE } state = NORMAL;
    185185
    186186    if (objc != 3) {
     
    190190
    191191    src = Tcl_GetString(objv[2]);
    192     len = strlen(src) + 2;
    193     sandbox = malloc(len);
     192    sandboxLength = strlen(src) + 2;
     193    sandbox = malloc(sandboxLength);
    194194    if (!sandbox) {
    195195        Tcl_SetResult(interp, "memory allocation failed", TCL_STATIC);
     
    214214                    *dst++ = ':';
    215215                    state = NORMAL;
     216                } else if (state == ACTION) {
     217                    /* : -> \0, we're done with this entry */
     218                    *dst++ = '\0';
     219                    state = NORMAL;
    216220                } else {
    217                     /* : -> \0, unless it has been escaped */
     221                    /* unescaped : should never occur in normal state */
     222                    free(sandbox);
     223                    Tcl_SetResult(interp, "Unexpected colon before action specification.", TCL_STATIC);
     224                    return TCL_ERROR;
     225                }
     226                break;
     227            case '=':
     228                if (state == ESCAPE) {
     229                    /* = was escaped, keep literally */
     230                    *dst++ = '=';
     231                    state = NORMAL;
     232                } else {
     233                    /* hit =, this is the end of the path, the action follows */
    218234                    *dst++ = '\0';
     235                    state = ACTION;
     236                }
     237                break;
     238            case '+':
     239            case '-':
     240            case '?':
     241                if (state == ACTION) {
     242                    /* control character after equals, convert to binary */
     243                    switch (*src) {
     244                        case '+':
     245                            *dst++ = FILEMAP_ALLOW;
     246                            break;
     247                        case '-':
     248                            *dst++ = FILEMAP_DENY;
     249                            break;
     250                        case '?':
     251                            *dst++ = FILEMAP_ASK;
     252                            break;
     253                    }
     254                } else {
     255                    /* before equals sign, copy literally */
     256                    *dst++ = *src;
    219257                }
    220258                break;
     
    223261                    /* unknown escape sequence, free buffer and raise an error */
    224262                    free(sandbox);
    225                     Tcl_SetResult(interp, "unknown escape sequence", TCL_STATIC);
     263                    Tcl_SetResult(interp, "Unknown escape sequence.", TCL_STATIC);
     264                    return TCL_ERROR;
     265                }
     266                if (state == ACTION) {
     267                    /* unknown control character, free buffer and raise an error */
     268                    free(sandbox);
     269                    Tcl_SetResult(interp, "Unknown control character. Possible values are +, -, and ?.", TCL_STATIC);
    226270                    return TCL_ERROR;
    227271                }
     
    311355 */
    312356static void send_file_map(int sock) {
    313     if (!filemap) {
    314         char *t, * _;
    315 
    316         size_t remaining = BUFSIZE;
    317         filemap = (char *)malloc(remaining);
    318         if (!filemap) {
    319             ui_warn("send_file_map: memory allocation failed");
    320             return;
    321         }
    322         t = filemap;
    323 
    324 #       define append_allow(path, resolution) do { strlcpy(t, path, remaining); \
    325             if (remaining < (strlen(t)+3)) { \
    326                 remaining=0; \
    327                 fprintf(stderr, "tracelib: insufficient filemap memory\n"); \
    328             } else { \
    329                 remaining-=strlen(t)+3; \
    330             } \
    331             t+=strlen(t)+1; \
    332             *t++=resolution; \
    333             *t++=0; \
    334         } while(0);
    335 
    336         if (enable_fence) {
    337             for (_ = sandbox; *_; _ += strlen(_) + 1) {
    338                 append_allow(_, 0);
    339             }
    340 
    341             append_allow("/bin", 0);
    342             append_allow("/sbin", 0);
    343             append_allow("/dev", 0);
    344             append_allow(Tcl_GetVar(interp, "prefix", TCL_GLOBAL_ONLY), 2);
    345             /* If there is no SDK we will allow everything in /usr /System/Library etc, else add binaries to allow, and redirect root to SDK. */
    346             if (sdk && *sdk) {
    347                 char buf[260];
    348                 buf[0] = '\0';
    349                 strlcat(buf, Tcl_GetVar(interp, "developer_dir", TCL_GLOBAL_ONLY), 260);
    350                 strlcat(buf, "/SDKs/", 260);
    351                 strlcat(buf, sdk, 260);
    352 
    353                 append_allow("/usr/bin", 0);
    354                 append_allow("/usr/sbin", 0);
    355                 append_allow("/usr/libexec/gcc", 0);
    356                 append_allow("/System/Library/Perl", 0);
    357                 append_allow("/", 1);
    358                 strlcpy(t - 1, buf, remaining);
    359                 t += strlen(t) + 1;
    360             } else {
    361                 append_allow("/usr", 0);
    362                 append_allow("/System/Library", 0);
    363                 append_allow("/Library", 0);
    364                 append_allow(Tcl_GetVar(interp, "developer_dir", TCL_GLOBAL_ONLY), 0);
    365             }
    366         } else {
    367             append_allow("/", 0);
    368         }
    369         append_allow("", 0);
    370         filemap_end = t;
    371 #       undef append_allow
    372     }
    373 
    374     answer_s(sock, filemap, filemap_end - filemap);
     357    if (enable_fence) {
     358        answer_s(sock, sandbox, sandboxLength);
     359    } else {
     360        char allowAllSandbox[5] = {'/', '\0', FILEMAP_ALLOW, '\0', '\0'};
     361        answer_s(sock, allowAllSandbox, sizeof(allowAllSandbox));
     362    }
    375363}
    376364
     
    782770        safe_free(name);
    783771    }
    784     if (filemap) {
    785         safe_free(filemap);
    786     }
    787772    if (depends) {
    788773        safe_free(depends);
     
    839824static int TracelibEnableFence(Tcl_Interp *interp UNUSED) {
    840825    enable_fence = 1;
    841     if (filemap) {
    842         free(filemap);
    843     }
    844     filemap = 0;
    845826    return TCL_OK;
    846827}
  • trunk/base/src/port1.0/porttrace.tcl

    r123425 r124146  
    3838
    3939namespace eval porttrace {
     40    proc appendEntry {sandbox path action} {
     41        upvar 2 $sandbox sndbxlst
     42
     43        set mapping {}
     44        # Escape backslashes with backslashes
     45        lappend mapping "\\" "\\\\"
     46        # Escape colons with \:
     47        lappend mapping ":" "\\:"
     48        # Escape equal signs with \=
     49        lappend mapping "=" "\\="
     50
     51        set normalizedPath [file normalize $path]
     52        lappend sndbxlst "[string map $mapping $path]=$action"
     53        if {$normalizedPath ne $path} {
     54            lappend sndbxlst "[string map $mapping $normalizedPath]=$action"
     55        }
     56    }
     57
     58    ##
     59    # Append a trace sandbox entry suitable for allowing access to
     60    # a directory to a given sandbox list.
     61    #
     62    # @param sandbox The name of the sandbox list variable
     63    # @param path The path that should be permitted
     64    proc allow {sandbox path} {
     65        appendEntry $sandbox $path "+"
     66    }
     67
     68    ##
     69    # Append a trace sandbox entry suitable for denying access to a directory
     70    # (and stopping processing of the sandbox) to a given sandbox list.
     71    #
     72    # @param sandbox The name of the sandbox list variable
     73    # @param path The path that should be denied
     74    proc deny {sandbox path} {
     75        appendEntry $sandbox $path "-"
     76    }
     77
     78    ##
     79    # Append a trace sandbox entry suitable for deferring the access decision
     80    # back to MacPorts to query for dependencies to a given sandbox list.
     81    #
     82    # @param sandbox The name of the sandbox list variable
     83    # @param path The path that should be handed back to MacPorts for further
     84    #             processing.
     85    proc ask {sandbox path} {
     86        appendEntry $sandbox $path "?"
     87    }
    4088}
    4189
    4290proc porttrace::trace_start {workpath} {
    43     global os.platform developer_dir macportsuser
     91    global prefix os.platform developer_dir macportsuser
    4492    if {${os.platform} == "darwin"} {
    4593        if {[catch {package require Thread} error]} {
     
    66114            }
    67115            set env(DARWINTRACE_LOG) "$trace_fifo"
     116
    68117            # The sandbox is limited to:
    69             # workpath
    70             # /tmp
    71             # /private/tmp
    72             # /var/tmp
    73             # /private/var/tmp
    74             # $TMPDIR
    75             # /dev/null
    76             # /dev/tty
    77             # /Library/Caches/com.apple.Xcode
    78             # $CCACHE_DIR
    79             # $HOMEDIR/.ccache
    80             set trace_sandbox [list \
    81             $workpath \
    82             $portpath \
    83             $distpath \
    84             /tmp \
    85             /private/tmp \
    86             /var/tmp \
    87             /private/var/tmp \
    88             /var/folders \
    89             /private/var/folders \
    90             /var/empty \
    91             /private/var/empty \
    92             /var/run \
    93             /private/var/run \
    94             /var/db/xcode_select_link \
    95             /private/var/db/xcode_select_link \
    96             /var/db/mds \
    97             /private/var/db/mds \
    98             /var/db/launchd.db \
    99             /private/var/db/launchd.db \
    100             [file normalize ~${macportsuser}/Library/Preferences/com.apple.dt.Xcode.plist] \
    101             "$env(HOME)/Library/Preferences/com.apple.dt.Xcode.plist" \
    102             /Library/Caches/com.apple.Xcode \
    103             /Library/LaunchDaemons \
    104             /Library/LaunchAgents \
    105             /dev \
    106             /etc/passwd \
    107             /etc/groups \
    108             /etc/localtime \
    109             [file normalize ${developer_dir}/../..] \
    110             "$env(HOME)/.ccache"]
     118            set trace_sandbox [list]
     119
     120            # Allow work-, port-, and distpath
     121            allow trace_sandbox $workpath
     122            allow trace_sandbox $portpath
     123            allow trace_sandbox $distpath
     124
     125            # Allow standard system directories
     126            allow trace_sandbox "/bin"
     127            allow trace_sandbox "/sbin"
     128            allow trace_sandbox "/dev"
     129            allow trace_sandbox "/usr/bin"
     130            allow trace_sandbox "/usr/sbin"
     131            allow trace_sandbox "/usr/include"
     132            allow trace_sandbox "/usr/lib"
     133            allow trace_sandbox "/usr/libexec"
     134            allow trace_sandbox "/usr/share"
     135            allow trace_sandbox "/System/Library"
     136            # Deny /Library/Frameworks, third parties install there
     137            deny  trace_sandbox "/Library/Frameworks"
     138            # But allow the rest of /Library
     139            allow trace_sandbox "/Library"
     140
     141            # Allow a few configuration files
     142            allow trace_sandbox "/etc/passwd"
     143            allow trace_sandbox "/etc/groups"
     144            allow trace_sandbox "/etc/localtime"
     145
     146            # Allow temporary locations
     147            allow trace_sandbox "/tmp"
     148            allow trace_sandbox "/var/tmp"
     149            allow trace_sandbox "/var/folders"
     150            allow trace_sandbox "/var/empty"
     151            allow trace_sandbox "/var/run"
    111152            if {[info exists env(TMPDIR)]} {
    112                 lappend trace_sandbox $env(TMPDIR)
    113             }
     153                set tmpdir [string trim $env(TMPDIR)]
     154                if {$tmpdir ne ""} {
     155                    allow trace_sandbox $tmpdir
     156                }
     157            }
     158
     159            # Allow access to some Xcode specifics
     160            allow trace_sandbox "/var/db/xcode_select_link"
     161            allow trace_sandbox "/var/db/mds"
     162            allow trace_sandbox [file normalize ~${macportsuser}/Library/Preferences/com.apple.dt.Xcode.plist]
     163            allow trace_sandbox "$env(HOME)/Library/Preferences/com.apple.dt.Xcode.plist"
     164
     165            # Allow access to developer_dir; however, if it ends with /Contents/Developer, strip
     166            # that. If it doesn't leave that in place to avoid allowing access to "/"!
     167            set ddsplit [file split [file normalize [file join ${developer_dir} ".." ".."]]]
     168            if {[llength $ddsplit] > 2 && [lindex $ddsplit end-1] eq "Contents" && [lindex $ddsplit end] eq "Developer"} {
     169                set ddsplit [lrange $ddsplit 0 end-2]
     170            }
     171            allow trace_sandbox [file join {*}$ddsplit]
     172
     173            # Allow launchd.db access to avoid failing on port-load(1)/port-unload(1)/port-reload(1)
     174            allow trace_sandbox "/var/db/launchd.db"
     175
     176            # Deal with ccache
     177            allow trace_sandbox "$env(HOME)/.ccache"
    114178            if {[info exists env(CCACHE_DIR)]} {
    115                 lappend trace_sandbox $env(CCACHE_DIR)
    116             }
     179                set ccachedir [string trim $env(CCACHE_DIR)]
     180                if {$ccachedir ne ""} {
     181                    allow trace_sandbox $ccachedir
     182                }
     183            }
     184
     185            # Defer back to MacPorts for dependency checks inside $prefix. This must be at the end,
     186            # or it'll be used instead of more specific rules.
     187            ask trace_sandbox $prefix
    117188
    118189            ui_debug "Tracelib Sandbox is:"
Note: See TracChangeset for help on using the changeset viewer.