Skip to content
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

Is the execstack flag required on any of the shared libraries? #20956

Open
JamesKingdon opened this issue Jan 16, 2025 · 7 comments
Open

Is the execstack flag required on any of the shared libraries? #20956

JamesKingdon opened this issue Jan 16, 2025 · 7 comments

Comments

@JamesKingdon
Copy link
Contributor

A customer reports failures of the JVM when running with SELinux enabled and configured to disallow execstack. The problem occurs because libj9jit29.so and libj9vm29.so are both flagged as requiring execstack. As an experiment I cleared the flag on both libraries and was able to run -version and a standard benchmark without problems. Is it possible that these libraries have been flagged in error?

I tested using Java 17.0.12.1 where both libraries are marked:

# execstack -q *.so
- libcuda4j29.so
- libj9dmp29.so
- libj9gc29.so
- libj9gcchk29.so
- libj9gcchk_full29.so
- libj9gc_full29.so
- libj9hookable29.so
- libj9jextract.so
X libj9jit29.so
- libj9jnichk29.so
- libj9jvmti29.so
- libj9prt29.so
- libj9shr29.so
- libj9thr29.so
- libj9trc29.so
X libj9vm29.so
- libj9vmchk29.so
- libj9vrb29.so
- libj9vrb_full29.so
- libj9zlib29.so
- libjclse29.so
- libjvm.so
- libmanagement_ext.so
- libomrsig.so

and also with ibm sdk 8.0.8.30 where only the jit library is affected. As a footnote, there is also at least one library in WebSphere that has the same problem.

@pshipton
Copy link
Member

I don't think it's explicitly set, since I can't find it in the code. I did find some occurrences of -noexecstack related to assembly options. I think either we're missing some, or GCC is setting it. I'm not sure atm how we track down which object file(s) set it.

I found this in the doc:
...
Furthermore, GCC trampoline code for e.g. nested functions requires executable stack on many architectures.
...
The marking is done automatically by recent GCC versions (objects using trampolines on the stack are marked as requiring executable stack, all other newly built objects are marked as not requiring it) and linker collects these markings into marking of the whole binary or shared library.

@pshipton
Copy link
Member

Are your execstack results from zlinux? I looked on X and while jit has it, vm does not.

@jdmpapin
Copy link
Contributor

jdmpapin commented Jan 16, 2025

From searching around, apparently when we link with object files produced from assembly sources (.s), those object files are assumed to potentially require executable stack unless they have a special section .note.GNU-stack to explicitly specify stack permissions.

The VM has this (somewhat) recent change, which might prevent newer VM libraries from indicating a need for executable stack. I think it was done to avoid the warning that was introduced in binutils 2.39:

ld: warning: <foo>.o: missing .note.GNU-stack section implies executable stack
ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker

Maybe the JIT still has some assembly sources that are missing the magic incantation.

The JIT library that I most recently built on my system doesn't demand executable stack, but it seems to be due to a difference in the behaviour of the ld installed on my system. I wrote a trivial .c file and a trivial .s file without a .note.GNU-stack section. If I link them with my installed ld, I get no warning and the stack is not executable. It says its version is "GNU ld version 2.43.1-5.fc41". But it so happens that I downloaded the binutils-2.43.1 source a while ago, and if I link them with that, I do get the warning and the stack is executable. So it seems like Fedora has essentially set -z noexecstack by default, or maybe more likely they've just stopped having the missing section imply executable stack, like the warning says will eventually happen.

@JamesKingdon
Copy link
Contributor Author

Are your execstack results from zlinux? I looked on X and while jit has it, vm does not.

I was testing on X linux

@jdmpapin
Copy link
Contributor

jdmpapin commented Jan 17, 2025

I've seen the same as Peter in a few builds with and without #20278, so apparently something else was already making sure that the VM library wouldn't have executable stack, at least at the time when that went in

@JamesKingdon
Copy link
Contributor Author

Interesting. I checked the ones I have quickly available;
certified 17.0.12.1: jit and jvm libs both flagged
open 17.0.10_7, 17.0.11_9, 17.0.12_7: both flagged
open 17.0.13_11: only the jit library is flagged

@jdmpapin
Copy link
Contributor

I found the link commands for both the VM and JIT libraries from a build log on my machine, and I lightly edited them to run using ld instead of g++ (by eliminating compiler options like -std= and warning options, changing -Wl,-foo,bar to -foo bar, and adding some libraries that would be implied when running g++) so that I could rerun the link step using upstream binutils 2.43.1, which warns and makes the stack executable when the .note.GNU-stack section is missing

Re-linking the libraries with #20284 and #20278 reverted, both had executable stack

Re-linking them without anything reverted OTOH, only the JIT library had executable stack

This was with a CMake build of JDK17 on x86-64 Linux. It would seem that the new .section directive does actually prevent the stack from being made executable in the VM library, and that's consistent with the Semeru builds just mentioned, since 17.0.13 is the first release to include #20278 (really #20285, since it's 0.48)

The .section directive affects the JIT library as well, since there are m4-generated assembly sources that get linked into it, e.g. xnathelp.s. I didn't make a list because those ones won't cause a problem anymore anyway, and the linker only gives this warning for one object file, presumably the first applicable one

With the VM's assembly sources out of the way, it seems that the problem (in my build...) is now just due to the .nasm files. I managed to link a JIT library with non-executable stack by adding

section .note.GNU-stack noalloc noexec nowrite progbits

to each of the following files:

  • runtime/compiler/x/amd64/runtime/AMD64Recompilation.nasm
  • runtime/compiler/x/runtime/X86ArrayTranslate.nasm
  • runtime/compiler/x/runtime/X86Codert.nasm
  • runtime/compiler/x/runtime/X86LockReservation.nasm
  • runtime/compiler/x/runtime/X86PicBuilder.nasm
  • runtime/compiler/x/runtime/X86Unresolveds.nasm

I'm not sure we should go about it that way though. We'd have to do the same exercise for every ISA, and it would be easy to accidentally make the stack executable again by introducing a new assembly file and forgetting the stack permissions section

I think it would be better to link using -z noexecstack so that we can't miss any files. Interestingly, my local build log has a lot of lines that say that LDFLAGS includes -Wl,-z,noexecstack (presumably because it's linking by running the compiler instead of the linker directly):

LDFLAGS := -Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack [...]

And apparently this does get passed to a bunch of link commands, mostly to produce binaries in support/modules_cmds, support/modules_libs, and support/test, but it doesn't get passed into any of the commands that link libj9*.so

As for the builds that I looked at before, they were UMA builds, not CMake builds. Maybe in those some noexecstack option(s) actually applied to all of the assembly files in the VM library so that the new section directive didn't make a difference, but didn't/don't apply to all the ones in the JIT library. They probably don't apply to the .nasm files, at least

Anyway, at this point I think I'm out of my depth 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants