Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single-file: Facilitate signing on mac #3671

Closed
swaroop-sridhar opened this issue Jul 4, 2019 · 41 comments
Closed

Single-file: Facilitate signing on mac #3671

swaroop-sridhar opened this issue Jul 4, 2019 · 41 comments
Assignees
Milestone

Comments

@swaroop-sridhar
Copy link
Contributor

The single-file bundler adds additional contents (the apps's dependencies) at the end of the host-binary. This violates the strict consistency checks performed by codesign tool in MAC.

This work item track the effort to make the MAC bundle amenable to signing.

Original issue

dotnet/core#2811

Repro stesps

  1. Create a console "Hello world" executable on macOS.
  2. Generate a single file executable followed: https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#single-file-executables
  3. run codesign with this exe.

You will get error message: main executable failed strict validation

If you add --no-strict option in codesign, you will get more detailed error messages:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate: the __LINKEDIT segment does not cover the end of the file (can't be processed) in: /Volumes/Data/temp/HelloDotNet/bin/Release/netcoreapp3.0/osx.10.12-x64/publish/MacOS/HelloDotNet
/Volumes/Data/temp/HelloDotNet/bin/Release/netcoreapp3.0/osx.10.12-x64/publish/MacOS/HelloDotNet: the codesign_allocate helper tool cannot be found or used
@swaroop-sridhar swaroop-sridhar self-assigned this Jul 4, 2019
@swaroop-sridhar
Copy link
Contributor Author

Here's an attempt to fixup the __LINKEDIT section to accommodate the SingleFile blob at the end of the file: https://github.com/dotnet/core-setup/compare/master...swaroop-sridhar:mac?expand=1

There are some downsides to doing this fixup:

  1. We cannot just fixup the size on disk, we also need to increase the vmsize of __LINKEDIT section (that is, the size as loaded). This means that the entire single-file is loaded by the OS loader when the program starts up.
    • In the current scheme of things, this leads to loading all the bundle contents twice, which is wasteful
    • When bundle contents are processed directly from disk, I think this scheme can be used more natuarally.
  2. With the above change, the __LINKEDIT section is loaded, and the program run successfully. However, the codesign tool is still not happy because it sees that there's no __LINKEDIT data that's referring to the content at the end of the section. Adding a reference to this data involves complex fixup with possible cascading effects for VM-addresses. The fixup for this is rather brittle without support from the native linker.

@MarcWils
Copy link

MarcWils commented Jul 17, 2019

Any update about when this will be fixed or available in a preview release?

We want to distribute a .NET Core 3.0 (preview6) app on MacOS. Code siging is mandatory.

Is there any workaround to publish a signed .NET Core MacOS application?

@pavelkhrulev
Copy link

@MarcWils Did you find some way to publish signed MacOS application?

@swaroop-sridhar
Copy link
Contributor Author

@MarcWils @pavelkhrulev

After dotnet/core-setup#8590, I have a better understanding of the file layout; I'll try out another fix for this issue to extend the __LINKEDIT section to cover the single-exe metadata.

@MarcWils
Copy link

@MarcWils Did you find some way to publish signed MacOS application?

No I didn't. We reverted to building a native macOS app.

swaroop-sridhar referenced this issue in swaroop-sridhar/core-setup Nov 1, 2019
The single-file bundler adds additional contents (the apps's dependencies) at the end of the host-binary.
This violates the strict consistency checks performed by codesign tool in MAC.

This change adjusts the MachO headers to accomodate the bytes added by the bundler.

This Method is a utility to adjust the apphost MachO-header
to include the bytes added by the single-file bundler at the end of the file.

Fixes #7065
@swaroop-sridhar
Copy link
Contributor Author

The MAC codesign tool places several restrictions on the layout

  • The __LINKEDIT segment must be the last one
  • The __LINKEDIT segment must cover the end of the file
  • All bytes in the __LINKEDIT segment are used by other linkage commands (ex: symbol/string table, dynamic load information etc)

In order to circumvent these restrictions, I implemented a change that:

  • Extends the __LINKEDIT segment to include the bundle-data
  • Extends the string table to include all the bundle-data
    (that is, the bundle-data appear as strings to the loader/codesign tool).

This method has certain limitations:

  • The bytes for the bundler may be unnecessarily loaded at startup
  • Tools that process the string table may be confused (although unindexed bytes in the string table should be OK)
  • The string table size is limited to 4GB. Bundles larger than that size cannot be accomodated by this utility.

Here's a change that implements the fix: https://github.com/dotnet/core-setup/compare/master...swaroop-sridhar:macsign?expand=1

@swaroop-sridhar
Copy link
Contributor Author

The fix is somewhat fragile in the long run, because it relies on the current behavior and checks implemented in codesign tool. It may break if the tool introduces more checks (ex: check that all bytes in the string table are referenced).

The reliable way to generate an image is to use the native tool chain, but this involves substantial support in and beyond the .net core SDK.

@swaroop-sridhar
Copy link
Contributor Author

CC: @jeffschwMSFT @jkotas

@swaroop-sridhar
Copy link
Contributor Author

CC: @noahfalk

@msftgits msftgits transferred this issue from dotnet/core-setup Jan 30, 2020
@msftgits msftgits added this to the 5.0 milestone Jan 30, 2020
@rlalance
Copy link

rlalance commented Feb 6, 2020

ok, this is going to block distribution of the app. Not cool.

@richardlalancetteyoui
Copy link

What is my alternative to start sharing my dotnet 3.1 application with my clients?

@swaroop-sridhar
Copy link
Contributor Author

swaroop-sridhar commented Feb 6, 2020

What is my alternative to start sharing my dotnet 3.1 application with my clients?

@richardlalancetteyoui You can distribute your app without publishing it as a single-file. The single-file-ness of apps is less important on MAC, sine MAC treats apps as folders.

@richardlalancetteyoui
Copy link

richardlalancetteyoui commented Feb 6, 2020

Oh that's a good point!
How do you package a .net core app if not single file?

@morphx666
Copy link

morphx666 commented Aug 14, 2020

I can confirm that, whenever selecting the option to create a single-file, the generated binary cannot be signed.

Is this going to be fixed?
What's the point of having a cross-platform framework if the generated binaries cannot be signed for distribution?

@agocke
Copy link
Member

agocke commented Aug 14, 2020

Apple has a variety of restrictions on exactly what needs to happen for signing. Those restrictions change over time and we try to address them for various deployment models. Single-file embedding is a new deployment model that will need new work to deal with additional signing restrictions. This probably won't make .NET 5, but there are a variety of other deployment models that are signable, including the existing self-contained deployment, that will continue to work for .NET 5.

Is there a particular issue that's blocking you from using self-contained deployment on macOS right now?

@ProbablyFaiz
Copy link

Single file is much smaller to distribute, which is very helpful for desktop applications running .NET Core (which I understand is not a priority, but it would be nice).

@agocke
Copy link
Member

agocke commented Aug 14, 2020

If the main concern is size, you can enable trimming even without enabling single file. There are some single-file specific size improvements, but AFAIK it's not huge for macOS at the moment.

@rlalance
Copy link

rlalance commented Oct 6, 2020

Guys. This is a make or break for my team. If this cannot be smoothed out, I might have to go for another ecosystem, and I would hate to have to give away .net core.

I'm going to be using .net core to build command line art processing tools, for our designer workflow and this really needs to get addressed as I will be distributing my tools to mac, windows and maybe linux users.

@agocke
Copy link
Member

agocke commented Oct 6, 2020

We do plan to fix this, and it's high priority for .NET 6, unfortunately we just haven't had time to fix it for 5.0. As @swaroop-sridhar mentioned, you can use a macOS app bundle to distribute a multi-file app that appears as a single file to consumers.

Unfortunately, command line apps are one of the tools that do not normally use macOS bundles. Until we can fix this authoring issue, it won't be possible to create single-file command line apps on macOS.

@Meowzz95
Copy link

Meowzz95 commented Oct 7, 2020

@richardlalancette
I know this is very important when deploying CLI to customers/users, and I tried countless method without any luck. Until one day I thought why not put the effort into providing an easier way for the user to bypass gatekeeper! You can write a "run script" to use spctl to whitelist the files/dylibs in single-file output and then execute the CLI tool. This way, at least, the user can run the tool easily, well, easier.

@rlalance
Copy link

rlalance commented Oct 7, 2020

Oh, this is a risky business @Meowzz95, but nonetheless a good lead. Thank you.

This can't be the final solution though.

@sttz
Copy link

sttz commented Oct 7, 2020

I'm using CoreRT for command line tools on macOS. It AOT-compiles to a single binary that can be signed and notarized.

CoreRT is experimental and has a bumpy future, so using it comes with some risk and you might not be able to use it with the latest .Net releases and features. But right now it's the only single-file solution I can use on macOS.

@Meowzz95
Copy link

Meowzz95 commented Oct 7, 2020

@richardlalancette Agreed that .net team should fix this. But using spctl to whitelist ONLY your application files, don't turn off the gatekeeper and it should be just fine, as least same as user manually trust the binary.

@rlalance
Copy link

rlalance commented Oct 7, 2020

OH I see! I didn't realise specific files could be changed. Well worth a quick research spike :) thank you. @Meowzz95

@Meowzz95
Copy link

Meowzz95 commented Oct 7, 2020

@richardlalancette HAHA, yes we can label specific files and whitelist them in gatekeeper, I'll show you my solution here.

echo "adding x permission to the program, you may need to enter sudo password or use biometric authentication"
sudo chmod +x YOUR_BINARY_EXEC
echo "adding exceptions to gatekeeper...you may need to enter sudo password or use biometric authentication"
ls | xargs -I {} echo $(pwd)/{}|  xargs -I {} spctl --add --label "SOME_LABEL" {}
spctl --enable --label "SOME_LABEL"
echo "launching YOUR APP..."
$(pwd)/YOUR_BINARY_EXEC

This is a very straight forward solution without much consideration on skipping the chomd and spctl on the second run, you can add logic to only run those in the first run so that user does not need to enter the password every time they use the app.

Hope this helps as a workaround for people who are distributing single-file to users

@rlalance
Copy link

rlalance commented Oct 7, 2020

@Meowzz95 Very generous of you to share your results. Thank you!

@vitek-karas
Copy link
Member

Related work in mono: mono/mono#17881

@VSadov VSadov self-assigned this Jan 4, 2021
@ghost ghost added in-pr There is an active PR which will close this issue when it is merged and removed in-pr There is an active PR which will close this issue when it is merged labels Jan 13, 2021
@VSadov
Copy link
Member

VSadov commented Jan 14, 2021

Fixed in #46558

@VSadov VSadov closed this as completed Jan 14, 2021
@Jmales
Copy link

Jmales commented Jan 18, 2021

Hey guys. Not sure how to solve my problem, even after @VSadov fix.

I have a singleFile bundle inside another App and when I sign the whole contents of the App it always fails in the singleFile bundle binary with the mentioned error. I'm failing to understand how to fix the issue...

@vitek-karas
Copy link
Member

As mentioned above by @VSadov this has been fixed for .NET 6 here: #46558. As far as I know we don't have plans to try to backport this to .NET 5.

@Jmales
Copy link

Jmales commented Jan 18, 2021

This single-file was our workaround to: #46990

Everything worked well, except for the signing of the SingleFile binary/bundle. Now we have no idea on how to tackle the problem at hands.

@VSadov
Copy link
Member

VSadov commented Jan 20, 2021

@Jmales - I am a bit confused. Did you have a problem signing a .NET 6.0 singlefile app?

I wonder what was the SDK build number. The fix is fairly recent and it takes some time for a fix to make it from the development branch to the published installers. Maybe the fix was not there yet.

@rlalance
Copy link

Really looking for this. This was a pretty major roadblock for my team.

@agocke
Copy link
Member

agocke commented Jan 21, 2021

Note that at the moment we have no plans to backport the fix to 5.0 -- are you OK with relying on a preview version or waiting for 6.0?

@VSadov
Copy link
Member

VSadov commented Feb 1, 2021

Recent 6.0 and 6.0.preview1 SDK builds should contain the fix.
@richardlalancette - could you check if the fix is sufficient for your scenario?

@rlalance
Copy link

rlalance commented Feb 1, 2021

I'm still on .net 5.0 here.

Is the 6.0 preview SDK good enough for production apps?

@ghost ghost locked as resolved and limited conversation to collaborators Mar 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests