Hey there,
I'm trying to employ the same pattern as demonstrated in the EvenBetterAuthorizationSample: an unsandboxed XPC service calls SMJobBless
to install a privileged helper service on behalf a sandboxed main app (which isn't allowed to call SMJobBless
). It then starts an XPC connection to the Mach service hosted by the privileged service, and hands over the connection back to the main app, along with the XPC service's connection to the security server (AuthorizationRef).
When I try to do call SMJobBless
from my XPC service, I get these messages:
info authd Process /usr/libexec/smd (PID 28881) evaluates 1 rights with flags 00000003 (engine 629): (
"com.apple.ServiceManagement.blesshelper"
)
error authd Fatal: interaction not allowed (session has no ui access) (engine 629)
default authd Failed to authorize right 'com.apple.ServiceManagement.blesshelper' by client '/usr/libexec/smd' [28881] for authorization created by '/MyApp.app/Contents/XPCServices/IntermediatorXPCService.xpc' [29325] (3,0) (-60007) (engine 629)
error authd copy_rights: authorization failed
This seems reasonable to me, because I wouldn't expect an XPC service to be capable of running graphics. However, this works just fine in the "App-Sandboxed" app in the EvenBetterAuthorizationSample project.
I poked around the available open source code, and found out that this message is logged when the processes' audit session doesn't have AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
set.
if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) {
os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (session has no ui access) (engine %lld)", engine->engine_index);
return errAuthorizationInteractionNotAllowed;
}
Out of curiosity, I compared the audit sessions of my XPC service to the one in EBAS using this code:
auditinfo_addr_t auditInfo;
int result = getaudit_addr(&auditInfo, sizeof(auditInfo));
assert(result == 0 );
if (auditInfo.ai_flags & AU_SESSION_FLAG_IS_INITIAL) {
NSLog(@"AU_SESSION_FLAG_IS_INITIAL");
}
if (auditInfo.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS) {
NSLog(@"AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS");
}
if (auditInfo.ai_flags & AU_SESSION_FLAG_HAS_TTY) {
NSLog(@"AU_SESSION_FLAG_HAS_TTY");
}
if (auditInfo.ai_flags & AU_SESSION_FLAG_IS_REMOTE) {
NSLog(@"AU_SESSION_FLAG_IS_REMOTE");
}
if (auditInfo.ai_flags & AU_SESSION_FLAG_HAS_CONSOLE_ACCESS) {
NSLog(@"AU_SESSION_FLAG_HAS_CONSOLE_ACCESS");
}
if (auditInfo.ai_flags & AU_SESSION_FLAG_HAS_AUTHENTICATED) {
NSLog(@"AU_SESSION_FLAG_HAS_AUTHENTICATED");
}
Sure enough, I got different results.
EBAS:
2021-11-20 18:45:52.792512-0500 com.example.apple-samplecode.EBAS.XPCService[25296:592874] result: 0
2021-11-20 18:45:52.792527-0500 com.example.apple-samplecode.EBAS.XPCService[25296:592874] AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
2021-11-20 18:45:52.792539-0500 com.example.apple-samplecode.EBAS.XPCService[25296:592874] AU_SESSION_FLAG_HAS_TTY
2021-11-20 18:45:52.792549-0500 com.example.apple-samplecode.EBAS.XPCService[25296:592874] AU_SESSION_FLAG_HAS_CONSOLE_ACCESS
(lldb) p auditInfo
(auditinfo_addr_t) $0 = {
ai_auid = 501
ai_mask = (am_success = 4294967295, am_failure = 4294967295)
ai_termid = {
at_port = 50331650
at_type = 4
at_addr = ([0] = 0, [1] = 0, [2] = 0, [3] = 0)
}
ai_asid = 100019
ai_flags = 8240
}
My XPC service:
2021-11-20 21:33:44.355007-0500 IntermediatorXPCService[29325:698278] result: 0
(lldb) p auditInfo
▿ __C.auditinfo_addr
- ai_auid: 4294967295
▿ ai_mask: __C.au_mask
- am_success: 4294967295
- am_failure: 4294967295
▿ ai_termid: __C.au_tid_addr
- at_port: 0
- at_type: 4
▿ at_addr: (4 elements)
- .0: 0
- .1: 0
- .2: 0
- .3: 0
- ai_asid: 102293
- ai_flags: 0
It looks like ai_flags
is all 0. Any ideas why that might be? What is making EBAS special?
And also, how can AU_SESSION_FLAG_HAS_TTY
and AU_SESSION_FLAG_HAS_CONSOLE_ACCESS
be false? I'm reading these logs from the console?!
(Another curious observation: audit_session_flags
is imported into Swift as RawRepresentable
, but not as an OptionSet
)