Giter Site home page Giter Site logo

securexpc's People

Contributors

amomchilov avatar jakaplan avatar vincent-le-normand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

securexpc's Issues

Verify that exporting a connection for a Mach service works correctly

fatalError("""
The ability to export the endpoint of an XPCServer for a Mach Service is untested, and likely broken.
See https://github.com/trilemma-dev/SecureXPC/issues/33
""")

Fatal-error this code path to say that it's untested, and treat it as effectively not-yet-implemented.

...

Let's go with option 2 for now. I'd volunteer to try testing it out, but between end of year busyness at work and heading off on holiday soon I just won't have time before early January. Can revisit it then.

Originally posted by @jakaplan in #23 (comment)

Helper crashing in Catalina & Big Sur.

As per title, my helper is crashing in Catalina & Big Sur. It is fine in Monterey. After launching it runs a bunch of route requests fine, but then crashes with EXC_BAD_ACCESS.

It doesn't seem to crash in any of my route handling code nor on any particular route call, so I'm assuming it must be something to do with my route definitions, although I can't see what. I am wondering if anything jumps out to you in the crash log?

Click to expand crash log (truncated to fit allowed GitHub post size):
Process:               com.test.AppHelper.Debug [3028]
Path:                  /Library/PrivilegedHelperTools/com.test.AppHelper.Debug
Identifier:            com.test.AppHelper.Debug
Version:               1.0.0-beta.4 (100)
Code Type:             X86-64 (Native)
Parent Process:        launchd [1]
Responsible:           com.test.AppHelper.Debug [3028]
User ID:               0

Date/Time:             2022-05-01 18:11:55.299 +1200
OS Version:            macOS 11.6 (20G165)
Report Version:        12
Anonymous UUID:        DDCC3E05-CCE8-DB38-43E5-8378F721024C

Sleep/Wake UUID:       C6BAE207-875A-4EB8-BF73-823D7FDC7C8E

Time Awake Since Boot: 15000 seconds
Time Since Wake:       6900 seconds

System Integrity Protection: enabled

Crashed Thread:        1  Dispatch queue: com.apple.root.default-qos.overcommit

Exception Type:        EXC_BAD_ACCESS (SIGABRT)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

VM Regions Near 0:
--> 
	__TEXT                      10027c000-10070c000    [ 4672K] r-x/r-x SM=COW  /Library/PrivilegedHelperTools/*.Debug

Application Specific Information:
=================================================================
==3028==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7fff2ca35dc7 bp 0x7000037a0820 sp 0x7000037a0800 T2)
==3028==The signal is caused by a READ memory access.
==3028==Hint: address points to the zero page.
	#0 0x7fff2ca35dc7 in swift::ResolveAsSymbolicReference::operator()(swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*)+0x37 (libswiftCore.dylib:x86_64+0x33cdc7)
	#1 0x7fff2ca582dc in swift::Demangle::__runtime::Demangler::demangleSymbolicReference(unsigned char)+0x8c (libswiftCore.dylib:x86_64+0x35f2dc)
	#2 0x7fff2ca552a7 in swift::Demangle::__runtime::Demangler::demangleType(__swift::__runtime::llvm::StringRef, std::__1::function<swift::Demangle::__runtime::Node* (swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*)>)+0xa7 (libswiftCore.dylib:x86_64+0x35c2a7)
	#3 0x7fff2ca3b5a3 in swift_getTypeByMangledNameImpl(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<swift::TargetMetadata<swift::InProcess> const* (unsigned int, unsigned int)>, std::__1::function<swift::TargetWitnessTable<swift::InProcess> const* (swift::TargetMetadata<swift::InProcess> const*, unsigned int)>)+0x203 (libswiftCore.dylib:x86_64+0x3425a3)
	#4 0x7fff2ca38d6c in swift::swift_getTypeByMangledName(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<swift::TargetMetadata<swift::InProcess> const* (unsigned int, unsigned int)>, std::__1::function<swift::TargetWitnessTable<swift::InProcess> const* (swift::TargetMetadata<swift::InProcess> const*, unsigned int)>)+0x1dc (libswiftCore.dylib:x86_64+0x33fd6c)
	#5 0x7fff2ca38f9a in swift_getTypeByMangledNameInContext+0xaa (libswiftCore.dylib:x86_64+0x33ff9a)
	#6 0x100553ee8 in __swift_instantiateConcreteTypeFromMangledName+0x58 (com.test.AppHelper.Debug:x86_64+0x1002d7ee8)
	#7 0x7fff201a2805 in _dispatch_client_callout+0x7 (libdispatch.dylib:x86_64+0x3805)
	#8 0x7fff201a398b in _dispatch_once_callout+0x13 (libdispatch.dylib:x86_64+0x498b)
	#9 0x7fff2ca47169 in swift_once+0x19 (libswiftCore.dylib:x86_64+0x34e169)
	#10 0x100678f80 in XPCRequestContext._currentForTask.unsafeMutableAddressor+0x30 (com.test.AppHelper.Debug:x86_64+0x1003fcf80)
	#11 0x1006792d3 in $s9SecureXPC17XPCRequestContextC10setForTask10connection7message9operationScTyxq_GSo13OS_xpc_object_p_SoAI_pAHyKXEtKs5ErrorR_r0_lFZ+0x343 (com.test.AppHelper.Debug:x86_64+0x1003fd2d3)
	#12 0x1005c8191 in XPCServer.handleMessage(connection:message:)+0x1b91 (com.test.AppHelper.Debug:x86_64+0x10034c191)
	#13 0x1005c59e6 in XPCServer.handleEvent(connection:event:)+0x3e6 (com.test.AppHelper.Debug:x86_64+0x1003499e6)
	#14 0x1005c4c7a in closure #1 in XPCServer.startClientConnection(_:)+0x1aa (com.test.AppHelper.Debug:x86_64+0x100348c7a)
	#15 0x10053cd43 in thunk for @escaping @callee_guaranteed (@guaranteed OS_xpc_object) -> ()+0x93 (com.test.AppHelper.Debug:x86_64+0x1002c0d43)
	#16 0x7fff20092c23 in _xpc_connection_call_event_handler+0x37 (libxpc.dylib:x86_64+0xcc23)
	#17 0x7fff20091a9a in _xpc_connection_mach_event+0x3a9 (libxpc.dylib:x86_64+0xba9a)
	#18 0x7fff201a28a5 in _dispatch_client_callout4+0x8 (libdispatch.dylib:x86_64+0x38a5)
	#19 0x7fff201b9a9f in _dispatch_mach_msg_invoke+0x1bb (libdispatch.dylib:x86_64+0x1aa9f)
	#20 0x7fff201a8492 in _dispatch_lane_serial_drain+0x106 (libdispatch.dylib:x86_64+0x9492)
	#21 0x7fff201ba5e1 in _dispatch_mach_invoke+0x1e3 (libdispatch.dylib:x86_64+0x1b5e1)
	#22 0x7fff201b2c0c in _dispatch_workloop_worker_thread+0x32a (libdispatch.dylib:x86_64+0x13c0c)
	#23 0x7fff2034945c in _pthread_wqthread+0x139 (libsystem_pthread.dylib:x86_64+0x345c)
	#24 0x7fff2034842e in start_wqthread+0xe (libsystem_pthread.dylib:x86_64+0x242e)
 
==3028==Register values:
rax = 0x0000000000000001  rbx = 0x00007000037a0b88  rcx = 0x000000000003556b  rdx = 0x0000000000000000  
rdi = 0x00007000037a0b88  rsi = 0x0000000000000000  rbp = 0x00007000037a0820  rsp = 0x00007000037a0800  
 r8 = 0x00000001006fd075   r9 = 0xffffe1ffff90bed0  r10 = 0x0000000000000001  r11 = 0x0000000000000000  
r12 = 0x000000000000000e  r13 = 0xffffffffffffffff  r14 = 0x0000000000000001  r15 = 0x0000000000000000  
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (libswiftCore.dylib:x86_64+0x33cdc7) in swift::ResolveAsSymbolicReference::operator()(swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*)+0x37
Thread T2 created by T0 here:
	<empty stack>
 
==3028==ABORTING
 
abort() called

Thread 0:
0   libsystem_pthread.dylib       	0x00007fff20348420 start_wqthread + 0

Thread 1 Crashed:: Dispatch queue: com.apple.root.default-qos.overcommit
0   libsystem_kernel.dylib        	0x00007fff2031d92e __pthread_kill + 10
1   libsystem_pthread.dylib       	0x00007fff2034c5bd pthread_kill + 263
2   libsystem_c.dylib             	0x00007fff202a1406 abort + 125
3   libclang_rt.asan_osx_dynamic.dylib	0x0000000100bc4916 __sanitizer::Abort() + 70
4   libclang_rt.asan_osx_dynamic.dylib	0x0000000100bc4044 __sanitizer::Die() + 196
5   libclang_rt.asan_osx_dynamic.dylib	0x0000000100baba66 __asan::ScopedInErrorReport::~ScopedInErrorReport() + 422
6   libclang_rt.asan_osx_dynamic.dylib	0x0000000100ba976d __asan::ReportDeadlySignal(__sanitizer::SignalContext const&) + 157
7   libclang_rt.asan_osx_dynamic.dylib	0x0000000100ba8eff __asan::AsanOnDeadlySignal(int, void*, void*) + 95
8   libsystem_platform.dylib      	0x00007fff20391d7d _sigtramp + 29
9   ???                           	000000000000000000 0 + 0
10  libswiftCore.dylib            	0x00007fff2ca582dd swift::Demangle::__runtime::Demangler::demangleSymbolicReference(unsigned char) + 141
11  libswiftCore.dylib            	0x00007fff2ca552a8 swift::Demangle::__runtime::Demangler::demangleType(__swift::__runtime::llvm::StringRef, std::__1::function<swift::Demangle::__runtime::Node* (swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*)>) + 168
12  libswiftCore.dylib            	0x00007fff2ca3b5a4 swift_getTypeByMangledNameImpl(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<swift::TargetMetadata<swift::InProcess> const* (unsigned int, unsigned int)>, std::__1::function<swift::TargetWitnessTable<swift::InProcess> const* (swift::TargetMetadata<swift::InProcess> const*, unsigned int)>) + 516
13  libswiftCore.dylib            	0x00007fff2ca38d6d swift::swift_getTypeByMangledName(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<swift::TargetMetadata<swift::InProcess> const* (unsigned int, unsigned int)>, std::__1::function<swift::TargetWitnessTable<swift::InProcess> const* (swift::TargetMetadata<swift::InProcess> const*, unsigned int)>) + 477
14  libswiftCore.dylib            	0x00007fff2ca38f9b swift_getTypeByMangledNameInContext + 171
15  com.test.AppHelper.Debug	0x0000000100553ee9 __swift_instantiateConcreteTypeFromMangledName + 89
16  libdispatch.dylib             	0x00007fff201a2806 _dispatch_client_callout + 8
17  libdispatch.dylib             	0x00007fff201a398c _dispatch_once_callout + 20
18  libswiftCore.dylib            	0x00007fff2ca4716a swift_once + 26
19  com.test.AppHelper.Debug	0x0000000100678f81 XPCRequestContext._currentForTask.unsafeMutableAddressor + 49
20  com.test.AppHelper.Debug	0x00000001006792d4 $s9SecureXPC17XPCRequestContextC10setForTask10connection7message9operationScTyxq_GSo13OS_xpc_object_p_SoAI_pAHyKXEtKs5ErrorR_r0_lFZ + 836
21  com.test.AppHelper.Debug	0x00000001005c8192 XPCServer.handleMessage(connection:message:) + 7058
22  com.test.AppHelper.Debug	0x00000001005c59e7 XPCServer.handleEvent(connection:event:) + 999
23  com.test.AppHelper.Debug	0x00000001005c4c7b closure #1 in XPCServer.startClientConnection(_:) + 427
24  com.test.AppHelper.Debug	0x000000010053cd44 thunk for @escaping @callee_guaranteed (@guaranteed OS_xpc_object) -> () + 148
25  libxpc.dylib                  	0x00007fff20092c24 _xpc_connection_call_event_handler + 56
26  libxpc.dylib                  	0x00007fff20091a9b _xpc_connection_mach_event + 938
27  libdispatch.dylib             	0x00007fff201a28a6 _dispatch_client_callout4 + 9
28  libdispatch.dylib             	0x00007fff201b9aa0 _dispatch_mach_msg_invoke + 444
29  libdispatch.dylib             	0x00007fff201a8493 _dispatch_lane_serial_drain + 263
30  libdispatch.dylib             	0x00007fff201ba5e2 _dispatch_mach_invoke + 484
31  libdispatch.dylib             	0x00007fff201b2c0d _dispatch_workloop_worker_thread + 811
32  libsystem_pthread.dylib       	0x00007fff2034945d _pthread_wqthread + 314
33  libsystem_pthread.dylib       	0x00007fff2034842f start_wqthread + 15

Thread 2:
0   libsystem_kernel.dylib        	0x00007fff2031cb0a __sigsuspend_nocancel + 10
1   libdispatch.dylib             	0x00007fff201b34e1 _dispatch_sigsuspend + 36
2   libdispatch.dylib             	0x00007fff201b34bd _dispatch_sig_thread + 53

Thread 1 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000000  rbx: 0x00007000037a4000  rcx: 0x000070000379f658  rdx: 0x0000000000000000
  rdi: 0x0000000000001803  rsi: 0x0000000000000006  rbp: 0x000070000379f680  rsp: 0x000070000379f658
   r8: 0x0000000100c96107   r9: 0x0000000000000001  r10: 0x0000000000000000  r11: 0x0000000000000246
  r12: 0x0000000000001803  r13: 0xffffffffffffffff  r14: 0x0000000000000006  r15: 0x0000000000000016
  rip: 0x00007fff2031d92e  rfl: 0x0000000000000246  cr2: 0x000010002091bc00
  
Logical CPU:     0
Error Code:      0x02000148
Trap Number:     133

Thread 1 instruction stream:
  89 98 05 00 e9 df fe ff-ff e8 cb d9 fe ff 0f 1f  ................
  00 f8 ff ff ff d0 ff ff-ff c0 ff ff ff cb ff ff  ................
  ff c7 ff ff ff 0f 1f 40-00 55 48 89 e5 41 57 41  [email protected]
  56 53 50 89 d0 48 89 fb-48 63 d1 4c 01 c2 83 f8  VSP..H..Hc.L....
  01 75 0e 40 84 f6 0f 85-8d 00 00 00 48 8b 12 eb  [email protected]...
  0f 40 84 f6 74 0a 48 8b-3b be 03 01 00 00 eb 21  [email protected].;......!
 [8b]02 89 c1 80 e1 1f 80-f9 03 74 0b 80 f9 04 75  ..........t....u	<==
  1f 66 b8 05 01 eb 04 66-b8 98 00 48 8b 3b 0f b7  .f.....f...H.;..
  f0 48 83 c4 08 5b 41 5e-41 5f 5d e9 09 fa 01 00  .H...[A^A_].....
  45 31 f6 48 85 d2 74 33-83 e0 10 74 2e 48 8b 3b  E1.H..t3...t.H.;
  be c3 00 00 00 e8 ef f9-01 00 49 89 c7 48 8b 3b  ..........I..H.;
  be c2 00 00 00 e8 4f f9-01 00 49 89 c6 48 8b 13  ......O...I..H..
  
Thread 1 last branch register state not available.

Client-level error handling

One thing that I've noticed in my use for SecureXPC was that all my clients' callbacks followed the same pattern: they all switch on the result, and called a shared error handling function (in addition to some route-specific error handling).

I think this might be a common use case, especially because changes to the connection state might want to be monitored, and that can happen on every call.

Adding a "global" error handler that applies across all routes of a client would be easy, but then you'd get duplicate reports of errors (once per callback, and then once again). Ideally, having a way to express "if the route callback doesn't handle the error, then give the client error handle a chance to handle it", but I don't know how we could detect if the callback handled the error or not.

Do you have any ideas for how we could improve this?

Type errors in routes are conflated with missing routes

With the way the server's routes are looked up today, a type error (e.g. a message is sent expecting a reply, but the server doesn't expect it to need a reply) ends up being diagnosed as routeNotRegistered.

What do you think about centralizing all route storage into a single table? If we find a route with a different type than expected, then we can emit a more specific "type error".

This also has the (beneficial, IMO) side-effect of making routes unique by solely their names, and not their "kinds" (with/without message, with/without reply)


I ran into this when just trying stuff out and copy-pasting a route on the client and server end, at a time when my client and server code didn't have a "shared" package where I could centralize the route definition. With all duplication like that comes the risk of de-synchronization, and indeed, that's what happened.

Sample use case

Continuing on from #22 (comment) ...

Sorry for going off-topic, but I just wanted to thank you both for your work on this.

Thanks for the kind words! If you have any feedback or questions, don't hesitate to open discussion or topic issues.

I'm hoping to migrate my XPC code to use SecureXPC and really appreciate the effort going into this. I think a lot of people will benefit from this work over time — it's really needed.

If you don't mind me asking, what is your use case for XPC? Always good to understand the diverse ways it's being used to make sure we're considering that as SecureXPC evolves.

My macOS app needs a helper tool to run a bunch of stuff as root — fairly typical stuff I would imagine. I really like your client/server design metaphor particularly the idea of defining routes. I also started to view things this way but only after having written most of my XPC communication code, so it was too late to really integrate the idea.

One area of significant trepidation for me was security — I read lots about this and it was a steep learning curve. It really felt like Apple should be improving their frameworks around all this, or at the very least providing a good solid demo app. As you would know their sample code in this area is ancient and actually insecure (I believe). And given that the accepted wisdom is to never write your own security implementation, there's another reason a package like this, with many more eyes on it, is invaluable.

SO, I was pretty excited when I found your project — in addition to the good work shared by others I believe this will provide a really solid and secure foundation for developers who need it. Actually I don't think it's hyperbolic to say this is likely to measurably increase the quality/security of mac apps (I don't do much iOS right now so I don't really know if it's useful there).

Improve `Data` encoding efficiency by using its native XPC representation

I think we should support the native xpc_data type


(That said, does it actually end up as a string?).

It's much worse than that. Storing it as a string (with say, Base64 for example), would have a 1.6x overhead (5 bits of payload per 8 bit character). The current encoding has an 8x overhead. It encodes one UInt8 of payload per UInt64 of payload.

Here's a section of one of my long comments

I think this is easy enough to do that it might be worth doing.

In particular, I've noticed that Data is really inefficient to encode. As it is today, it bloats sizes by 8x. It tries to encode itself as a [UInt8], but each byte gets widened into an 8 byte int64 in order to be passed to xpc_int64_create. Luckily, there is not per-number object allocation overhead there (that would have been brutal for my use-case haha), because the only possible int64 values here would be 0-255, all of which fit into the tagged pointer representation.

You can get a rough of idea of what that might look like, here: amomchilov/SecureXPC@add-intial-tests-for-XPCEncoder...Alex/new-scalar-support . Of course, I only changed the encoder half, and the decoder would need to match.

Originally posted by @amomchilov in #6 (comment)

Creating an `XPCAnonymousServer` or `XPCMachServer` and never starting it results in XPC API Misuse

If either of these types of servers are created, but never started, then when they are deallocated the following is thrown:

XPC API Misuse: Release of last reference on a suspended connection.

After a bunch of debugging and documentation reading I'm pretty sure what's going on is the following:

  • "XPC connections, like dispatch sources, are returned in a suspended state [...] connections must be resumed in order to be safely released. It is a programming error to release a suspended connection."
  • Both XPCAnonymousServer and XPCMachServer create listener connections as part of their initialization, but do not call xpc_connection_resume(...) on them as part of initializing
  • (If either of those servers are started, then resume is called and this issue is not experienced)
  • xpc_release is unavailable in Swift, but appears to be called by the Swift runtime (or possibly inserted at compile time?) when the listener connection's retain count reaches zero due to the runtime's builtin reference counting
  • When xpc_release is called on a listener connection the application/executable/test harness experiences a EXC_BAD_INSTRUCTION (SIGILL) due to the aforementioned: "XPC API Misuse: Release of last reference on a suspended connection."

Reproducing this issue with a test is trivial, just create a new test and the entire function's body should just be:

XPCServer.makeAnonymous()

Verify that `endpoint` works for `XPCServiceServer`

For the anonymous and the Mach services server, the connection turned into an endpoint is the listener connection. XPC Services don't have an (exposed) listener connection, so the implementation right now uses the incoming connection passed to xpc_main which likely does not work. This issue is to verify whether or not this works.

Add real XPC integration tests

I would like to contribute an integration test suite, which exercises the real client/server messaging functions. I would like to build this prior to making pretty big changes as part of #17 and #20.

As it turns out, this can be done without the need to spin up XPC or Mach services, using an anonymous XPC connection, whose ends both run within the same process. Quinn "The Eskimo!" documents how to do this with the NSXPCConnection APIs in Testing and Debugging XPC Code With an Anonymous Listener.

I found some more information about anonymous XPC connections in the C XPC APIs in WWDC 2013 - Session 702 - Efficient design with XPC (slides), at around 18:33 to 21:50, slides 47-56.

I've split the work into multiple PRs, each one building upon the previous

SMAppService and MachServiceCriteria

Hey!
First of all, AMAZING work!
I'm trying to use the framework to talk with a daemon launched by the new SMAppService api. The daemon launches, launches server but I can't make it to talk with the client. It fails on the first condition. But...
I'm not sure that validateThisProcessIsAnSMAppServiceDaemon should work at all. It checks for the Bundles bundleURL and it assumes that it'll receive a path with the Contents folder. It doesn't work in my case, it returns a path, but to the bundle itself (so the last component is *.app). Am I doing something wrong?

private func validateThisProcessIsAnSMAppServiceDaemon() -> ValidationResult {

Add support for encoding/decoding XPC connections


Originally posted by @amomchilov in #6 (comment):

File descriptors and shared memory are intentionally not supported as they are concepts incompatible with Codable which is designed for indefinite serialization and cross-device transfer. As such choosing Codable for SecureXPC had tradeoffs because XPC does not have the same requirements — it can represent live resources on a single device. However, I decided the tradeoff was worth it because of Swift's excellent built in support for Codable (particularly the compiler automatically generating conformance in many cases). If there was a desire to support file descriptors and shared memory, I can envision ways to add them in the future, although it would mean expanding the API quite considerably.

I don't have an immediate need for passing FDs or shared memory regions in my program yet, but my app does need to pass an xpc_endpoint_t. My main app is sandboxed, so the only way it can use SMBless is by delegating that work to an unsandboxed XPC helper service. Once the installation is done, it opens the XPC connection to the privileged helper service, and passes the endpoint back to the main app.

This is the approach that's recommended in Apple's EvenBetterAuthorizationSample, so I think supporting xpc_endpoint_t is pretty crucial. So at a minimum, at least some level of special-casing needs to happen.

`XPC_ERROR_CONNECTION_INTERRUPTED` doesn't appear to actually behave as documented

After releasing 0.3.0 of SecureXPC I started updating SwiftAuthorizationSample and have run into an unexpected issue:

  1. Over XPC the app asks the helper tool to uninstall itself
  2. As part of the helper tool uninstalling itself, the helper tool terminates
  3. This results in the client receiving XPC_ERROR_CONNECTION_INTERRUPTED.
    i. This is expected, Apple's documentation for interrupted says: "Will be delivered to the connection’s event handler if the remote service exited."
  4. Installer the helper tool again (under the hood via SMJobBless).
  5. The next send using the client results in a XPC_ERROR_CONNECTION_INVALID
    i. This is unexpected, Apple's documentation for interrupted also says: "The connection is still live even in this case, and resending a message will cause the service to be launched on-demand."
    ii. I can confirm the service is not launched on-demand.
  6. The subsequent send using the client results in the service being launched.
    i. This is not because of anything XPC is doing automatically, it's because when we received XPC_ERROR_CONNECTION_INVALID in step 4 we perform self.connection = nil which means we establish a new connection on the next send.

Enable GitHub discussions for the 3 repos

👋 Hey there!

I have some things I'd like to ask about, that aren't necessarily issues, per-se. Could you enable GitHub discussions on these repos so I can post there?

P.S. Thanks for open sourcing these. It caught me just at the right time, when I was about to start refactoring a huge chunk of my apps structs into @objc classes, solely to support NSCoding for XPC. That would have been a major headache, and I'm really hoping I can leverage this package to stay in swift-struct-land!

`XPCServer` factory functions should always return the same instance

Currently:

  • forThisXPCService() always returns the same instance
  • forThisBlessedHelperTool() and forThisMachService(...) return new instances each time

This inconsistency is undesirable as the server is stateful with routes and an error handler.

However, in practice this probably wouldn't be much of an issue as it's hard to envision why one of these functions would be called multiple times.

Using a concurrent DispatchQueue

I've set my server's target queue like so:

let server = try XPCServer.forThisBlessedHelperTool()

// Either one of:
server.targetQueue = DispatchQueue.global()
server.targetQueue = DispatchQueue(label: "queuename", attributes: .concurrent)

...but calling my test handler multiple times from the client still indicates them running serially.

static func testRouteHandler(withMsg msg: String) throws -> String {
    let process = Process()
    process.launchPath = "/bin/sleep"
    process.arguments = ["4"]
    process.launch()
    process.waitUntilExit()
    return "Finished: \(msg)"
}

I noticed the following in the xpc_connection_set_target_queue documentation:

If the target queue is a concurrent queue, then XPC still guarantees that there will never be more than one invocation of the connection's event handler block executing concurrently.

Is what I'm trying to do the right approach?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.