dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.47k stars 4.77k forks source link

CoreCLR Debugging and CoreCLR/Mono EventPipe Doesn't Work On OSX With Sandbox Enabled #94114

Open brianrob opened 1 year ago

brianrob commented 1 year ago

Description

Construction of the IPC channel fails for applications on OSX that run inside of the sandbox. This results in failures when using any IPC channel-based diagnostic commands (e.g. dotnet-trace).

Reproduction Steps

  1. Build a MAUI application targeting OSX.
  2. Enable execution in the sandbox.
  3. Build and sign the package.
  4. Start the application.
  5. Run dotnet-trace collect -p <pid>

Expected behavior

dotnet-trace is able to attach to the application and capture a trace.

Actual behavior

dotnet-trace isn't able to connect to the application because the diagnostic IPC channel doesn't exist.

Regression?

No response

Known Workarounds

Disable the sandbox by re-compiling the application.

Configuration

No response

Other information

No response

brianrob commented 1 year ago

@lateralusX

ghost commented 1 year ago

Tagging subscribers to 'os-maccatalyst': @steveisok, @akoeplinger See info in area-owners.md if you want to be subscribed.

Issue Details
### Description Construction of the IPC channel fails for applications on OSX that run inside of the sandbox. This results in failures when using any IPC channel-based diagnostic commands (e.g. dotnet-trace). ### Reproduction Steps 1. Build a MAUI application targeting OSX. 2. Enable execution in the sandbox. 3. Build and sign the package. 4. Start the application. 5. Run `dotnet-trace collect -p ` ### Expected behavior `dotnet-trace` is able to attach to the application and capture a trace. ### Actual behavior `dotnet-trace` isn't able to connect to the application because the diagnostic IPC channel doesn't exist. ### Regression? _No response_ ### Known Workarounds Disable the sandbox by re-compiling the application. ### Configuration _No response_ ### Other information _No response_
Author: brianrob
Assignees: -
Labels: `EventPipe`, `untriaged`, `os-maccatalyst`, `area-Diagnostics-mono`, `needs-area-label`
Milestone: -
lateralusX commented 1 year ago

Running an application inside the sandbox on macOS either as an OSX or MacCatalyst app gets their file system rooted to ~/Libraries/Containers/<apps bundle id>/Data, and can not create any files outside that folder. CoreCLR OSX apps and Mono MacCatalyst apps uses EventPipe IPC channels for its diagnostic server implementation, and since Unix Domain Sockets (UDS) uses file system, it will fail to create the UDS if it uses a path outside the sandboxed file system.

Diagnostic tools asdotnet-trace gets installed as a global tool and runs as a regular OSX app meaning it won't be part of the apps sandbox and will get a different default tmp directory setup compared to the sandboxed app. This means that the default UDS won't be visible to the diagnostic tools if they don't follow a specific naming pattern based out of the default tmp directory. Since sandboxed apps won't have its default tmp dir setup as other apps, the default UDS created by sandboxed apps won't be visible to diagnostic tools like dotnet-trace.

One solution could be to use the reverse connect model for diagnostic tooling, in that case the sandboxed app could connect to a UDS created by for example dotnet-trace inside the sandboxed apps file system setup the app using DOTNET_DiagnosticPorts and let it connect to the UDS, that should work but comes with a hard limitation. OnmacOS the max length of an UDS path is set by the OS and can only be up to 104 characters long. Since the path needs to be inside the apps sandboxed file system that includes the apps bundle id, it will break as soon as the apps bundle id is long enough, but as long as the full UDS path used in the reverse connect model is shorter than 104 characters this could be used as a workaround, /Users/xxx/Library/Containers/<app bundle id>/Data, that gives us ~70 characters for user <uid> + <app bundle id> + <name of UDS file>. If that exceeds ~70 characters then apps will fail to create the UDS.

For the default UDS listener things are a little more complicated, first, it uses a unique naming schema based out of default tmp path, meaning that default UDS listeners created by sandboxed apps won't be visible to diagnostic tooling. Second, the default naming schema of default UDS listeners adds a number of characters to the total path length, by default the default diagnostic server UDS listener has the following format, dotnet-diagnostic-<pid>-<key>-socket, 26 characters + <pid> + <key> that will be reduced from the 70 characters that is available for <uid> + <app bundle id> + <name> of UDS. Here is an example of the default HelloWorld samples UDS path:

/Users/<uid>/Library/Containers/net.dot-HelloiOS/Data/tmp/dotnet-diagnostic-2460-1698654835-socket

so 93 characters + <uid> is getting very close to the 104 character limit.

If however the default UDS path is short enough and created inside the apps sandboxed file system it should be possible to manually connect diagnostic tooling using the --diagnostic-port <uds path>,connect argument.

There are a couple of workarounds to overcome this issue:

NOTE that all of above must fit into full UDS path not exceeding the maximum of 104 characters path.

Possible long term solutions:

Looks like another issue is hitting similar issue but in that case causing issue with CoreCLR managed debugging on sandboxed OSX apps, https://github.com/dotnet/runtime/issues/79852. Managed debugging is using a different set of default UDS listeners, but most likely running into by same underlying issue when trying to debug a sandboxed app.

/cc @tommcdon

dotnet-policy-service[bot] commented 4 months ago

Tagging subscribers to this area: @tommcdon See info in area-owners.md if you want to be subscribed.