add rudimentary sandboxing support for commands run via system proc

git-svn-id: https://svn.macports.org/repository/macports/trunk/base@98156 d073be05-634f-4543-b044-5fe20cf6d1d6
This commit is contained in:
Joshua Root
2012-09-26 16:16:41 +00:00
parent c19772244d
commit b30559f404
7 changed files with 167 additions and 7 deletions
Vendored
+41
View File
@@ -710,6 +710,7 @@ TAR
SWIG
SVN
SED
SANDBOX_EXEC
RSYNC
RMDIR
PAX
@@ -5544,6 +5545,46 @@ $as_echo "no" >&6; }
fi
# Extract the first word of "sandbox-exec", so it can be a program name with args.
set dummy sandbox-exec; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_SANDBOX_EXEC+:} false; then :
$as_echo_n "(cached) " >&6
else
case $SANDBOX_EXEC in
[\\/]* | ?:[\\/]*)
ac_cv_path_SANDBOX_EXEC="$SANDBOX_EXEC" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in /usr/bin
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_SANDBOX_EXEC="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
SANDBOX_EXEC=$ac_cv_path_SANDBOX_EXEC
if test -n "$SANDBOX_EXEC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SANDBOX_EXEC" >&5
$as_echo "$SANDBOX_EXEC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
# Extract the first word of "sed", so it can be a program name with args.
set dummy sed; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+1
View File
@@ -133,6 +133,7 @@ AC_PATH_PROG(PATCH, [patch], [])
AC_PATH_PROG(PAX, [pax], [])
AC_PATH_PROG(RMDIR, [rmdir], [])
AC_PATH_PROG(RSYNC, [rsync], [])
AC_PATH_PROG(SANDBOX_EXEC, [sandbox-exec], [], [/usr/bin])
AC_PATH_PROG(SED, [sed])
AC_PATH_PROG(SVN, [svn], [])
AC_PATH_PROG(SWIG, [swig], [], [$PATH:/usr/local/bin])
+50 -6
View File
@@ -77,14 +77,42 @@ struct linebuf {
char *line;
};
static int check_sandboxing(Tcl_Interp *interp, char **sandbox_exec_path, char **profilestr)
{
Tcl_Obj *tcl_result;
int supported;
int len;
tcl_result = Tcl_GetVar2Ex(interp, "portsandbox_supported", NULL, TCL_GLOBAL_ONLY);
if (!tcl_result || Tcl_GetBooleanFromObj(interp, tcl_result, &supported) != TCL_OK || !supported) {
return 0;
}
tcl_result = Tcl_GetVar2Ex(interp, "portutil::autoconf::sandbox_exec_path", NULL, TCL_GLOBAL_ONLY);
if (!tcl_result || !(*sandbox_exec_path = Tcl_GetString(tcl_result))) {
return 0;
}
tcl_result = Tcl_GetVar2Ex(interp, "portsandbox_profile", NULL, TCL_GLOBAL_ONLY);
if (!tcl_result || !(*profilestr = Tcl_GetStringFromObj(tcl_result, &len))
|| len == 0) {
return 0;
}
return 1;
}
/* usage: system ?-notty? ?-nice value? ?-W path? command */
int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *buf;
struct linebuf circbuf[CBUFSIZ];
size_t linelen;
char *args[4];
char *args[7];
char *cmdstring;
int sandbox = 0;
char *sandbox_exec_path;
char *profilestr;
FILE *pdes;
int fdset[2], nullfd;
int fline, pos, ret;
@@ -128,6 +156,11 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
}
}
#if 0
/* check if and how we should use sandbox-exec */
sandbox = check_sandboxing(interp, &sandbox_exec_path, &profilestr);
#endif
/*
* Fork a child to run the command, in a popen() like fashion -
* popen() itself is not used because stderr is also desired.
@@ -178,11 +211,22 @@ int SystemCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Ob
}
/* XXX ugly string constants */
args[0] = "sh";
args[1] = "-c";
args[2] = cmdstring;
args[3] = NULL;
execve("/bin/sh", args, environ);
if (sandbox) {
args[0] = "sandbox-exec";
args[1] = "-p";
args[2] = profilestr;
args[3] = "sh";
args[4] = "-c";
args[5] = cmdstring;
args[6] = NULL;
execve(sandbox_exec_path, args, environ);
} else {
args[0] = "sh";
args[1] = "-c";
args[2] = cmdstring;
args[3] = NULL;
execve("/bin/sh", args, environ);
}
_exit(1);
break;
default: /* parent */
+2 -1
View File
@@ -6,7 +6,8 @@ SRCS= port.tcl portchecksum.tcl portconfigure.tcl portextract.tcl \
portlint.tcl portclean.tcl porttest.tcl portactivate.tcl \
portdeactivate.tcl portsubmit.tcl port_autoconf.tcl portstartupitem.tcl \
porttrace.tcl portlivecheck.tcl portdistcheck.tcl portmirror.tcl \
portload.tcl portunload.tcl portdistfiles.tcl fetch_common.tcl
portload.tcl portunload.tcl portdistfiles.tcl fetch_common.tcl \
portsandbox.tcl
include ../../Mk/macports.subdir.mk
include ../../Mk/macports.autoconf.mk
+1
View File
@@ -58,3 +58,4 @@ package require portload 1.0
package require portunload 1.0
package require portdistfiles 1.0
package require portsandbox 1.0
+1
View File
@@ -65,6 +65,7 @@ namespace eval portutil::autoconf {
variable xcode_select_path "@XCODE_SELECT@"
variable xcodebuild_path "@XCODEBUILD@"
variable xcrun_path "@XCRUN@"
variable sandbox_exec_path "@SANDBOX_EXEC@"
variable sed_command "@SED@"
variable sed_ext_flag "@SED_EXT@"
variable tar_command "@TAR_CMD@"
+71
View File
@@ -0,0 +1,71 @@
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
# $Id$
#
# Copyright (c) 2012 The MacPorts Project
#
# 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 The MacPorts Project 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 THE COPYRIGHT HOLDERS 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 COPYRIGHT
# OWNER 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.
package provide portsandbox 1.0
namespace eval portsandbox {
}
options portsandbox_supported portsandbox_profile
default portsandbox_supported {[file executable $portutil::autoconf::sandbox_exec_path]}
default portsandbox_profile {[portsandbox::get_default_profile]}
# produce a suitable profile to pass to sandbox-exec
# command line usage would be:
# sandbox-exec -p '(version 1) (allow default) (deny file* (subpath "/usr/local") (subpath "/Library/Frameworks"))' some-command
proc portsandbox::get_default_profile {} {
global os.major prefix frameworks_dir
set prefix_conflict [expr {$prefix == "/usr/local" || [string match $prefix "/usr/local/*"]}]
set frameworks_conflict [expr {$frameworks_dir == "/Library/Frameworks" || [string match $frameworks_dir "/Library/Frameworks/*"]}]
if {$prefix_conflict && $frameworks_conflict} {
return ""
}
set profile "(version 1) (allow default) (deny "
if {${os.major} > 9} {
append profile "file* "
if {!$prefix_conflict} {
append profile {(subpath "/usr/local")}
}
if {!$frameworks_conflict} {
append profile { (subpath "/Library/Frameworks")}
}
} else {
append profile "file-read* file-write* (regex "
if {!$prefix_conflict} {
append profile {#"^/usr/local/"}
}
if {!$frameworks_conflict} {
append profile { #"^/Library/Frameworks/"}
}
append profile ")"
}
append profile ")"
return $profile
}