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

Commit 9d586927 authored by Nick Kralevich's avatar Nick Kralevich Committed by Gerrit Code Review
Browse files

Merge "Automatically assign default seinfo labels using the string "default"."

parents 4d6cb77a 5e16bc5a
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -492,12 +492,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
@@ -139,9 +139,6 @@ public final class SELinuxMMAC {
                    case "signer":
                        policies.add(readSignerOrThrow(parser));
                        break;
                    case "default":
                        policies.add(readDefaultOrThrow(parser));
                        break;
                    default:
                        skip(parser);
                }
@@ -235,45 +232,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
@@ -340,35 +298,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;
    }

    /**
@@ -509,30 +460,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);
    }
@@ -547,15 +484,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.
     *
@@ -587,10 +515,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) + "... ");
        }
@@ -612,11 +536,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>
@@ -628,8 +547,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.
@@ -639,7 +556,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)) {
@@ -652,24 +568,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;

@@ -678,19 +592,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
@@ -713,11 +614,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.
@@ -743,9 +641,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
@@ -803,42 +699,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);
            }
@@ -847,7 +718,6 @@ final class Policy {
                        "a signer stanza.";
                throw new IllegalStateException(err);
            }
            }

            return p;
        }
@@ -861,7 +731,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}.
@@ -878,11 +747,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;
@@ -890,7 +754,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());