-
Notifications
You must be signed in to change notification settings - Fork 70
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
Call ld-linux relative to cwd; invoke application without launching ld-linux explicitly #49
Comments
https://github.com/Juuliuus/commandoo is what you are trying to package? Can you please post all steps to build and make an AppImage that you used, then I can try to recreate the issue. I tried probonopd/commandoo@325370f but I am getting
Can you show me your code where you are checking XDG_CONFIG_HOME? |
Please note that commandoo will not run until libqt5pas is installed (that is the small detail I mentioned in other posts), and I imagine that would also make the appdir build fail if that library is not there. Also note this is all designed for 2020 distros (commandoo was built in Kubuntu 20.04). Find in: Step 1: Step 2: If you have a question regarding the "org.timepirate.commandoo.desktop" filename, this was the only way I could get it all to be error free when checking the xml validity with the gnu online tools. And, anyway, it all works absolutely perfectly...except for this ~/.config problem. |
result := GetAppConfigDir( False );//gets home "." location false is xdg .config, true is system /etc This goes to lazarus: which goes to: |
Hi, You know I just thought of something. I believe I mentioned my main computer well and truly died a couple days ago. I'm using an older laptop until I get a new main computer, and even though everything is running seemingly good, I'm noticing some small irregularities (behavior of listbox displays, of label caption displays in lazarus), so maybe it has something to do with this computer? Maybe don't spend too much time on this and I can check again when the new compuer is here (a couple weeks). If you want itt should be simple to reproduce with the files I included the .tar.gz, but now I'm simply not sure that something is messed up on ths temporary replacement computer. |
You know what: I just double-clicked the AppImage from your tar.gz and it immediately worked: Xubuntu 18.04, no Qt installed, no Lazarus installed. After running the AppImage, I do have:
|
I think I know what is going on. Your application correctly gets the path to The reason for the strange behavior is that in order to make the AppImage fully standalone, we are shipping a private copy of the
You can see it when you run
Hence, when you try to read the name of the running executable using something like Instead, you could just hardcode But we can also think about whether we can do someting on the AppImage side of things to prevent this from happening. Possibly a solution might be to use https://github.com/AppImageCrafters/AppRun - @azubieta, can you confirm? When I launch https://transfersh.com/T2cuU/glmark2-latest-x86_64.AppImage and then do
See, no So maybe I will switch go-appimage to use https://github.com/AppImageCrafters/AppRun - once I understand it well enough. |
Ah, yes I see. Thank you for testing this. BTW, that is what I meant when I said earlier that it does seem to be completely self-contained. I ran it in OpenSuse which did not work before (linuxdeploy version) because OpenSuse has glibc 2.26 and my app requires 2.29. But the self contained version did, in fact, open and work in OpenSuse. Pretty cool. |
I did check. I take exactly what is given to me from the XDG_CONFIG_HOME and that is normally ~/.confg/commandoo I do not add anything, so the ld-linux bit is replacing 'commandoo', perhaps the inner workings of linux is taking argv[0]. |
Sorry, apparently I'm tired. You are correct. Lazarus appends "applicationname" as it fetches XDG_CONFIG_HOME. |
I think by using https://github.com/AppImageCrafters/AppRun we can get this fixed but I need some help from @azubieta to show me how to do this. I tried using his |
By the way @Juuliuus your AppImage can even run on Ubuntu 16.04 LTS, just tested it. |
Well @probonopd, how cool is that?! I was starting to suspect it might work in older versions after I saw OpenSuse work. |
azubieta confirmed that using https://github.com/AppImageCrafters/AppRun can solve this issue indeed. |
Hi @probonopd . There is no urgent need to use the AppImageCrafters tools at this time. I found a simple way to use normal "-s deploy" in go-appimage to work "better" than the AIC AppRun and hook lib (details below) resulting in argv[0] pointing to the payload and not ld-linux. As I reported at https://discourse.appimage.org/t/is-it-possible-with-s-deploy-to-include-libraries-loaded-at-runtime/1779/36, I was able to make AIC's system work finally by patching the payload to use the copied ld-linux file. But. It gives a really big problem, at least as regards the needs of my program. A word of explanation: my program is a CLI database =and= testing platform. While the program did finally run on Ubuntu 16, it fails spectacularly at one of its primary aims: testing CLI's. The program worked perfectly in its database functions (libsqlite also bundled inside!). My program depends, heavily, on starting processes and getting the results of stdout/stderr. But even a simple process invoking the "which" command to find the location of the "id" command fails with "which" failing! So the AIC method has somehow made the entire system dependent on my glibc needs?! Ouch. But taking a bit of the methodology of AIC I was able to modify appdirtool.go to work (including using your original AppRun shell script). The resulting Appimage runs flawlessly on Ubuntu 16, and the March version of OpenSuse (the original problem distro). Both storage and testing in my program work perfectly. The changes to go-appimage are as follows:
This makes no use of the "-l" switch, it isn't needed. I can supply you with all the code I wrote, just let me know if you want that and how to go about it. Does this have side effects? I don't know and I leave that to you with your greater experience. All I know is that commandoo runs perfectly in every system I've tested it on, and the solution, as it is, is quite simple and doesn't depend on anything outside of go-appimage. One final note: Another testing distro was the nixos distro. AIC's method allows the program to run in nixos, but with the same failure to be not allowed to run my own processes. The modified go-appimage fails in nixos, core dump. A quick glance at strace showed it using a chroot command that I had not seen before, so there is another problem to be solved as regards nixos. |
Can we find a solution without this step? I think this is what https://github.com/probonopd/libhookexecv is solving (for Wine). |
This is provably because the LD_LIBRARY_PATH is being leaked to external process, to avoid this you need to export the following companion variables:
Please check https://github.com/AppImageCrafters/AppRun#libapprun_hooks
Using the embed ld-linux does the trick for running new software in old system, but if fails for the opposite environment. This will remain true as long as we use at least one lib from the system (NVIDIA). @probonopd Prefixing ld-linux may seem to do the job, but this has a nasty consequence. The /pro/self/exec will point to ld-linux instead of the real application path. Many applications (all the qt ones and the AppImage runtime) depend on this path to know their binary location, those applications will fail. That's why I opted for patching the PT_INTERPRETER segment on the elf executables. |
Hi @azubieta and @probonopd
You are correct and the two env vars fixed the issue, but with a whole brand new failure. My program now runs and can execute processes with AIC method =IF= I send them directly to the system through a created process. However, my program also allows piped constructions like "ps -A | grep -i commandoo". When running CLI's of this type I send it out to the shell (bash, zsh, etc). These now fail with core dumps for every command in the pipe except the last. When I test with my solution those piped commands work properly... |
Great, that's progress! About the new issue, AppRun removes the AppImage private execution environment when an external binary like (/bin/bash) is executed. This also remove the hooks library. If the execution flows returns into the AppDir like in your case where an external The solution will be to also bundle |
Could what https://github.com/probonopd/libhookexecv does be a solution that combines the advantages of both approaches? |
Running binaries using |
Hi all,
@azubieta : I bundled bash first alone, then bash, ps, & grep. In all cases the core dump for the elements of the pipes continues to occur. Even though I tried this just to see =IF= it would work, this solution is no good for my program (or any program that may create a process to the system using pipes). commandoo is a CLI program (the user can run, literally, anything they want) and it should, and it does, allow the user to use whatever shell they want. I simply read the SHELL env var and send piped commands to that. So, for me, and for the tests I've run, the AIC method, elegant though it is, simply is not the answer and becomes prohibitively unfeasible.
@probonopd : I tried a couple variations just to see if they would work: I copied the ld-linux... to the bin folder next to my exec and patched the exec to "./ld-linux..." and "ld-linux...". As I expected (given from what I've read on inet) this did not work: file not found. The only way to get around it that I can see is that we have control over what the mount is named so that we can patch the exec to find ld-linux in the ..../lib64/ folder of the mount. I believe you've already said this isn't possible? If we could control the name of the mount then there would be no need to copy ld-linux, we could just point to the folder containing it. If the above is not possible, then I'm not sure why you have concern over this copying step. My experience is not as deep in linux as yours, and maybe it has consequences that I'm not yet aware of. But for a couple of reasons I find it a very simple solution to the problem of completely self-contained appimages, and, if nothing else, could be a next stage for go-appimage development. First: It completely solves the argv[0] problem. Second: Simple changes only were necessary to your go-appimagetool code, nothing was touched in the methods you use, and, it works in all cases: OpenSuse, Ubuntu 16.04, and even (sort of) in nixos!! (I got it working in nixos, more detail below if you are interested). Calling processes works out of the box. Piped commands work out of the box. What better result can there be for such a simple change? In addition, running multiple copies of the appimage will use the same file because its based on a guid that bundles itself into the appimage. I can't get the resulting appimages to fail in any way, they work perfectly. Third: there seems to be perfect separation of what my program needs to run (the self containment) and yet the freedom to use the host distro's files to do work ("ps -A | grep xxx"). FWIW, if you are interested in the nixos problem: As I've mentioned before one needs to run the appimage with nixos's "appimage-run". Even though the appimage builds fail in nixos, I noticed that the entire process got far enough along to extract the appimage =and= to copy the ld-linux... file to the /tmp/ folder. In nixos appimage-run extracts the appimage to: Going there I could run commandoo directly from that folder. It ran perfectly! Processes. Piped commands. I could run Geany through commandoo as a child process. And this is despite the fact that all the libraries in that folder are patched by go-appimage, and that the commandoo is patched to use the ld-linux... in the /tmp/ folder (ld-linux needed to be modified to be executable, that didn't get copied over, probably nixos security issue). The bash commandoo used came from the SHELL env var and was pointed to the peculiar folder that the nixos system uses to keep "snapshots" separate. It's true that there were no APPDIR or APPIMAGE env variables running it this way, but everything is pointed to the self containment and the separate ld-linux. Because of this my program could not find libsqlite but I allow specifying it and when I pointed it to the libsqlite bundled within, it worked great. So my feeling at this time is that appimage-run needs an issue for this appimage method, which, after all this is ironed out, I plan to submit. But the resulting appimage is, truly, self contained and, apparently, will work anywhere. |
Do we need this at AppImage creation time or at AppImage run time? |
I've added a new feature to appimage-builder, now it's capable to take an file level snapshot of an application and generate a recipe the includes all the files that were loaded. This allows to build use the tool on non-debian based system. A similar approach can be used by go-appiamge:
|
Cool, I'll look at that after I've got all this current go-appimagetool issue down
Both actually. Remember the "magic" fix for argv[0] is that the payload (or payloads?) have to be patchelf'd to point to the bundled But you told me that the mount name is randomized when the AppImage starts up. Then we can not know what the path is until the AppImage starts up and therefore can't patch our payload with a known ld-linux location.. -IF- we can influence the name of the mount, then we could use the $APPDIR/lib64/ path which will then be known to us at build-time since we are influencing the mount name.. This is the best solution for sure, but is it possible? If so, the mount name should be done with a per AppImage GUID so that AppImages don't collide with each other. If we cannot influence the mount name then there is no other way except to (run-time) copy the ld-linux to a name of our (build-time) choice in the /tmp/ folder (GUID based that travels with the AppImage). This is what I'm currently doing and, as mentioned, it is working everywhere. if you want to do this all at run-time so that the payload can be patched to look at $APPDIR/lib64/ then patchelf must be included in every appimage, and it must be patched to find a suitable ld-linux. This starts getting circular and creates more prolbems than |
Hi @probonopd
I'm not sure it you saw the rest of this conversation yet or not. Would you like the code I wrote that addresses this by run-time copying of a build-time determined path? It should be possible to include, along with the original -s and -l switches, yet another switch (-c for complete or copy??) that would encapsulate all of this. Then, in time, it could be decided what works and/or is the most practical? |
Hi @Juuliuus actually this thread has been long both in terms of when it started as well as number of lines to read. Hence I have probably lost track. Hence, can you please give the "TL;DR:" summary (<= 5 lines) of what you think we should do, and why? Thanks! |
Hi @probonopd (full answer is 3 posts up, Oct 30) The "magic" fix for argv[0] is that the payload (or payloads?) have to be patchelf'd to point to the bundled |
Well. The whole situation is not nice.
I'm almost thinking that we should not try to fix Could a custom ld-linux modify |
But you were ok with the -l option using appimagecrafters which is a similar setup, but even more complicated with a settings file, binary AppRun, a special library, and also a copied ld-linux. The method I have (which works great everywhere but nixos [and even that can be manually fixed]) uses your original apprun shell script with the difference of calling the payload directly, and, yes, a copy of the ld-linux to /tmp/.
As to the last two questions: In my mind argv[0] is non-negotiable. By convention it is the first param of a command line sequence which must be an executable. I'm not familiar with how a custom ld-linux would be made. The keep it as simple as possible philosophy would argue against generating a separate ld-linux I think, but you have more knowledge and experience with that side of things. And the last: I'm not familiar with LD_PRELOAD. Remember, I didn't even know ld-linux existed until a few months ago... :-O |
Yes, but this is |
In that case, I guess I would say leave argv[0] as it is, pointing to ld-linux. It's not horrible, but it, also, is not terribly pretty. I fixed my program to take that into account, so it doesn't hurt the user other than sorting taskbars: by alpha puts "c"ommandoo down with the "L"s.... |
Oh, actually. THE answer would simply be: being able to specify the /tmp/ folder mount name. You mentioned to me before that that mount name is random. But is it out of our control? If we can specify the mounted folder name, all the problems go away, and one simply points to the local APPDIR/lib64/...but that would also still break an extracted appimage, yes? |
How? What would you do with that information? |
Same thing (patchelf the payload so that it can be argv[0]) but this time no need for an external copy of ld-linux. Just patch to the -mountname-/lib64/.... But again, extracting the appimage with the expectation that I could run the payload by double clicking it would be broken...? Right? I've never extracted an appimage thinking that I would run it. And in this case we're talking about "-s" deploys.... |
Yes, being able to run |
Hmmm. Then I'm thinking its a broken dream. From what I understand ld-linux MUST be called with an absolute path and those paths would then be different for the mounted version vs. the extracted version. And, hence, AppRun would be broken. |
Hi @probonopd So I found a solution that is is pretty simple: rename appdir/lib64/ld-linux-x86-64.so.2 to appdir/lib64/PayloadName, and change AppRun to use that "ld-linux" to run the payload. Tested on Dev machine & ubuntu16.04 VM I also tested, in ubuntu 16.04, --appimage-extract and --appimage-extract-and-run, everything runs and argv[0] is "PayloadName". |
When the system glibc is newer than the one in the AppDir you should use the system |
Hi @azubieta
Ahhh. These are things I'm not familiar with, I must say. I'm focusing on the argv[0] problem. As regards Nvidea, I have no idea, I will leave that for @probonopd to decide/determine. However, I also want to point out that this argv[0] problem is only for the experimental self-contained version of go-appimage. In that case, as far as I know (and we've probably reached my level of behind the scenes interactive linux knowledge), this appimage is required to stay in and use the bundled libraries. If something is going on behind our backs by nvidea, then that becomes a rather ticklish problem...? Also if the nvidia problem is something that can be addressed, then the decision can still be made if necessary. After all, the re-named to PayloadName file is still, inside, an ld-linux file and can be switched in some manner...? |
Hi @probonopd. |
Maybe changing the Please test https://github.com/orivej/ldcp and see whether that solution suffers from the same issue. If it doesn't, we should look into it. |
No. A payload executable might launch another payload executable from the same AppDir, in which case it'd get really messy really quickly. |
No, ld-linux can be called relatively, but it's relative to cwd, not |
@ArcticLampyrid if this turns out to work, it's the best application bundle discovery of the decade. No kidding! |
I would really appreciate an explanation of how to do this exactly. Tried the example they did with bash with a different binary after deploying everything with go-appimage, it just causes the binary to segfault after running Anyways, to fix this issue I found this very useful tool which does some tricks with hardlinks. It also doesn't need to set the rpath of binaries/libraries, since it tells the ld-*.so their location. |
Well, well, well... what we'd actually want is "relative to $ORIGIN", not "relative to cwd"... is this something that would need to be supported in the Linux kernel? |
Unfortunately, the kernel currently has no concept of At present, AppImageCrafters/AppRun employs a trick: it switches the working directory to load the required See also: |
Maybe it would be worthwhile to propose such a concept to the kernel, what do you think? To patch the Linux kernel to allow for the resolution of
Roughly like this: // fs/binfmt_elf.c
// ...
static char *resolve_origin(const char *path, const char *origin)
{
if (origin == NULL)
return NULL;
char *resolved_path = NULL;
size_t len = strlen(origin) + strlen(path) + 2;
resolved_path = kmalloc(len, GFP_KERNEL);
if (resolved_path == NULL)
return NULL;
strcpy(resolved_path, origin);
strcat(resolved_path, path);
/* Remove any trailing slash. */
if (resolved_path[strlen(resolved_path) - 1] == '/')
resolved_path[strlen(resolved_path) - 1] = '\0';
/* Remove any .. components. */
char *p = resolved_path;
while (1)
{
char *dotdot = strstr(p, "..");
if (dotdot == NULL)
break;
char *prev_slash = strrchr(p, '/');
if (prev_slash == NULL)
{
/* .. at the beginning of the path. */
memmove(p, dotdot + 2, strlen(dotdot));
p += 2;
}
else
{
memmove(prev_slash, dotdot + 2, strlen(dotdot));
p = prev_slash;
}
}
return resolved_path;
}
static int load_elf_binary(struct linux_binprm *bprm)
{
// ...
/* Find the ld-linux for this ELF executable */
if (elf_interpreter) {
char *interp = elf_interpreter;
char *origin = NULL;
// Find the path of the executable being loaded
origin = kmalloc(PATH_MAX, GFP_KERNEL);
if (origin == NULL)
return -ENOMEM;
if (get_task_comm(origin, PATH_MAX, current) < 0) {
kfree(origin);
return -EIO;
}
// Resolve the $ORIGIN token
char *resolved_interp = resolve_origin(interp, origin);
if (resolved_interp == NULL) {
kfree(origin);
return -EIO;
}
// Search for the ld-linux loader
elf_interpreter = resolved_interp;
bprm->interp = load_elf_interp(resolved_interp,
&loc->elf_ex,
&elf_headers,
&interp_load_addr,
&interp_map_addr);
if (bprm->interp == NULL) {
kfree(origin);
kfree(resolved_interp);
return -EIO;
}
kfree(origin);
kfree(resolved_interp);
}
// ...
} Is anyone around who could help to turn this into a working kernel patch and to submit it to the Linux kernel mailing list for review and inclusion in the mainline kernel? (Llama 3.1 70B was consulted to point me in this direction.) |
Hi,
After the fix in #44 -s deploy does indeed work for qt5 and it does appear to be completely self contained.
However a strange problem has arisen that was not an issue before. The same thing occurs at build 495 and that is why I tested build 497.
My application checks XDG_CONFIG_HOME for the location of the user's config folder.
That is now coming back as: /home/juus/.config/ld-linux-x86-64.so
This is also the case where a "My.AppImage.config" folder is available, putting an ld-linux-x86-64.so folder in there too.
Within that .config/ld-linux-x86-64.so folder everything then follows as if it was the normal .config folder, putting a folder with my Appname inside.
I've checked older AppImages (built with linuxdeploy) and that was not a problem, it always returned either /home/juus/.config or My.AppImage.config.
In the log references to "ld-linux-x86-64.so" were:
2020/08/02 11:16:48 Deploying /lib64/ld-linux-x86-64.so.2...
...
2020/08/02 11:16:49 Copying in and patching ELFs which are not already in the AppDir...
2020/08/02 11:16:49 Not writing rpath in commandoo.AppDir/usr/lib64/ld-linux-x86-64.so.2 because itname starts with ld-...
2020/08/02 11:16:49 Patching qt_prfxpath, otherwise can't load platform plugin...
2020/08/02 11:16:49 Offset of qt_prfxpath: 3561388
2020/08/02 11:16:49 Qt prefix directory in the AppDir: commandoo.AppDir/usr/lib/x86_64-linux-gnu/qt
2020/08/02 11:16:49 Relative path from ld-linux to Qt prefix directory in the AppDir: ../usr/lib/x864-linux-gnu/qt5
2020/08/02 11:16:49 Patching qt_prfxpath in libQt5Core.so.5 to ..
2020/08/02 11:16:50 Copying in copyright files...
The text was updated successfully, but these errors were encountered: