Bug 551690 - AccessControlException triggered when a SecurityManager is installed
Summary: AccessControlException triggered when a SecurityManager is installed
Status: RESOLVED FIXED
Alias: None
Product: JGit
Classification: Technology
Component: JGit (show other bugs)
Version: 5.4.2   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: 5.7   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-10-02 01:37 EDT by Alex Jitianu CLA
Modified: 2020-01-28 04:29 EST (History)
4 users (show)

See Also:


Attachments
A test case that fails because of missing read/write permissions (2.54 KB, application/octet-stream)
2019-11-28 03:17 EST, Alex Jitianu CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Jitianu CLA 2019-10-02 01:37:58 EDT
I frequently get the error from below. It looks like it is related with the use of a java.util.concurrent.CompletableFuture inside FileStoreAttributes.measureFsTimestampResolution(). If a SecurityManager is installed, a java.util.concurrent.ForkJoinPool.InnocuousForkJoinWorkerThreadFactory will be used which runs with restricted permissions:

        static {
            Permissions innocuousPerms = new Permissions();
            innocuousPerms.add(modifyThreadPermission);
            innocuousPerms.add(new RuntimePermission(
                                   "enableContextClassLoaderOverride"));
            innocuousPerms.add(new RuntimePermission(
                                   "modifyThreadGroup"));
            innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
                    new ProtectionDomain(null, innocuousPerms)
                });
        }


8 ERROR [ ForkJoinPool.commonPool-worker-2 ] org.eclipse.jgit.util.FS - java.security.AccessControlException: access denied ("java.io.FilePermission" "D:\projects\samples\debugger\.git\refs\heads\.probe-4786be8d-dec1-4a99-b634-ecc04f70e00b" "write")
java.util.concurrent.CompletionException: java.security.AccessControlException: access denied ("java.io.FilePermission" "D:\projects\samples\debugger\.git\refs\heads\.probe-4786be8d-dec1-4a99-b634-ecc04f70e00b" "write")
	at java.util.concurrent.CompletableFuture.encodeThrowable(Unknown Source)
	at java.util.concurrent.CompletableFuture.completeThrowable(Unknown Source)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(Unknown Source)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(Unknown Source)
	at java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(Unknown Source)
	at java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
	at java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)
Caused by: java.security.AccessControlException: access denied ("java.io.FilePermission" "D:\projects\samples\debugger\.git\refs\heads\.probe-4786be8d-dec1-4a99-b634-ecc04f70e00b" "write")
	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkWrite(Unknown Source)
	at ro.sync.security.manager.SandboxSecurityManager.checkWrite(SandboxSecurityManager.java:177)
	at sun.nio.fs.WindowsChannelFactory.open(Unknown Source)
	at sun.nio.fs.WindowsChannelFactory.newFileChannel(Unknown Source)
	at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(Unknown Source)
	at java.nio.file.Files.newByteChannel(Unknown Source)
	at java.nio.file.Files.createFile(Unknown Source)
	at org.eclipse.jgit.util.FS$FileStoreAttributes.measureFsTimestampResolution(FS.java:461)
	at org.eclipse.jgit.util.FS$FileStoreAttributes.lambda$0(FS.java:341)
	... 6 more
Comment 1 Sorin Carbunaru CLA 2019-10-22 10:57:21 EDT
Happened to me too...
Comment 2 Sorop Adrian CLA 2019-10-29 11:37:24 EDT
I had the same problem.
Comment 3 Thomas Wolf CLA 2019-10-29 16:43:46 EDT
If the use of the innocuous thread was the problem, then why does org.eclipse.jgit.api.SecurityManagerTest _not_ fail? It _does_ execute this CompletableFuture, and runs, as far as I see in the debugger, in an innocuous thread.
Comment 4 Alex Jitianu CLA 2019-11-27 09:00:17 EST
After a quick glance at SecutiryManagerTest, I'm not sure if it's intended to catch this behavior. It's not like the application crashes, it logs this exception and moves on with a fallback. This fallback:

org.eclipse.jgit.util.FS.FileStoreAttributes.FALLBACK_FILESTORE_ATTRIBUTES


I've made a small JUNIT test that uses an java.util.concurrent.CompletableFuture<Void> with an install SecurityManager and when the task gets executed there are no write permisions:

  @Test
  public void testWritePerm() throws Exception {
	  refreshPolicy(Policy.getPolicy());
	  System.setSecurityManager(new SecurityManager());

	  SecurityManager sm = System.getSecurityManager();

	  String file = "D:\\test\\.probe-64fe0316-10fa-4fa1-b163-d79366318e4b";

	  CompletableFuture<Void> f = CompletableFuture.supplyAsync(new Supplier<Void>() {
		  @Override
		  public Void get() {
			  sm.checkWrite(file);

			  return null;
		  }
	  });

	  f.get();
  }
  
  /**
   * Refresh the Java Security Policy.
   *  
   * @param policy The policy object.
   * 
   * @throws IOException If the temporary file that contains the policy could not be created.
   */
  private static void refreshPolicy(Policy policy) throws IOException {
    // Starting with an all permissions policy.
    String policyString = "grant { permission java.security.AllPermission; };";
    
    // Do not use TemporaryFilesFactory, it will create a dependency cycle 
    File policyFile = File.createTempFile("oxy_policy", ".txt");
    
    try {
      //Write the policy
      try (OutputStream fos = java.nio.file.Files.newOutputStream(policyFile.toPath())) {
        fos.write(policyString.getBytes(StandardCharsets.UTF_8));
      }
      
      System.setProperty("java.security.policy", policyFile.toURI().toURL().toString());
      //Refresh the policy
      policy.refresh();
    } finally {
      try {
        java.nio.file.Files.delete(policyFile.toPath());
      } catch (IOException e) {
    	  e.printStackTrace();
      }
    }
  }
Comment 5 Thomas Wolf CLA 2019-11-27 10:03:38 EST
(In reply to Alex Jitianu from comment #4)
> After a quick glance at SecutiryManagerTest, I'm not sure if it's intended
> to catch this behavior. It's not like the application crashes, it logs this
> exception and moves on with a fallback.

So let me phrase the question differently then: why don't we see this error logged in the test runs? We should see it there, too. SecurityManagerTest does install a security manager and runs this CompletableFuture on an innocuous thread, so it should run into precisely the same problem. But somehow it doesn't.
Comment 6 Alex Jitianu CLA 2019-11-28 03:15:58 EST
(In reply to Thomas Wolf from comment #5)
> So let me phrase the question differently then: why don't we see this error
> logged in the test runs? We should see it there, too. 

I can't say, but I'll attach a JUnit test case that fails on my system. I'm using JGIT version 5.5.1.201910021850-r and I also have the a slf4j-log4j dependenncy in my pom:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-log4j12</artifactId>
	<version>1.7.25</version>
</dependency>
Comment 7 Alex Jitianu CLA 2019-11-28 03:17:07 EST
Created attachment 280805 [details]
A test case that fails because of missing read/write permissions

The test fails because of exceptions such as:

0 ERROR [ ForkJoinPool.commonPool-worker-1 ] org.eclipse.jgit.util.FS - java.security.AccessControlException: access denied ("java.io.FilePermission" "C:\Program Files\Git\mingw64\etc\gitconfig" "read")
java.util.concurrent.CompletionException: java.security.AccessControlException: access denied ("java.io.FilePermission" "C:\Program Files\Git\mingw64\etc\gitconfig" "read")
	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Comment 8 Thomas Wolf CLA 2019-11-29 02:49:33 EST
(In reply to Alex Jitianu from comment #7)
> Created attachment 280805 [details]
> A test case that fails because of missing read/write permissions

Thanks for that test case! I can reproduce with this, and I have a fix. However, I need you to push this test to Gerrit. Otherwise I cannot use it -- Eclipse legal rules. Once it's in Gerrit, I can adapt it and add the bug fix. I'm not allowed to just copy-paste your code and modify it unless it's been contributed properly under the EDL license.

You'll need to sign a Contributor Agreement and then push this to Gerrit. See https://wiki.eclipse.org/EGit/Contributor_Guide#Contributing_Patches for more information.
Comment 9 Alex Jitianu CLA 2019-12-02 08:44:53 EST
I tried to commit the test case but I failed miserably. I haven't worked with Gerrit , but I assume I'm not committing in the right branch:

git -c diff.mnemonicprefix=false -c core.quotepath=false push -v origin master:master
POST git-receive-pack (2326 bytes)
remote: Branch refs/heads/master:        
remote: You are not allowed to perform this operation.        
remote: To push into this reference you need 'Push' rights.        
remote: User: ajitianuvt6        
remote: Please read the documentation and contact an administrator        
remote: if you feel the configuration is incorrect        
remote: 
remote: Processing changes: refs: 1
remote: Processing changes: refs: 1, done            







Pushing to https://git.eclipse.org/r/jgit/jgit
To https://git.eclipse.org/r/jgit/jgit
 ! [remote rejected]     master -> master (prohibited by Gerrit: ref update access denied)
error: failed to push some refs to 'https://git.eclipse.org/r/jgit/jgit'



Completed with errors, see above.
Comment 10 Thomas Wolf CLA 2019-12-02 09:06:42 EST
(In reply to Alex Jitianu from comment #9)
> I tried to commit the test case but I failed miserably. I haven't worked
> with Gerrit , but I assume I'm not committing in the right branch:
> 
> git -c diff.mnemonicprefix=false -c core.quotepath=false push -v origin
> master:master
> POST git-receive-pack (2326 bytes)
> remote: Branch refs/heads/master:        
> remote: You are not allowed to perform this operation.        
> remote: To push into this reference you need 'Push' rights.        
> remote: User: ajitianuvt6        
> remote: Please read the documentation and contact an administrator        
> remote: if you feel the configuration is incorrect        
> remote: 
> remote: Processing changes: refs: 1
> remote: Processing changes: refs: 1, done            
> 
> 
> 
> 
> 
> 
> 
> Pushing to https://git.eclipse.org/r/jgit/jgit
> To https://git.eclipse.org/r/jgit/jgit
>  ! [remote rejected]     master -> master (prohibited by Gerrit: ref update
> access denied)
> error: failed to push some refs to 'https://git.eclipse.org/r/jgit/jgit'
> 
> 
> 
> Completed with errors, see above.

You need to push to refs/for/master, and the commit message should have a Change-ID:-line. Haven't done this on the command-line for ages; I think if you push without Change-Id to refs/for/master, Gerrit will again reject it but give you in the message a command to download and install a git hook to add that line on commit. You may then need to amend your commit once to have that hook run before pushing again.
Comment 11 Alex Jitianu CLA 2019-12-03 04:32:56 EST
I finally managed to commit the changes. Hope it's all there!
Comment 12 Alex Jitianu CLA 2019-12-03 04:33:06 EST
https://git.eclipse.org/r/#/c/153691/
Comment 13 Sorin Carbunaru CLA 2020-01-27 08:47:00 EST
Hi! Any plans to fix this soon?
Comment 14 Eclipse Genie CLA 2020-01-28 04:22:44 EST
Gerrit change https://git.eclipse.org/r/153691 was merged to [master].
Commit: http://git.eclipse.org/c/jgit/jgit.git/commit/?id=64715a189fe19e8a25bb8757591e3ef60f3f9aa8