/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3.0 of the License, or * (at your option) any later version. * * EvoSuite is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.runtime.sandbox; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.LogManager; import org.evosuite.runtime.RuntimeSettings; import org.junit.*; import javax.swing.*; public class MSecurityManagerTest { private static ExecutorService executor; private static MSecurityManager securityManager; @BeforeClass public static void initClass(){ executor = Executors.newCachedThreadPool(); securityManager = new MSecurityManager(); } @AfterClass public static void doneWithClass(){ executor.shutdownNow(); } @Before public void initTest(){ securityManager.apply(); securityManager.goingToExecuteTestCase(); } @After public void doneWithTestCase(){ securityManager.goingToEndTestCase(); securityManager.restoreDefaultManager(); } @Test public void testSpecifyStreamHandler() throws Exception{ File tmp = null; try { tmp = File.createTempFile("testFile_"+System.currentTimeMillis(), "txt"); tmp.deleteOnExit(); final String text = "The answer is 42"; BufferedWriter out = new BufferedWriter(new FileWriter(tmp)); out.write(text); out.flush(); out.close(); final String fileName = tmp.getAbsolutePath(); //check that reading from URL is fine Future<?> future = executor.submit(new Runnable(){ @Override public void run() { try { URL url = new URL("file:"+fileName); BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); String input = in.readLine(); Assert.assertEquals(text, input); in.close(); } catch (Exception e) { throw new Error(e); } } }); future.get(1000, TimeUnit.MILLISECONDS); //check that writing from URL is forbidden future = executor.submit(new Runnable(){ @Override public void run() { try { URL url = new URL("file:"+fileName); URLConnection connection = url.openConnection(); connection.setDoOutput(true); /* * URL cannot be used to write to a file. if try to do it, a UnknownServiceException * should be thrown */ BufferedWriter out = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream())); out.write(text); out.flush(); out.close(); } catch(SecurityException se){ throw se; }catch (Exception e) { throw new Error(e); } } }); try{ future.get(1000, TimeUnit.MILLISECONDS); Assert.fail(); } catch(ExecutionException e){ if(! (e.getCause().getCause() instanceof java.net.UnknownServiceException) ){ Assert.fail("Cause is "+e.getCause().getCause().getMessage()); } } } catch (Exception e) { if(tmp!=null){ tmp.delete(); } throw e; } } @Test public void testReadButNotWriteOfFiles() throws IOException, InterruptedException, ExecutionException, TimeoutException{ File tmp = null; final String text = "EvoSuite rock!"; try{ //even if securityManager is on, the thread that set it should be able to write files tmp = File.createTempFile("foo_"+System.currentTimeMillis(), "tmp"); tmp.deleteOnExit(); //just in case... BufferedWriter out = new BufferedWriter(new FileWriter(tmp)); out.write(text); out.flush(); out.close(); final String fileName = tmp.getAbsolutePath(); //check that reading is fine Future<?> future = executor.submit(new Runnable(){ @Override public void run() { try { File reading = new File(fileName); BufferedReader in = new BufferedReader(new FileReader(reading)); String input = in.readLine(); Assert.assertEquals(text, input); in.close(); } catch (Exception e) { throw new Error(e); } } }); future.get(1000, TimeUnit.MILLISECONDS); //check that writing is forbidden future = executor.submit(new Runnable(){ @Override public void run() { try { BufferedWriter out = new BufferedWriter(new FileWriter(fileName)); out.write(text); out.flush(); out.close(); } catch(SecurityException se){ throw se; } catch (Exception e) { throw new Error(e); } } }); try{ future.get(1000, TimeUnit.MILLISECONDS); Assert.fail(); } catch(ExecutionException e){ if(! (e.getCause() instanceof SecurityException) ){ Assert.fail(); } } } finally { if(tmp!=null){ tmp.delete(); } } } /* * Note: this comes from Guava library's Files.createTempDir(). * Java 6 does not have such method, but should be in Java 7 */ public static File createTempDir() { final int TEMP_DIR_ATTEMPTS = 10000; File baseDir = new File(System.getProperty("java.io.tmpdir")); String baseName = System.currentTimeMillis() + "-"; for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { File tempDir = new File(baseDir, baseName + counter); if (tempDir.mkdir()) { return tempDir; } } throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')'); } @Test public void cannotCreateDeleteDirectory() throws InterruptedException, ExecutionException, TimeoutException{ File dir = createTempDir(); dir.deleteOnExit(); Assert.assertTrue(dir.exists()); dir.delete(); Thread.sleep(100); Assert.assertTrue( ! dir.exists()); final File toDelete = createTempDir(); toDelete.deleteOnExit(); Assert.assertTrue(toDelete.exists()); Future<?> future = executor.submit(new Runnable(){ @Override public void run() { try{ createTempDir(); Assert.fail("Failed to block creating a new dir"); } catch(SecurityException e){ //EvoSuite should block creating a new folder } try{ toDelete.delete(); Assert.fail("Failed to block deleting an existing dir"); } catch(SecurityException e){ //EvoSuite should block deleting folder } } }); future.get(1000, TimeUnit.MILLISECONDS); Assert.assertTrue(toDelete.exists()); toDelete.delete(); } /* * System permissions are now forbidden to modify. * they are handled in REPLACE_CALLS */ @Ignore @Test public void testReadAndWriteOfProperties() throws InterruptedException, ExecutionException, TimeoutException{ final String userDir = System.getProperty("user.dir"); Assert.assertNotNull(userDir); final String rocks = "EvoSuite Rocks!"; Assert.assertNotSame(rocks, userDir); //check that reading is fine Future<?> future = executor.submit(new Runnable(){ @Override public void run() { String readUserDir = System.getProperty("user.dir"); Assert.assertEquals(userDir, readUserDir); System.setProperty("user.dir", rocks); } }); future.get(1000, TimeUnit.MILLISECONDS); String modified = System.getProperty("user.dir"); Assert.assertEquals(rocks, modified); //now, "stopping" the test case should re-store value try{ securityManager.goingToEndTestCase(); modified = System.getProperty("user.dir"); Assert.assertEquals(userDir, modified); } finally { securityManager.goingToExecuteTestCase(); //needed } } @Test public void testCanLoadSwingStuff() throws InterruptedException, ExecutionException, TimeoutException{ /* * This is needed, as it sets a hook, which will be called in the static * initializer of several swing components. So we need to call it * here on the main thread */ LogManager.getLogManager(); /* * Note: this test is not particularly robust. Eg, one thing it tests is whether SUT can load * the gui native code but that "could" be already loaded (shouldn't be though) */ Future<?> future = executor.submit(new Runnable(){ @Override public void run() { try { /* * Note, this JUnit class shouldn't have a static link to AWt (eg "import"), otherwise this * test would be pointless */ Class.forName("javax.swing.JFrame"); } catch (ClassNotFoundException e) { throw new Error(e); } } }); future.get(1000, TimeUnit.MILLISECONDS); } }