Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1293b953 authored by Nick Kralevich's avatar Nick Kralevich Committed by Android Git Automerger
Browse files

am 712205ba: am 9d586927: Merge "Automatically assign default seinfo labels...

am 712205ba: am 9d586927: Merge "Automatically assign default seinfo labels using the string "default"."

* commit '712205ba':
  Automatically assign default seinfo labels using the string "default".
parents 5fa874a3 712205ba
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -531,12 +531,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {

    /**
     * String retrieved from the seinfo tag found in selinux policy. This value
     * is useful in setting an SELinux security context on the process as well
     * as its data directory.
     * can be overridden with a value set through the mac_permissions.xml policy
     * construct. This value is useful in setting an SELinux security context on
     * the process as well as its data directory. The String default is being used
     * here to represent a catchall label when no policy matches.
     *
     * {@hide}
     */
    public String seinfo;
    public String seinfo = "default";

    /**
     * Paths to all shared libraries this application is linked against.  This
+48 −184
Original line number Diff line number Diff line
@@ -136,9 +136,6 @@ public final class SELinuxMMAC {
                    case "signer":
                        policies.add(readSignerOrThrow(parser));
                        break;
                    case "default":
                        policies.add(readDefaultOrThrow(parser));
                        break;
                    default:
                        skip(parser);
                }
@@ -232,45 +229,6 @@ public final class SELinuxMMAC {
        return pb.build();
    }

    /**
     * Loop over a default element looking for seinfo child tags. A {@link Policy}
     * instance will be created and returned in the process. All other tags encountered
     * will be skipped.
     *
     * @param parser an XmlPullParser object representing a default element.
     * @return the constructed {@link Policy} instance
     * @throws IOException
     * @throws XmlPullParserException
     * @throws IllegalArgumentException if any of the validation checks fail while
     *         parsing tag values.
     * @throws IllegalStateException if any of the invariants fail when constructing
     *         the {@link Policy} instance.
     */
    private static Policy readDefaultOrThrow(XmlPullParser parser) throws IOException,
            XmlPullParserException {

        parser.require(XmlPullParser.START_TAG, null, "default");
        Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
        pb.setAsDefaultPolicy();

        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }

            String tagName = parser.getName();
            if ("seinfo".equals(tagName)) {
                String seinfo = parser.getAttributeValue(null, "value");
                pb.setGlobalSeinfoOrThrow(seinfo);
                readSeinfo(parser);
            } else {
                skip(parser);
            }
        }

        return pb.build();
    }

    /**
     * Loop over a package element looking for seinfo child tags. If found return the
     * value attribute of the seinfo tag, otherwise return null. All other tags encountered
@@ -337,35 +295,28 @@ public final class SELinuxMMAC {

    /**
     * Applies a security label to a package based on an seinfo tag taken from a matched
     * policy. All signature based policy stanzas are consulted first and, if no match
     * is found, the default policy stanza is then consulted. The security label is
     * attached to the ApplicationInfo instance of the package in the event that a matching
     * policy was found.
     * policy. All signature based policy stanzas are consulted and, if no match is
     * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
     * used. The security label is attached to the ApplicationInfo instance of the package
     * in the event that a matching policy was found.
     *
     * @param pkg object representing the package to be labeled.
     * @return boolean which determines whether a non null seinfo label was assigned
     *         to the package. A null value simply represents that no policy matched.
     */
    public static boolean assignSeinfoValue(PackageParser.Package pkg) {
    public static void assignSeinfoValue(PackageParser.Package pkg) {
        synchronized (sPolicies) {
            for (Policy policy : sPolicies) {
                String seinfo = policy.getMatchedSeinfo(pkg);
                if (seinfo != null) {
                    pkg.applicationInfo.seinfo = seinfo;
                    if (DEBUG_POLICY_INSTALL) {
                        Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
                               "seinfo=" + seinfo);
                    }
                    return true;
                    break;
                }
            }
        }

        if (DEBUG_POLICY_INSTALL) {
            Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
                   "seinfo will remain null");
            Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
                    "seinfo=" + pkg.applicationInfo.seinfo);
        }
        return false;
    }

    /**
@@ -506,30 +457,16 @@ public final class SELinuxMMAC {
 *         .build();
 * }
 * </pre>
 * <p>
 * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
 * default based Policy instance.
 * </p>
 * <pre>
 * {@code
 * Policy policy = new Policy.PolicyBuilder()
 *         .setAsDefaultPolicy()
 *         .setGlobalSeinfoOrThrow("default")
 *         .build();
 * }
 * </pre>
 */
