Change SELinux neverallow tests to be sepolicy-analyze based.

Change I47c16ccb910ac730c092cb3ab977c59cb8197ce0 added support to
sepolicy-analyze for checking the SELinux policy binary for neverallow rule
violations.  This offers an improvement over the current tests, since this now
checks the entire policy rather than just the components which are extracted
from the AOSP policy.  Remove the old tests and replace them with the new.

Cherry-pick from commit: 1e4bf6161c7e771c48540cd77d8e7ada69af8c95

Bug: 19191637
Change-Id: I594a9df75ad52a07b101d71d11d9517dbf9d79be
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index a42ee8a..50e0226 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -28,6 +28,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.host.security
 
 LOCAL_JAVA_RESOURCE_FILES := $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
+LOCAL_JAVA_RESOURCE_FILES += $(call intermediates-dir-for,ETC,general_sepolicy.conf)/general_sepolicy.conf
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
index 36d060b..18d6a17 100644
--- a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
@@ -26,9 +26,10 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.FileOutputStream;
 import java.lang.String;
 import java.net.URL;
 import java.util.Scanner;
@@ -42,15 +43,42 @@
  */
 public class SELinuxHostTest extends DeviceTestCase {
 
+    private File sepolicyAnalyze;
+    private File devicePolicyFile;
+
     /**
      * A reference to the device under test.
      */
     private ITestDevice mDevice;
 
+    private File copyResourceToTempFile(String resName) throws IOException {
+        InputStream is = this.getClass().getResourceAsStream(resName);
+        File tempFile = File.createTempFile("SELinuxHostTest", ".tmp");
+        FileOutputStream os = new FileOutputStream(tempFile);
+        int rByte = 0;
+        while ((rByte = is.read()) != -1) {
+            os.write(rByte);
+        }
+        os.flush();
+        os.close();
+        tempFile.deleteOnExit();
+        return tempFile;
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mDevice = getDevice();
+
+        /* retrieve the sepolicy-analyze executable from jar */
+        sepolicyAnalyze = copyResourceToTempFile("/sepolicy-analyze");
+        sepolicyAnalyze.setExecutable(true);
+
+        /* obtain sepolicy file from running device */
+        devicePolicyFile = File.createTempFile("sepolicy", ".tmp");
+        devicePolicyFile.deleteOnExit();
+        mDevice.executeAdbCommand("pull", "/sys/fs/selinux/policy",
+                devicePolicyFile.getAbsolutePath());
     }
 
     /**
@@ -60,25 +88,9 @@
      */
     public void testAllEnforcing() throws Exception {
 
-        /* retrieve the sepolicy-analyze executable from jar */
-        InputStream is = this.getClass().getResourceAsStream("/sepolicy-analyze");
-        File execFile = File.createTempFile("sepolicy-analyze", ".tmp");
-        FileOutputStream os = new FileOutputStream(execFile);
-        int rByte = 0;
-        while ((rByte = is.read()) != -1) {
-            os.write(rByte);
-        }
-        os.flush();
-        os.close();
-        execFile.setExecutable(true);
-
-        /* obtain sepolicy file from running device */
-        File policyFile = File.createTempFile("sepolicy", ".tmp");
-        mDevice.executeAdbCommand("pull", "/sys/fs/selinux/policy", policyFile.getAbsolutePath());
-
         /* run sepolicy-analyze permissive check on policy file */
-        ProcessBuilder pb = new ProcessBuilder(execFile.getAbsolutePath(), "-p", "-P",
-                policyFile.getAbsolutePath());
+        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(), "-p", "-P",
+                devicePolicyFile.getAbsolutePath());
         pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
         pb.redirectErrorStream(true);
         Process p = pb.start();
@@ -90,11 +102,35 @@
             errorString.append(line);
             errorString.append("\n");
         }
-
-        /* clean up and check condition */
-        execFile.delete();
-        policyFile.delete();
         assertTrue("The following SELinux domains were found to be in permissive mode:\n"
                    + errorString, errorString.length() == 0);
     }
+
+    /**
+     * Checks the policy running on-device against a set of neverallow rules
+     *
+     * @throws Exception
+     */
+    public void testNeverallowRules() throws Exception {
+
+        File neverallowRules = copyResourceToTempFile("/general_sepolicy.conf");
+
+        /* run sepolicy-analyze neverallow check on policy file using given neverallow rules */
+        ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
+                "-n", neverallowRules.getAbsolutePath(), "-P",
+                devicePolicyFile.getAbsolutePath());
+        pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+        pb.redirectErrorStream(true);
+        Process p = pb.start();
+        p.waitFor();
+        BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        StringBuilder errorString = new StringBuilder();
+        while ((line = result.readLine()) != null) {
+            errorString.append(line);
+            errorString.append("\n");
+        }
+        assertTrue("The following errors were encountered when validating the SELinux"
+                   + "neverallow rules:\n" + errorString, errorString.length() == 0);
+    }
 }
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index de58783..c41ee58 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -34,22 +34,6 @@
 
 LOCAL_SDK_VERSION := current
 
-intermediates.COMMON := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)
-
-sepolicy_asset_dir := $(intermediates.COMMON)/assets
-
-LOCAL_ASSET_DIR := $(sepolicy_asset_dir)
-
 include $(BUILD_CTS_PACKAGE)
 
-selinux_policy.xml := $(sepolicy_asset_dir)/selinux_policy.xml
-selinux_policy_parser := cts/tools/selinux/src/gen_SELinux_CTS.py
-general_sepolicy_policy.conf := $(call intermediates-dir-for,ETC,general_sepolicy.conf)/general_sepolicy.conf
-$(selinux_policy.xml): PRIVATE_POLICY_PARSER := $(selinux_policy_parser)
-$(selinux_policy.xml): $(general_sepolicy_policy.conf) $(selinux_policy_parser)
-	mkdir -p $(dir $@)
-	$(PRIVATE_POLICY_PARSER) $< $@ neverallow_only=t
-
-$(R_file_stamp): $(selinux_policy.xml)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/security/src/android/security/cts/SELinuxPolicyRule.java b/tests/tests/security/src/android/security/cts/SELinuxPolicyRule.java
deleted file mode 100644
index d06fd75..0000000
--- a/tests/tests/security/src/android/security/cts/SELinuxPolicyRule.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.util.Xml;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.HashMap;
-
-
-/**
- * A class for generating representations of SELinux avc rules parsed from an xml file.
- */
-public class SELinuxPolicyRule {
-    public final List<String> source_types;
-    public final List<String> target_types;
-    public final Multimap<String, String> obj_classes;
-    public final String name;
-    public final String type;
-
-    private SELinuxPolicyRule(List<String> source_types, List<String> target_types,
-            Multimap<String, String> obj_classes, String name, String type) {
-        this.source_types = source_types;
-        this.target_types = target_types;
-        this.obj_classes = obj_classes;
-        this.name = name;
-        this.type = type;
-    }
-
-    public static SELinuxPolicyRule readRule(XmlPullParser xpp) throws IOException, XmlPullParserException {
-        List<String> source_types = new ArrayList<String>();
-        List<String> target_types = new ArrayList<String>();
-        Multimap<String, String> obj_classes = HashMultimap.create();
-        xpp.require(XmlPullParser.START_TAG, null, "avc_rule");
-        String ruleName = xpp.getAttributeValue(null, "name");
-        String ruleType = xpp.getAttributeValue(null, "type");
-        while (xpp.next() != XmlPullParser.END_TAG) {
-            if (xpp.getEventType() != XmlPullParser.START_TAG) {
-                continue;
-            }
-            String name = xpp.getName();
-            if (name.equals("type")) {
-                if (xpp.getAttributeValue(null, "type").equals("source")) {
-                    source_types.add(readType(xpp));
-                } else if (xpp.getAttributeValue(null, "type").equals("target")) {
-                    target_types.add(readType(xpp));
-                } else {
-                    skip(xpp);
-                }
-            } else if (name.equals("obj_class")) {
-                String obj_name = xpp.getAttributeValue(null, "name");
-                List<String> perms = readObjClass(xpp);
-                obj_classes.putAll(obj_name, perms);
-            } else {
-                skip(xpp);
-            }
-        }
-        return new SELinuxPolicyRule(source_types, target_types, obj_classes, ruleName, ruleType);
-    }
-
-    public static List<SELinuxPolicyRule> readRulesFile(InputStream in) throws IOException, XmlPullParserException {
-        List<SELinuxPolicyRule> rules = new ArrayList<SELinuxPolicyRule>();
-        XmlPullParser xpp = Xml.newPullParser();
-        xpp.setInput(in, null);
-        xpp.nextTag();
-        xpp.require(XmlPullParser.START_TAG, null, "SELinux_AVC_Rules");
-
-        /* read rules */
-        while (xpp.next()  != XmlPullParser.END_TAG) {
-            if (xpp.getEventType() != XmlPullParser.START_TAG) {
-                continue;
-            }
-            String name = xpp.getName();
-            if (name.equals("avc_rule")) {
-                SELinuxPolicyRule r = readRule(xpp);
-                rules.add(r);
-            } else {
-                skip(xpp);
-            }
-        }
-        return rules;
-    }
-
-    private static List<String> readObjClass(XmlPullParser xpp) throws IOException, XmlPullParserException {
-        List<String> perms = new ArrayList<String>();
-        xpp.require(XmlPullParser.START_TAG, null, "obj_class");
-        while (xpp.next() != XmlPullParser.END_TAG) {
-        if (xpp.getEventType() != XmlPullParser.START_TAG) {
-                continue;
-            }
-            String name = xpp.getName();
-            if (name.equals("permission")) {
-                perms.add(readPermission(xpp));
-            } else {
-                skip(xpp);
-            }
-        }
-        return perms;
-    }
-
-    private static String readType(XmlPullParser xpp) throws IOException, XmlPullParserException {
-        xpp.require(XmlPullParser.START_TAG, null, "type");
-        String type = readText(xpp);
-        xpp.require(XmlPullParser.END_TAG, null, "type");
-        return type;
-    }
-
-    private static String readPermission(XmlPullParser xpp) throws IOException, XmlPullParserException {
-        xpp.require(XmlPullParser.START_TAG, null, "permission");
-        String permission = readText(xpp);
-        xpp.require(XmlPullParser.END_TAG, null, "permission");
-        return permission;
-    }
-
-    private static String readText(XmlPullParser xpp) throws IOException, XmlPullParserException {
-        String result = "";
-        if (xpp.next() == XmlPullParser.TEXT) {
-            result = xpp.getText();
-            xpp.nextTag();
-        }
-        return result;
-    }
-
-    public static void skip(XmlPullParser xpp) throws XmlPullParserException, IOException {
-        if (xpp.getEventType() != XmlPullParser.START_TAG) {
-            throw new IllegalStateException();
-        }
-        int depth = 1;
-        while (depth != 0) {
-            switch (xpp.next()) {
-            case XmlPullParser.END_TAG:
-                depth--;
-                break;
-            case XmlPullParser.START_TAG:
-                depth++;
-                break;
-            }
-        }
-    }
-}
diff --git a/tests/tests/security/src/android/security/cts/SELinuxTest.java b/tests/tests/security/src/android/security/cts/SELinuxTest.java
index 8e57037..711cb91 100644
--- a/tests/tests/security/src/android/security/cts/SELinuxTest.java
+++ b/tests/tests/security/src/android/security/cts/SELinuxTest.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.AssetManager;
-import android.security.cts.SELinuxPolicyRule;
 import android.test.AndroidTestCase;
 
 import junit.framework.TestCase;
@@ -82,130 +81,6 @@
         assertEquals(0, files.length);
     }
 
-    /**
-     * Verify all of the rules described by the selinux_policy.xml file are in effect.  Allow rules
-     * should return access granted, and Neverallow should return access denied.  All checks are run
-     * and then a list of specific failed checks is printed.
-     */
-    public void testSELinuxPolicyFile() throws IOException, XmlPullParserException {
-        List<String> failedChecks = new ArrayList<String>();
-        Map<String, Boolean> contextsCache = new HashMap<String, Boolean>();
-        int invalidContextsCount = 0;
-        int totalChecks = 0;
-        int totalFailedChecks = 0;
-        AssetManager assets = mContext.getAssets();
-        InputStream in = assets.open("selinux_policy.xml");
-        Collection<SELinuxPolicyRule> rules = SELinuxPolicyRule.readRulesFile(in);
-        for (SELinuxPolicyRule r : rules) {
-            PolicyFileTestResult result = runRuleChecks(r, contextsCache);
-            totalChecks += result.numTotalChecks;
-            if (result.numFailedChecks != 0) {
-                totalFailedChecks += result.numFailedChecks;
-
-                /* print failures to log, so as not to run OOM in the event of large policy mismatch,
-                   but record actual rule type and number */
-                failedChecks.add("SELinux avc rule " + r.type + r.name + " failed " + result.numFailedChecks +
-                        " out of " + result.numTotalChecks + " checks.");
-                for (String k : result.failedChecks) {
-                    System.out.println(r.type + r.name + " failed " + k);
-                }
-            }
-        }
-        if (totalFailedChecks != 0) {
-
-            /* print out failed rules, just the rule number and type */
-            for (String k : failedChecks) {
-                System.out.println(k);
-            }
-            System.out.println("Failed SELinux Policy Test: " + totalFailedChecks + " failed out of " + totalChecks);
-        }
-        for (String k : contextsCache.keySet()) {
-            if (!contextsCache.get(k)) {
-                invalidContextsCount++;
-                System.out.println("Invalid SELinux context encountered: " + k);
-            }
-        }
-        System.out.println("SELinuxPolicy Test Encountered: " + invalidContextsCount + " missing contexts out of " + contextsCache.size());
-        assertTrue(totalFailedChecks == 0);
-    }
-
-    /**
-     * A class for containing all of the results we care to know from checking each SELinux rule
-     */
-    private class PolicyFileTestResult {
-        private int numTotalChecks;
-        private int numFailedChecks;
-        private List<String> failedChecks = new ArrayList<String>();
-    }
-
-    private PolicyFileTestResult runRuleChecks(SELinuxPolicyRule r, Map<String, Boolean> contextsCache) {
-        PolicyFileTestResult result = new PolicyFileTestResult();
-
-        /* run checks by going through every possible 4-tuple specified by rule.  Start with class
-           and perm to allow early-exit based on context. */
-        for (String c : r.obj_classes.keySet()) {
-            for (String p : r.obj_classes.get(c)) {
-                for (String s : r.source_types) {
-
-                    /* check source context */
-                    String source_context = createAvcContext(s, false, c, p);
-                    if (!contextsCache.containsKey(source_context)) {
-                        contextsCache.put(source_context, checkSELinuxContext(source_context));
-                    }
-                    if (!contextsCache.get(source_context)) {
-                        continue;
-                    }
-                    for (String t : r.target_types) {
-                        if (t.equals("self")) {
-                            t = s;
-                        }
-
-                        /* check target context */
-                        String target_context = createAvcContext(t, true, c, p);
-                        if (!contextsCache.containsKey(target_context)) {
-                            contextsCache.put(target_context, checkSELinuxContext(target_context));
-                        }
-                        if (!contextsCache.get(target_context)) {
-                            continue;
-                        }
-                        boolean canAccess  = checkSELinuxAccess(source_context, target_context,
-                                c, p, "");
-                        result.numTotalChecks++;
-                        if ((r.type.equals("allow") && !canAccess)
-                                || (r.type.equals("neverallow") && canAccess)) {
-                            String failureNotice = s + ", " + t + ", " + c + ", " + p;
-                            result.numFailedChecks++;
-                            result.failedChecks.add(failureNotice);
-                        }
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    /* createAvcContext - currently uses class type and perm to determine user, role and mls values.
-     *
-     * @param target - false if source domain, true if target.
-     */
-    private String createAvcContext(String domain, boolean target,
-            String obj_class, String perm) {
-        String usr = "u";
-        String role;
-
-        /* understand role labeling better */
-        if (obj_class.equals("filesystem") && perm.equals("associate")) {
-            role = "object_r";
-        } else if(obj_class.equals("process") || obj_class.endsWith("socket")) {
-            role = "r";
-        } else if (target) {
-            role = "object_r";
-        } else {
-            role = "r";
-        }
-        return String.format("%s:%s:%s:s0", usr, role, domain);
-    }
-
     private static native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm, String extra);
 
     private static native boolean checkSELinuxContext(String con);