am 9d586927: Merge "Automatically assign default seinfo labels using the string "default"."
* commit '9d586927102b597845607ccc82661e350821de82': Automatically assign default seinfo labels using the string "default".
This commit is contained in:
@@ -531,12 +531,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* String retrieved from the seinfo tag found in selinux policy. This value
|
* 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
|
* can be overridden with a value set through the mac_permissions.xml policy
|
||||||
* as its data directory.
|
* 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}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public String seinfo;
|
public String seinfo = "default";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paths to all shared libraries this application is linked against. This
|
* Paths to all shared libraries this application is linked against. This
|
||||||
|
|||||||
@@ -136,9 +136,6 @@ public final class SELinuxMMAC {
|
|||||||
case "signer":
|
case "signer":
|
||||||
policies.add(readSignerOrThrow(parser));
|
policies.add(readSignerOrThrow(parser));
|
||||||
break;
|
break;
|
||||||
case "default":
|
|
||||||
policies.add(readDefaultOrThrow(parser));
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
skip(parser);
|
skip(parser);
|
||||||
}
|
}
|
||||||
@@ -232,45 +229,6 @@ public final class SELinuxMMAC {
|
|||||||
return pb.build();
|
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
|
* 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
|
* 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
|
* 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
|
* policy. All signature based policy stanzas are consulted and, if no match is
|
||||||
* is found, the default policy stanza is then consulted. The security label is
|
* found, the default seinfo label of 'default' (set in ApplicationInfo object) is
|
||||||
* attached to the ApplicationInfo instance of the package in the event that a matching
|
* used. The security label is attached to the ApplicationInfo instance of the package
|
||||||
* policy was found.
|
* in the event that a matching policy was found.
|
||||||
*
|
*
|
||||||
* @param pkg object representing the package to be labeled.
|
* @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) {
|
synchronized (sPolicies) {
|
||||||
for (Policy policy : sPolicies) {
|
for (Policy policy : sPolicies) {
|
||||||
String seinfo = policy.getMatchedSeinfo(pkg);
|
String seinfo = policy.getMatchedSeinfo(pkg);
|
||||||
if (seinfo != null) {
|
if (seinfo != null) {
|
||||||
pkg.applicationInfo.seinfo = seinfo;
|
pkg.applicationInfo.seinfo = seinfo;
|
||||||
if (DEBUG_POLICY_INSTALL) {
|
break;
|
||||||
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
|
|
||||||
"seinfo=" + seinfo);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG_POLICY_INSTALL) {
|
if (DEBUG_POLICY_INSTALL) {
|
||||||
Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
|
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
|
||||||
"seinfo will remain null");
|
"seinfo=" + pkg.applicationInfo.seinfo);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -506,30 +457,16 @@ public final class SELinuxMMAC {
|
|||||||
* .build();
|
* .build();
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </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 {
|
final class Policy {
|
||||||
|
|
||||||
private final String mSeinfo;
|
private final String mSeinfo;
|
||||||
private final boolean mDefaultStanza;
|
|
||||||
private final Set<Signature> mCerts;
|
private final Set<Signature> mCerts;
|
||||||
private final Map<String, String> mPkgMap;
|
private final Map<String, String> mPkgMap;
|
||||||
|
|
||||||
// Use the PolicyBuilder pattern to instantiate
|
// Use the PolicyBuilder pattern to instantiate
|
||||||
private Policy(PolicyBuilder builder) {
|
private Policy(PolicyBuilder builder) {
|
||||||
mSeinfo = builder.mSeinfo;
|
mSeinfo = builder.mSeinfo;
|
||||||
mDefaultStanza = builder.mDefaultStanza;
|
|
||||||
mCerts = Collections.unmodifiableSet(builder.mCerts);
|
mCerts = Collections.unmodifiableSet(builder.mCerts);
|
||||||
mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
|
mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
|
||||||
}
|
}
|
||||||
@@ -544,15 +481,6 @@ final class Policy {
|
|||||||
return mCerts;
|
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.
|
* Return whether this policy object contains package name mapping refinements.
|
||||||
*
|
*
|
||||||
@@ -584,10 +512,6 @@ final class Policy {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (mDefaultStanza) {
|
|
||||||
sb.append("defaultStanza=true ");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Signature cert : mCerts) {
|
for (Signature cert : mCerts) {
|
||||||
sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
|
sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
|
||||||
}
|
}
|
||||||
@@ -609,11 +533,6 @@ final class Policy {
|
|||||||
* is determined using the following steps:
|
* is determined using the following steps:
|
||||||
* </p>
|
* </p>
|
||||||
* <ul>
|
* <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
|
* <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.
|
* instance are tested for set equality. If this fails then null is returned.
|
||||||
* </li>
|
* </li>
|
||||||
@@ -625,8 +544,6 @@ final class Policy {
|
|||||||
* the global seinfo value. The returned value can be null in this case.
|
* the global seinfo value. The returned value can be null in this case.
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
* <p>
|
||||||
* In all cases, a return value of null should be interpreted as the apk failing
|
* 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.
|
* 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.
|
* A value of null can also be returned if no match occured.
|
||||||
*/
|
*/
|
||||||
public String getMatchedSeinfo(PackageParser.Package pkg) {
|
public String getMatchedSeinfo(PackageParser.Package pkg) {
|
||||||
if (!mDefaultStanza) {
|
|
||||||
// Check for exact signature matches across all certs.
|
// Check for exact signature matches across all certs.
|
||||||
Signature[] certs = mCerts.toArray(new Signature[0]);
|
Signature[] certs = mCerts.toArray(new Signature[0]);
|
||||||
if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
|
if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
|
||||||
@@ -649,24 +565,22 @@ final class Policy {
|
|||||||
if (seinfoValue != null) {
|
if (seinfoValue != null) {
|
||||||
return seinfoValue;
|
return seinfoValue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return the global seinfo value (even if it's null).
|
// Return the global seinfo value.
|
||||||
return mSeinfo;
|
return mSeinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A nested builder class to create {@link Policy} instances. A {@link Policy}
|
* 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
|
* 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
|
* file. A valid policy stanza is defined to be a signer stanza which obeys the rules
|
||||||
* which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
|
* outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
|
||||||
* {@link #build} method ensures a set of invariants are upheld enforcing the correct
|
* ensures a set of invariants are upheld enforcing the correct stanza structure
|
||||||
* stanza structure before returning a valid Policy object.
|
* before returning a valid Policy object.
|
||||||
*/
|
*/
|
||||||
public static final class PolicyBuilder {
|
public static final class PolicyBuilder {
|
||||||
|
|
||||||
private String mSeinfo;
|
private String mSeinfo;
|
||||||
private boolean mDefaultStanza;
|
|
||||||
private final Set<Signature> mCerts;
|
private final Set<Signature> mCerts;
|
||||||
private final Map<String, String> mPkgMap;
|
private final Map<String, String> mPkgMap;
|
||||||
|
|
||||||
@@ -675,19 +589,6 @@ final class Policy {
|
|||||||
mPkgMap = new HashMap<String, String>(2);
|
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
|
* 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
|
* 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
|
* 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
|
* when attached to a signer tag represents the assignment when there isn't a
|
||||||
* its context. When attached to a signer tag the global seinfo represents an
|
* further inner package refinement in policy.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @param seinfo the seinfo value given as a String.
|
* @param seinfo the seinfo value given as a String.
|
||||||
* @return The reference to this PolicyBuilder.
|
* @return The reference to this PolicyBuilder.
|
||||||
@@ -740,9 +638,7 @@ final class Policy {
|
|||||||
/**
|
/**
|
||||||
* Create a package name to seinfo value mapping. Each mapping represents
|
* Create a package name to seinfo value mapping. Each mapping represents
|
||||||
* the seinfo value that will be assigned to the described package name.
|
* the seinfo value that will be assigned to the described package name.
|
||||||
* These localized mappings allow the global seinfo to be overriden. This
|
* These localized mappings allow the global seinfo to be overriden.
|
||||||
* mapping provides no value when used in conjunction with a default stanza;
|
|
||||||
* enforced through the {@link #build} method.
|
|
||||||
*
|
*
|
||||||
* @param pkgName the android package name given to the app
|
* @param pkgName the android package name given to the app
|
||||||
* @param seinfo the seinfo value that will be assigned to the passed pkgName
|
* @param seinfo the seinfo value that will be assigned to the passed pkgName
|
||||||
@@ -800,42 +696,17 @@ final class Policy {
|
|||||||
* Those invariants are:
|
* Those invariants are:
|
||||||
* </p>
|
* </p>
|
||||||
* <ul>
|
* <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> at least one cert must be found </li>
|
||||||
* <li> either a global seinfo value is present OR at least one
|
* <li> either a global seinfo value is present OR at least one
|
||||||
* inner package mapping must be present BUT not both. </li>
|
* inner package mapping must be present BUT not both. </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @return an instance of {@link Policy} with the options set from this builder
|
* @return an instance of {@link Policy} with the options set from this builder
|
||||||
* @throws IllegalStateException if an invariant is violated.
|
* @throws IllegalStateException if an invariant is violated.
|
||||||
*/
|
*/
|
||||||
public Policy build() {
|
public Policy build() {
|
||||||
Policy p = new Policy(this);
|
Policy p = new Policy(this);
|
||||||
|
|
||||||
if (p.mDefaultStanza) {
|
if (p.mCerts.isEmpty()) {
|
||||||
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.";
|
String err = "Missing certs with signer tag. Expecting at least one.";
|
||||||
throw new IllegalStateException(err);
|
throw new IllegalStateException(err);
|
||||||
}
|
}
|
||||||
@@ -844,7 +715,6 @@ final class Policy {
|
|||||||
"a signer stanza.";
|
"a signer stanza.";
|
||||||
throw new IllegalStateException(err);
|
throw new IllegalStateException(err);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -858,7 +728,6 @@ final class Policy {
|
|||||||
* <ul>
|
* <ul>
|
||||||
* <li> signer stanzas with inner package mappings </li>
|
* <li> signer stanzas with inner package mappings </li>
|
||||||
* <li> signer stanzas with global seinfo tags </li>
|
* <li> signer stanzas with global seinfo tags </li>
|
||||||
* <li> default stanza </li>
|
|
||||||
* </ul>
|
* </ul>
|
||||||
* This comparison also checks for duplicate entries on the input selectors. Any
|
* This comparison also checks for duplicate entries on the input selectors. Any
|
||||||
* found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
|
* found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
|
||||||
@@ -875,11 +744,6 @@ final class PolicyComparator implements Comparator<Policy> {
|
|||||||
@Override
|
@Override
|
||||||
public int compare(Policy p1, Policy p2) {
|
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
|
// Give precedence to stanzas with inner package mappings
|
||||||
if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
|
if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
|
||||||
return p1.hasInnerPackages() ? -1 : 1;
|
return p1.hasInnerPackages() ? -1 : 1;
|
||||||
@@ -887,7 +751,7 @@ final class PolicyComparator implements Comparator<Policy> {
|
|||||||
|
|
||||||
// Check for duplicate entries
|
// Check for duplicate entries
|
||||||
if (p1.getSignatures().equals(p2.getSignatures())) {
|
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()) {
|
if (p1.hasGlobalSeinfo()) {
|
||||||
duplicateFound = true;
|
duplicateFound = true;
|
||||||
Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
|
Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
|
||||||
|
|||||||
Reference in New Issue
Block a user