final class Policy {

    private final String mSeinfo;
    private final boolean mDefaultStanza;
    private final Set<Signature> mCerts;
    private final Map<String, String> mPkgMap;

    // Use the PolicyBuilder pattern to instantiate
    private Policy(PolicyBuilder builder) {
        mSeinfo = builder.mSeinfo;
        mDefaultStanza = builder.mDefaultStanza;
        mCerts = Collections.unmodifiableSet(builder.mCerts);
        mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
    }
@@ -544,15 +481,6 @@ final class Policy {
        return mCerts;
    }

    /**
     * Return whether this policy object represents a default stanza.
     *
     * @return A boolean indicating if this object represents a default policy stanza.
     */
    public boolean isDefaultStanza() {
        return mDefaultStanza;
    }

    /**
     * Return whether this policy object contains package name mapping refinements.
     *
@@ -584,10 +512,6 @@ final class Policy {
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        if (mDefaultStanza) {
            sb.append("defaultStanza=true ");
        }

        for (Signature cert : mCerts) {
            sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
        }
@@ -609,11 +533,6 @@ final class Policy {
     * is determined using the following steps:
     * </p>
     * <ul>
     *   <li> If this Policy instance is defined as a default stanza:
     *       <ul><li>Return the global seinfo value</li></ul>
     *   </li>
     *   <li> If this Policy instance is defined as a signer stanza:
     *     <ul>
     *   <li> All certs used to sign the apk and all certs stored with this policy
     *     instance are tested for set equality. If this fails then null is returned.
     *   </li>
@@ -625,8 +544,6 @@ final class Policy {
     *     the global seinfo value. The returned value can be null in this case.
     *   </li>
     * </ul>
     *   </li>
     * </ul>
     * <p>
     * In all cases, a return value of null should be interpreted as the apk failing
     * to match this Policy instance; i.e. failing this policy stanza.
@@ -636,7 +553,6 @@ final class Policy {
     *         A value of null can also be returned if no match occured.
     */
    public String getMatchedSeinfo(PackageParser.Package pkg) {
        if (!mDefaultStanza) {
        // Check for exact signature matches across all certs.
        Signature[] certs = mCerts.toArray(new Signature[0]);
        if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
@@ -649,24 +565,22 @@ final class Policy {
        if (seinfoValue != null) {
            return seinfoValue;
        }
        }

        // Return the global seinfo value (even if it's null).
        // Return the global seinfo value.
        return mSeinfo;
    }

    /**
     * A nested builder class to create {@link Policy} instances. A {@link Policy}
     * class instance represents one valid policy stanza found in a mac_permissions.xml
     * file. A valid policy stanza is defined to be either a signer or default stanza
     * which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
     * {@link #build} method ensures a set of invariants are upheld enforcing the correct
     * stanza structure before returning a valid Policy object.
     * file. A valid policy stanza is defined to be a signer stanza which obeys the rules
     * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
     * ensures a set of invariants are upheld enforcing the correct stanza structure
     * before returning a valid Policy object.
     */
    public static final class PolicyBuilder {

        private String mSeinfo;
        private boolean mDefaultStanza;
        private final Set<Signature> mCerts;
        private final Map<String, String> mPkgMap;

@@ -675,19 +589,6 @@ final class Policy {
            mPkgMap = new HashMap<String, String>(2);
        }

        /**
         * Sets this stanza as a default stanza. All policy stanzas are assumed to
         * be signer stanzas unless this method is explicitly called. Default stanzas
         * are treated differently with respect to allowable child tags, ordering and
         * when and how policy decisions are enforced.
         *
         * @return The reference to this PolicyBuilder.
         */
        public PolicyBuilder setAsDefaultPolicy() {
            mDefaultStanza = true;
            return this;
        }

        /**
         * Adds a signature to the set of certs used for validation checks. The purpose
         * being that all contained certs will need to be matched against all certs
@@ -710,11 +611,8 @@ final class Policy {

        /**
         * Set the global seinfo tag for this policy stanza. The global seinfo tag
         * represents the seinfo element that is used in one of two ways depending on
         * its context. When attached to a signer tag the global seinfo represents an
         * assignment when there isn't a further inner package refinement in policy.
         * When used with a default tag, it represents the only allowable assignment
         * value.
         * when attached to a signer tag represents the assignment when there isn't a
         * further inner package refinement in policy.
         *
         * @param seinfo the seinfo value given as a String.
         * @return The reference to this PolicyBuilder.
@@ -740,9 +638,7 @@ final class Policy {
        /**
         * Create a package name to seinfo value mapping. Each mapping represents
         * the seinfo value that will be assigned to the described package name.
         * These localized mappings allow the global seinfo to be overriden. This
         * mapping provides no value when used in conjunction with a default stanza;
         * enforced through the {@link #build} method.
         * These localized mappings allow the global seinfo to be overriden.
         *
         * @param pkgName the android package name given to the app
         * @param seinfo the seinfo value that will be assigned to the passed pkgName
@@ -800,42 +696,17 @@ final class Policy {
         * Those invariants are:
         * </p>
         * <ul>
         *      <li> If a default stanza
         *        <ul>
         *          <li> an attached global seinfo tag must be present </li>
         *          <li> no signatures and no package names can be present </li>
         *        </ul>
         *      </li>
         *      <li> If a signer stanza
         *        <ul>
         *   <li> at least one cert must be found </li>
         *   <li> either a global seinfo value is present OR at least one
         *     inner package mapping must be present BUT not both. </li>
         * </ul>
         *      </li>
         *    </ul>
         *
         * @return an instance of {@link Policy} with the options set from this builder
         * @throws IllegalStateException if an invariant is violated.
         */
        public Policy build() {
            Policy p = new Policy(this);

            if (p.mDefaultStanza) {
                if (p.mSeinfo == null) {
                    String err = "Missing global seinfo tag with default stanza.";
                    throw new IllegalStateException(err);
                }
                if (p.mCerts.size() != 0) {
                    String err = "Certs not allowed with default stanza.";
                    throw new IllegalStateException(err);
                }
                if (!p.mPkgMap.isEmpty()) {
                    String err = "Inner package mappings not allowed with default stanza.";
                    throw new IllegalStateException(err);
                }
            } else {
                if (p.mCerts.size() == 0) {
            if (p.mCerts.isEmpty()) {
                String err = "Missing certs with signer tag. Expecting at least one.";
                throw new IllegalStateException(err);
            }
@@ -844,7 +715,6 @@ final class Policy {
                        "a signer stanza.";
                throw new IllegalStateException(err);
            }
            }

            return p;
        }
@@ -858,7 +728,6 @@ final class Policy {
 * <ul>
 *   <li> signer stanzas with inner package mappings </li>
 *   <li> signer stanzas with global seinfo tags </li>
 *   <li> default stanza </li>
 * </ul>
 * This comparison also checks for duplicate entries on the input selectors. Any
 * found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
@@ -875,11 +744,6 @@ final class PolicyComparator implements Comparator<Policy> {
    @Override
    public int compare(Policy p1, Policy p2) {

        // Give precedence to signature stanzas over default stanzas
        if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
            return p1.isDefaultStanza() ? 1 : -1;
        }

        // Give precedence to stanzas with inner package mappings
        if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
            return p1.hasInnerPackages() ? -1 : 1;
@@ -887,7 +751,7 @@ final class PolicyComparator implements Comparator<Policy> {

        // Check for duplicate entries
        if (p1.getSignatures().equals(p2.getSignatures())) {
            // Checks if default stanza or a signer w/o inner package names
            // Checks if signer w/o inner package names
            if (p1.hasGlobalSeinfo()) {
                duplicateFound = true;
                Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());