Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.io.File.setReadable(false) has no effect inside docker

Tags:

java

file

docker

The following code succeeds on Ubuntu 18.04 with OpenJDK 8, but fails inside the Docker image maven:3-jdk-8-slim which is based on OpenJDK 8:

String userHome = System.getProperty("user.home");
System.out.println(String.format("system property user.home: %s",
        userHome));
File file = new File(userHome, "file");
if(!file.createNewFile()) {
    throw new IOException("test arrangement failed");
}
if(!file.setReadable(false)) {
    throw new IOException("test arrangement failed");
}
assertFalse(file.canRead());

Failure details:

java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:86)
    at org.junit.Assert.assertTrue(Assert.java:41)
    at org.junit.Assert.assertFalse(Assert.java:64)
    at org.junit.Assert.assertFalse(Assert.java:74)
    at de.richtercloud.docker.java.file.readability.TheTest.testSomeMethod(TheTest.java:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

which refers to the assertFalse(file.canRead()) assertion. This assertion should pass because file.setReadable(false) returned true and thus succeeded.

I reproduced the issue in a SSCCE with the Docker-based GitLab CI, so that detailed output can be found at https://gitlab.com/krichter/docker-java-file-readability/-/jobs/203311757. The SSCCE does not contain more information than the above code excerpt, but makes local investigation easier.

I'm looking for an explanation, not a workaround.

like image 736
Kalle Richter Avatar asked Jul 28 '18 11:07

Kalle Richter


1 Answers

The documentation of File.canRead() contains a note that its result may be confusing:

public boolean canRead()

Tests whether the application can read the file denoted by this abstract pathname. On some platforms it may be possible to start the Java virtual machine with special privileges that allow it to read files that are marked as unreadable. Consequently this method may return true even though the file does not have read permissions.

Under docker processes usually run as root giving them privileges unseen by regular users.

Proof that root can read files lacking read permission:

$ echo abcd > somefile
$ ls -l somefile 
-rw-rw-r-- 1 leon leon 5 Aug 26 21:43 somefile

$ cat somefile
abcd

$ chmod a-rw somefile 
$ ls -l somefile 
---------- 1 leon leon 5 Aug 26 21:43 somefile

$ cat somefile
cat: somefile: Permission denied

$ sudo cat somefile
abcd
like image 143
Leon Avatar answered Sep 27 '22 20:09

Leon