#include <mach/kern_return.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
-#include "mach_notify.h"
+#include "mach_notifyServer.h"
#include <security_utilities/debugging.h>
#include <malloc/malloc.h>
# include <sys/time.h>
#endif
+#define SEC_MACH_AUDIT_TOKEN_PID (5)
+
namespace Security {
namespace MachPlusPlus {
//
void MachServer::add(Port receiver)
{
- SECURITY_MACHSERVER_PORT_ADD(receiver);
+ secinfo("machserver", "port add: %d", receiver.port());
mPortSet += receiver;
}
void MachServer::remove(Port receiver)
{
- SECURITY_MACHSERVER_PORT_REMOVE(receiver);
+ secinfo("machserver", "port remove: %d", receiver.port());
mPortSet -= receiver;
}
highestWorkerCount = 1;
// run server loop in initial (immortal) thread
- SECURITY_MACHSERVER_START_THREAD(false);
+ secinfo("machserver", "start thread");
runServerThread(false);
- SECURITY_MACHSERVER_END_THREAD(false);
+ secinfo("machserver", "end thread");
// primary server thread exited somehow (not currently possible)
assert(false);
Time::Absolute rightNow = Time::now();
if (rightNow >= nextCheckTime) { // reaping period complete; process
UInt32 idlers = leastIdleWorkers;
- SECURITY_MACHSERVER_REAP(workerCount, idlers);
+ secinfo("machserver", "reaping workers: %d %d", (uint32_t) workerCount, (uint32_t) idlers);
nextCheckTime = rightNow + workerTimeout;
leastIdleWorkers = INT_MAX;
if (idlers > 1) // multiple idle threads throughout measuring interval...
timeout = workerTimeout;
}
}
- if (SECURITY_MACHSERVER_RECEIVE_ENABLED())
- SECURITY_MACHSERVER_RECEIVE(indefinite ? 0 : timeout.seconds());
-
+
// receive next IPC request (or wait for timeout)
mach_msg_return_t mr = indefinite ?
mach_msg_overwrite(bufRequest,
// process received request message below
break;
default:
- SECURITY_MACHSERVER_RECEIVE_ERROR(mr);
+ secinfo("machserver", "received error: %d", mr);
continue;
}
+ // reset the buffer each time, handlers don't consistently set out params
+ bufReply.clearBuffer();
+
// process received message
if (bufRequest.msgId() >= MACH_NOTIFY_FIRST &&
bufRequest.msgId() <= MACH_NOTIFY_LAST) {
// mach kernel notification message
// we assume this is quick, so no thread arbitration here
+ mach_msg_audit_trailer_t *tlr = bufRequest.auditTrailer();
+ if (tlr == NULL || tlr->msgh_audit.val[SEC_MACH_AUDIT_TOKEN_PID] != 0) {
+ secnotice("machserver", "ignoring invalid notify message");
+ continue;
+ }
cdsa_notify_server(bufRequest, bufReply);
} else {
// normal request message
StLock<MachServer, &MachServer::busy, &MachServer::idle> _(*this);
- SECURITY_MACHSERVER_BEGIN(bufRequest.localPort(), bufRequest.msgId());
+ secinfo("machserver", "begin request: %d, %d", bufRequest.localPort().port(), bufRequest.msgId());
// try subsidiary handlers first
bool handled = false;
handle(bufRequest, bufReply);
}
- SECURITY_MACHSERVER_END();
+ secinfo("machserver", "end request");
}
// process reply generated by handler
* To avoid falling off the kernel's fast RPC path unnecessarily,
* we only supply MACH_SEND_TIMEOUT when absolutely necessary.
*/
- mr = mach_msg_overwrite(bufReply,
+ mr = mach_msg_overwrite(bufReply,
(MACH_MSGH_BITS_REMOTE(bufReply.bits()) ==
MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
MACH_SEND_MSG | mMsgOptions :
MACH_SEND_MSG | MACH_SEND_TIMEOUT | mMsgOptions,
bufReply.length(), 0, MACH_PORT_NULL,
0, MACH_PORT_NULL, NULL, 0);
- switch (mr) {
- case MACH_MSG_SUCCESS:
- break;
- default:
- SECURITY_MACHSERVER_SEND_ERROR(mr, bufReply.remotePort());
- bufReply.destroy();
- break;
- }
+ switch (mr) {
+ case MACH_MSG_SUCCESS:
+ break;
+ case MACH_SEND_INVALID_DEST:
+ case MACH_SEND_TIMED_OUT:
+ secinfo("machserver", "send error: %d %d", mr, bufReply.remotePort().port());
+ bufReply.destroy();
+ break;
+ default:
+ secinfo("machserver", "send error: %d %d", mr, bufReply.remotePort().port());
+ break;
+ }
// clean up after the transaction
if (memory) {
set<Allocation> &releaseSet = perThread().deferredAllocations;
assert(releaseSet.find(Allocation(memory, alloc)) == releaseSet.end());
- SECURITY_MACHSERVER_ALLOC_REGISTER(memory, &alloc);
+ secinfo("machserver", "allocing register %p with alloc %p", memory, &alloc);
releaseSet.insert(Allocation(memory, alloc));
}
}
{
set<Allocation> &releaseSet = perThread().deferredAllocations;
for (set<Allocation>::iterator it = releaseSet.begin(); it != releaseSet.end(); it++) {
- SECURITY_MACHSERVER_ALLOC_RELEASE(it->addr, it->allocator);
-
+ secinfo("machserver", "releasing alloc at %p with %p", it->addr, it->allocator);
+
// before we release the deferred allocation, zap it so that secrets aren't left in memory
size_t memSize = malloc_size(it->addr);
bzero(it->addr, memSize);
// register the worker thread and go
server.addThread(this);
try {
- SECURITY_MACHSERVER_START_THREAD(true);
+ secinfo("machserver", "start thread");
server.runServerThread(true);
- SECURITY_MACHSERVER_END_THREAD(false);
+ secinfo("machserver", "end thread");
} catch (...) {
// fell out of server loop by error. Let the thread go quietly
- SECURITY_MACHSERVER_END_THREAD(true);
+ secinfo("machserver", "end thread (due to error)");
}
server.removeThread(this);
}
return false; // nothing (more) to be done now
} // drop lock; work has been retrieved
try {
- SECURITY_MACHSERVER_TIMER_START(top, top->longTerm(), Time::now().internalForm());
+ secinfo("machserver", "timer start: %p, %d, %f", top, top->longTerm(), Time::now().internalForm());
StLock<MachServer::Timer,
&MachServer::Timer::select, &MachServer::Timer::unselect> _t(*top);
if (top->longTerm()) {
} else {
top->action();
}
- SECURITY_MACHSERVER_TIMER_END(false);
+ secinfo("machserver", "timer end (false)");
} catch (...) {
- SECURITY_MACHSERVER_TIMER_END(true);
+ secinfo("machserver", "timer end (true)");
}
return true;
}
//
// Notification hooks and shims. Defaults do nothing.
//
-void cdsa_mach_notify_dead_name(mach_port_t, mach_port_name_t port)
+kern_return_t cdsa_mach_notify_dead_name(mach_port_t, mach_port_name_t port)
{
try {
MachServer::active().notifyDeadName(port);
} catch (...) {
}
+ // the act of receiving a dead name notification allocates a dead-name
+ // right that must be deallocated
+ mach_port_deallocate(mach_task_self(), port);
+ return KERN_SUCCESS;
}
void MachServer::notifyDeadName(Port) { }
-void cdsa_mach_notify_port_deleted(mach_port_t, mach_port_name_t port)
+kern_return_t cdsa_mach_notify_port_deleted(mach_port_t, mach_port_name_t port)
{
try {
MachServer::active().notifyPortDeleted(port);
} catch (...) {
}
+ return KERN_SUCCESS;
}
void MachServer::notifyPortDeleted(Port) { }
-void cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port)
+kern_return_t cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port)
{
try {
MachServer::active().notifyPortDestroyed(port);
} catch (...) {
}
+ return KERN_SUCCESS;
}
void MachServer::notifyPortDestroyed(Port) { }
-void cdsa_mach_notify_send_once(mach_port_t port)
+kern_return_t cdsa_mach_notify_send_once(mach_port_t port)
{
try {
MachServer::active().notifySendOnce(port);
} catch (...) {
}
+ return KERN_SUCCESS;
}
void MachServer::notifySendOnce(Port) { }
-void cdsa_mach_notify_no_senders(mach_port_t port, mach_port_mscount_t count)
+kern_return_t cdsa_mach_notify_no_senders(mach_port_t port, mach_port_mscount_t count)
{
try {
MachServer::active().notifyNoSenders(port, count);
} catch (...) {
}
+ return KERN_SUCCESS;
}
void MachServer::notifyNoSenders(Port, mach_port_mscount_t) { }