Handling /tmp partition mounted as noexec
Background
Widely recognized authorities including the Center for Internet Security (CIS) and NIST are regularly publishing and updating sets of security best practices for the configuration of IT systems like CIS Benchmarks and NIST 800-53. One of these recommendations is to have /tmp mounted as a separate partition with a number of mount options, including the noexec flag ^1 ^2 ^3 ^4 ^5.
Java programs can access native shared libraries using Java Native Access (JNA). Bio-Formats and OMERO make extensive use of this approach for the handling tiles compressed using JPEG, JPEG-XR or Blosc. Practically, this logic involves the creation of temporary files/folders where platform-specific libraries (e.g. .so, .aarch64) are extracted and loaded dynamically. By default, these files are created and executed from the Java temporary directory which points to /tmp on Unix systems. As a result, some of the reading functionalities of OMERO are directly impacted on systems where /tmp is mounted as a noexec partition.
For end-users, this issue will result into tile loading failures ^6 ^7. The application logs will include errors similar to:
java.lang.NoClassDefFoundError: Could not initialize class com.sun.jna.NativeLong
or
java.lang.UnsatisfiedLinkError: 'void org.libjpegturbo.turbojpeg.TJDecompressor.init()'
Workaround
There are two approaches to fix Java usage of native shared libraries in an environment where /tmp is mounted as noexec:
- modify the mount options of the
/tmppartition. This option should be highly discouraged as it goes against security practices and institutional policies. - specify an alternate temporary directory by setting the
java.io.tmpdirJava system property ^8.
In bioformats2raw, setting java.io.tmpdir appropriately is already the recommended workaround ^9. Given the variety of environments and platforms from where the conversion utility can be invoked, it is the responsibility of the caller to choose a temporary directory with appropriate permissions.
In OMERO, additional a priori assumptions can be made about the executing environment to use an alternative temporary location. After reviewing a few layouts, Glencoe Software started standardizing its deployments to use $OMERODIR/var/tmp (/opt/omero/OMERO.current/var/tmp) as the temporary directory for Java & JNA processes both for the OMERO.server and the OMERO micro-services.
Depending on the OMERO component, Java system properties must be set using different strategies:
- via omero.jvmcfg.append for OMERO.server
- via the
JAVA_OPTSenvironment variable for imports usingomero import - via the
JAVA_OPTSenvironment variable within the systemd service file for OMERO micro-services
Proposal
Given the prevalence of environments where /tmp is mounted with noexec, the following changes aim to make backwards-compatible changes to various OMERO components so that the application works without modification.
OMERO.py and OMERO.server
-
Update the OMERO CLI admin plugin a. check for the existence of
$OMERODIR/var/tmpand create it if necessary b. setjava.io.tmpdirto$OMERODIR/var/tmpfor anyomero admincommand invoking Java -
Update the OMERO.server bundle to create an empty
var/tmpsubfolder -
Update the OMERO CLI import plugin to set
java.io.tmpdirtoa.
$OMERODIR/var/tmpfor in-place imports (likeomero admin) b. the OMERO temporary directory, typically~/omero/tmp, for client-side imports
OMERO micro-services
- Update the default systemd service file shipped with the image-region micro-service to set
java.io.tmpdirinJAVA_OPTS - Update the default systemd service file shipped with the pixel-buffer micro-service to set
java.io.tmpdirinJAVA_OPTS
OMERO documentation
- Document the /tmp noexec issue and the current workaround
- Suggest an upgrade to the relevant set of components as a resolution once released