guava: From Guava 32.0.1-jre, Files.createTempDir() and FileBackedOutputStream can fail or create un-deletable directories/files when used from a Windows service
Hello I rencently upgraded from 31.1-jre to 32.0.1-jre. FYI 32.0.0-jre was KO because of the then-corrected-in-32.0.1-jre error: java.lang.UnsupportedOperationException: ‘posix:permissions’ not supported as initial attribute. So let’s not talk about this version.
In 32.0.1-jre the method Files.createTempDir() has been modified and a program RUNNING ON WINDOWS is now unable to delete its own folders created by this call.
Here is a sample creating a folder with java’s own “createTempDirectory” and deleting it (this works fine) and then the same with Guava and it cannot delete it’s own folder created with guava.
@Test
public void testApp() throws IOException {
Path tempDir = java.nio.file.Files.createTempDirectory("temp");
displayDirectoryPermissions(tempDir);
boolean isDeleted = tempDir.toFile().delete();
assertTrue(isDeleted);
System.out.println(" - - - - - - - - - ");
Path tempDir2 = Files.createTempDir().toPath();
displayDirectoryPermissions(tempDir2);
boolean isDeleted2 = tempDir2.toFile().delete();
assertTrue(isDeleted2);
}
private static void displayDirectoryPermissions(Path directory) throws IOException {
System.out.println("Informations sur les droits d'accès du répertoire : " + directory.toAbsolutePath());
AclFileAttributeView view = java.nio.file.Files.getFileAttributeView(directory, AclFileAttributeView.class);
System.out.println(view.toString());
view.getAcl().forEach(it -> System.out.println(it.toString()));
}
Here are the (desidentified) trace and there is a huge difference beween both calls:
Informations sur les droits d'accès du répertoire : e:\xxxxxxx\target\temp18063228888024228555
sun.nio.fs.WindowsAclFileAttributeView@7494f96a
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
BUILTIN\Administrators:FILE_INHERIT/DIRECTORY_INHERIT/INHERIT_ONLY:ALLOW
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
NT AUTHORITY\SYSTEM:FILE_INHERIT/DIRECTORY_INHERIT/INHERIT_ONLY:ALLOW
NT AUTHORITY\Authenticated Users:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/SYNCHRONIZE:ALLOW
NT AUTHORITY\Authenticated Users:DELETE:FILE_INHERIT/DIRECTORY_INHERIT/INHERIT_ONLY:ALLOW
BUILTIN\Users:READ_DATA/READ_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/READ_ACL/SYNCHRONIZE:ALLOW
BUILTIN\Users:FILE_INHERIT/DIRECTORY_INHERIT/INHERIT_ONLY:ALLOW
- - - - - - - - -
Informations sur les droits d'accès du répertoire : e:\xxxxxxx\target\3980498532511240827
sun.nio.fs.WindowsAclFileAttributeView@32502377
WINDOWS-DOMAIN\computerName$:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:FILE_INHERIT/DIRECTORY_INHERIT:ALLOW
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 20 (12 by maintainers)
Commits related to this issue
- Fix `Files.createTempDir` and `FileBackedOutputStream` under Windows _services_, a rare use case. Fixes https://github.com/google/guava/issues/6634 Relevant to https://github.com/google/guava/issues... — committed to google/guava by cpovirk 9 months ago
- clone of https://github.com/google/guava/pull/6730 but with Windows testing on JDK8 Fix `Files.createTempDir` and `FileBackedOutputStream` under Windows _services_, a rare use case. Fixes https://gi... — committed to google/guava by cpovirk 9 months ago
- clone of https://github.com/google/guava/pull/6730 but without the prod change -- should fail Windows testing Fix `Files.createTempDir` and `FileBackedOutputStream` under Windows _services_, a rare u... — committed to google/guava by cpovirk 9 months ago
- Fix `Files.createTempDir` and `FileBackedOutputStream` under Windows _services_, a rare use case. Fixes https://github.com/google/guava/issues/6634 Relevant to https://github.com/google/guava/issues... — committed to google/guava by cpovirk 9 months ago
- Fix `Files.createTempDir` and `FileBackedOutputStream` under Windows _services_, a rare use case. Fixes https://github.com/google/guava/issues/6634 Relevant to https://github.com/google/guava/issues... — committed to google/guava by cpovirk 9 months ago
- Skip a couple `ServiceManager` tests when running Java 8 on Windows. I've found them to be [flaky](https://github.com/google/guava/pull/6731#issuecomment-1736298607). We already [skip](https://github... — committed to google/guava by cpovirk 9 months ago
- Skip a couple `ServiceManager` tests when running Java 8 on Windows. I've found them to be [flaky](https://github.com/google/guava/pull/6731#issuecomment-1736298607). We already [skip](https://github... — committed to google/guava by cpovirk 9 months ago
- Fix `Files.createTempDir` and `FileBackedOutputStream` under Windows _services_ (at least under JDK 9+), a rare use case. Fixes https://github.com/google/guava/issues/6634 Relevant to https://github... — committed to google/guava by cpovirk 9 months ago
- Fix double-source-jar error during releases: ``` Building and deploying the android flavor (this may take a while)... [ERROR] We have duplicated artifacts attached. [ERROR] Failed to execute goal org... — committed to google/guava by cpovirk 9 months ago
- Fix double-source-jar error during releases: ``` Building and deploying the android flavor (this may take a while)... [ERROR] We have duplicated artifacts attached. [ERROR] Failed to execute goal org... — committed to google/guava by cpovirk 9 months ago
- Fix double-source-jar error during releases: ``` Building and deploying the android flavor (this may take a while)... [ERROR] We have duplicated artifacts attached. [ERROR] Failed to execute goal org... — committed to google/guava by cpovirk 9 months ago
- Fix double-source-jar error during releases: ``` Building and deploying the android flavor (this may take a while)... [ERROR] We have duplicated artifacts attached. [ERROR] Failed to execute goal org... — committed to google/guava by cpovirk 9 months ago
For anyone who’s following here but not following our repo as a whole: The fix for this is part of last week’s https://github.com/google/guava/releases/tag/v32.1.3. If you see any problems with that version, please let us know.
Because the java process is launched from another process, i couldn’t easily inject that system property. Instead i just let the Jenkins service run with an ordinary Admin User instead of the local service account. That works now fine.
thanks @cpovirk , we are using java 17 LTS
thanks @cpovirk , I’m using Java11
I’m going to implement that approach now, since the Stack Overflow question sounds like just the same situation.
@cpovirk We run into a similar issue. Root cause is the same, but we can not even create a temp dir. We have here a Jenkins based CI running on windows. The jobs are executed by Jenkins nodes which are installed as windows services, hence running as windows
SYSTEM
account, which is the default service user under windows. Some test code callsFiles.createTempDir()
, which internally resolves system propertyuser.name
toPIPELINE$
(PIPELINE is the computer name) instead ofSYSTEM
. Hence creating of temp dir fails, as there is no user namedPIPELINE$
. we see then the following exceptionwindows version
trying to workarround by setting
user.name
toSYSTEM
as java argument when invoking test commandThanks for the additional details and testing.
It does seem extremely likely that plain
java.nio.file.Files.createTempDirectory
is secure. But the Linux-related JDK docs are noncommittal, saying something like like “the file/directory created might have more restricted permissions than you asked for.” That sounds like it might be referring to the umask, but I was seeing even more restricted permissions than the umask asked for (which is good from the security perspective). Perhaps because of the ambiguity, some docs suggest setting the permissions explicitly. And then Windows is its own story, with the temporary directory itself normally secure, as you said. Here’s some previous discussion.I’m going to re-title this bug to reflect that it applies just to the daemon case. If we end up hearing from more affected users, we can reevaluate. Thanks for your flexibility.
Hello, a few comments & answer below:
to cgdecker: I’m not in Guava team but I know that the default windows temp dir is user-specific. So from my (limited) point of view, there is not really a need to set anything specific. In my case I explicitly tell Java to use another dir (through
-Djava.io.tmpdir=e:\xxxxxxx\target
) so responsibility for setting limited rights could be on my side. I would find it fair.to cpovirk 1-: please do not modify anything for me. I already simply moved my tests away from using Guava’s
createTempDir()
tojava.nio.file.Files.createTempDirectory()
. That was an easy move. Ijust reported the bug so that you know there is a problem others may face. It’s not a blocker anymore for me.to cpovirk 2-: you were right, launching my tests with
-Duser.name=SYSTEM
corrected the problem. The process was able to correctly delete it’s own temporary dir.for the record, the problem mentioned in JENKINS-71375 is specific to version 32.0.0-jre and was corrected in 32.0.1-jre and I think that only daemon services (and maybe especially the ones changing the default temp dir like I did) will be hurt with the same bug as described here.
Thanks for all the details.
At first glance, I’m puzzled: We test that we can delete the directory, and we have had our tests running under Windows. We have also tested manually under Windows, as have other users, and we’ve heard of apps that started working again at 32.0.1. So there must be some variation between systems that accounts for this.
One thing that I’d wondered was whether the system property
user.name
is the right one to use. Maybe it’s not? It looks like the code ended up granting permissions to a user “computerName$” (if I’m understanding right). Maybe that’s not actually the user that we need? (I do think I found that Java would fail if we tried to set a user that does not exist, at least in the testing I did.) It’s interesting that thejava.nio.file.Files.createTempDirectory()
output doesn’t appear to mention a specific user at all (again, if I’m understanding right). I think I’d seen a specific user listed in my testing.One frustrating part of this is that we might not need to set explicit permissions at all: The Windows temporary directory is very likely to be secure, and the Java’s Linux implementation appears to set restricted permissions by default (but its docs are coy about this). Maybe I should just rip out all the permissions code. I’ve been hesitant to do so because it would look quite bad if such a change somehow reintroduced the security bug. (And of course now we’ve already had a bunch of releases in quick succession…)
Does anything about the username issue give you any ideas? Does anyone else have thoughts?