1/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2/* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6#include "nsSandboxViolationSink.h" 7 8#import <Foundation/NSObjCRuntime.h> 9 10#include <unistd.h> 11#include <time.h> 12#include <asl.h> 13#include <dispatch/dispatch.h> 14#include <notify.h> 15#include "mozilla/Preferences.h" 16#include "mozilla/Sprintf.h" 17 18int nsSandboxViolationSink::mNotifyToken = 0; 19uint64_t nsSandboxViolationSink::mLastMsgReceived = 0; 20 21void nsSandboxViolationSink::Start() { 22 if (mNotifyToken) { 23 return; 24 } 25 notify_register_dispatch( 26 SANDBOX_VIOLATION_NOTIFICATION_NAME, &mNotifyToken, 27 dispatch_queue_create(SANDBOX_VIOLATION_QUEUE_NAME, DISPATCH_QUEUE_SERIAL), ^(int token) { 28 ViolationHandler(); 29 }); 30} 31 32void nsSandboxViolationSink::Stop() { 33 if (!mNotifyToken) { 34 return; 35 } 36 notify_cancel(mNotifyToken); 37 mNotifyToken = 0; 38} 39 40// We need to query syslogd to find out what violations occurred, and whether 41// they were "ours". We can use the Apple System Log facility to do this. 42// Besides calling notify_post("com.apple.sandbox.violation.*"), Apple's 43// sandboxd also reports all sandbox violations (sent to it by the Sandbox 44// kernel extension) to syslogd, which stores them and makes them viewable 45// in the system console. This is the database we query. 46 47// ViolationHandler() is always called on its own secondary thread. This 48// makes it unlikely it will interfere with other browser activity. 49 50void nsSandboxViolationSink::ViolationHandler() { 51 aslmsg query = asl_new(ASL_TYPE_QUERY); 52 53 asl_set_query(query, ASL_KEY_FACILITY, "com.apple.sandbox", ASL_QUERY_OP_EQUAL); 54 55 // Only get reports that were generated very recently. 56 char query_time[30] = {0}; 57 SprintfLiteral(query_time, "%li", time(NULL) - 2); 58 asl_set_query(query, ASL_KEY_TIME, query_time, ASL_QUERY_OP_NUMERIC | ASL_QUERY_OP_GREATER_EQUAL); 59 60 // This code is easier to test if we don't just track "our" violations, 61 // which are (normally) few and far between. For example (for the time 62 // being at least) four appleeventsd sandbox violations happen every time 63 // we start the browser in e10s mode. But it makes sense to default to 64 // only tracking "our" violations. 65 if (mozilla::Preferences::GetBool("security.sandbox.mac.track.violations.oursonly", true)) { 66 // This makes each of our processes log its own violations. It might 67 // be better to make the chrome process log all the other processes' 68 // violations. 69 char query_pid[20] = {0}; 70 SprintfLiteral(query_pid, "%u", getpid()); 71 asl_set_query(query, ASL_KEY_REF_PID, query_pid, ASL_QUERY_OP_EQUAL); 72 } 73 74 aslresponse response = asl_search(nullptr, query); 75 76 // Each time ViolationHandler() is called we grab as many messages as are 77 // available. Otherwise we might not get them all. 78 if (response) { 79 while (true) { 80 aslmsg hit = nullptr; 81 aslmsg found = nullptr; 82 const char* id_str; 83 84 while ((hit = aslresponse_next(response))) { 85 // Record the message id to avoid logging the same violation more 86 // than once. 87 id_str = asl_get(hit, ASL_KEY_MSG_ID); 88 uint64_t id_val = atoll(id_str); 89 if (id_val <= mLastMsgReceived) { 90 continue; 91 } 92 mLastMsgReceived = id_val; 93 found = hit; 94 break; 95 } 96 if (!found) { 97 break; 98 } 99 100 const char* pid_str = asl_get(found, ASL_KEY_REF_PID); 101 const char* message_str = asl_get(found, ASL_KEY_MSG); 102 NSLog(@"nsSandboxViolationSink::ViolationHandler(): id %s, pid %s, message %s", id_str, 103 pid_str, message_str); 104 } 105 aslresponse_free(response); 106 } 107} 108