Skip to content

Commit ccfaee7

Browse files
authored
Merge pull request #252 from melissalinkert/tmp-noexec-handling
Document and fail fast if tmp directory is noexec
2 parents 530e28b + c772b46 commit ccfaee7

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,29 @@ If using features that rely on OpenCV (see the [Downsampling type](#downsampling
3333

3434
__NOTE:__ If you are setting `jna.library.path` via the `JAVA_OPTS` environment variable, make sure the path is to the folder __containing__ the library not path to the library itself.
3535

36+
Temporary directory usage
37+
=========================
38+
39+
Beginning with 0.10.0, if the default temporary directory (usually `/tmp/`) is mounted as `noexec`, conversion will fail immediately by default.
40+
[CIS security benchmarks](https://www.cisecurity.org/benchmark) recommend that `/tmp/` be mounted as `noexec`; these standards are increasingly
41+
being adopted by major Linux distributions. For certain types of input data (e.g. NDPI, JPEG-XR compression), bioformats2raw needs
42+
to extract a native library from one or more jars to a temporary location. In these cases, the extracted native library must be executable in order
43+
to read image data.
44+
45+
The recommended solution is to choose a different temporary directory by adding `-Djava.io.tmpdir=/path/to/alternate/tmp` to `JAVA_OPTS`.
46+
If multiple properties need to be set via `JAVA_OPTS`, separate them with a space, e.g. `JAVA_OPTS="-Djava.io.tmpdir/path/to/alternate/tmp -Djna.library.path=/path/to/blosc"`.
47+
48+
If you know this issue does not affect your input data and wish to warn instead of immediately stopping conversion, the `--warn-no-exec` option can be used.
49+
For input data that relies on native library loading (e.g. NDPI, JPEG-XR compression), using `--warn-no-exec` instead of specifying an alternate
50+
temporary directory will simply cause the conversion to fail at a later point.
51+
52+
For additional information, please see:
53+
54+
* https://github.com/glencoesoftware/bioformats2raw/pull/252
55+
* https://github.com/scijava/native-lib-loader/issues/41
56+
* https://forum.image.sc/t/after-omero-server-upgrade-hamamatsu-ndpi-files-display-only-in-low-resolution/81868
57+
* https://forum.image.sc/t/bioformats-unable-to-read-czi-files-with-jpegxr-compression-on-almalinux-os-java-lang-unsatisfiedlinkerror-ome-jxrlib-jxrjni-new-decodecontext-j/82646
58+
3659
Installation
3760
============
3861

src/main/java/com/glencoesoftware/bioformats2raw/Converter.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ public class Converter implements Callable<Integer> {
128128
private volatile Path inputPath;
129129
private volatile String outputLocation;
130130

131+
private volatile boolean warnNoExec = false;
132+
131133
private Map<String, String> outputOptions;
132134
private volatile Integer pyramidResolutions;
133135
private volatile List<Integer> seriesList;
@@ -424,6 +426,23 @@ public void setProgressBars(boolean useProgressBars) {
424426
progressBars = useProgressBars;
425427
}
426428

429+
/**
430+
* Configure whether to warn instead of throwing an exception
431+
* if files created in the temporary directory
432+
* ("java.io.tmpdir" system property) will not be executable.
433+
*
434+
* @param warnOnly true if a warning should be logged instead of an exception
435+
*/
436+
@Option(
437+
names = {"--warn-no-exec"},
438+
description = "Warn instead of throwing an exception if " +
439+
"java.io.tmpdir is not executable",
440+
defaultValue = "false"
441+
)
442+
public void setWarnOnNoExec(boolean warnOnly) {
443+
warnNoExec = warnOnly;
444+
}
445+
427446
/**
428447
* Configure whether to print version information and exit
429448
* without converting.
@@ -966,6 +985,14 @@ public boolean getProgressBars() {
966985
return progressBars;
967986
}
968987

988+
/**
989+
* @return true if a warning is logged instead of an exception when the tmp
990+
* directory is noexec
991+
*/
992+
public boolean getWarnNoExec() {
993+
return warnNoExec;
994+
}
995+
969996
/**
970997
* @return true if only version info is displayed
971998
*/
@@ -1194,6 +1221,37 @@ public Integer call() throws Exception {
11941221
tileWidth, tileHeight);
11951222
}
11961223

1224+
// if the tmpdir is mounted as noexec, then any native library
1225+
// loading (OpenCV, turbojpeg, etc.) is expected to fail, which
1226+
// can cause conversion to fail with an exception that is not user friendly
1227+
//
1228+
// try to detect this case early and fail before the conversion begins,
1229+
// with a more informative message
1230+
1231+
// a temp file is created and set as executable
1232+
// in the noexec case, setting as executable is expected to silently fail
1233+
File tmpdirCheck = File.createTempFile("noexec-test", ".txt");
1234+
try {
1235+
// expect 'success' to be true in the noexec case, even though
1236+
// the file will not actually be executable
1237+
boolean success = tmpdirCheck.setExecutable(true);
1238+
if (!success || !tmpdirCheck.canExecute()) {
1239+
String msg = System.getProperty("java.io.tmpdir") +
1240+
" is noexec; fix it or specify a different java.io.tmpdir." +
1241+
" See https://github.com/glencoesoftware/bioformats2raw/" +
1242+
"blob/master/README.md#temporary-directory-usage for details";
1243+
if (getWarnNoExec()) {
1244+
LOGGER.warn(msg);
1245+
}
1246+
else {
1247+
throw new RuntimeException(msg);
1248+
}
1249+
}
1250+
}
1251+
finally {
1252+
tmpdirCheck.delete();
1253+
}
1254+
11971255
OpenCVTools.loadOpenCV();
11981256

11991257
if (progressBars) {

0 commit comments

Comments
 (0)