[110144] trunk/base/src/darwintracelib1.0/darwintrace.c
cal at macports.org
cal at macports.org
Tue Aug 27 08:57:20 PDT 2013
Revision: 110144
https://trac.macports.org/changeset/110144
Author: cal at macports.org
Date: 2013-08-27 08:57:20 -0700 (Tue, 27 Aug 2013)
Log Message:
-----------
darwintrace: more comments, implement avoiding reporting sandbox violations from readdir, report violations when accessing port files that are outside the sandbox, support checking a script's interpreter for sandbox compliance
Modified Paths:
--------------
trunk/base/src/darwintracelib1.0/darwintrace.c
Modified: trunk/base/src/darwintracelib1.0/darwintrace.c
===================================================================
--- trunk/base/src/darwintracelib1.0/darwintrace.c 2013-08-27 15:39:45 UTC (rev 110143)
+++ trunk/base/src/darwintracelib1.0/darwintrace.c 2013-08-27 15:57:20 UTC (rev 110144)
@@ -43,8 +43,6 @@
#include <sys/cdefs.h>
#endif
-#include <stdint.h>
-
#if defined(_DARWIN_FEATURE_64_BIT_INODE) && !defined(_DARWIN_FEATURE_ONLY_64_BIT_INODE)
/* The architecture we're building for has multiple versions of stat.
We need to undo sys/cdefs.h changes for _DARWIN_FEATURE_64_BIT_INODE */
@@ -63,12 +61,15 @@
#include <sys/paths.h>
#endif
+#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -256,7 +257,6 @@
}
}
-
/**
* Return 0 if str doesn't begin with prefix, 1 otherwise. Note that this is
* not a simple string comparison, but works on a path component level.
@@ -360,7 +360,7 @@
}
/* 4 is sufficient for the three variables we copy and the terminator */
- copy = malloc(sizeof(char *) * (envlen + 5));
+ copy = malloc(sizeof(char *) * (envlen + 4));
enviter = envp;
copyiter = copy;
@@ -550,7 +550,7 @@
* stored when the function was called last.
*/
static inline void __darwintrace_setup() {
- /**
+ /*
* Check whether this is a child process and we've inherited the socket. We
* want to avoid race conditions with our parent process when communicating
* with tracelib and thus re-open all sockets, if that's the case. Note
@@ -617,7 +617,8 @@
}
/**
- * Send a path to tracelib either form a given path, or from an FD.
+ * Send a path to tracelib either given a path, or an FD (where
+ * fcntl(F_GETPATH) will be used).
*
* \param[in] op the operation (sent as-is to tracelib, should be interpreted
* as command)
@@ -847,9 +848,14 @@
* bytes large. If newpath[0] isn't 0 after the call,
* redirection should occur and the path from newpath
* should be used for the syscall instead.
+ * \param[in] report If access to this path is being denied, report it as
+ * sandbox violation. Set this to \c true for all operations
+ * that read file contents. Set this to \c false for
+ * operations that only check for the file's existance, e.g.,
+ * reading a directory.
* \return 1, if the file is within sandbox bounds, 0, if access should be denied
*/
-static inline int __darwintrace_is_in_sandbox(const char *path, char *newpath) {
+static inline int __darwintrace_is_in_sandbox(const char *path, char *newpath, bool report) {
char *t, *_;
char *strpos, *normpos;
char lpath[MAXPATHLEN];
@@ -864,6 +870,7 @@
return 1;
}
+ /* Make sure the path is absolute. */
if (*path == '/') {
strcpy(lpath, path);
} else {
@@ -875,6 +882,9 @@
strlcat(lpath, path, MAXPATHLEN);
}
+ /* Make sure the path is normalized. NOTE: Do _not_ use realpath(3) here.
+ * Doing so _will_ lead to problems. This is essentially a very simple
+ * re-implementation of realpath(3). */
normalizedpath[0] = '\0';
strpos = lpath + 1;
normpos = normalizedpath;
@@ -912,6 +922,7 @@
strcat(normalizedpath, "/");
}
+ /* Iterate over the sandbox bounds and try to find a directive matching this path */
for (__darwintrace_filemap_iterator_init(&filemap_it);
(t = __darwintrace_filemap_iter(&command, &replacementpath, &filemap_it));) {
if (__darwintrace_pathbeginswith(normalizedpath, t)) {
@@ -938,12 +949,18 @@
/* ask the socket whether this file is OK */
switch (dependency_check(normalizedpath)) {
case 1:
+ return 1;
case -1:
/* if the file isn't known to MacPorts, allow
- * access anyway. TODO find a better solution */
+ * access anyway, but report a sandbox violation.
+ * TODO find a better solution */
+ if (report)
+ __darwintrace_log_op("sandbox_violation", normalizedpath, 0);
return 1;
case 0:
/* file belongs to a foreign port, deny access */
+ if (report)
+ __darwintrace_log_op("sandbox_violation", normalizedpath, 0);
return 0;
}
default:
@@ -953,7 +970,8 @@
}
}
- __darwintrace_log_op("sandbox_violation", normalizedpath, 0);
+ if (report)
+ __darwintrace_log_op("sandbox_violation", normalizedpath, 0);
return 0;
}
@@ -967,7 +985,7 @@
debug_printf("open(%s)\n", path);
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
debug_printf("open %s was forbidden\n", path);
errno = ((flags & O_CREAT) > 0) ? EACCES : ENOENT;
return -1;
@@ -1001,7 +1019,7 @@
debug_printf("readlink(%s)\n", path);
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
errno = ENOENT;
return -1;
}
@@ -1015,56 +1033,66 @@
}
int execve(const char *path, char *const argv[], char *const envp[]) {
-#define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
+#define execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
#define close(x) syscall(SYS_close, (x))
#define lstat(x, y) syscall(SYS_lstat, (x), (y))
debug_printf("execve(%s)\n", path);
__darwintrace_setup();
struct stat sb;
- /* for symlinks, we want to capture both the original path and the
- * modified one, since for /usr/bin/gcc -> gcc-4.0, both "gcc_select"
- * and "gcc" are contributors
+ /* for symlinks, we want to capture both the original path and the modified
+ * one, since for $prefix/bin/gcc -> mp-gcc-4.8, both "gcc_select" and
+ * "gcc48" are contributors. This requires changes to the select code such
+ * that the symlinks are registered to the *_select ports. Since this
+ * a general problem (when executing $prefix/libexec/mysql/bin/foo where
+ * $prefix/libexec/mysql is a symlink to $prefix/libexec/mysql55, the
+ * mysql_select port needs to be a contributor!) we should really implement
+ * this in __darwintrace_is_in_sandbox().
*/
if (lstat(path, &sb) == 0) {
- if (!__darwintrace_is_in_sandbox(path, NULL)) {
+ if (!__darwintrace_is_in_sandbox(path, NULL, true)) {
errno = ENOENT;
return -1;
}
-#if 0
int fd = open(path, O_RDONLY, 0);
if (fd > 0) {
char buffer[MAXPATHLEN + 1];
ssize_t bytes_read;
- /* read the file for the interpreter */
+ /* Read the file for the interpreter. Fortunately, on OS X:
+ * The system guarantees to read the number of bytes requested if
+ * the descriptor references a normal file that has that many
+ * bytes left before the end-of-file, but in no other case.
+ * That _does_ save us another ugly loop to get things right. */
bytes_read = read(fd, buffer, MAXPATHLEN);
- buffer[bytes_read] = 0;
+ buffer[bytes_read] = '\0';
+ const char *buffer_end = buffer + bytes_read;
if (bytes_read > 2 && buffer[0] == '#' && buffer[1] == '!') {
- const char *interp = &buffer[2];
- int i;
+ char *interp = buffer + 2;
+
/* skip past leading whitespace */
- for (i = 2; i < bytes_read; ++i) {
- if (buffer[i] != ' ' && buffer[i] != '\t') {
- interp = &buffer[i];
- break;
- }
+ while (interp < buffer_end && isblank(*interp)) {
+ ++interp;
}
/* found interpreter (or ran out of data); skip until next
* whitespace, then terminate the string */
- for (; i < bytes_read; ++i) {
- if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
- buffer[i] = 0;
- break;
- }
+ if (interp < buffer_end) {
+ char *interp_end = interp;
+ strsep(&interp_end, " \t");
}
+
+ /* check the iterpreter against the sandbox */
+ if (!__darwintrace_is_in_sandbox(interp, NULL, true)) {
+ close(fd);
+ errno = ENOENT;
+ return -1;
+ }
}
- /* TODO check the iterpreter against the sandbox */
close(fd);
+
}
-#endif
}
/* our variables won't survive exec, clean up */
@@ -1072,7 +1100,7 @@
__darwintrace_pid = (pid_t) - 1;
/* call the original execve function, but fix the environment if required. */
- return __execve(path, argv, __darwintrace_restore_env(envp));
+ return execve(path, argv, __darwintrace_restore_env(envp));
#undef lstat
#undef close
#undef open
@@ -1133,7 +1161,7 @@
char newpath[MAXPATHLEN];
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
debug_printf("unlink %s was forbidden\n", path);
errno = ENOENT;
return -1;
@@ -1155,7 +1183,7 @@
char newpath[MAXPATHLEN];
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
struct stat st;
if (-1 == lstat(path, &st)) {
if (errno == ENOENT) {
@@ -1182,7 +1210,7 @@
*/
int rmdir(const char *path) {
#define __rmdir(x) syscall(SYS_rmdir, (x))
- if (!__darwintrace_is_in_sandbox(path, NULL)) {
+ if (!__darwintrace_is_in_sandbox(path, NULL, true)) {
debug_printf("removing directory %s was forbidden\n", path);
errno = ENOENT;
return -1;
@@ -1197,13 +1225,13 @@
*/
int rename(const char *from, const char *to) {
#define __rename(x,y) syscall(SYS_rename, (x), (y))
- if (!__darwintrace_is_in_sandbox(from, NULL)) {
+ if (!__darwintrace_is_in_sandbox(from, NULL, true)) {
/* outside sandbox, forbid */
debug_printf("renaming from %s was forbidden\n", from);
errno = ENOENT;
return -1;
}
- if (!__darwintrace_is_in_sandbox(to, NULL)) {
+ if (!__darwintrace_is_in_sandbox(to, NULL, true)) {
debug_printf("renaming to %s was forbidden\n", to);
errno = EACCES;
return -1;
@@ -1229,7 +1257,7 @@
}
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
errno = ENOENT;
return -1;
}
@@ -1259,7 +1287,7 @@
}
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
errno = ENOENT;
return -1;
}
@@ -1294,7 +1322,7 @@
}
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
errno = ENOENT;
return -1;
}
@@ -1324,7 +1352,7 @@
}
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
errno = ENOENT;
return -1;
}
@@ -1393,7 +1421,7 @@
struct dirent64 *dent = (struct dirent64 *)(((char *) buf) + offset);
dirname[dnamelen] = '\0';
strcat(dirname, dent->d_name);
- if (!__darwintrace_is_in_sandbox(dirname, NULL)) {
+ if (!__darwintrace_is_in_sandbox(dirname, NULL, false)) {
debug_printf("__getdirentries64: filtered %s\n", dirname);
dent->d_ino = 0;
} else {
@@ -1441,7 +1469,7 @@
struct dirent32 *dent = (struct dirent32 *)(buf + offset);
dirname[dnamelen] = '\0';
strcat(dirname, dent->d_name);
- if (!__darwintrace_is_in_sandbox(dirname, NULL)) {
+ if (!__darwintrace_is_in_sandbox(dirname, NULL, false)) {
debug_printf("getdirentries: filtered %s\n", dirname);
dent->d_ino = 0;
} else {
@@ -1471,7 +1499,7 @@
}
*newpath = '\0';
- if (!__darwintrace_is_in_sandbox(path, newpath)) {
+ if (!__darwintrace_is_in_sandbox(path, newpath, true)) {
errno = ENOENT;
return -1;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20130827/54774ce4/attachment.html>
More information about the macports-changes
mailing list