Post

Replies

Boosts

Views

Activity

When is XPC_ERROR_TERMINATION_IMMINENT sent?
No matter what I try to do to quit/kill my XPC service while its processing a message, my client only ever gets XPC_ERROR_CONNECTION_INTERRUPTED and never XPC_ERROR_TERMINATION_IMMINENT. To be specific, I tried all these things: Quitting the service while it's idle (SIGTERM) Force-quitting the service while it's idle (SIGKILL) Quitting the service while it's in the middle of processing a message (SIGTERM) Force-quitting the service while it's in the middle of processing a message (SIGKILL) Making the service quit itself in the middle of processing a message (exit(EXIT_SUCCESS)) Making the service cancel the connection in the middle of processing a message (xpc_connection_cancel(connection)) Hoping to find some examples of its usage, I searched around GitHub, and haven't really found anyone do much at all in response to this message. Some parts look like they come up from a common ancestor (probably some guide or template): https://github.com/search?q=%22The+client+process+on+the+other+end+of+the+connection+has+either%22&type=Code Even Apple's own WebKit2 doesn't seem to do much with it: https://github.com/apple-opensource/WebKit2/search?q=XPC_ERROR_TERMINATION_IMMINENT When does XPC_ERROR_TERMINATION_IMMINENT ever come into play?
3
0
1.1k
Jan ’22
SMJobBless fails when called from an XPC Service.
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)
4
0
1.9k
Nov ’21
Obtaining CPU usage by process
Hi there, I'm working on an app that contains a mini system monitoring utility. I would like to list the top CPU-using processes. As Quinn “The Eskimo!” has repeatedly cautioned, relying on private frameworks is just begging for maintenance effort in the future. Ideally, I want to go through public headers/frameworks. I've gone to great lengths to try to find this information myself, and at this point I'm just struggling. I detail my research below. Any pointers in the right direction would be much appreciated! Attempts Libproc First I looked at libproc. Using proc_pidinfo with PROC_PIDTHREADINFO, I'm able to get each thread of an app, with its associated CPU usage percentage. Summing these, I could get the total for an app. Unfortunately, this has two downsides: Listing a table of processes now takes O(proces_count) rather than just O(process_count), and causes way more syscalls to be made It doesn't work for processes owned by other users. Perhaps running as root could alleviate that, but that would involve making a priviliedged helper akin to the existing sysmond that Activity Monitor.app uses. I'm a little scared of that, because I don't want to put my users at risk. Sysctl Using the keys [CTL_KERN, KERN_PROC, KERN_PROC_PID, someProcessID], I'm able to get a kinfo_proc - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/sysctl.h#L750-L776 instance. Accessing its .kp_proc - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/proc.h#L96-L150.p_pctcpu - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/proc.h#L123 looked really promising, but that value is always zero. Digging deeper, I found the kernel code that fills this struct in (fill_user64_externproc - https://github.com/apple-opensource/xnu/blob/c76cff20e09b8d61688d1c3dfb8cc855cccb93ad/bsd/kern/kern_sysctl.c#L1121-L1168). The assignment of p_pctcpu - https://github.com/apple-opensource/xnu/blob/c76cff20e09b8d61688d1c3dfb8cc855cccb93ad/bsd/kern/kern_sysctl.c#L1149 is in a conditional region, relying on the _PROC_HAS_SCHEDINFO_ flag. Disassembling the kernel on my mac, I could confirm that the assignment of that field never happens (thus _PROC_HAS_SCHEDINFO_ wasn't set during compilation, and the value will always stay zero) Reverse engineering Activity Monitor.app Activity Monitor.app makes proc_info and sysctl system calls, but from looking at the disassembly, it doesn't look like that's where its CPU figures come from. From what I can tell, it's using private functions from /usr/lib/libsysmon.dylib. That's a user library which wraps an XPC connection to sysmond (/usr/libexec/sysmond), allowing you to create requests (sysmon_request_create), add specific attributes you want to retrieve (sysmon_request_add_attribute), and then functions to query that data out (sysmon_row_get_value). Getting the data "striaght from the horses mouth" like this sounds ideal. But unfortunately, the only documentation/usage I can find of sysmond is from bug databases demonstrating a privilege escalation vulnerability lol. There are some partial reverse engineered header files floating around, but they're incomplete, and have the usual fragility/upkeep issues associated with using private APIs. On one hand, I don't want to depend on a private API, because that takes a lot of time to reverse engineer, keep up with changes, etc. On the other, making my own similar privileged helper would be duplicating effort, and expose a bigger attack surface. Needless to say, I have no confidence in being able to make a safer privileged helper than Apple's engineers lol Reverse engineering iStat Menus Looks like they're using proc_pid_rusage - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/libsyscall/wrappers/libproc/libproc.h#L103-L108 . However, I don't know how to convert the cpu_*_time fields of the resulting struct rusage_info_v4 - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/resource.h#L306-L343 to compute a "simple" percentage. Even if I came up with some formula that produces plausible looking results, I have no real guarantee it's correct or equivalent to what Activity Monitor shows.
5
1
6.6k
Mar ’24
When is XPC_ERROR_TERMINATION_IMMINENT sent?
No matter what I try to do to quit/kill my XPC service while its processing a message, my client only ever gets XPC_ERROR_CONNECTION_INTERRUPTED and never XPC_ERROR_TERMINATION_IMMINENT. To be specific, I tried all these things: Quitting the service while it's idle (SIGTERM) Force-quitting the service while it's idle (SIGKILL) Quitting the service while it's in the middle of processing a message (SIGTERM) Force-quitting the service while it's in the middle of processing a message (SIGKILL) Making the service quit itself in the middle of processing a message (exit(EXIT_SUCCESS)) Making the service cancel the connection in the middle of processing a message (xpc_connection_cancel(connection)) Hoping to find some examples of its usage, I searched around GitHub, and haven't really found anyone do much at all in response to this message. Some parts look like they come up from a common ancestor (probably some guide or template): https://github.com/search?q=%22The+client+process+on+the+other+end+of+the+connection+has+either%22&type=Code Even Apple's own WebKit2 doesn't seem to do much with it: https://github.com/apple-opensource/WebKit2/search?q=XPC_ERROR_TERMINATION_IMMINENT When does XPC_ERROR_TERMINATION_IMMINENT ever come into play?
Replies
3
Boosts
0
Views
1.1k
Activity
Jan ’22
SMJobBless fails when called from an XPC Service.
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)
Replies
4
Boosts
0
Views
1.9k
Activity
Nov ’21
Obtaining CPU usage by process
Hi there, I'm working on an app that contains a mini system monitoring utility. I would like to list the top CPU-using processes. As Quinn “The Eskimo!” has repeatedly cautioned, relying on private frameworks is just begging for maintenance effort in the future. Ideally, I want to go through public headers/frameworks. I've gone to great lengths to try to find this information myself, and at this point I'm just struggling. I detail my research below. Any pointers in the right direction would be much appreciated! Attempts Libproc First I looked at libproc. Using proc_pidinfo with PROC_PIDTHREADINFO, I'm able to get each thread of an app, with its associated CPU usage percentage. Summing these, I could get the total for an app. Unfortunately, this has two downsides: Listing a table of processes now takes O(proces_count) rather than just O(process_count), and causes way more syscalls to be made It doesn't work for processes owned by other users. Perhaps running as root could alleviate that, but that would involve making a priviliedged helper akin to the existing sysmond that Activity Monitor.app uses. I'm a little scared of that, because I don't want to put my users at risk. Sysctl Using the keys [CTL_KERN, KERN_PROC, KERN_PROC_PID, someProcessID], I'm able to get a kinfo_proc - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/sysctl.h#L750-L776 instance. Accessing its .kp_proc - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/proc.h#L96-L150.p_pctcpu - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/proc.h#L123 looked really promising, but that value is always zero. Digging deeper, I found the kernel code that fills this struct in (fill_user64_externproc - https://github.com/apple-opensource/xnu/blob/c76cff20e09b8d61688d1c3dfb8cc855cccb93ad/bsd/kern/kern_sysctl.c#L1121-L1168). The assignment of p_pctcpu - https://github.com/apple-opensource/xnu/blob/c76cff20e09b8d61688d1c3dfb8cc855cccb93ad/bsd/kern/kern_sysctl.c#L1149 is in a conditional region, relying on the _PROC_HAS_SCHEDINFO_ flag. Disassembling the kernel on my mac, I could confirm that the assignment of that field never happens (thus _PROC_HAS_SCHEDINFO_ wasn't set during compilation, and the value will always stay zero) Reverse engineering Activity Monitor.app Activity Monitor.app makes proc_info and sysctl system calls, but from looking at the disassembly, it doesn't look like that's where its CPU figures come from. From what I can tell, it's using private functions from /usr/lib/libsysmon.dylib. That's a user library which wraps an XPC connection to sysmond (/usr/libexec/sysmond), allowing you to create requests (sysmon_request_create), add specific attributes you want to retrieve (sysmon_request_add_attribute), and then functions to query that data out (sysmon_row_get_value). Getting the data "striaght from the horses mouth" like this sounds ideal. But unfortunately, the only documentation/usage I can find of sysmond is from bug databases demonstrating a privilege escalation vulnerability lol. There are some partial reverse engineered header files floating around, but they're incomplete, and have the usual fragility/upkeep issues associated with using private APIs. On one hand, I don't want to depend on a private API, because that takes a lot of time to reverse engineer, keep up with changes, etc. On the other, making my own similar privileged helper would be duplicating effort, and expose a bigger attack surface. Needless to say, I have no confidence in being able to make a safer privileged helper than Apple's engineers lol Reverse engineering iStat Menus Looks like they're using proc_pid_rusage - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/libsyscall/wrappers/libproc/libproc.h#L103-L108 . However, I don't know how to convert the cpu_*_time fields of the resulting struct rusage_info_v4 - https://github.com/apple-opensource/xnu/blob/24525736ba5b8a67ce3a8a017ced469abe101ad5/bsd/sys/resource.h#L306-L343 to compute a "simple" percentage. Even if I came up with some formula that produces plausible looking results, I have no real guarantee it's correct or equivalent to what Activity Monitor shows.
Replies
5
Boosts
1
Views
6.6k
Activity
Mar ’24