-
-
Notifications
You must be signed in to change notification settings - Fork 565
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
problems making appimage reproducible #929
Comments
First of all, congrats on making your builds reproducible. That's a very noble cause. The rationale is discussed here: We explicitly discussed reproducible builds back then, but I don't remember how this has actually been dealt with in the current implementation. Can you shed some light on this @TheAssassin? (@TheAssassin: I hope I am not mixing things up here. AppImageCommunity/AppImageUpdate#83 is about increasing AppImageUpdate efficiency, but the description for digest-md5 is stated as "desktop integration purposes for a given AppImage". Looking back at the discussion, it seems like I did not understand the purpose of digest-md5 from the beginning and it was not clearly explained in the PR: #768 (comment)) |
You mixed up a few things. You've found an entry for the software The section contains an MD5 hash of the squashfs image embedded in the AppImage, this is used to check for the equality of two AppImages (e.g., in AppImageUpdate). If the contents differ, the hash differs. Simple as that. Reproducibility is tested and verified in our continuous deployment scripts. If you use the same version of appimagetool, it will create the same AppImage for the same contents. Must be your test that is wrong here. There's nothing like "almost identical". Either they are or are not. |
I just mean that there only seems to be a small and structured difference between the binaries. Anyway, it's semantics.
Ok. So let me detail what the script is doing then. Broadly, it creates some directory structure, and then uses appimagetool to create the binary from that.
So I unpack appimagetool using Now, even if I do this in a virtual machine and take a snapshot of the whole VM between the two lines, so directly before running
Okay. But that seems to contradict what I just described to have observed. |
I've now tried creating only the directory structure in docker, once, then copying that to the host machine, where fuse can be used, and using appimagetool directly twice in a row on the unchanged directory structure. The produced binaries are not identical. Using appimagetool release 11 ( |
Our reproducibility test only covers the case where you want to create an AppImage for the exact same directory, and I just tested that with the latest continuous build and it works fine here. You probably have metadata changes on every build which cause the resulting squashfs image to be different. I tested that and on my computer, the resulting AppImages are different now, too. Your tool diffoscope is wrong; the changes are not only in that section. You should always test with a second tool. I tried both diffoscope and the good ol' hexdiff, and hexdiff finds differences in other places, too (most likely squashfs metadata). |
Thanks. You are right. Looking at the raw bytes, there are other diffs later in the file.
If I build two appimages and run --appimage-extract on them, should the reason for this difference between the binaries be visible also on the extracted folders? As in, should I expect to see some difference in the extracted folders?
I am still left wondering why I cannot build the same binaries even when taking a snapshot of the whole VM. i.e.
Now binaries A and B are different. This is with using latest VirtualBox (6.0.4). If you really suspect the reason is metadata changes on the appdir, do you have a suggestion how to detect/inspect that? |
Metadata can be access or modification timestamps. The issue here is that when the files are extracted, the original metadata contained in the squashfs image is not restored. Therefore, all files look like they're freshly created (i.e., they have the current timestamp set for mtime/atime; atime must be available of course). The issue is the extraction code in the runtime. You can try to mount the AppImage instead of extracting it. Then, run appimagetool on the mountpoint and check if that works. In any case, I do want to keep storing timestamps, therefore we must fix the runtime to set those correctly on extraction. CC @azubieta |
I've already been resetting all st_atime and st_mtime timestamps to fixed values; but I admit I forgot about symlinks (touch -h option), so thanks for explicitly mentioning timestamps. Regardless, I still fail to deterministicly build the binary I want. So I've started deleting files from my appdir, to see if some specific files are at fault. If I delete almost everything (only leaving the bare minimum to let appimagetool succeed), I can reproducibly build the same binary every time. No need to tinker with timestamps between builds. If I start leaving in (not deleting) more and more files, the build no longer remains deterministic, after some threshold. It does not matter which files I keep. Specifically, if there are about 50 files in my AppDir, the built binary will no longer have the same hash; rather it will have one out of two hashes randomly.
If I leave even more files in, the set of possible hashes for the binary increases. When I have around 100 files in my AppDir, it is still quite likely that I get a hash that I have seen before. I've built 500 binaries, which had 237 unique hashes. (maybe it's about cumulative file size, not number of files; or something else related) Do you still think this can be explained with metadata of the AppDir? I highly doubt it at this point. |
As far as I can see, this must be a bug in squashfs. Our software behaves correctly by calculating different hashsums and putting them into I'm not a squashfs expert, we're just "customers" using tools provided by them. I guess we need to carry that bug upstream to them. Mind to open an issue over here? The thing with squashfs-tools is that the project doesn't seem to be very active any more. |
Thanks for pointing to plougher/squashfs-tools
I see you also apply some patch to squashfs-tools locally, during the build I see you've seen the squashfskit fork too from a very brief look at the patches, and your local patch, it was obvious you are missing at least squashfskit/squashfskit@afc0c76 I then tried to just change to the squashfskit fork. With success. With the squashfskit fork I can reproducibly build my intended binary. Here is a patch for AppImageKit to make it clear what I did: diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake
index 9f7901f..236cb6b 100644
--- a/cmake/dependencies.cmake
+++ b/cmake/dependencies.cmake
@@ -50,15 +50,14 @@ if(xz_LIBRARY_DIRS)
endif()
ExternalProject_Add(mksquashfs
- GIT_REPOSITORY https://github.com/plougher/squashfs-tools/
- GIT_TAG 5be5d61
+ GIT_REPOSITORY https://github.com/squashfskit/squashfskit/
+ GIT_TAG 68ea4ae7553f3d58c14be19443cfc9e84b7244c0
UPDATE_COMMAND "" # ${MAKE} sure CMake won't try to fetch updates unnecessarily and hence rebuild the dependency every time
- PATCH_COMMAND patch -N -p1 < ${PROJECT_SOURCE_DIR}/src/mksquashfs-mkfs-fixed-timestamp.patch || true
CONFIGURE_COMMAND ${SED} -i "s|CFLAGS += -DXZ_SUPPORT|CFLAGS += ${mksquashfs_cflags}|g" <SOURCE_DIR>/squashfs-tools/Makefile
COMMAND ${SED} -i "s|LIBS += -llzma|LIBS += -Bstatic ${mksquashfs_ldflags}|g" <SOURCE_DIR>/squashfs-tools/Makefile
COMMAND ${SED} -i "s|install: mksquashfs unsquashfs|install: mksquashfs|g" squashfs-tools/Makefile
COMMAND ${SED} -i "/cp unsquashfs/d" squashfs-tools/Makefile
- BUILD_COMMAND env CC=${CC} CXX=${CXX} LDFLAGS=${LDFLAGS} ${MAKE} -C squashfs-tools/ XZ_SUPPORT=1 mksquashfs
+ BUILD_COMMAND env CC=${CC} CXX=${CXX} LDFLAGS=${LDFLAGS} ${MAKE} -C squashfs-tools/ XZ_SUPPORT=0 mksquashfs
# ${MAKE} install unfortunately expects unsquashfs to be built as well, hence can't install the binary
# therefore using built file in SOURCE_DIR
# TODO: implement building out of source
diff --git a/src/appimagetool.c b/src/appimagetool.c
index 8316d58..57dd1db 100644
--- a/src/appimagetool.c
+++ b/src/appimagetool.c
@@ -198,9 +198,6 @@ int sfs_mksquashfs(char *source, char *destination, int offset) {
args[i++] = exclude_file;
}
- args[i++] = "-mkfs-fixed-time";
- args[i++] = "0";
-
args[i++] = 0;
if (verbose) { Then I built appimagetool, and then I built my binary as So, would you consider switching to that fork of squashfs-tools? Alternatively, if I figured out exactly what patches on top of squashfs-tools are needed and made a PR, would you be interested in that? |
Yes, that'd be a good idea. And I think we can even send them our |
We build our own mksquashfs from squashfskit which supports generating reproducible squashfs images. We use a small wrapper script to remove the -mkfs-fixed-time which appimagekit passes but squashfskits mksquashfs does not support. ----- taken from Electron-Cash/Electron-Cash@dd1f106 see AppImage/AppImageKit#929
Now official squashfs 4.4 makes reproducible images by default, see: https://lore.kernel.org/lkml/CAB3wodcL=gnQOmHGGNukWK3OUbU2p=OHzLmzPi7ns_WNTGBEwg@mail.gmail.com/ |
Can we get an eta on when the updated squashfs would make it into a stable It's been almost a year since this was fixed upstream, and I see that the latest stable release from AppImageKit still uses
I stumbled on several examples of hacks to fix Is there an ETA on when we can expect the latest stable release of |
Hello @maltfield at this point I am not working on the "old" appimagetool anymore but am focusing on the new Go-based implementation over at https://github.com/probonopd/go-appimage/tree/master/src/appimagetool. That one currently uses an external |
oh, ok. I wasn't aware that this repo was being deprecated. Do you have any eta on when the first stable release will be out for the new |
No, it's a work-in-progress but usable for many apps already at this point. Maybe you want to give it a try and report there in case you are running into issues. Thanks! Just for clarification, this repo is not going to be deprecated, but likely |
* #3 Unfortunately the latest stable version of appimagetool (v12 from 2019-05) uses a very old version of mksquashfs (v4.3 from 2014-05) which does not support building reproducable builds due to some parallelization optimizations * https://github.com/AppImage/AppImageKit/releases * https://sourceforge.net/p/squashfs/code/ci/master/tree/CHANGES * AppImage/AppImageKit#929 (comment) Other projects like the electurm crypto wallet got around this issue by hacking the latest stable appimagetool to use a fork of squashfs-tools = squashfskit * https://github.com/squashfskit/squashfskit * https://github.com/SomberNight/electrum/blob/ae714772c38410a0169f2c76a14a64a62c0daff0/contrib/build-linux/appimage/build.sh#L212-L225 But in 2019-08, squashfs-tools released an updated version (v4.4) which added support for reproducable builds, as well as fixed a couple CVEs and other changes * https://lore.kernel.org/lkml/CAB3wodcL=gnQOmHGGNukWK3OUbU2p=OHzLmzPi7ns_WNTGBEwg@mail.gmail.com/ Therefore, in this commit, I've added the code to make changes to appimagetool's latest release to use the updated version of squashfs-tools. The asked the maintainer of AppImageKit about this, and they said there's no future releases expected for the existing appimagetools repo, as development has been moved to a Go version, which is currently still a work-in-progress with no eta on it becoming stableo * https://github.com/SomberNight/electrum/blob/ae714772c38410a0169f2c76a14a64a62c0daff0/contrib/build-linux/appimage/build.sh#L212-L225 So, for now, this hack is as good as it gets.
Would it be possible to bump the squashfs version here (or use the fork that was mentioned above with the provided diff) and release a new version, even though work is primarily done on a rewrite of the appimagetool? |
I would happily review a PR that updates the build system. It shouldn't be too difficult to build another version of squashfs-tools. |
if anyone peruses this, it would probably be better to use squashfs-tools v4.4 instead of the fork, as it fixed a few CVEs which I don't think made it into the fork (I haven't looked into the specifics) fwiw, here's I'm doing to swap out |
The latest release of appimagetool bundles a new enough version of mksquashfs. We had been building a fork of mksquashfs but all the relevant patches there had been upstreamed. Note: we still need a wrapper when calling mksquashfs, as appimagetool calls it with "-mkfs-time 0" and we have the SOURCE_DATE_EPOCH env var set; and these two would conflict. Two ways to fix: either unset SOURCE_DATE_EPOCH for that context, or build a wrapper that removes the "-mkfs-time 0". The former would be cleaner but for some reason I did not manage to build reproducibly that way. The latter seems to work. related: - AppImage/AppImageKit#929 (comment) > Now official squashfs 4.4 makes reproducible images by default - AppImage/AppImageKit#996
The latest release of appimagetool bundles a new enough version of mksquashfs. We had been building a fork of mksquashfs but all the relevant patches there had been upstreamed. Note: we still need a wrapper when calling mksquashfs, as appimagetool calls it with "-mkfs-time 0" and we have the SOURCE_DATE_EPOCH env var set; and these two would conflict. Two ways to fix: either unset SOURCE_DATE_EPOCH for that context, or build a wrapper that removes the "-mkfs-time 0". The former would be cleaner but for some reason I did not manage to build reproducibly that way. The latter seems to work. related: - AppImage/AppImageKit#929 (comment) > Now official squashfs 4.4 makes reproducible images by default - AppImage/AppImageKit#996
With appimagetool release 13 (which bundles new enough mksquashfs (#996)), the situation is now much better. When building an appimage for the Electrum project, we previously had to
Using appimagetool 13, we no longer have to build a fork of mksquashfs, but we still have to:
This is needed as mksquashfs errors if both I have tried calling appimagetool AppRun with see (does not produce reproducible binaries): SomberNight/electrum@6e0865f Due to these reasons, I think it might be better if appimage was not passing AppImageKit/src/appimagetool.c Lines 200 to 201 in 1681fd8
|
The latest release of appimagetool bundles a new enough version of mksquashfs. We had been building a fork of mksquashfs but all the relevant patches there had been upstreamed. Note: we still need a wrapper when calling mksquashfs, as appimagetool calls it with "-mkfs-time 0" and we have the SOURCE_DATE_EPOCH env var set; and these two would conflict. Two ways to fix: either unset SOURCE_DATE_EPOCH for that context, or build a wrapper that removes the "-mkfs-time 0". The former would be cleaner but for some reason I did not manage to build reproducibly that way. The latter seems to work. related: - AppImage/AppImageKit#929 (comment) > Now official squashfs 4.4 makes reproducible images by default - AppImage/AppImageKit#996 backport of spesmilo@ca2d1ee
The latest release of appimagetool bundles a new enough version of mksquashfs. We had been building a fork of mksquashfs but all the relevant patches there had been upstreamed. Note: we still need a wrapper when calling mksquashfs, as appimagetool calls it with "-mkfs-time 0" and we have the SOURCE_DATE_EPOCH env var set; and these two would conflict. Two ways to fix: either unset SOURCE_DATE_EPOCH for that context, or build a wrapper that removes the "-mkfs-time 0". The former would be cleaner but for some reason I did not manage to build reproducibly that way. The latter seems to work. related: - AppImage/AppImageKit#929 (comment) > Now official squashfs 4.4 makes reproducible images by default - AppImage/AppImageKit#996 backport of spesmilo@ca2d1ee
The latest release of appimagetool bundles a new enough version of mksquashfs. We had been building a fork of mksquashfs but all the relevant patches there had been upstreamed. Note: we still need a wrapper when calling mksquashfs, as appimagetool calls it with "-mkfs-time 0" and we have the SOURCE_DATE_EPOCH env var set; and these two would conflict. Two ways to fix: either unset SOURCE_DATE_EPOCH for that context, or build a wrapper that removes the "-mkfs-time 0". The former would be cleaner but for some reason I did not manage to build reproducibly that way. The latter seems to work. related: - AppImage/AppImageKit#929 (comment) > Now official squashfs 4.4 makes reproducible images by default - AppImage/AppImageKit#996 backport of spesmilo@ca2d1ee
The latest release of appimagetool bundles a new enough version of mksquashfs. We had been building a fork of mksquashfs but all the relevant patches there had been upstreamed. Note: we still need a wrapper when calling mksquashfs, as appimagetool calls it with "-mkfs-time 0" and we have the SOURCE_DATE_EPOCH env var set; and these two would conflict. Two ways to fix: either unset SOURCE_DATE_EPOCH for that context, or build a wrapper that removes the "-mkfs-time 0". The former would be cleaner but for some reason I did not manage to build reproducibly that way. The latter seems to work. related: - AppImage/AppImageKit#929 (comment) > Now official squashfs 4.4 makes reproducible images by default - AppImage/AppImageKit#996 backport of spesmilo@ca2d1ee
I am trying to make the AppImage binary for Electrum reproducible/deterministic.
Looking at e.g. #625, I take it this should be possible.
I am using appimagetool release 11.
I think I've managed to build almost identical binaries (only been testing on one machine for now).
Would like to request pointers/help regarding what might be missing.
If I build two binaries, and run --appimage-extract on them, the extracted folders seem identical (e.g. recursive md5sum, and then diff of that, is empty)
diff of recursive md5sum of extracted contents
So that's good I guess :)
If I use diffoscope to compare the binaries themselves, it tells me the only difference is due to an elf section called
digest_md5
:I've found this in the appimage docs:
Is that in the docs related to this elf section?
Any idea what I need to make the build deterministic?
The text was updated successfully, but these errors were encountered: