https://bugs.winehq.org/show_bug.cgi?id=46471
Bug ID: 46471 Summary: amd k10 keepass2 dotnet472 divide by zero in encryption Product: Wine Version: 4.0-rc6 Hardware: x86 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: bcrypt Assignee: wine-bugs@winehq.org Reporter: noabody@yahoo.com Distribution: ---
Created attachment 63291 --> https://bugs.winehq.org/attachment.cgi?id=63291 divide by zero 64-bit .wine prefix
AMD K10 class processor lacks AES/AVX/SSE4.1 instructions:
64-bit .wine prefix, winetricks dotnet472 32-bit .wine32 prefix, winetricks dotnet472 Keepass2 2.41 exe install in both prefix
Of 8 computers with installed Ubuntu 18.04, only K10 class exhibit this failure.
Either prefix running winehq stable 3.0.4 has no problem with Keepass2. Either prefix running winehq devel or staging 4.0rc6 exhibits divide by zero.
All 6 computers with AES/AVX/SSE4.1 have no issue running Keepass2 in any environmental combination.
This is clearly an issue with decryption mechanisms that touch nettle/gnutls and the internal wine bcrypt implementation. Although I cannot prove it, the indication is that recent changes require a processor with SSE4.1 instruction set.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #1 from noabody@yahoo.com --- Created attachment 63292 --> https://bugs.winehq.org/attachment.cgi?id=63292 divide by zero 32-bit .wine32 prefix
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #2 from noabody@yahoo.com --- Created attachment 63293 --> https://bugs.winehq.org/attachment.cgi?id=63293 no fail, wine-stable
https://bugs.winehq.org/show_bug.cgi?id=46471
noabody@yahoo.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Distribution|--- |Ubuntu Hardware|x86 |x86-64
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #3 from Hans Leidekker hans@meelstraat.net --- (In reply to noabody from comment #0)
Created attachment 63291 [details] divide by zero 64-bit .wine prefix
This is clearly an issue with decryption mechanisms that touch nettle/gnutls and the internal wine bcrypt implementation. Although I cannot prove it, the indication is that recent changes require a processor with SSE4.1 instruction set.
The AES fallback implementation is broken in libgnutls. The question is why it is used on your system. There are several accelerated implementations, one of which uses the SSE3 instruction set.
How was your gnutls package built? Make sure it's not built without hardware acceleration support (enabled by default).
It could also be a problem with runtime detection of CPU capabilities. You can try overriding it by setting the GNUTLS_CPUID_OVERRIDE environment variable:
0x1: Disable all run-time detected optimizations 0x2: Enable AES-NI 0x4: Enable SSSE3 0x8: Enable PCLMUL 0x10: Enable AVX 0x100000: Enable VIA padlock 0x200000: Enable VIA PHE 0x400000: Enable VIA PHE SHA512
E.g. GNUTLS_CPUID_OVERRIDE=0x4 wine /path/to/keepass2.exe
Does that make a difference?
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #4 from Henri Verbeet hverbeet@gmail.com --- I don't think K10 has SSSE3.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #5 from noabody@yahoo.com --- Those options don't seem to affect the problem. K10 has PNI "Prescott New Instructions" which, apparently, is an alias for SSE3.
The environment variables don't have any effect. Through the last few weeks of trouble-shooting, I pulled the sources for wine, nettle, gnutls and tried to find any indication of machine specific optimizations that may have flowed to the global repository and then to me.
I have, thus far, been unable to locate any such optimizations. Debian variants make it relatively easy to rebuild source packages with:
sudo apt build-dep gnutls28 apt --build source gnutls28
Of the resultant debs, the only one that was originally installed on my system was libgnutls30, as shown in the logs. One could presume that, by building the package locally, then manually overwriting libgnutls30, any question of compiler optimizations would be ruled out. This cannot be done without a force install via dpkg because of a changelog conflict. I suppose I could host a local repo with said files but, since they are core to my system, I'd be running the risk of breaking it.
That still wouldn't address the fact that my repository version of gnutls works with wine-stable and not staging within the exact same prefix. Granted encryption stubs in stable may have been replaced with an implementation in staging and that could explain the disparity.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #6 from Hans Leidekker hans@meelstraat.net --- (In reply to noabody from comment #5)
Those options don't seem to affect the problem. K10 has PNI "Prescott New Instructions" which, apparently, is an alias for SSE3.
You'd need SSSE3, not SSE3. Apparently the K10 processor family predates SSSE3, so there's no way around the bug in GnuTLS I'm afraid.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #7 from noabody@yahoo.com --- Which still doesn't explain why it works in wine-stable on the exact same prefix.
Clearly gnutls is throwing the divide by zero in staging but what component is making a function call to divide by zero? I suppose I'll have to figure out valgrind to get more information.
I recently notified mono-project they were rolling out a distribution that requires sse4.1, in their AOT "Ahead Of Time", per-machine, compiler optimization. They said it was an issue with LLVM and added a check to only run AOT via LLVM if sse4.1 is available.
That said, mono can launch Keepass and the database decrypts without a problem. All of this is mounting evidence that rules out gnutls as the source in so far as it divides by zero because it's being asked to divide by zero. To take it one step further, I built both nettle and gnutls locally then took libgnutls.so.30 and libnettle.so.6 and put them in the LD_LIBRARY= path.
GNUTLS_CPUID_OVERRIDE=0x1 GNUTLS_DEBUG_LEVEL=9 LD_LIBRARY_PATH=$HOME/.local/lib wine KeePass.exe
Still divide by zero. I'm confident that the flagged libraries are not optimized for SSSE3 because, if they were, my machine would be incapable of compiling them successfully. I had already built wine staging locally and it still had the same problem.
I do appreciate the help, and have spent a great deal of time troubleshooting this problem on my own. The weight of that doesn't suggest a problem with ancillary libraries but something in wine-staging.
What I believe I'm hearing is that current versions of wine not longer stub functions that are optimized for SSSE3 by dotnet/mono and possibly keepass (since it has a history of its own). That mono itself will not work with AMD K10 architecture. That's just writing on the wall, though.
The K10 is unquestionably a serviceable architecture for general purpose work. It's the last vestige of early multi-core 64-bit architecture. Single-core 32-bit non-sse2 went into disuse some time ago.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #8 from noabody@yahoo.com --- Implausible as it might be, I worked around the problem by building keepass2 via msbuild provided by the mono-project. This would suggest the divide by zero was being requested by a keepass2 internal request based on the platform that it was build on.
https://www.mono-project.com/download/stable
https://sourceforge.net/projects/keepass/files/KeePass%202.x/2.41/KeePass-2....
(cd Build && sh PrepMonoDev.sh) msbuild KeePass.sln /p:"Platform=Mixed Platforms" /p:"Configuration=Release" /t:Clean,Build mkdir -p "$HOME/.wine/drive_c/Program Files/keepass2" && find -regextype posix-extended -type f ( -iregex '.*/Build.*/Release.*(.exe|.config|.dll|.xml).*' ) -exec cp "{}" "$HOME/.wine/drive_c/Program Files/keepass2" ;
Extract the source then shell navigate to the folder and use the commands to build the project and copy it to a default wine prefix. Or just run via mono. Anyone wishing to build a debian package can look into debuild/dget and use sid's latest version http://deb.debian.org/debian/pool/main/k/keepass2/keepass2_2.40+dfsg-1.dsc
sudo apt build-dep keepass2
sudo apt install $(apt -s install $(debuild -b -uc -us -j4 2>/dev/null | grep -Pio '(?<=dependencies: ).*' | perl -pe 's| (.+?)||g') | grep -Pio '(?<=^inst ).+?\s' | tr '\n' ' ')
The first build-dep will setup for current distro. The second gathers the missing package list, from a failed build attempt, and installs them if the're in the package management system. It's a quick and dirty way to build packages hosted by Debian on Ubuntu.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #9 from noabody@yahoo.com --- Based on the input from this report, my understanding is that gnutls/nettle have optimized encryption routines for various CPU instruction sets. Normally these would fallback based on what the processor can handle.
My belief is that, when keepass2 was compiled, its internal encryption libraries homed to the instruction set on the machine upon which it was built. This then would cause a flow-through where it had SIMD SSSE3 optimized gnutls requests which can't fallback because they're called explicitly.
It just flows from keepass2 through dotnet472 and wine bcrypt to nettle/gnutls/gmp/hogweed. The division by zero happens when the instruction set cannot be utilized. There's probably an interaction in there that could be addressed by wine but, ultimately, appears to be a fault in keepass2 itself.
I'll have to build locally on a non-K10 to see if keepass2, built by linux mono, still exposes the SIMD instructions whose resultant exe will fail on K10.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #10 from noabody@yahoo.com --- Problem is in: $HOME/.wine/drive_c/Program Files (x86)/KeePass Password Safe 2/KeePassLibC64.dll
Rename file to: $HOME/.wine/drive_c/Program Files (x86)/KeePass Password Safe 2/KeePassLibC64.bak
And keepass2 starts normally. Any version of keepass downloaded from official channels has a very different layout than if built locally, whether via mono or vs2017. Official builds look like this:
KeePass.chm KeePass.exe KeePass.exe.config KeePassLibC32.dll KeePassLibC64.dll KeePass.XmlSerializers.dll License.txt ShInstUtil.exe
Personal builds look like this:
KeePass.exe KeePassLib.dll KeePassLib.xml
Pretty big difference. Not real sure why that is but all of the personal build I did looked like they were "AnyCPU" or combined architecture, which might just default to non-64bit. Presumably KeePassLibC64.dll wants to use enhanced CPU instructions, wine bycrypt advertises their availability, gnutls provided the capability, and the CPU cannot process.
I like to think of the K10 cpu instruction set deficiency as:
Keepass wants it (one of the following SIMD/SSSE3/AES-NI/AVX/SSE4.1) Wine says it has it gnutls provides it cpu fails to process it
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #11 from Hans Leidekker hans@meelstraat.net --- (In reply to noabody from comment #10)
I like to think of the K10 cpu instruction set deficiency as:
Keepass wants it (one of the following SIMD/SSSE3/AES-NI/AVX/SSE4.1) Wine says it has it gnutls provides it cpu fails to process it
There's is no way to ask for a specific implementation in bcrypt. By default GnuTLS is built with all hardware accelarated implementations that the build host supports, as well as a software fallback implementation. GnuTLS decides at runtime which optimized implementation will be used, based on the processor's capabilities.
You can verify this by running Wine's bcrypt test on a machine that supports e.g. SSSE3. The test should pass. If you set GNUTLS_CPUID_OVERRIDE=0x1 (disabling optimizations) and run the test again you should get the same divide-by-zero exception.
https://bugs.winehq.org/show_bug.cgi?id=46471
--- Comment #12 from noabody@yahoo.com --- With that in mind we can build an abstract of the problem.
KeePassLibC64.dll uses SSSE3 encryption functions KeePassLibC32.dll doesn't use SSSE3 AMD K10 lacks SSSE3
But the program works on K10 in Win64 so we'll expand:
KeePassLibC64.dll uses SSSE3 encryption functions KeePassLibC32.dll doesn't use SSSE3 AMD K10 lacks SSSE3 KeePass.exe tries to use LibC64 and falls back to LibC32 if SSSE3 not found
Now we'll apply that to wine stable:
KeePassLibC64.dll uses SSSE3 encryption functions KeePassLibC32.dll doesn't use SSSE3 AMD K10 lacks SSSE3 KeePass.exe tries to use LibC64 KeePass.exe falls back to LibC32 because a wine stubbed API function is not available Encryption is handed off to gnutls Program executes normally
And to wine-devel/staging:
KeePassLibC64.dll uses SSSE3 encryption functions KeePassLibC32.dll doesn't use SSSE3 AMD K10 lacks SSSE3 KeePass.exe uses LibC64 because a wine stubbed API function is available Encryption is handed off to gnutls gnutls returns a divide by zero
What changed between wine stable and devel with no change in keepass? We can surmise that a previously stubbed encryption call is now implemented.
But it's a bug in gnutls, right, that is the mechanism that handles encryption? It should see the SSSE3 instruction request, recognize that the CPU lacks the instruction set, and fallback to a software only implementation.
That suggests that any given SSSE3 instruction has an identical software function to wrap to. Maybe there is. Maybe the version of gnutls in Ubuntu 18.04 currently lacks the code to wrap the function call properly.
https://bugs.winehq.org/show_bug.cgi?id=46471
Hans Leidekker hans@meelstraat.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Component|bcrypt |-unknown Resolution|--- |NOTOURBUG Status|UNCONFIRMED |RESOLVED
--- Comment #13 from Hans Leidekker hans@meelstraat.net --- Resolving as NOTOURBUG.