[141420] trunk/base
cal at macports.org
cal at macports.org
Sat Dec 12 01:27:24 PST 2015
Revision: 141420
https://trac.macports.org/changeset/141420
Author: cal at macports.org
Date: 2015-10-17 17:49:32 -0700 (Sat, 17 Oct 2015)
Log Message:
-----------
base: Fix trace mode on El Capitan
OS X El Capitan introduces System Integrity Protection for files. Executables
with this flag set will be started in a sanitized environment by the kernel,
stripping all DYLD_* variables. This breaks trace mode, because tracing relies
on preloading to wrap file related system calls using DYLD_INSERT_LIBRARIES.
A trivial workaround for the problem is to make a copy of the affected
binaries, which will strip the flag, and then adjust the invocation of the
binary to execute the copy instead (but leaving argv[0] as-is to avoid giving
the program an indication of being run from a non-standard location).
This change implements this approach by copying the SIP-flagged binaries to
$prefix/var/macports/sip-workaround on demand iff
- the system has the SF_RESTRICTED flag defined
- a binary is started with DYLD_INSERT_LIBRARIES set
- the file exists and has SF_RESTRICTED set
- the file isn't SUID or SGID (which we could not reliably copy, and which
have never preserved DYLD_* variables)
If the file to be executed is a script and has a shebang line, the checks are
run on the interpreter instead, and if necessary, the interpreter is copied.
This requires interpreting the shebang line in user space.
Copies are created on-demand and are lazy: The file modification times are
checked before overwriting an existing copy. Copies are created in a per-user
folder, which will be created on-demand in a 1777 directory (like /tmp).
Changes are also needed way before darwintrace.dylib first runs: The DYLD_*
variables are already stripped in src/pextlib1.0/system.c, where
/usr/bin/sandbox-exec and /bin/sh are run, which both have the SF_RESTRICTED
flag on 10.11 now. Consequently, the same copying approach is applied there.
Because macports build run in a sandbox, the sandbox boundaries are extended to
allow access to $prefix/var/macports/sip-workaround.
Modified Paths:
--------------
trunk/base/configure.ac
trunk/base/doc/base.mtree.in
trunk/base/src/darwintracelib1.0/Makefile.in
trunk/base/src/darwintracelib1.0/proc.c
trunk/base/src/pextlib1.0/Makefile.in
trunk/base/src/pextlib1.0/system.c
trunk/base/src/port1.0/portsandbox.tcl
Added Paths:
-----------
trunk/base/src/pextlib1.0/sip_copy_proc.c
trunk/base/src/pextlib1.0/sip_copy_proc.h
Property Changed:
----------------
trunk/base/src/darwintracelib1.0/
Modified: trunk/base/configure.ac
===================================================================
--- trunk/base/configure.ac 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/configure.ac 2015-10-18 00:49:32 UTC (rev 141420)
@@ -312,6 +312,14 @@
eval "prefix_expanded=$prefix"
eval "exec_prefix_expanded=$exec_prefix"
AC_SUBST(prefix_expanded)
+
+# Define a path where our trace mode workaround for SIP-protected binaries on
+# >= 10.11 puts copies
+AC_DEFINE_UNQUOTED(
+ [DARWINTRACE_SIP_WORKAROUND_PATH],
+ ["${prefix}/var/macports/sip-workaround"],
+ [Absolute path to a directory used by darwintrace to copy SIP-protected files before executing])
+
# do this twice, since there is a nested variable of
# ${prefix} inside of ${sysconfdir}
eval "MPCONFIGDIR_EXPANDED=$MPCONFIGDIR"
Modified: trunk/base/doc/base.mtree.in
===================================================================
--- trunk/base/doc/base.mtree.in 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/doc/base.mtree.in 2015-10-18 00:49:32 UTC (rev 141420)
@@ -23,6 +23,8 @@
..
registry
..
+ sip-workaround mode=01777
+ ..
software
..
..
Property changes on: trunk/base/src/darwintracelib1.0
___________________________________________________________________
Modified: svn:ignore
- Makefile
darwintrace.dylib
+ *.d
Makefile
darwintrace.dylib
sip_copy_proc.c
sip_copy_proc.h
Modified: trunk/base/src/darwintracelib1.0/Makefile.in
===================================================================
--- trunk/base/src/darwintracelib1.0/Makefile.in 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/src/darwintracelib1.0/Makefile.in 2015-10-18 00:49:32 UTC (rev 141420)
@@ -5,30 +5,62 @@
# This Makefile will only be run on Darwin systems; we can safely use
# Apple-specifics here
-SRCS= $(wildcard *.c)
-OBJS= $(SRCS:%.c=%.o)
-SHLIB_NAME= darwintrace${SHLIB_SUFFIX}
-INSTALLDIR= ${DESTDIR}${TCL_PACKAGE_PATH}/darwintrace1.0
+SRCS = \
+ access.c \
+ close.c \
+ darwintrace.c \
+ dup2.c \
+ mkdir.c \
+ open.c \
+ proc.c \
+ readdir.c \
+ readlink.c \
+ rename.c \
+ rmdir.c \
+ sip_copy_proc.c \
+ stat.c \
+ unlink.c
+OBJS = $(SRCS:%.c=%.o)
+SHLIB_NAME = darwintrace$(SHLIB_SUFFIX)
+INSTALLDIR = $(DESTDIR)$(TCL_PACKAGE_PATH)/darwintrace1.0
+
# Yes, we know having $ signs in identifiers is not a very good idea; in the
# case of darwintrace we still need them, though.
-CFLAGS_PEDANTIC=
-CFLAGS+= -fPIC ${UNIVERSAL_ARCHFLAGS}
-SHLIB_LDFLAGS+=${UNIVERSAL_ARCHFLAGS}
+CFLAGS_PEDANTIC =
+CFLAGS += -fPIC $(UNIVERSAL_ARCHFLAGS)
+SHLIB_LDFLAGS += $(UNIVERSAL_ARCHFLAGS)
-all:: ${SHLIB_NAME}
+# Generate dependency information
+CPPFLAGS += -MMD -MP
-$(SHLIB_NAME):: ${OBJS}
- ${SHLIB_LD} ${OBJS} -o ${SHLIB_NAME} ${SHLIB_LDFLAGS} ${LIBS}
+all:: $(SHLIB_NAME)
+# Copy sip_copy_proc.{c,h} from pextlib1.0 where they are also needed
+sip_copy_proc.c: ../pextlib1.0/sip_copy_proc.c sip_copy_proc.h
+ cp $< $@
+
+sip_copy_proc.h: ../pextlib1.0/sip_copy_proc.h
+ cp $< $@
+
+# This won't be automatically detected during the first run of make, where the
+# .d files do not exist yet
+proc.c: sip_copy_proc.h
+
+$(SHLIB_NAME):: $(OBJS)
+ $(SHLIB_LD) $(OBJS) -o $(SHLIB_NAME) $(SHLIB_LDFLAGS) $(LIBS)
+
clean::
- rm -f ${OBJS} ${SHLIB_NAME} so_locations
+ rm -f $(OBJS) $(SHLIB_NAME) so_locations sip_copy_proc.c sip_copy_proc.h $(SRCS:%.c=%.d)
distclean:: clean
rm -f Makefile
install:: all
- $(INSTALL) -d -o "${DSTUSR}" -g "${DSTGRP}" -m "${DSTMODE}" "${INSTALLDIR}"
- $(INSTALL) -o "${DSTUSR}" -g "${DSTGRP}" -m 444 "${SHLIB_NAME}" "${INSTALLDIR}"
+ $(INSTALL) -d -o "$(DSTUSR)" -g "$(DSTGRP)" -m "$(DSTMODE)" "$(INSTALLDIR)"
+ $(INSTALL) -o "$(DSTUSR)" -g "$(DSTGRP)" -m 444 "$(SHLIB_NAME)" "$(INSTALLDIR)"
test::
+
+# Include dependency information
+-include $(SRCS:%.c=%.d)
Modified: trunk/base/src/darwintracelib1.0/proc.c
===================================================================
--- trunk/base/src/darwintracelib1.0/proc.c 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/src/darwintracelib1.0/proc.c 2015-10-18 00:49:32 UTC (rev 141420)
@@ -37,6 +37,7 @@
#define DARWINTRACE_USE_PRIVATE_API 1
#include "darwintrace.h"
+#include "sip_copy_proc.h"
#include <ctype.h>
#include <dlfcn.h>
@@ -278,7 +279,7 @@
// Call the original execve function, but restore environment
char **newenv = restore_env(envp);
- result = execve(path, argv, newenv);
+ result = sip_copy_execve(path, argv, newenv);
free(newenv);
}
}
@@ -334,7 +335,7 @@
* we need to call the original posix_spawn from here. */
// call the original posix_spawn function, but restore environment
char **newenv = restore_env(envp);
- result = posix_spawn(pid, path, file_actions, attrp, argv, newenv);
+ result = sip_copy_posix_spawn(pid, path, file_actions, attrp, argv, newenv);
free(newenv);
}
}
Modified: trunk/base/src/pextlib1.0/Makefile.in
===================================================================
--- trunk/base/src/pextlib1.0/Makefile.in 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/src/pextlib1.0/Makefile.in 2015-10-18 00:49:32 UTC (rev 141420)
@@ -4,11 +4,32 @@
include ../../Mk/macports.autoconf.mk
OBJS= \
- Pextlib.o strsed.o fgetln.o md5cmd.o setmode.o xinstall.o \
- fs-traverse.o strcasecmp.o vercomp.o filemap.o base32cmd.o \
- sha1cmd.o curl.o rmd160cmd.o sha256cmd.o readline.o uid.o \
- tracelib.o tty.o readdir.o pipe.o adv-flock.o system.o \
- mktemp.o realpath.o
+ Pextlib.o \
+ adv-flock.o \
+ base32cmd.o \
+ curl.o \
+ fgetln.o \
+ filemap.o \
+ fs-traverse.o \
+ md5cmd.o \
+ mktemp.o \
+ pipe.o \
+ readdir.o \
+ readline.o \
+ realpath.o \
+ rmd160cmd.o \
+ setmode.o \
+ sha1cmd.o \
+ sha256cmd.o \
+ sip_copy_proc.o \
+ strcasecmp.o \
+ strsed.o \
+ system.o \
+ tracelib.o \
+ tty.o \
+ uid.o \
+ vercomp.o \
+ xinstall.o
ifneq (@ac_cv_func_strlcat@,yes)
OBJS+=strlcat.o
endif
Added: trunk/base/src/pextlib1.0/sip_copy_proc.c
===================================================================
--- trunk/base/src/pextlib1.0/sip_copy_proc.c (rev 0)
+++ trunk/base/src/pextlib1.0/sip_copy_proc.c 2015-10-18 00:49:32 UTC (rev 141420)
@@ -0,0 +1,503 @@
+/* vim: set et sw=4 ts=4 sts=4: */
+/*
+ * sip_copy_proc.c
+ * $Id$
+ *
+ * Copyright (c) 2015 Clemens Lang <cal at macports.org>
+ * Copyright (c) 2015 The MacPorts Project
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#define _DARWIN_FEATURE_64_BIT_INODE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include "sip_copy_proc.h"
+
+#include <config.h>
+#ifndef DARWINTRACE_SIP_WORKAROUND_PATH
+#warning No value for DARWINTRACE_SIP_WORKAROUND_PATH found in config.h, using default of /tmp/macports-sip, which will fail unless you create it with mode 01777
+#define DARWINTRACE_SIP_WORKAROUND_PATH "/tmp/macports-sip"
+#endif
+
+/**
+ * Frees an array of strings and the array itself.
+ */
+static void free_argv(char *argv[]) {
+ char **arg = argv;
+ while (arg && *arg) {
+ free(*arg);
+ *arg = NULL;
+ arg++;
+ }
+
+ free(argv);
+}
+
+typedef enum _copy_needed_return_t {
+ copy_needed_error,
+ copy_not_needed,
+ copy_is_needed
+} copy_needed_return_t;
+
+/**
+ * Helper function to determine whether the binary indicated by \a path
+ * supports library injection using DYLD_INSERT_LIBRARIES directly or needs to
+ * be copied to a temporary path to support it.
+ *
+ * The following conditions must be fulfilled for the copy to be necessary:
+ * - \a environ needs to contain a variable that starts with
+ * DYLD_INSERT_LIBRARIES
+ * - If the file at \a path has a shebang, its shebang line will be read and
+ * the following checks will be done against the interpreter binary.
+ * Additionally, if the copy is necessary, the arguments given in \a argc
+ * (the number of arguments) and \a argv (the arguments itself) will be
+ * prefixed with the command and arguments from the shebang line. The
+ * original first argument will be replaced with \a path to make sure it is
+ * absolute.
+ * - \a path (or the interpreter given in the shebang of path) must have the
+ * \c SF_RESTRICTED flag set.
+ * - \a path (or the interpreter given in the shebang of path) must not be
+ * SUID or SGID.
+ *
+ * @param path The absolute path of the binary to be executed
+ * @param argc The number of arguments passed in \a argv
+ * @param argv The arguments to be passed to the file to be executed
+ * @param outargv Pointer to a modified array of arguments. Only valid if \c
+ * copy_is_needed is returned. May be \c NULL, in which case no
+ * modifications to the original \c argv were necessary. If
+ * non-null, a dynamically allocated array of dynamically
+ * allocated elements. The last element of the array is \c NULL,
+ * which makes \c *outargv suitable for passing to execve(2).
+ * Note that instead of the given \c path, you should pass \c
+ * (*outargv)[0] to execve(2) as first argument.
+ * @param environ The environment for the program to be started. Will be
+ * checked for the presence of a DYLD_INSERT_LIBRARIES variable.
+ * @param st Pointer to struct stat that will contain information about \c
+ * path, or of \c outargv isn't \c NULL, about \c (*outargv)[0]. This
+ * can be used to determine metadata of the file such as modification
+ * time and size to avoid unnecessary copies.
+ * @return \c copy_isneeded iff a copy is required. \c copy_not_needed if a copy
+ * is not needed. \c copy_needed_error on error, where errno will be
+ * set.
+ */
+static copy_needed_return_t copy_needed(const char *path, char *const argv[],
+ char **outargv[], char *const environ[], struct stat *st) {
+#ifndef SF_RESTRICTED /* no system integrity protection */
+ return copy_not_needed;
+#else /* defined(SF_RESTRICTED) */
+ // check whether DYLD_INSERT_LIBRARIES is set
+ bool dyld_insert_libraries_present = false;
+ char *const *env = environ;
+ while (env && *env) {
+ if (strncmp("DYLD_INSERT_LIBRARIES=", *env, strlen("DYLD_INSERT_LIBRARIES=")) == 0) {
+ dyld_insert_libraries_present = true;
+ break;
+ }
+ env++;
+ }
+ // if we didn't find DYLD_INSERT_LIBRARIES, a copy isn't needed
+ if (!dyld_insert_libraries_present) {
+ return copy_not_needed;
+ }
+
+ // open file to check for shebangs
+ const char *realpath = path;
+ size_t new_argc = 0;
+ char **new_argv = NULL;
+ FILE *f = fopen(path, "r");
+ if (!f) {
+ // if opening fails we won't be able to copy anyway
+ return copy_not_needed;
+ }
+
+ /* no error checking for fgetc(3) here, because this isn't a shebang if an
+ * error occurs */
+ if (fgetc(f) == '#' && fgetc(f) == '!') {
+ /* This is an interpreted script. The interpreter's flags are what
+ * affects whether DYLD_* is stripped, so read the interpreter's path
+ * from the file to check that instead. Additionally, read any flags
+ * that may be passed to the interpreter, since we'll have to do the
+ * shebang expansion in user space if we move the interpreter. */
+ char *linep = NULL;
+ size_t linecapp = 0;
+ // read first line to get the interpreter and its arguments
+ if (getline(&linep, &linecapp, f) > 0) {
+ char *ctxt;
+ char *word;
+ size_t idx;
+ // do word splitting on the interpreter line and store it in new_argv
+ for (idx = 0, word = strtok_r(linep, " \t\n", &ctxt);
+ word != NULL;
+ idx++, word = strtok_r(NULL, " \t\n", &ctxt)) {
+ // make sure we have enough space allocated
+ if (new_argv == NULL) {
+ if ((new_argv = malloc(2 * sizeof(*new_argv))) == NULL) {
+ free(linep);
+ return copy_needed_error;
+ }
+ new_argc = 1;
+
+ // new_argv[0] will be overwritten in a second
+ // new_argv[1] is the terminating NULL
+ new_argv[0] = NULL;
+ new_argv[1] = NULL;
+ } else if (idx >= new_argc) {
+ // realloc to increase the size
+ char **oldargv = new_argv;
+ if ((new_argv = realloc(oldargv, (idx + 2) * sizeof(*new_argv))) == NULL) {
+ free_argv(oldargv);
+ free(linep);
+ return copy_needed_error;
+ }
+ new_argc = idx + 1;
+ }
+
+ // store a copy of the word in new_argv
+ new_argv[idx] = strdup(word);
+ if (!new_argv[idx]) {
+ free_argv(new_argv);
+ free(linep);
+ return copy_needed_error;
+ }
+ new_argv[idx + 1] = NULL;
+ }
+
+ free(linep);
+
+ if (new_argv && *new_argv) {
+ // interpreter found, check that instead of given path
+ realpath = *new_argv;
+ }
+ }
+ }
+
+ // check whether the binary has SF_RESTRICTED and isn't SUID/SGID
+ if (-1 == stat(realpath, st)) {
+ // on error, return and let execve(2) deal with it
+ free_argv(new_argv);
+ return copy_not_needed;
+ } else {
+ if (!(st->st_flags & SF_RESTRICTED)) {
+ // no SIP on this binary
+ free_argv(new_argv);
+ return copy_not_needed;
+ }
+ if ((st->st_flags & (S_ISUID | S_ISGID)) > 0) {
+ // the binary is SUID/SGID, which would get lost when copying;
+ // DYLD_ variables are stripped for SUID/SGID binaries anyway
+ free_argv(new_argv);
+ return copy_not_needed;
+ }
+ }
+
+ // prefix the shebang line to the original argv
+ if (new_argv != NULL) {
+ size_t argc = 0;
+ for (char *const *argvwalk = argv; argvwalk && *argvwalk; ++argvwalk) {
+ argc++;
+ }
+
+ // realloc to increase the size
+ char **oldargv = new_argv;
+ if ((new_argv = realloc(oldargv, (new_argc + argc + 1) * sizeof(*new_argv))) == NULL) {
+ free_argv(oldargv);
+ return copy_needed_error;
+ }
+
+ new_argv[new_argc] = strdup(path);
+ if (!new_argv[new_argc]) {
+ free_argv(new_argv);
+ return copy_needed_error;
+ }
+ new_argv[new_argc + 1] = NULL;
+
+ for (size_t idx = 1; idx < argc; ++idx) {
+ new_argv[new_argc + idx] = strdup(argv[idx]);
+ if (!new_argv[new_argc + idx]) {
+ free_argv(new_argv);
+ return copy_needed_error;
+ }
+ new_argv[new_argc + idx + 1] = NULL;
+ }
+
+ new_argc = new_argc + argc;
+
+ *outargv = new_argv;
+ }
+
+ return copy_is_needed;
+#endif /* defined(SF_RESTRICTED) */
+}
+
+static char *lazy_copy(const char *path, struct stat *in_st) {
+ char *retval = NULL;
+ uid_t euid = geteuid();
+ int outfd = -1;
+ int infd = -1;
+
+ char *target_folder = NULL;
+ char *target_path = NULL;
+ char *target_path_temp = NULL;
+ char *dir = strdup(path);
+ if (!dir) {
+ goto lazy_copy_out;
+ }
+ char *endslash = strrchr(dir, '/');
+ if (endslash) {
+ *endslash = '\0';
+ }
+
+ if (-1 == asprintf(&target_folder, "%s/%lu%s", DARWINTRACE_SIP_WORKAROUND_PATH, (unsigned long) euid, dir)) {
+ goto lazy_copy_out;
+ }
+
+ if (-1 == asprintf(&target_path, "%s/%lu%s", DARWINTRACE_SIP_WORKAROUND_PATH, (unsigned long) euid, path)) {
+ goto lazy_copy_out;
+ }
+
+ if (-1 == asprintf(&target_path_temp, "%s/%lu/.XXXXXXXXXXXXXX", DARWINTRACE_SIP_WORKAROUND_PATH, (unsigned long) euid)) {
+ goto lazy_copy_out;
+ }
+
+ // ensure directory exists
+ char *pos = target_folder + strlen(DARWINTRACE_SIP_WORKAROUND_PATH);
+ while (pos && *pos) {
+ *pos = '\0';
+ if (-1 == mkdir(target_folder, 0755) && errno != EEXIST) {
+ fprintf(stderr, "sip_copy_proc: mkdir(%s): %s\n", target_folder, strerror(errno));
+ goto lazy_copy_out;
+ }
+ *pos = '/';
+ pos++;
+ pos = strchr(pos, '/');
+ }
+ if (-1 == mkdir(target_folder, 0755) && errno != EEXIST) {
+ fprintf(stderr, "sip_copy_proc: mkdir(%s): %s\n", target_folder, strerror(errno));
+ goto lazy_copy_out;
+ }
+
+ // check whether copying is needed; it isn't if the file exists and the
+ // modification times match
+ struct stat out_st;
+ if ( -1 != stat(target_path, &out_st)
+ && in_st->st_mtimespec.tv_sec == out_st.st_mtimespec.tv_sec
+ && in_st->st_mtimespec.tv_nsec == out_st.st_mtimespec.tv_nsec) {
+ // copying not needed
+ retval = target_path;
+ goto lazy_copy_out;
+ }
+
+ // create temporary file to copy into and then later atomically replace
+ // target file
+ if (-1 == (outfd = mkstemp(target_path_temp))) {
+ fprintf(stderr, "sip_copy_proc: mkstemp(%s): %s\n", target_path_temp, strerror(errno));
+ goto lazy_copy_out;
+ }
+
+ if (-1 == (infd = open(path, O_RDONLY | O_CLOEXEC))) {
+ fprintf(stderr, "sip_copy_proc: open(%s, O_RDONLY | O_CLOEXEC): %s\n", path, strerror(errno));
+ goto lazy_copy_out;
+ }
+
+ // ensure mode is copied
+ if (-1 == fchmod(outfd, in_st->st_mode)) {
+ fprintf(stderr, "sip_copy_proc: fchmod(%s, %o): %s\n", target_path_temp, in_st->st_mode, strerror(errno));
+ goto lazy_copy_out;
+ }
+
+ char *buf = malloc(in_st->st_blksize);
+ ssize_t bytes_read = 0;
+ ssize_t bytes_written = 0;
+ bool error = false;
+ do {
+ bytes_read = read(infd, buf, in_st->st_blksize);
+ if (bytes_read < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ } else {
+ error = true;
+ break;
+ }
+ }
+ if (bytes_read == 0) {
+ // EOF
+ break;
+ }
+
+ bytes_written = 0;
+ while (bytes_written < bytes_read) {
+ ssize_t written = write(outfd, buf + bytes_written, bytes_read - bytes_written);
+ if (written < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ error = true;
+ break;
+ }
+
+ bytes_written += written;
+ }
+ } while (!error);
+ if (bytes_read < 0 || bytes_written < 0) {
+ goto lazy_copy_out;
+ }
+
+ struct timeval times[2];
+ TIMESPEC_TO_TIMEVAL(×[0], &in_st->st_mtimespec);
+ TIMESPEC_TO_TIMEVAL(×[1], &in_st->st_mtimespec);
+ if (-1 == futimes(outfd, times)) {
+ fprintf(stderr, "sip_copy_proc: futimes(%s): %s\n", target_path_temp, strerror(errno));
+ goto lazy_copy_out;
+ }
+
+ if (-1 == rename(target_path_temp, target_path)) {
+ fprintf(stderr, "sip_copy_proc: rename(%s, %s): %s\n", target_path_temp, target_path, strerror(errno));
+ goto lazy_copy_out;
+ }
+
+ retval = target_path;
+
+lazy_copy_out:
+ {
+ int errno_save = errno;
+ close(outfd);
+ close(infd);
+ if (target_path_temp != NULL && -1 == unlink(target_path_temp) && errno != ENOENT) {
+ fprintf(stderr, "sip_copy_proc: unlink(%s): %s\n", target_path_temp, strerror(errno));
+ retval = NULL;
+ } else {
+ errno = errno_save;
+ }
+ }
+ free(dir);
+ free(target_path_temp);
+ free(target_folder);
+ if (retval != target_path) {
+ free(target_path);
+ }
+ return retval;
+}
+
+/**
+ * Behaves like execve(2), but checks whether trace mode is enabled (by
+ * checking for DYLD_INSERT_LIBRARIES in the environment) and the binary is
+ * covered by 10.11's new system integrity protection. If it is, the binary
+ * will be copied to a separate folder (or updated if already there and
+ * modification time differs) and executed from there.
+ */
+int sip_copy_execve(const char *path, char *const argv[], char *const envp[]) {
+ char **outargv = NULL;
+ struct stat st;
+
+ copy_needed_return_t need_copy = copy_needed(path, argv, &outargv, envp, &st);
+ switch (need_copy) {
+ case copy_needed_error:
+ return -1;
+ break;
+ case copy_not_needed:
+ return execve(path, argv, envp);
+ break;
+ case copy_is_needed: {
+ const char *to_be_copied = path;
+ char *const *to_be_argv = argv;
+ if (outargv) {
+ to_be_copied = outargv[0];
+ to_be_argv = outargv;
+ }
+
+ char *new_path = lazy_copy(to_be_copied, &st);
+ if (!new_path) {
+ return -1;
+ }
+
+ int ret = execve(new_path, to_be_argv, envp);
+ free_argv(outargv);
+ free(new_path);
+ return ret;
+ }
+ break;
+ }
+}
+
+/**
+ * Behaves like posix_spawn(2), but checks whether trace mode is enabled (by
+ * checking for DYLD_INSERT_LIBRARIES in the environment) and the binary is
+ * covered by 10.11's new system integrity protection. If it is, the binary
+ * will be copied to a separate folder (or updated if already there and
+ * modification time differs) and executed from there.
+ */
+int sip_copy_posix_spawn(
+ pid_t *restrict pid,
+ const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]) {
+ char **outargv = NULL;
+ struct stat st;
+
+ copy_needed_return_t need_copy = copy_needed(path, argv, &outargv, envp, &st);
+ switch (need_copy) {
+ case copy_needed_error:
+ return -1;
+ break;
+ case copy_not_needed:
+ return posix_spawn(pid, path, file_actions, attrp, argv, envp);
+ break;
+ case copy_is_needed: {
+ const char *to_be_copied = path;
+ char *const *to_be_argv = argv;
+ if (outargv) {
+ to_be_copied = outargv[0];
+ to_be_argv = outargv;
+ }
+
+ char *new_path = lazy_copy(to_be_copied, &st);
+ if (!new_path) {
+ return -1;
+ }
+
+ int ret = posix_spawn(pid, new_path, file_actions, attrp, to_be_argv, envp);
+ free_argv(outargv);
+ free(new_path);
+ return ret;
+ }
+ break;
+ }
+}
Added: trunk/base/src/pextlib1.0/sip_copy_proc.h
===================================================================
--- trunk/base/src/pextlib1.0/sip_copy_proc.h (rev 0)
+++ trunk/base/src/pextlib1.0/sip_copy_proc.h 2015-10-18 00:49:32 UTC (rev 141420)
@@ -0,0 +1,60 @@
+/* vim: set et sw=4 ts=4 sts=4: */
+/*
+ * system.c
+ * $Id: system.c 138943 2015-07-24 20:35:45Z raimue at macports.org $
+ *
+ * Copyright (c) 2015 Clemens Lang <cal at macports.org>
+ * Copyright (c) 2015 The MacPorts Project
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <spawn.h>
+
+/**
+ * Behaves like execve(2), but checks whether trace mode is enabled (by
+ * checking for DYLD_INSERT_LIBRARIES in the environment) and the binary is
+ * covered by 10.11's new system integrity protection. If it is, the binary
+ * will be copied to a separate folder (or updated if already there and
+ * modification time differs) and executed from there.
+ */
+int sip_copy_execve(const char *path, char *const argv[], char *const envp[]);
+
+
+/**
+ * Behaves like posix_spawn(2), but checks whether trace mode is enabled (by
+ * checking for DYLD_INSERT_LIBRARIES in the environment) and the binary is
+ * covered by 10.11's new system integrity protection. If it is, the binary
+ * will be copied to a separate folder (or updated if already there and
+ * modification time differs) and executed from there.
+ */
+int sip_copy_posix_spawn(
+ pid_t *restrict pid,
+ const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]);
Modified: trunk/base/src/pextlib1.0/system.c
===================================================================
--- trunk/base/src/pextlib1.0/system.c 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/src/pextlib1.0/system.c 2015-10-18 00:49:32 UTC (rev 141420)
@@ -58,6 +58,7 @@
#include <errno.h>
#include "system.h"
+#include "sip_copy_proc.h"
#include "Pextlib.h"
#if HAVE_CRT_EXTERNS_H
@@ -237,13 +238,13 @@
args[4] = "-c";
args[5] = cmdstring;
args[6] = NULL;
- execve(sandbox_exec_path, args, environ);
+ sip_copy_execve(sandbox_exec_path, args, environ);
} else {
args[0] = "sh";
args[1] = "-c";
args[2] = cmdstring;
args[3] = NULL;
- execve("/bin/sh", args, environ);
+ sip_copy_execve("/bin/sh", args, environ);
}
exit(128);
/*NOTREACHED*/
Modified: trunk/base/src/port1.0/portsandbox.tcl
===================================================================
--- trunk/base/src/port1.0/portsandbox.tcl 2015-10-18 00:49:18 UTC (rev 141419)
+++ trunk/base/src/port1.0/portsandbox.tcl 2015-10-18 00:49:32 UTC (rev 141420)
@@ -42,7 +42,7 @@
# command line usage would be:
# sandbox-exec -p '(version 1) (allow default) (deny file-write*) (allow file-write* <filter>)' some-command
proc portsandbox::set_profile {target} {
- global os.major portsandbox_profile workpath distpath altprefix \
+ global os.major portsandbox_profile workpath distpath prefix altprefix \
package.destpath configure.ccache ccache_dir
switch $target {
@@ -78,6 +78,7 @@
# TODO: remove altprefix support
lappend allow_dirs $workpath $altprefix
+ lappend allow_dirs $prefix/var/macports/sip-workaround
if {${configure.ccache}} {
lappend allow_dirs $ccache_dir
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20151212/687affee/attachment-0001.html>
More information about the macports-changes
mailing list