0

In other words, are modern GNU/Linux or JVM (ideally Java 11+) able to prevent a Java process from executing other processes?

Issues such as Log4Shell and Spring4Shell seem possible because the JVM allows a Java application to execute other programs.

At the OS level, I imagine it may be possible with some process isolation, jails etc. Are there complete examples about that?

How about the JVM itself? With the Security Manager gone in recent versions, what options exist to harden a Java Virtual Machine?

pyb
  • 4,813
  • 2
  • 27
  • 45

1 Answers1

1

I'm not sure there's a good way to do that. As discussed in Prevent forking in a child process, you can set RLIMIT_NPROC limit.

However, don't do that for your java app - you will break it. Threads are just a special type of a process on Linux and if you restrict nproc you won't be able to create new threads.

Observe this behavior on a running java application

prlimit
...
NPROC      max number of processes                15107     15107 processes

prlimit --pid $(pgrep java) --nproc=10

Then on the stdout of the java app

[9816123.415s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 2048k, guardsize: 0k, detached.

I tried this for a production app running in a docker container.

Note that nproc limit isn't enforced if you the process is running as root.

Morever, it's quite easy to reproduce it with a simple Clojure REPL (or JShell variant of it):

# start a clojure/java process
user=> (require '[clojure.java.shell :as sh])

user=> (dotimes [i 100] (future (sh/sh "sleep" "2")))
nil


# then get change the nproc limit for the process - make sure to pass proper pid
prlimit --pid 2769227 --nproc=99

# then again in the Clojure REPL: 
user=> (dotimes [i 100] (future (sh/sh "sleep" "2")))
[200.656s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
[200.656s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
[200.657s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
[200.657s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
[200.657s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 0k, detached.
Execution error (OutOfMemoryError) at java.lang.Thread/start0 (Thread.java:-2).
unable to create native thread: possibly out of memory or process/resource limits reached

Resources:

Juraj Martinka
  • 3,991
  • 2
  • 23
  • 25
  • Thank you! I wonder if this could work by creating a thread pool that would "consume" RLIMIT_NPROC on startup. – pyb Apr 11 '22 at 13:03
  • Perhaps it's possible to allow Java to fork itself while preventing it from running other executables? – pyb Apr 11 '22 at 13:04
  • 1
    I don't think you can work-around the nproc limit to allow creating threads but preventing processes. Moreover, there are also internal threads managed by JVM and not necessarily just your own program code. For anything but a trivial application this might become a nightmare. – Juraj Martinka Apr 12 '22 at 08:23