Doug's Note System
Using task_for_pid on Mac OS X
Prior to the Mac OS X 10.5 (Tiger), it was completely legal for one process to modify another
for the purpose of controlling its execution (single stepping, resuming, stopping etc) and
inspecting/modifying its memory. In Tiger, this policy was modified so that only a process
owned by root or with a primary effective group of procmod or procview
has this privilege. In Leopard (Mac OS X 10.5), this policy was changed such that a debugger
process now depends on the security framework to authorize use of the task_for_pid
system service which gives a process the capability to control another process. The details
are in the man page for the taskgated daemon. The default launch configuration
for this daemon (in the file /System/Library/LaunchDaemons/com.apple.taskgated.plist)
runs the daemon in the aforementioned Tiger mode.
The reason I mention all this is that the
Maxine VM has a companion tool
(called the Inspector)
that is used for debugging a running instance of the VM. That is, the Inspector process
needs the ability to control the VM process. Up to (and including) Leopard, the Inspector
was granted this capability by means of a (somewhat insecure) workaround. Given that the
Inspector is itself a Java program, one could simply modify the java executable
used to run it. For example:
% sudo chgrp procmod /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/bin/java % sudo chmod g+s /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/bin/java
It should be obvious of course, that this opens up potential security vulnerabilities that
can be exploited by other Java programs run by the same executable. This was considered tolerable
for those developers working on Inspector on a Mac. However, with the release of Snow Leopard
(Mac OS X 10.6), this workaround was rendered ineffective. If one tries to run the inspector
on Snow Leopard with the altered java executable, the result on the console is:
2009-09-16 11:14:23.307 java[1654:903] The application with bundle ID (null) is running setugid(), which is not allowed.
Not being a very knowledgeable Mac developer (nor wanting to invest the time to become one just yet!),
I'm not exactly sure what this means. However, the outcome is that modifying the ownership and
permission bits of the java executable is no longer possible on Snow Leopard. So, what
is an Inspector user on Snow Leopard to do?! Unfortunately, the
current solution is to force the
Inspector to be launched as root via sudo.
However, the ideal solution is to use the
Authorization Services
on a Mac to dynamically obtain the privileges necessary for the Inspector to use task_for_pid.
Unfortunately, use of this framework turns out not to be as straight forward as I thought it would (should!) be.
Based on the sample code
provided by Apple, I would have thought the following code is sufficient to
acquire the privilege for calling task_for_pid:
#include "auth.h"
#include <Security/Authorization.h>
int acquireTaskportRight() {
AuthorizationRef authorization;
OSStatus status = AuthorizationCreate (NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorization);
if (status != 0) {
fprintf(stderr, "Error creating authorization reference\n");
return -1;
}
AuthorizationItem right = { "system.privilege.taskport", 0, 0 , 0 };
AuthorizationItem items[] = { right };
AuthorizationRights rights = { sizeof(items) / sizeof(items[0]), items };
AuthorizationFlags flags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize;
status = AuthorizationCopyRights (authorization, &rights, kAuthorizationEmptyEnvironment, flags, NULL);
if (status != 0) {
fprintf(stderr, "Error authorizing current process with right to call task_for_pid\n");
return -1;
}
return 0;
}
When executed, this code results in the expected authentication dialog:
When I enter an administrator name and password, the dialog closes and the authorization appears to succeed.
This suspicion is supported by the entry written to /var/log/secure.log:
Sep 16 11:11:28 isquawk com.apple.SecurityServer[21]: Succeeded authorizing right 'system.privilege.taskport' by client \
'/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/bin/java' for authorization created by \
'/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/bin/java'
However, a following call to task_for_pid returns an error code of 5 (i.e. a generic
kernel failure). At this point, I'm at a loss as to what extra steps are required to convince the OS
that I indeed have the permission to debug one of my own programs!
Posted at 01:59PM Sep 16, 2009 by Doug Simon in Sun | Comments[7]
Opening multiple Eclipse instances on Mac OS X
While I'm generally only working within one Eclipse workspace, I occasionally have the need to open more than one Eclipse instance. One good example for this need is when debugging a regression. In this case, it can be quite useful to run side-by-side debug sessions; one on my current code, the other on an earlier version that I know does not contain the bug. To do so, I simply want to create a copy of the earlier version (using 'hg clone -r <good version number>' since I'm using Mercurial) and bring it up in a new instance of Eclipse. This is straight forward on most systems but on Mac OS X, launching an application by double clicking its icon simply brings a running instance of the app to the foreground. So, to achieve the desired effect on Mac, one needs to resort to the command line:
open -n /Applications/eclipse/Eclipse.app
This forces a new instance of the app to start. In theory, this should be sufficient. However, as I found out in my case, there is (at least) one other complication that my present itself. I have JDK 6 installed on my Mac and due to the way I've configured my PATH variable, it's the default version of Java launched from a terminal with an unqualified use of the java command. It appears as though this is how the Eclipse launcher starts its embedded Java process. The problem then is that Eclipse is a 32-bit app and JDK 6 on the Mac is 64-bit only and not surprisingly the result is a crash. The trick is therefore to modify one's path to ensure the JDK 5 java command is the default on the command line:
env PATH=/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Commands:$PATH open -n /Application/eclipse/Eclipse.app
I thought a better solution maybe to explicitly specify the JDK 5 java executable in /Applications/eclipse/Eclipse.app/Contents/MacOS/eclipse.ini with the following line:
-vm /System/Library/Frameworks/JavaVM.framework/Versions/1.5/Commands/java
but that doesn't work for some reason.
Posted at 10:32PM Jan 18, 2009 by Doug Simon in Sun | Comments[7]
VM documentation
Since joining Sun Labs in 2001, I've worked mostly on the design and implementation of language-level virtual machines. No prizes for guessing which language these VMs implement! Now that the second and third VM I've worked on have been released as open source, it's a good time to start a blog discussing the interesting parts of these VMs. That way, I can remember exactly what I was thinking when it comes time to debug/modify/discard the code. While most of these notes should be reflected in the javadoc associated with the code, I'm aware of some people's preference for reading webpages over reading javadoc. Maybe I should consider going straight to maintaining entries on Wikipedia - astute observers can then debug my VM design and implementation decisions with no more than a web browser ;-)
Posted at 05:27PM Jun 04, 2008 by Doug Simon in Sun | Comments[3]