That won't help you rebuild the binary, but at least you can find them.
In addition to making it easier to do security updates in situations like log4j, it'd also make it easy to comply with LGPL license terms.
Afaik, the ELF format allows you to replace sections in a binary. The code (or data) is packed as "Sections" and mapped to memory locations. You use a tool to unpack the ELF sections and replace them. The application accesses those sections of memory and uses whatever ABI the application and library are designed to interact with. As long as you patch a section with the same ABI that an app/library used before, nobody will notice. And the ELF ABI never changes. But of course, not every system uses ELFs.
But all this depends on the compiler/linker/etc and how they generate sections and store them in the binary (for example, is it all compiled into one blob-section, or does it store libraries as separate sections, which might be inefficient?). I somehow doubt Go does things in such a way to allow this kind of patching. They probably generate a giant blob full of random functions and record versions in a header without the ability to extricate a whole library.
What you're describing would be more akin to shared linkage just in a single blob. That seems like it'd be a worst-of-both-worlds result.
And yes, it has dependencies! So does your go file, I'm afraid.
With Go, can you look at a compiled binary in an image on the artifact repo and identify what libraries it used and if those libraries have vulnerabilities?
(and it appears that my question was answered in a sibling comment)
Even Linux distributions where rebuilding the world is easy (like Debian) insist on breaking dependencies out into shared libaries, since tracking ad hoc vendored dependencies is just too difficult.
For example, sometimes people play dynamic loading and renaming tricks to allow multiple versions of the same Java library to coexist. That can usually be detected by vulnerability scanners, but not always.
I am also not aware of any Java developers who build 3rd party libraries from source and avoid using maven (or gradle, or the odd one with ivy).
Your "what if..." doesn't describe any workflow that I have ever experienced with Java in a professional (and even hobbyist) context.
I have exploded war deployments ( https://www.jrebel.com/learn/what-exploded-and-packaged-depl... ) put in a Tomcat image and the scanner is able to identify the libraries that the classes came from and their vulnerabilities.
I've also got fat jars for Spring Boot batch jobs that are single jars with all of the dependencies packaged in them for ease of copying around a single thing on the server... and the dependency checker is able issues there to based on fingerprints of individual class files.
These work on the "you downloaded this from a known package management server". As long as you are using maven to download the dependencies, a vulnerability checker will be able to identify it. One built into maven ( https://owasp.org/www-project-dependency-check/ // https://jeremylong.github.io/DependencyCheck/dependency-chec... ) will be able to catch these as part of the build itself - irrespective of the shading of the final artifact.
If you are building from source, and obscuring the class names - yes, you can foil an external vulnerability checker (and since you're doing it from source, you are also not downloading it and thus avoiding a maven plugin use)... however, I don't know any projects that go through such lengths to compile 3rd party Java code themselves rather than using a jar, and are trying to evade vulnerability (and license) checkers.
This isn't even a new situation. We had the exact same problem some time ago with zlib: it was also embedded everywhere, and just finding all the affected apps was a nightmare. It's the reason most Linux distributions came to deeply dislike bundling libraries, instead of using a dynamically linked shared copy from a separate package. Unfortunately, it seems the lessons from that zlib incident are being forgotten, perhaps because too much time has passed (IIRC, in the order of decades) since then.
Is it, though? Seems like it would be trivial for a distribution maintainer to write a script to go through the dependency trees of every package, and then automatically rebuild any that depend on the vulnerable library. I don't think discovery is the problem.
I suspect this is really a legacy of when disk space was not so cheap; dynamic linking means smaller binaries (usually). And, even today, many distros would probably prefer their users to only download a 2MB library update from them than have to download 500MB worth of updated programs. Bandwidth is still not as cheap as we'd hope.
Edit: just realized you're probably talking about software packages vendoring in their own version of a library, not about a package statically linking with a system-provided copy of the library.
That said, I think this missing the full picture- we have the same problem further down the stack, at the OS level, where old machines are running without receiving security updates on a regular basis.
I don't know that there's really much of a good answer to the problem short of "don't leave your children unattended". Unlike real kids and the real world, there's plenty of bad actors looking for unattended services to stab.
Is that a particular problem? What's the difficulty with recompiling?
1. How do I find out which programs on my system are Go programs? I have a lot of programs scattered all over. Someone will have to come up with a method (probably search through $PATH for files, run `strings` on it, grep for "Go", pray that's enough) to identify them.
2. They don't list a website, so I have to google the name of every program and find their website.
3. How do I tell which ones are affected by the vuln? I can hope their websites tell me, but maybe they're no longer maintained, or they haven't updated their READMEs.
4. If they don't provide a patched version (most probably won't), I might have to upgrade, which may break things (probably will), assuming they even have an upgradeable version that isn't affected.
5. If I can't upgrade and have to patch, am I even a software developer and know how to do that?
6. If I luckily happen to be one, what system compiled this app 8 years ago, with what dependencies, with what version of Go, etc? Can I recreate that system and learn their build tools to finally patch & recompile? (I am not a Go developer and it has taken me days to figure out how to get different Go programs to compile, for reasons I don't understand)
7. Once I apply the patch how do I test it? (Log4j had multiple iterations of patches/mitigations, some didn't work)
If I can't find the source code, can't upgrade it, & can't patch it, I am just stuck with a vulnerable version until I can somehow replace the program. For the programs I was able to identify as vulnerable, anyway.
Log4j was "easy" compared to this, because you could just find all the jars on your system and unzip them, find a file, replace it, zip it back up. Log4j was actually a nightmare though, and Go apps will be worse.
Well how are these programs getting onto your system?
Presumably via some package manager, or an image builder?
Don't those manage the update for you?
If you're running code that you don't know who wrote, with no source code, that you can't patch, that nobody is taking responsibility for, then yeah you've got issues. But you had issues already if that's the predicament you're in. Some of this applies to Java too - obfuscation breaks the fixes you described using!
> If you're running code that you don't know who wrote, with no source code, that you can't patch, that nobody is taking responsibility for, then yeah you've got issues
25 million computers around the world still use Windows XP. It was launched 21 years ago, EOL 8 years ago. Very common actually, especially since most software in the world is not open source. People just keep using software that works.
This is the default state of affairs for nearly everyone who uses a computer.
We can either throw our hands up and futilely say "well they shouldn't do that!", or we can try to solve the problem.
This isn't relevant. What's relevant is if any of the specific programs I am responsible for have a vulnerability. If so, I need to update those specific programs. The notion of implementation language, shared library, dependency, these are all abstraction leaks. The atomic unit of responsibility, at the machine level, is program/service.
Alternatively, a more-savvy user has to hear about this Log4Go vulnerability and see if any of their applications use it and might need an update (which might involve contacting the maintainer to inform them that they need to update their software). But the vast majority of users aren't even going to hear about the Log4Go vulnerability, let alone understand what it means or what they need to do to protect themselves.
The safest thing would be for every application to dynamically link to a system-provided version of Log4Go, and OS maintainers would be the ones to send out an update via their OS's auto-update service. This does create other problems, but at least they are problems that technically-unsophisticated users do not need to solve or concern themselves with.
(Of course, there is no mechanism to do this with Go modules, so the entire thing is moot.)
This is why I get annoyed when developers say "I have to vendor library X into my application, because I'm afraid that the system copy will get updated to a version that breaks my app". Well then, maybe you shouldn't use a library whose author can't abide by semver and provide a reasonably-strong promise that minor and patch version updates won't break things. Otherwise you are just outsourcing your problems to your users.
Nor should it. A dependency should be encapsulated by its consumers. A vulnerability that leaks to the consumer application is a bug in the consumer application.
> The safest thing would be for every application to dynamically link to a system-provided version of Log4Go,
Unfortunately this means that any application which uses Log4Go cannot make any definitive assertions about the specific code which is executed by their distributed artifact. This is a problem, and the cost of this problem is far higher than the benefits conveyed by dynamic linking. The future of application distribution is absolutely static linking.
> "I have to vendor library X into my application, because I'm afraid that the system copy will get updated to a version that breaks my app". Well then, maybe you shouldn't use a library whose author can't abide by semver and provide a reasonably-strong promise that minor and patch version updates won't break things. Otherwise you are just outsourcing your problems to your users.
As a software producer, it should not be possible for a dependency to impact my users without my knowledge.
It is infeasible to rely on any specific level of versioning stability from my dependencies. Every dependency I adopt represents a risk which I am taking on.
When 98% of your users only have the binary and not the source code it means 98% of your users won't even be aware that they need a new version that isn't vulnerable.
Remember the vulnerability disclosure will be something like "Log4Go has a vulnerability!!", not that the binary apps you've downloaded have a vulnerability. So if it affects 200 projects, every one of those projects will also have to publish vulnerability notifications independently.
And frankly 80% of those projects will likely be abandoned or at least neglected after a couple of years, leaving many people with vulnerable binaries they don't even know to check for vulnerabilities.
In other words, they very advantage of Go (easy to distribute binaries directly!) is a security disadvantage. If you instead installed the app using a package manager, the package manager could at least notify you that you have a package with a security issue. But that's nothing new; security and ease-of-use are often at odds.
When they find a critical bug in a Go module or a Rust crate, you usually end up with a litany of packages that had to be updated as well because everyone and their crab relies on that crate/module.
Count in release managers (or whatever that's called at your shop) who pin all dependencies to the most exact minor version before shipping, because they have learned to do it like a mantra without actually understanding all the "whys" of it and just keep religiously applying that hammer everywhere.
People keep complaining about how distributions work and how the traditional package management sucks all the time (of thousands complaining, I estimate that maybe 20 people actually know what they are talking about and thus are qualified to whine), but they somehow keep forgetting that those tools exist for a reason and that they are about to rediscover it the hard way. Chesterton's fence and all that.