Closed craigraw closed 1 year ago
E/io.matthewnelson.kmp.tor.manager.common.exceptions.TorManagerException: Failed to read control.txt
Not 100% certain why it is failing immediately; there is a 10s limit set to wait for Tor to create the file REF
- Whether my Java syntax of interacting with the Kotlin libraries is correct (my Kotlin knowledge is limited)
Kotlin compiles it down to java byte code, so should not be an issue at all. There are some things that are a little wonky with IDEs not liking some inheritance structures, but Java interop is great. Best bet is to follow the :samples:java:javafx
sample provided.
- The recommended approach to create a Tor-based socket. I have been using
Not necessary anymore. kmp-tor
is all event based whereby things are dispatched to whatever listeners you have attached to TorManager
. This is to create a buffered medium between Tor, and your application's state.
Once Tor is done bootstrapping, an AddressInfo
object is dispatched to your listeners such that you are able to instantiate whatever http client you want to use, however you see fit. See HERE.
I was adamant about limiting dependencies to only what was absolutely necessary. You can utilize just a straight up java.net.Socket
by passing it the resulting ProxyAddress
(retrieved from the AddressInfo
).
private fun createSocksSocket(proxy: ProxyAddress): Socket {
return Socket(
Proxy(
Proxy.Type.Socks,
InetSocketAddress(proxy.address.value, proxy.port.value)
)
)
}
In the event you modify the Socks, Http, Trans, Dns, etc ports or UnixSocket addresses, once Tor has finished reacting to what it received over the control port, another AddressInfo
object will be dispatched with the changes.
Oh! try applying the kotlin gradle plugin
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.8.10'
}
Oh! try applying the kotlin gradle plugin
plugins { id 'org.jetbrains.kotlin.jvm' version '1.8.10' }
Tried your sample with the kotlin jvm
plugin. Works for me on linux x64
and macOS x64
.
Edit: Also tried it w/o the plugin and it worked fine. So this seems like some issue with a configuration setting that the arm64
binaries do not like. Could you try providing an empty config (which will use default settings)?
return new TorConfig.Builder().build();
Also, you're instantiating new instances of TorManager
every time the button is clicked. The instance should be static, and the button click should just call torManager.startQuietly()
.
Think this is actually the issue that you're seeing. So, multiple clicks is dropping the last TorManager
reference and setting a new instance which is spinning up a new Tor daemon with the same settings. Tor can't overwrite the control port file b/c the last TorManager
instance wrote it to disk already. If you wish to use multiple instances, you can do that via the MultiInstanceManager
whereby your workDir
must be different to avoid such issues.
Thanks for the PR, and the other answers - I completely missed the Java example, which is very useful!
Unfortunately, no change on this particular issue. I did a test on macOS x64 and it runs fine, so it appears to be related to the macOS arm64 binaries. After upgrading JavaFX to v18 on the sample app, and making a few changes to ensure that the arm64 binaries are installed, I managed to reproduce the issue on the Java sample app too.
Executing the extracted Tor directly results in
/var/folders/7y/cvqm9r6n0cgddhm921cm1zwc0000gn/T/kmptor-j/work/.kmptor/tor
[1] 10978 killed /var/folders/7y/cvqm9r6n0cgddhm921cm1zwc0000gn/T/kmptor-j/work/.kmptor/tor
I'll keep digging to see if I can find any root cause.
I believe this might be related to a MacOS signature issue. When I sign the tor binary with my developer certificate, it executes successfully and Tor starts as normal, instead of being immediately killed. I haven't yet managed to get the Java app to work however.
Confirmed - I've managed to get the Java app to start by signing the tor
andlibevent-2.1.7.dylib
arm64 binaries. They appear to be unsigned:
❯ spctl --assess --type install --context context:primary-signature -v "/var/folders/7y/cvqm9r6n0cgddhm921cm1zwc0000gn/T/.kmp-tor-java/work/.kmptor/libevent-2.1.7.dylib"
/var/folders/7y/cvqm9r6n0cgddhm921cm1zwc0000gn/T/.kmp-tor-java/work/.kmptor/libevent-2.1.7.dylib: rejected
source=no usable signature
❯ spctl --assess --type install --context context:primary-signature -v "/var/folders/7y/cvqm9r6n0cgddhm921cm1zwc0000gn/T/.kmp-tor-java/work/.kmptor/tor"
/var/folders/7y/cvqm9r6n0cgddhm921cm1zwc0000gn/T/.kmp-tor-java/work/.kmptor/tor: rejected
source=no usable signature
Just checked the macosx64
binaries and they are unsigned as well. :thinking:
Looking into this.
So even the expert bundles that the tor project publishes HERE are unsigned.
wget https://dist.torproject.org/torbrowser/12.5a3/tor-expert-bundle-12.5a3-macos-x86_64.tar.gz
wget https://dist.torproject.org/torbrowser/12.5a3/tor-expert-bundle-12.5a3-macos-aarch64.tar.gz
tar -xzf tor-expert-bundle-12.5a3-macos-x86_64.tar.gz
cd tor
spctl --assess --type install --context context:primary-signature -v tor
spctl --assess --type install --context context:primary-signature -v libevent-2.17.dylib
cd ..
rm -rf tor
rm -rf data
tar -xzf tor-expert-bundle-12.5a3-macos-aarch64.tar.gz
cd tor
spctl --assess --type install --context context:primary-signature -v tor
spctl --assess --type install --context context:primary-signature -v libevent-2.17.dylib
Unfortunate :cry:
Got a few q's that I hope you may be able to answer:
spctl
returns correctly?
PGP
signatures, or some apple thing (sorry not an apple user)?To ad hoc sign binaries you can do
codesign --force --deep -s - tor
codesign --force --deep -s - libevent-2.1.7.dylib
This does however change the files.
However, it's confusing: I am able to run the tor
contained in tor-expert-bundle-12.5a3-macos-aarch64.tar.gz
. spctl
returns the same
spctl --assess -v tor
tor: rejected
source=no usable signature
Back on kmptor
, I have found the relevant error when the process is killed in the macOS Console:
AMFI: hook..execve() killing pid 12760: Attempt to execute completely unsigned code (must be at least ad-hoc signed).
This article provides more information: https://eclecticlight.co/2021/01/26/when-you-dont-have-permission-to-run-an-app-on-an-m1-mac/
Still looking into this.
However, it's confusing: I am able to run the tor contained in tor-expert-bundle-12.5a3-macos-aarch64.tar.gz. spctl returns the same
Does the system check for signatures every single time they are executed on? Only thing I can think of is that you signed the files previously and the system didn't check after you replaced them with those from the expert bundle.
Trying to figure out how I might overcome this. Was banking on these binaries being reproducibly built for security purposes, verifiable by anyone by simply running the build script. Binaries from TorBrowser for macOS are signed, but they're combined x86_64
+ aarch64
(they run on both architectures). So cannot yeet them from there.
Going to publish a -SNAPSHOT
version of the expert bundle binaries repackaged, if you could try running those on aarch64
?
Does the system check for signatures every single time they are executed on?
Yes, every time. It's pretty mental. I can reproduce all of this reliably (so I don't think it's due to some previous action I took), but I'm completely stumped as to why the expert bundle tor
works. Perhaps macOS has an exception for it?
Going to publish a
-SNAPSHOT
version of the expert bundle binaries repackaged, if you could try running those onaarch64
?
Yes sure
Alright, I published a -SNAPSHOT
of kmp-tor-binary branch issue/66-repackage-expert-bundle which is just a repacking of all the expert bundles (after gpg verifying each, will move this into a script if we're successful).
If you could add to your build.gradle
file the following:
https://s01.oss.sonatype.org/content/repositories/snapshots/
io.matthewnelson.kotlin-components:kmp-tor-binary-macosarm64:4.7.13-2-SNAPSHOT
io.matthewnelson.kotlin-components:kmp-tor-binary-extract:4.7.13-2-SNAPSHOT
and give it a try.
Unfortunately that didn't work :( Same error as before, Attempt to execute completely unsigned code
It gets stranger though: I have verified that the tor
from the expert bundle is exactly the same as the tor
that is unpacked (with shasum -a 256 tor
). So it appears to be something external to the file that is the culprit here. I had previously thought this to be something related to xattr
, but neither of the files report anything from xattr tor
. It does however look like signatures can get stripped with some kinds of compression: https://eclecticlight.co/2019/11/12/preparing-for-new-security-rules-how-signatures-can-get-stripped/.
That said, it gets even stranger - copying tor
and libevent
extracted from kmptor
into the extracted expert bundle also results in working Tor. So there is something else about the expert bundle that is the key. I'll keep looking tomorrow.
Think there is some sort of linking behavior that is being preserved by the tar archive? On Linux for the Process
environment it is setting LD_LIBRARY_PATH
Could you clone this repo and try running the sample (./gradlew :samples:kotlin:javafx:run -PKMP_TARGETS="JVM"
). If same error, try modifying that line to also include macos (don't use :samples:java:javafx
b/c that relies on the maven dependency and won't pull in any changes below from the project).
if (installer.isLinux || installer.isMacos) {
?
EDIT: I really wish I had an M1/2 to debug this on...
EDIT2: If the above does not work using LD_LIBRARY_PATH
, could also try the following
if (installer.isMacos) {
env["DYLD_LIBRARY_PATH"] = installationDir.absolutePath
}
Ok, I think I have found the issue. For some reason, macOS prevents calling an unsigned binary with a path, but allows it to be called without a path from the directory the binary is located in. This is what I was doing previously by accident - calling the expert bundle tor
without a path specified, but specifying the full path to the extracted tor
used by kmptor.
I have verified that this works:
ProcessBuilder pb = new ProcessBuilder("tor");
pb.directory(new File(System.getProperty("user.home") + "/tor"));
p = pb.start();
while this does not:
ProcessBuilder pb = new ProcessBuilder(System.getProperty("user.home") + "/tor/tor");
p = pb.start();
I think that's running the tor package you have installed on your machine, not the binaries that we are extracting. I tried modifying the loader to use tor
instead of the absolute path to the extracted tor file + setting the ProcessBuilder.directory
, and debug info indicated that it was running an older version of tor (the version I have on my linux laptop). Running the same code on macOS x86_64 vm resulted in a file not found error (b/c tor is not installed as a package on there).
~Going to yeet the binaries from TorBrowser (b/c they're signed)~ Going to codesign macos binaries and publish another -SNAPSHOT
if you could test them out on your M1/2.
I think that's running the tor package you have installed on your machine
You're right - seems obvious in retrospect!
Going to codesign macos binaries
Great. Note it doesn't look like the adhoc signing I mentioned above helps much. A developer certificate is needed for codesign
to create distributable binaries afaik.
Note it doesn't look like the adhoc signing I mentioned above helps much. A developer certificate is needed for codesign to create distributable binaries afaik.
Well shit, lol. I just published a 4.7.13-3-SNAPSHOT
with the adhoc signing. Could you run your sample using steps outlined in https://github.com/05nelsonm/kmp-tor/issues/285#issuecomment-1470493580 but with the new version just to check?
It worked! It looks like the adhoc signing is enough, at least for my machine.
That said, it's probably better to have a developer cert signed binary, since spctl
still rejects it, so I'm not feeling that confident yet.
That said, it's probably better to have a developer cert signed binary
Definitely. Will ask devs if they plan to codesign the expert package binaries or not in order to figure out next steps (build program that extracts tor from TorBrowser, or uses the expert package which I much prefer).
Can publish a new release (4.7.13-2
) using developer cert signed binaries from TorBrowser macos in the mean time if that works for you?
Can publish a new release (4.7.13-2) using developer cert signed binaries from TorBrowser macos in the mean time if that works for you?
Yes, that's probably a good step for now. Is there a particular reason you prefer the expert bundle binaries - simply more platform targetted?
Yes, that's probably a good step for now.
Will publish a new -2
version with the developer codesigned binaries from TorBrowser macOS and get to work on figuring out next steps.
simply more platform targetted?
That, and the expert bundles are just .tar.gz
archives with the same directory hierarchy and file names across all publications. TorBrowser has different file names and locations of the tor files depending on the build. So, coding up an extraction and packaging script is much easier using the expert bundles.
What I'd prefer is to be able to build them from source, as I have been working on RBM
scripts for tor-browser-build
to also do reproducible builds for iOS, tvOS, watchOS. Because signing the binaries breaks reproducibility, I need to look into a few different avenues before coding anything up.
What are your thoughts on using binaries signed by me, instead of the tor project? I would only do this if I am able to create a binary signature stripping tool such that kmp-tor-binary
library consumers are able to verify the stripped binaries match those that they have reproducibly built on their own (by running the build_binaries.sh
script as noted in the kmp-tor-binary/README.md
).
Alright @craigraw . I published a -4-SNAPSHOT
using the developer signed binaries from TorBrowser. If you could check 1 last time for me on aarch64
, would be much appreciated.
I've already run it on macOS x86_64
, but just want to be certain things are in working order before bumping release versions to 4.7.13-2
.
If you could check 1 last time for me on aarch64, would be much appreciated.
Confirmed working!
What are your thoughts on using binaries signed by me, instead of the tor project?
I'd be happy with this - in fact it would be my ideal outcome I think, since I take your points around the expert vs TorBrowser bundles. I was considering signing the macOS binaries myself as a custom install, but I'd be much happier if you maintained this.
Andrew Chow created an open source Apple code signing utility at https://github.com/achow101/signapple. I haven't tried it, but it was specifically created to manage Bitcoin Core code signing duties afaik, with the need for reproducible builds. The idea is that detached signatures are released which someone trying to reproduce the build can use to create the final signed binary (without actually signing it). See https://github.com/bitcoin/bitcoin/blob/master/doc/release-process.md#codesigning
Release 4.7.13-2-1.4.0 has been published which resolves things for the time being.
Further work on the binary build/verification process to resolve the underlying issues found in this ticket can be followed via kmp-tor-binary #66, which will be completed before the next tor version bump from 0.4.7.13
.
Closing this ticket, and picking things up in kmp-tor-binary-#66
Thanks for helping figure this thing out @craigraw !
I've started writing a demo JavaFX app in Java to test out kmp-tor: https://github.com/craigraw/kmp-tor-java
I've run into a problem to which the answer is not readily apparent - Tor shuts down/is destroyed immediately on startup:
I'd also appreciate any insight on:
com.runjva.sourceforge.jsocks.protocol.SocksSocket
.