summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/seccomp/debug.cc
diff options
context:
space:
mode:
authornsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-31 01:16:35 +0000
committernsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-31 01:16:35 +0000
commitfb7b5328a5fd3aecfc27f765dea94b961c657597 (patch)
tree84adc617db0031a881265e95f9c569de66fa733d /sandbox/linux/seccomp/debug.cc
parent7302ea910ce937d482780649d6a84bbfff4ac521 (diff)
downloadchromium_src-fb7b5328a5fd3aecfc27f765dea94b961c657597.zip
chromium_src-fb7b5328a5fd3aecfc27f765dea94b961c657597.tar.gz
chromium_src-fb7b5328a5fd3aecfc27f765dea94b961c657597.tar.bz2
Revert 57921 - Pull seccomp-sandbox in via DEPS rather than using an in-tree copy
This means changes to the sandbox won't have to be committed twice, to both trees. BUG=none TEST=smoke test of running chromium with --enable-seccomp-sandbox Review URL: http://codereview.chromium.org/3249003 TBR=mseaborn@chromium.org Review URL: http://codereview.chromium.org/3245011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57933 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/linux/seccomp/debug.cc')
-rw-r--r--sandbox/linux/seccomp/debug.cc363
1 files changed, 363 insertions, 0 deletions
diff --git a/sandbox/linux/seccomp/debug.cc b/sandbox/linux/seccomp/debug.cc
new file mode 100644
index 0000000..5d6de49
--- /dev/null
+++ b/sandbox/linux/seccomp/debug.cc
@@ -0,0 +1,363 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NDEBUG
+
+#include "debug.h"
+
+namespace playground {
+
+bool Debug::enabled_;
+int Debug::numSyscallNames_;
+const char **Debug::syscallNames_;
+std::map<int, std::string> Debug::syscallNamesMap_;
+
+Debug Debug::debug_;
+
+Debug::Debug() {
+ // Logging is disabled by default, but can be turned on by setting an
+ // appropriate environment variable. Initialize this code from a global
+ // constructor, so that it runs before the sandbox is turned on.
+ enabled_ = !!getenv("SECCOMP_SANDBOX_DEBUGGING");
+
+ // Read names of system calls from header files, if available. Symbolic
+ // names make debugging so much nicer.
+ if (enabled_) {
+ static const char *filenames[] = {
+ #if __WORDSIZE == 64
+ "/usr/include/asm/unistd_64.h",
+ #elif __WORDSIZE == 32
+ "/usr/include/asm/unistd_32.h",
+ #endif
+ "/usr/include/asm/unistd.h",
+ NULL };
+ numSyscallNames_ = 0;
+ for (const char **fn = filenames; *fn; ++fn) {
+ FILE *fp = fopen(*fn, "r");
+ if (fp) {
+ std::string baseName;
+ int baseNum = -1;
+ char buf[80];
+ while (fgets(buf, sizeof(buf), fp)) {
+ // Check if the line starts with "#define"
+ static const char* whitespace = " \t\r\n";
+ char *token, *save;
+ token = strtok_r(buf, whitespace, &save);
+ if (token && !strcmp(token, "#define")) {
+
+ // Only parse identifiers that start with "__NR_"
+ token = strtok_r(NULL, whitespace, &save);
+ if (token) {
+ if (strncmp(token, "__NR_", 5)) {
+ continue;
+ }
+ std::string syscallName(token + 5);
+
+ // Parse the value of the symbol. Try to be forgiving in what
+ // we accept, as the file format might change over time.
+ token = strtok_r(NULL, "\r\n", &save);
+ if (token) {
+ // Some values are defined relative to previous values, we
+ // detect these examples by finding an earlier symbol name
+ // followed by a '+' plus character.
+ bool isRelative = false;
+ char *base = strstr(token, baseName.c_str());
+ if (baseNum >= 0 && base) {
+ base += baseName.length();
+ while (*base == ' ' || *base == '\t') {
+ ++base;
+ }
+ if (*base == '+') {
+ isRelative = true;
+ token = base;
+ }
+ }
+
+ // Skip any characters that are not part of the syscall number.
+ while (*token < '0' || *token > '9') {
+ token++;
+ }
+
+ // If we now have a valid datum, enter it into our map.
+ if (*token) {
+ int sysnum = atoi(token);
+
+ // Deal with symbols that are defined relative to earlier
+ // ones.
+ if (isRelative) {
+ sysnum += baseNum;
+ } else {
+ baseNum = sysnum;
+ baseName = syscallName;
+ }
+
+ // Keep track of the highest syscall number that we know
+ // about.
+ if (sysnum >= numSyscallNames_) {
+ numSyscallNames_ = sysnum + 1;
+ }
+
+ syscallNamesMap_[sysnum] = syscallName;
+ }
+ }
+ }
+ }
+ }
+ fclose(fp);
+ break;
+ }
+ }
+ if (numSyscallNames_) {
+ // We cannot make system calls at the time, when we are looking up
+ // the names. So, copy them into a data structure that can be
+ // accessed without having to allocated memory (i.e. no more STL).
+ syscallNames_ = reinterpret_cast<const char **>(
+ calloc(sizeof(char *), numSyscallNames_));
+ for (std::map<int, std::string>::const_iterator iter =
+ syscallNamesMap_.begin();
+ iter != syscallNamesMap_.end();
+ ++iter) {
+ syscallNames_[iter->first] = iter->second.c_str();
+ }
+ }
+ }
+}
+
+bool Debug::enter() {
+ // Increment the recursion level in TLS storage. This allows us to
+ // make system calls from within our debugging functions, without triggering
+ // additional debugging output.
+ //
+ // This function can be called from both the sandboxed process and from the
+ // trusted process. Only the sandboxed process needs to worry about
+ // recursively calling system calls. The trusted process doesn't intercept
+ // system calls and thus doesn't have this problem. It also doesn't have
+ // a TLS. We explicitly set the segment selector to zero, when in the
+ // trusted process, so that we can avoid tracking recursion levels.
+ int level;
+ #if defined(__x86_64__)
+ asm volatile("mov %%gs, %0\n"
+ "test %0, %0\n"
+ "jz 1f\n"
+ "movl %%gs:0x1050-0xE0, %0\n"
+ "incl %%gs:0x1050-0xE0\n"
+ "1:\n"
+ : "=r"(level)
+ :
+ : "memory");
+ #elif defined(__i386__)
+ asm volatile("mov %%fs, %0\n"
+ "test %0, %0\n"
+ "jz 1f\n"
+ "movl %%fs:0x1034-0x58, %0\n"
+ "incl %%fs:0x1034-0x58\n"
+ "1:\n"
+ : "=r"(level)
+ :
+ : "memory");
+ #else
+ #error "Unsupported target platform"
+ #endif
+ return !level;
+}
+
+bool Debug::leave() {
+ // Decrement the recursion level in TLS storage. This allows us to
+ // make system calls from within our debugging functions, without triggering
+ // additional debugging output.
+ //
+ // This function can be called from both the sandboxed process and from the
+ // trusted process. Only the sandboxed process needs to worry about
+ // recursively calling system calls. The trusted process doesn't intercept
+ // system calls and thus doesn't have this problem. It also doesn't have
+ // a TLS. We explicitly set the segment selector to zero, when in the
+ // trusted process, so that we can avoid tracking recursion levels.
+ int level;
+ #if defined(__x86_64__)
+ asm volatile("mov %%gs, %0\n"
+ "test %0, %0\n"
+ "jz 1f\n"
+ "decl %%gs:0x1050-0xE0\n"
+ "movl %%gs:0x1050-0xE0, %0\n"
+ "1:\n"
+ : "=r"(level)
+ :
+ : "memory");
+ #elif defined(__i386__)
+ asm volatile("mov %%fs, %0\n"
+ "test %0, %0\n"
+ "jz 1f\n"
+ "decl %%fs:0x1034-0x58\n"
+ "movl %%fs:0x1034-0x58, %0\n"
+ "1:\n"
+ : "=r"(level)
+ :
+ : "memory");
+ #else
+ #error Unsupported target platform
+ #endif
+ return !level;
+}
+
+void Debug::_message(const char* msg) {
+ if (enabled_) {
+ Sandbox::SysCalls sys;
+ size_t len = strlen(msg);
+ if (len && msg[len-1] != '\n') {
+ // Write operations should be atomic, so that we don't interleave
+ // messages from multiple threads. Append a newline, if it is not
+ // already there.
+ char copy[len + 1];
+ memcpy(copy, msg, len);
+ copy[len] = '\n';
+ Sandbox::write(sys, 2, copy, len + 1);
+ } else {
+ Sandbox::write(sys, 2, msg, len);
+ }
+ }
+}
+
+void Debug::message(const char* msg) {
+ if (enabled_) {
+ if (enter()) {
+ _message(msg);
+ }
+ leave();
+ }
+}
+
+void Debug::gettimeofday(long long* tm) {
+ if (tm) {
+ struct timeval tv;
+ #if defined(__i386__)
+ // Zero out the lastSyscallNum, so that we don't try to coalesce
+ // calls to gettimeofday(). For debugging purposes, we need the
+ // exact time.
+ asm volatile("movl $0, %fs:0x102C-0x58");
+ #elif !defined(__x86_64__)
+ #error Unsupported target platform
+ #endif
+ ::gettimeofday(&tv, NULL);
+ *tm = 1000ULL*1000ULL*static_cast<unsigned>(tv.tv_sec) +
+ static_cast<unsigned>(tv.tv_usec);
+ }
+}
+
+void Debug::syscall(long long* tm, int sysnum, const char* msg, int call) {
+ // This function gets called from the system call wrapper. Avoid calling
+ // any library functions that themselves need system calls.
+ if (enabled_) {
+ if (enter() || !tm) {
+ gettimeofday(tm);
+
+ const char *sysname = NULL;
+ if (sysnum >= 0 && sysnum < numSyscallNames_) {
+ sysname = syscallNames_[sysnum];
+ }
+ static const char kUnnamedMessage[] = "Unnamed syscall #";
+ char unnamed[40];
+ if (!sysname) {
+ memcpy(unnamed, kUnnamedMessage, sizeof(kUnnamedMessage) - 1);
+ itoa(unnamed + sizeof(kUnnamedMessage) - 1, sysnum);
+ sysname = unnamed;
+ }
+ #if defined(__NR_socketcall) || defined(__NR_ipc)
+ char extra[40];
+ *extra = '\000';
+ #if defined(__NR_socketcall)
+ if (sysnum == __NR_socketcall) {
+ static const char* socketcall_name[] = {
+ 0, "socket", "bind", "connect", "listen", "accept", "getsockname",
+ "getpeername", "socketpair", "send", "recv", "sendto","recvfrom",
+ "shutdown", "setsockopt", "getsockopt", "sendmsg", "recvmsg",
+ "accept4"
+ };
+ if (call >= 1 &&
+ call < (int)(sizeof(socketcall_name)/sizeof(char *))) {
+ strcat(strcpy(extra, " "), socketcall_name[call]);
+ } else {
+ itoa(strcpy(extra, " #") + 2, call);
+ }
+ }
+ #endif
+ #if defined(__NR_ipc)
+ if (sysnum == __NR_ipc) {
+ static const char* ipc_name[] = {
+ 0, "semop", "semget", "semctl", "semtimedop", 0, 0, 0, 0, 0, 0,
+ "msgsnd", "msgrcv", "msgget", "msgctl", 0, 0, 0, 0, 0, 0,
+ "shmat", "shmdt", "shmget", "shmctl" };
+ if (call >= 1 && call < (int)(sizeof(ipc_name)/sizeof(char *)) &&
+ ipc_name[call]) {
+ strcat(strcpy(extra, " "), ipc_name[call]);
+ } else {
+ itoa(strcpy(extra, " #") + 2, call);
+ }
+ }
+ #endif
+ #else
+ static const char extra[1] = { 0 };
+ #endif
+ char buf[strlen(sysname) + strlen(extra) + (msg ? strlen(msg) : 0) + 4];
+ strcat(strcat(strcat(strcat(strcpy(buf, sysname), extra), ": "),
+ msg ? msg : ""), "\n");
+ _message(buf);
+ }
+ leave();
+ }
+}
+
+char* Debug::itoa(char* s, int n) {
+ // Remember return value
+ char *ret = s;
+
+ // Insert sign for negative numbers
+ if (n < 0) {
+ *s++ = '-';
+ n = -n;
+ }
+
+ // Convert to decimal (in reverse order)
+ char *start = s;
+ do {
+ *s++ = '0' + (n % 10);
+ n /= 10;
+ } while (n);
+ *s-- = '\000';
+
+ // Reverse order of digits
+ while (start < s) {
+ char ch = *s;
+ *s-- = *start;
+ *start++ = ch;
+ }
+
+ return ret;
+}
+
+void Debug::elapsed(long long tm, int sysnum, int call) {
+ if (enabled_) {
+ if (enter()) {
+ // Compute the time that has passed since the system call started.
+ long long delta;
+ gettimeofday(&delta);
+ delta -= tm;
+
+ // Format "Elapsed time: %d.%03dms" without using sprintf().
+ char buf[80];
+ itoa(strrchr(strcpy(buf, "Elapsed time: "), '\000'), delta/1000);
+ delta %= 1000;
+ strcat(buf, delta < 100 ? delta < 10 ? ".00" : ".0" : ".");
+ itoa(strrchr(buf, '\000'), delta);
+ strcat(buf, "ms");
+
+ // Print system call name and elapsed time.
+ syscall(NULL, sysnum, buf, call);
+ }
+ leave();
+ }
+}
+
+} // namespace
+
+#endif // NDEBUG