case "signer":
policies.add(readSignerOrThrow(parser));
break;
- case "default":
- policies.add(readDefaultOrThrow(parser));
- break;
default:
skip(parser);
}
}
/**
- * 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
* will be skipped.
/**
* 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;
}
/**
* .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);
}
}
/**
- * 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.
*
* @return A boolean indicating if this object has inner package name mappings.
@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) + "... ");
}
* 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> 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>
+ * <li> If all certs match then an appropriate inner package stanza is
+ * searched based on package name alone. If matched, the stored seinfo
+ * value for that mapping is returned.
* </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>
- * <li> If all certs match then an appropriate inner package stanza is
- * searched based on package name alone. If matched, the stored seinfo
- * value for that mapping is returned.
- * </li>
- * <li> If all certs matched and no inner package stanza matches then return
- * the global seinfo value. The returned value can be null in this case.
- * </li>
- * </ul>
+ * <li> If all certs matched and no inner package stanza matches then return
+ * the global seinfo value. The returned value can be null in this case.
* </li>
* </ul>
* <p>
* 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)) {
- return null;
- }
+ // Check for exact signature matches across all certs.
+ Signature[] certs = mCerts.toArray(new Signature[0]);
+ if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+ return null;
+ }
- // Check for inner package name matches given that the
- // signature checks already passed.
- String seinfoValue = mPkgMap.get(pkg.packageName);
- if (seinfoValue != null) {
- return seinfoValue;
- }
+ // Check for inner package name matches given that the
+ // signature checks already passed.
+ String seinfoValue = mPkgMap.get(pkg.packageName);
+ 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;
}
/**
- * 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
* contained with an apk.
/**
* 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.
/**
* 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
* about the expected structure of a policy stanza.
* 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>
- *
+ * <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>
* @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) {
- String err = "Missing certs with signer tag. Expecting at least one.";
- throw new IllegalStateException(err);
- }
- if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
- String err = "Only seinfo tag XOR package tags are allowed within " +
- "a signer stanza.";
- throw new IllegalStateException(err);
- }
+ if (p.mCerts.isEmpty()) {
+ String err = "Missing certs with signer tag. Expecting at least one.";
+ throw new IllegalStateException(err);
+ }
+ if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+ String err = "Only seinfo tag XOR package tags are allowed within " +
+ "a signer stanza.";
+ throw new IllegalStateException(err);
}
return p;
* <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}.
@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;
// 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());