Changeset 18709 for trunk/base


Ignore:
Timestamp:
Jul 24, 2006, 5:55:44 AM (14 years ago)
Author:
pguyot (Paul Guyot)
Message:

option -t update : now creations (and file write) outside workpath, and
temporary directories are forbidden (instead of just being reported).

Notes:

file deletion aren't forbidden.
there are other ways to alter the filesystem that aren't trapped and watched.

This works with the following changes:

  • darwintracelib1.0 now can forbid creations/writing outside the sandbox. This is controlled at compile time with a global variable to define the sandbox bounds.
  • option -t of port(1) now uses this feature and reports the violations
  • trace test was updated to work with this new feature (actually, I realized the test only passed on my box because the $pwd was hard coded).
Location:
trunk/base
Files:
7 edited

Legend:

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

    r18692 r18709  
    11/*
    22 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
    3  * $Id: darwintrace.c,v 1.14 2006/07/23 00:36:42 pguyot Exp $
     3 * Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
     4 * All rights reserved.
     5 *
     6 * $Id: darwintrace.c,v 1.15 2006/07/24 05:55:43 pguyot Exp $
    47 *
    58 * @APPLE_BSD_LICENSE_HEADER_START@
     
    5659 * DARWINTRACE_SHOW_PROCESS: show the process id of every access
    5760 * DARWINTRACE_LOG_CREATE: log creation of files as well.
     61 * DARWINTRACE_SANDBOX: control creation and writing to files.
    5862 * DARWINTRACE_LOG_FULL_PATH: use F_GETPATH to log the full path.
    5963 * DARWINTRACE_DEBUG_OUTPUT: verbose output of stuff to debug darwintrace.
     64 *
     65 * global variables (only checked when setup is first called)
     66 * DARWINTRACE_LOG
     67 *    path to the log file (no logging happens if it's unset).
     68 * DARWINTRACE_SANDBOX_BOUNDS
     69 *    : separated allowed paths for the creation of files.
     70 *    \: -> :
     71 *    \\ -> \
    6072 */
    6173
     
    6476#endif
    6577#ifndef DARWINTRACE_LOG_CREATE
    66 #define DARWINTRACE_LOG_CREATE 1
     78#define DARWINTRACE_LOG_CREATE 0
     79#endif
     80#ifndef DARWINTRACE_SANDBOX
     81#define DARWINTRACE_SANDBOX 1
    6782#endif
    6883#ifndef DARWINTRACE_DEBUG_OUTPUT
     
    8095 * Prototypes.
    8196 */
     97inline int __darwintrace_strbeginswith(const char* str, const char* prefix);
    8298inline void __darwintrace_log_op(const char* op, const char* procname, const char* path, int fd);
    8399inline void __darwintrace_setup();
     
    91107static pid_t __darwintrace_pid = -1;
    92108#endif
     109#if DARWINTRACE_SANDBOX
     110static char** __darwintrace_sandbox_bounds = NULL;
     111#endif
    93112
    94113#if __STDC_VERSION__==199901L
     
    105124#endif
    106125#endif
     126
     127/*
     128 * return 0 if str doesn't begin with prefix, 1 otherwise.
     129 */
     130inline int __darwintrace_strbeginswith(const char* str, const char* prefix) {
     131        char theCharS;
     132        char theCharP;
     133        do {
     134                theCharS = *str++;
     135                theCharP = *prefix++;
     136        } while(theCharP && (theCharP == theCharS));
     137        return (theCharP == 0);
     138}
    107139
    108140inline void __darwintrace_setup() {
     
    134166                if (progname && *progname) {
    135167                        strcpy(__darwintrace_progname, *progname);
     168                }
     169        }
     170#endif
     171#if DARWINTRACE_SANDBOX
     172        if (__darwintrace_sandbox_bounds == NULL) {
     173                char* paths = getenv("DARWINTRACE_SANDBOX_BOUNDS");
     174                if (paths != NULL) {
     175                        /* copy the string */
     176                        char* copy = strdup(paths);
     177                        if (copy != NULL) {
     178                                int nbPaths = 1;
     179                                int nbAllocatedPaths = 5;
     180                                char** paths = (char**) malloc(sizeof(char*) * nbAllocatedPaths);
     181                                char* crsr = copy;
     182                                char** pathsCrsr = paths;
     183                                /* first path */
     184                                *pathsCrsr++ = crsr;
     185                                /* parse the paths (modify the copy) */
     186                                do {
     187                                        char theChar = *crsr;
     188                                        if (theChar == '\0') {
     189                                                /* the end of the paths */
     190                                                break;
     191                                        }
     192                                        if (theChar == ':') {
     193                                                /* the end of this path */
     194                                                *crsr = 0;
     195                                                nbPaths++;
     196                                                if (nbPaths == nbAllocatedPaths) {
     197                                                        nbAllocatedPaths += 5;
     198                                                        paths = (char**) realloc(paths, sizeof(char*) * nbAllocatedPaths);
     199                                                        /* reset the cursor in case paths pointer was moved */
     200                                                        pathsCrsr = paths + (nbPaths - 1);
     201                                                }
     202                                                *pathsCrsr++ = crsr + 1;
     203                                        }
     204                                        if (theChar == '\\') {
     205                                                /* escape character. test next char */
     206                                                char nextChar = crsr[1];
     207                                                if (nextChar == '\\') {
     208                                                        /* rewrite the string */
     209                                                        char* rewriteCrsr = crsr + 1;
     210                                                        do {
     211                                                                char theChar = *rewriteCrsr;
     212                                                                rewriteCrsr[-1] = theChar;
     213                                                                rewriteCrsr++;
     214                                                        } while (theChar != 0);
     215                                                } else if (nextChar == ':') {
     216                                                        crsr++;
     217                                                }
     218                                                /* otherwise, ignore (keep the backslash) */
     219                                        }
     220                                       
     221                                        /* next char */
     222                                        crsr++;
     223                                } while (1);
     224                                /* null terminate the array */
     225                                *pathsCrsr = 0;
     226                                /* resize and save it */
     227                                __darwintrace_sandbox_bounds = (char**) realloc(paths, sizeof(char*) * (nbPaths + 1));
     228                        }
    136229                }
    137230        }
     
    258351        mode = va_arg(args, int);
    259352        va_end(args);
     353#if DARWINTRACE_SANDBOX
     354        result = 0;
     355        if (flags & (O_CREAT | O_APPEND | O_RDWR | O_WRONLY | O_TRUNC)) {
     356                __darwintrace_setup();
     357                if (__darwintrace_sandbox_bounds != NULL) {
     358                        /* check the path */
     359                        char** basePathsCrsr = __darwintrace_sandbox_bounds;
     360                        char* basepath = *basePathsCrsr++;
     361                        /* normalize the path */
     362                        char createpath[MAXPATHLEN];
     363                        if (realpath(path, createpath) != NULL) {
     364                                __darwintrace_cleanup_path(createpath);
     365                                /* forbid unless allowed */
     366                                result = -1;
     367                                while (basepath != NULL) {
     368                                        if (__darwintrace_strbeginswith(createpath, basepath)) {
     369                                                result = 0;
     370                                                break;
     371                                        }
     372                                        basepath = *basePathsCrsr++;;
     373                                }
     374                        } /* otherwise, open will fail anyway */
     375                }
     376                if (result == 0) {
     377                        dprintf("darwintrace: creation/writing was allowed at %s\n", path);
     378                }
     379        }
     380        if (result == 0) {
     381                result = open(path, flags, mode);
     382        } else {
     383                dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
     384                __darwintrace_log_op("sandbox_violation", NULL, path, result);
     385                errno = EACCES;
     386        }
     387#else
    260388        result = open(path, flags, mode);
     389#endif
    261390        if (result >= 0) {
    262391                /* check that it's a file */
  • trunk/base/src/port1.0/porttrace.tcl

    r18687 r18709  
    22# porttrace.tcl
    33#
    4 # $Id: porttrace.tcl,v 1.16 2006/07/22 09:16:10 pguyot Exp $
    5 #
    6 # Copyright (c) 2005 Paul Guyot <pguyot@kallisys.net>,
     4# $Id: porttrace.tcl,v 1.17 2006/07/24 05:55:44 pguyot Exp $
     5#
     6# Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
    77# All rights reserved.
    88#
     
    4242                        ui_warn "trace requires Tcl Thread package ($error)"
    4343                } else {
    44                         global env trace_fifo
     44                        global env trace_fifo trace_sandboxbounds
    4545                        # Create a fifo.
    4646                        set trace_fifo "$workpath/trace_fifo"
     
    5757                        set env(DYLD_FORCE_FLAT_NAMESPACE) 1
    5858                        set env(DARWINTRACE_LOG) "$trace_fifo"
    59                 }
     59                        # The sandbox is limited to:
     60                        # workpath
     61                        # /tmp
     62                        # /var/tmp
     63                        # $TMPDIR
     64                        # /dev/null
     65                        # /dev/tty
     66                        set trace_sandboxbounds "/tmp:/var/tmp:/dev/null:/dev/tty:${workpath}"
     67                        if {[info exists env(TMPDIR)]} {
     68                                set trace_sandboxbounds "${trace_sandboxbounds}:$env(TMPDIR)"
     69                        }
     70                }
     71        }
     72}
     73
     74# Enable the fence.
     75# Only done for targets that should only happen in the sandbox.
     76proc trace_enable_fence {} {
     77        global env trace_sandboxbounds
     78        set env(DARWINTRACE_SANDBOX_BOUNDS) $trace_sandboxbounds       
     79}
     80
     81# Disable the fence.
     82# Unused yet.
     83proc trace_disable_fence {} {
     84        global env
     85        if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
     86                unset env(DARWINTRACE_SANDBOX_BOUNDS)
    6087        }
    6188}
     
    83110}
    84111
    85 # Check that no file were created outside workpath.
    86 # Output a warning for every created file the trace revealed.
     112# Check that no violation happened.
     113# Output a warning for every sandbox violation the trace revealed.
    87114# This method must be called after trace_start
    88 proc trace_check_create {} {
    89         # Get the list of created files.
    90         set created [slave_send slave_get_created]
     115proc trace_check_violations {} {
     116        # Get the list of violations.
     117        set violations [slave_send slave_get_sandbox_violations]
    91118       
    92         # Compare with portslist
    93         set created [lsort $created]
    94         foreach created_file $created {
    95                 ui_warn "A file was created outside \${workpath}: $created_file"
     119        foreach violation [lsort $violations] {
     120                ui_warn "A file creation/writing was attempted outside sandbox: $violation"
    96121        }
    97122}
     
    106131                unset env(DYLD_FORCE_FLAT_NAMESPACE)
    107132                unset env(DARWINTRACE_LOG)
     133                if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
     134                        unset env(DARWINTRACE_SANDBOX_BOUNDS)
     135                }
    108136
    109137                # Clean up.
     
    162190# Slave method to read a line from the trace.
    163191proc slave_read_line {chan} {
    164         global ports_list trace_filemap created_list workpath
     192        global ports_list trace_filemap sandbox_violation_list workpath
    165193        global env
    166194
     
    213241                                        }
    214242                                }
    215                         } elseif {$op == "create"} {
    216                                 # Only keep entries not under workpath, under /tmp/, under
    217                                 # /var/tmp/, $TMPDIR and /dev/null
    218                                 if {![string equal -length [string length "/tmp/"] "/tmp/" $path]
    219                                         && ![string equal -length [string length "/var/tmp/"] "/var/tmp/" $path]
    220                                         && (![info exists env(TMPDIR)]
    221                                                 || ![string equal -length [string length $env(TMPDIR)] $env(TMPDIR) $path])
    222                                         && ![string equal "/dev/null" $path]
    223                                         && ![string equal -length [string length $workpath] $workpath $path]} {
    224                                         lappend created_list $path
    225                                 }
     243                        } elseif {$op == "sandbox_violation"} {
     244                                lappend sandbox_violation_list $path
    226245                        }
    227246                }
     
    232251# Slave init method.
    233252proc slave_start {fifo p_workpath} {
    234         global ports_list trace_filemap created_list trace_fifo_r_chan \
     253        global ports_list trace_filemap sandbox_violation_list trace_fifo_r_chan \
    235254                trace_fifo_w_chan workpath
    236255        # Save the workpath.
     
    239258        filemap create trace_filemap
    240259        set ports_list {}
    241         set created_list {}
     260        set sandbox_violation_list {}
    242261        set trace_fifo_r_chan [open $fifo {RDONLY NONBLOCK}]
    243262        # To prevent EOF when darwintrace closes the file, I also open the pipe
     
    271290
    272291# Private.
    273 # Slave created export method.
    274 proc slave_get_created {} {
    275         global created_list
    276         return $created_list
    277 }
     292# Slave sandbox violations export method.
     293proc slave_get_sandbox_violations {} {
     294        global sandbox_violation_list
     295        return $sandbox_violation_list
     296}
  • trunk/base/src/port1.0/portutil.tcl

    r18144 r18709  
    11# et:ts=4
    22# portutil.tcl
    3 # $Id: portutil.tcl,v 1.192 2006/05/29 16:57:03 mww Exp $
     3# $Id: portutil.tcl,v 1.193 2006/07/24 05:55:44 pguyot Exp $
    44#
    55# Copyright (c) 2004 Robert Shaw <rshaw@opendarwin.org>
     
    636636                                && $target != "clean")} {
    637637                                trace_start $workpath
     638
     639                                # Enable the fence to prevent any creation/modification
     640                                # outside the sandbox.
     641                                if {$target != "activate"
     642                                        && $target != "archive"
     643                                        && $target != "fetch"
     644                                        && $target != "install"} {
     645                                        trace_enable_fence
     646                                }
    638647                        }
    639648
     
    709718                                }
    710719                                trace_check_deps $target $depsPorts
     720                                trace_check_violations
    711721                               
    712                                 # Check files that were created.
    713                                 if {$target != "activate"
    714                                         && $target != "archive"
    715                                         && $target != "fetch"
    716                                         && $target != "install"} {
    717                                         trace_check_create
    718                                 }
    719 
    720722                                # End of trace.
    721723                                trace_stop
  • trunk/base/tests/Makefile

    r18681 r18709  
    3434                                PORTSRC=$(PWD)/test-ports.conf $(bindir)/port test > output 2>&1 \
    3535                                        || (cat output; exit 1) && \
    36                         diff output master 2>&1 | tee difference && \
     36                        sed -e "s|${PWD}|PWD|g" < output > output.sed && \
     37                        diff output.sed master 2>&1 | tee difference && \
    3738                        if [ -s difference ]; then \
    3839                                exit 1; \
  • trunk/base/tests/trace/Makefile

    r13743 r18709  
    1010        @PORTSRC=$(PORTSRC) $(bindir)/port clean > /dev/null
    1111        @PORTSRC=$(PORTSRC) $(bindir)/port -t test > output 2>&1 || (cat output; exit 1)
    12         @diff output master 2>&1 | tee difference
     12        @sed -e "s|${PWD}|PWD|g" < output > output.sed
     13        @diff output.sed master 2>&1 | tee difference
    1314        @if [ -s difference ]; then \
    1415                exit 1; \
  • trunk/base/tests/trace/Portfile

    r13743 r18709  
    1 # $Id: Portfile,v 1.1 2005/08/27 07:24:35 pguyot Exp $
     1# $Id: Portfile,v 1.2 2006/07/24 05:55:44 pguyot Exp $
    22
    33PortSystem 1.0
     
    2020
    2121test { 
    22         system "rm -f hello-trace"
    23         system "touch hello-trace"
    24         system "rm hello-trace"
     22        catch {system "rm -f hello-trace && touch hello-trace && rm hello-trace"}
     23        catch {system "rm -f /tmp/hello-trace && /tmp/hello-trace && rm /tmp/hello-trace"}
    2524}
  • trunk/base/tests/trace/master

    r13743 r18709  
    55--->  Building trace with target all
    66--->  Testing trace
    7 Warning: A file was created outside ${workpath}: /Junk/src/opendarwin/darwinports/base/tests/trace/hello-trace
     7Warning: A file creation/writing was attempted outside sandbox: PWD/hello-trace
Note: See TracChangeset for help on using the changeset viewer.