am 4bcea122: Merge "Add seinfo parsing to PackageManagerService."

* commit '4bcea1222ce447d9969d12927995ffdfad7c8322':
  Add seinfo parsing to PackageManagerService.
This commit is contained in:
Geremy Condra
2013-03-25 14:49:25 -07:00
committed by Android Git Automerger
8 changed files with 311 additions and 11 deletions

View File

@ -28,7 +28,7 @@ dir_rec_t android_app_lib_dir;
dir_rec_t android_media_dir;
dir_rec_array_t android_system_dirs;
int install(const char *pkgname, uid_t uid, gid_t gid)
int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
{
char pkgdir[PKG_PATH_MAX];
char libsymlink[PKG_PATH_MAX];
@ -91,7 +91,7 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
return -1;
}
if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) {
ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
unlink(libsymlink);
unlink(pkgdir);

View File

@ -31,7 +31,7 @@ static int do_ping(char **arg, char reply[REPLY_MAX])
static int do_install(char **arg, char reply[REPLY_MAX])
{
return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */
}
static int do_dexopt(char **arg, char reply[REPLY_MAX])
@ -134,7 +134,7 @@ struct cmdinfo {
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
{ "install", 3, do_install },
{ "install", 4, do_install },
{ "dexopt", 3, do_dexopt },
{ "movedex", 2, do_move_dex },
{ "rmdex", 1, do_rm_dex },

View File

@ -192,7 +192,7 @@ int ensure_media_user_dirs(userid_t userid);
/* commands.c */
int install(const char *pkgname, uid_t uid, gid_t gid);
int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo);
int uninstall(const char *pkgname, uid_t persona);
int renamepkg(const char *oldpkgname, const char *newpkgname);
int fix_uid(const char *pkgname, uid_t uid, gid_t gid);

View File

@ -397,6 +397,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public String[] resourceDirs;
/**
* 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.
*
* {@hide}
*/
public String seinfo;
/**
* Paths to all shared libraries this application is linked against. This
* field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
@ -477,6 +486,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + resourceDirs);
}
if (seinfo != null) {
pw.println(prefix + "seinfo=" + seinfo);
}
pw.println(prefix + "dataDir=" + dataDir);
if (sharedLibraryFiles != null) {
pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
@ -544,6 +556,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
publicSourceDir = orig.publicSourceDir;
nativeLibraryDir = orig.nativeLibraryDir;
resourceDirs = orig.resourceDirs;
seinfo = orig.seinfo;
sharedLibraryFiles = orig.sharedLibraryFiles;
dataDir = orig.dataDir;
uid = orig.uid;
@ -583,6 +596,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(publicSourceDir);
dest.writeString(nativeLibraryDir);
dest.writeStringArray(resourceDirs);
dest.writeString(seinfo);
dest.writeStringArray(sharedLibraryFiles);
dest.writeString(dataDir);
dest.writeInt(uid);
@ -621,6 +635,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
publicSourceDir = source.readString();
nativeLibraryDir = source.readString();
resourceDirs = source.readStringArray();
seinfo = source.readString();
sharedLibraryFiles = source.readStringArray();
dataDir = source.readString();
uid = source.readInt();

View File

@ -2171,7 +2171,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// the PID of the new process, or else throw a RuntimeException.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, null, null);
app.info.targetSdkVersion, app.info.seinfo, null);
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
synchronized (bs) {

View File

@ -188,7 +188,7 @@ public final class Installer {
}
}
public int install(String name, int uid, int gid) {
public int install(String name, int uid, int gid, String seinfo) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
builder.append(name);
@ -196,6 +196,8 @@ public final class Installer {
builder.append(uid);
builder.append(' ');
builder.append(gid);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
return execute(builder.toString());
}

View File

@ -352,6 +352,9 @@ public class PackageManagerService extends IPackageManager.Stub {
final HashMap<String, FeatureInfo> mAvailableFeatures =
new HashMap<String, FeatureInfo>();
// If mac_permissions.xml was found for seinfo labeling.
boolean mFoundPolicyFile;
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
@ -1020,6 +1023,8 @@ public class PackageManagerService extends IPackageManager.Stub {
readPermissions();
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
long startTime = SystemClock.uptimeMillis();
@ -3582,9 +3587,9 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
private int createDataDirsLI(String packageName, int uid) {
private int createDataDirsLI(String packageName, int uid, String seinfo) {
int[] users = sUserManager.getUserIds();
int res = mInstaller.install(packageName, uid, uid);
int res = mInstaller.install(packageName, uid, uid, seinfo);
if (res < 0) {
return res;
}
@ -3847,6 +3852,10 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
if (mFoundPolicyFile) {
SELinuxMMAC.assignSeinfoValue(pkg);
}
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
@ -3985,7 +3994,8 @@ public class PackageManagerService extends IPackageManager.Stub {
recovered = true;
// And now re-install the app.
ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (ret == -1) {
// Ack should not happen!
msg = prefix + pkg.packageName
@ -4031,7 +4041,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (ret < 0) {
// Error from installer
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;

View File

@ -0,0 +1,272 @@
/*
* Copyright (C) 2012 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 com.android.server.pm;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
import android.content.pm.Signature;
import android.os.Environment;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
/**
* Centralized access to SELinux MMAC (middleware MAC) implementation.
* {@hide}
*/
public final class SELinuxMMAC {
private static final String TAG = "SELinuxMMAC";
private static final boolean DEBUG_POLICY = false;
private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
// Signature seinfo values read from policy.
private static final HashMap<Signature, String> sSigSeinfo =
new HashMap<Signature, String>();
// Package name seinfo values read from policy.
private static final HashMap<String, String> sPackageSeinfo =
new HashMap<String, String>();
// Locations of potential install policy files.
private static final File[] INSTALL_POLICY_FILE = {
new File(Environment.getDataDirectory(), "system/mac_permissions.xml"),
new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"),
null};
private static void flushInstallPolicy() {
sSigSeinfo.clear();
sPackageSeinfo.clear();
}
/**
* Parses an MMAC install policy from a predefined list of locations.
* @param none
* @return boolean indicating whether an install policy was correctly parsed.
*/
public static boolean readInstallPolicy() {
return readInstallPolicy(INSTALL_POLICY_FILE);
}
/**
* Parses an MMAC install policy given as an argument.
* @param File object representing the path of the policy.
* @return boolean indicating whether the install policy was correctly parsed.
*/
public static boolean readInstallPolicy(File policyFile) {
return readInstallPolicy(new File[]{policyFile,null});
}
private static boolean readInstallPolicy(File[] policyFiles) {
FileReader policyFile = null;
int i = 0;
while (policyFile == null && policyFiles != null && policyFiles[i] != null) {
try {
policyFile = new FileReader(policyFiles[i]);
break;
} catch (FileNotFoundException e) {
Slog.d(TAG,"Couldn't find install policy " + policyFiles[i].getPath());
}
i++;
}
if (policyFile == null) {
Slog.d(TAG, "No policy file found. All seinfo values will be null.");
return false;
}
Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath());
flushInstallPolicy();
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(policyFile);
XmlUtils.beginDocument(parser, "policy");
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String tagName = parser.getName();
if ("signer".equals(tagName)) {
String cert = parser.getAttributeValue(null, "signature");
if (cert == null) {
Slog.w(TAG, "<signer> without signature at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
Signature signature;
try {
signature = new Signature(cert);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "<signer> with bad signature at "
+ parser.getPositionDescription(), e);
XmlUtils.skipCurrentTag(parser);
continue;
}
String seinfo = readSeinfoTag(parser);
if (seinfo != null) {
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo="
+ seinfo);
sSigSeinfo.put(signature, seinfo);
}
} else if ("default".equals(tagName)) {
String seinfo = readSeinfoTag(parser);
if (seinfo != null) {
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo);
// The 'null' signature is the default seinfo value
sSigSeinfo.put(null, seinfo);
}
} else if ("package".equals(tagName)) {
String pkgName = parser.getAttributeValue(null, "name");
if (pkgName == null) {
Slog.w(TAG, "<package> without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
String seinfo = readSeinfoTag(parser);
if (seinfo != null) {
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "<package> tag: (" + pkgName +
") assigned seinfo=" + seinfo);
sPackageSeinfo.put(pkgName, seinfo);
}
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got execption parsing ", e);
} catch (IOException e) {
Slog.w(TAG, "Got execption parsing ", e);
}
try {
policyFile.close();
} catch (IOException e) {
//omit
}
return true;
}
private static String readSeinfoTag(XmlPullParser parser) throws
IOException, XmlPullParserException {
int type;
int outerDepth = parser.getDepth();
String seinfo = null;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG
|| type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if ("seinfo".equals(tagName)) {
String seinfoValue = parser.getAttributeValue(null, "value");
if (seinfoValue != null) {
seinfo = seinfoValue;
} else {
Slog.w(TAG, "<seinfo> without value at "
+ parser.getPositionDescription());
}
}
XmlUtils.skipCurrentTag(parser);
}
return seinfo;
}
/**
* Labels a package based on an seinfo tag from install policy.
* The label is attached to the ApplicationInfo instance of the package.
* @param PackageParser.Package object representing the package
* to labeled.
* @return String holding the value of the seinfo label that was assigned.
* Value may be null which indicates no seinfo label was assigned.
*/
public static void assignSeinfoValue(PackageParser.Package pkg) {
/*
* Non system installed apps should be treated the same. This
* means that any post-loaded apk will be assigned the default
* tag, if one exists in the policy, else null, without respect
* to the signing key.
*/
if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||
((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
// We just want one of the signatures to match.
for (Signature s : pkg.mSignatures) {
if (s == null)
continue;
if (sSigSeinfo.containsKey(s)) {
String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s);
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "package (" + pkg.packageName +
") labeled with seinfo=" + seinfo);
return;
}
}
// Check for seinfo labeled by package.
if (sPackageSeinfo.containsKey(pkg.packageName)) {
String seinfo = pkg.applicationInfo.seinfo = sPackageSeinfo.get(pkg.packageName);
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "package (" + pkg.packageName +
") labeled with seinfo=" + seinfo);
return;
}
}
// If we have a default seinfo value then great, otherwise
// we set a null object and that is what we started with.
String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null);
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "package (" + pkg.packageName +
") labeled with seinfo=" + (seinfo == null ? "null" : seinfo));
}
}