am 4bcea122
: Merge "Add seinfo parsing to PackageManagerService."
* commit '4bcea1222ce447d9969d12927995ffdfad7c8322': Add seinfo parsing to PackageManagerService.
This commit is contained in:
@ -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);
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
272
services/java/com/android/server/pm/SELinuxMMAC.java
Normal file
272
services/java/com/android/server/pm/SELinuxMMAC.java
Normal 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));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user