summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/installd/commands.c33
-rw-r--r--services/java/com/android/server/pm/Installer.java4
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java284
3 files changed, 181 insertions, 140 deletions
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 8e4d7ed..e3acad9 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -141,39 +141,54 @@ int renamepkg(const char *oldpkgname, const char *newpkgname)
return 0;
}
-int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
+int fix_uid(const char *pkgname, uid_t uid, uid_t userId)
{
char pkgdir[PKG_PATH_MAX];
struct stat s;
int rc = 0;
- if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
- ALOGE("invalid uid/gid: %d %d\n", uid, gid);
+ if (uid < AID_SYSTEM) {
+ ALOGE("invalid uid: %d\n", uid);
return -1;
}
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
+ if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) {
ALOGE("cannot create package path\n");
return -1;
}
if (stat(pkgdir, &s) < 0) return -1;
- if (s.st_uid != 0 || s.st_gid != 0) {
- ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid);
+ if (((s.st_uid != 0) && (s.st_uid != AID_INSTALL))
+ || ((s.st_gid != 0) && (s.st_gid != AID_INSTALL))) {
+ ALOGE("fixing uid of pkg not owned by install or root: %s %lu %lu\n", pkgdir, s.st_uid,
+ s.st_gid);
+ return -1;
+ }
+
+ if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
+ ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(pkgdir);
return -1;
}
if (chmod(pkgdir, 0751) < 0) {
ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
- return -errno;
+ return -1;
}
- if (chown(pkgdir, uid, gid) < 0) {
+ if (chown(pkgdir, uid, uid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
- return -errno;
+ return -1;
}
+#ifdef HAVE_SELINUX
+ if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
+ ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(pkgdir);
+ return -1;
+ }
+#endif
return 0;
}
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 71a6a01..0247911 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -243,14 +243,14 @@ public final class Installer {
return execute(builder.toString());
}
- public int fixUid(String name, int uid, int gid) {
+ public int fixUid(String name, int uid, int userId) {
StringBuilder builder = new StringBuilder("fixuid");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
builder.append(' ');
- builder.append(gid);
+ builder.append(userId);
return execute(builder.toString());
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 4c6f589..66d2f24 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1008,6 +1008,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mHandler = new PackageHandler(mHandlerThread.getLooper());
File dataDir = Environment.getDataDirectory();
+ mAppInstallDir = new File(dataDir, "app");
+ mAppLibInstallDir = new File(dataDir, "app-lib");
mAppDataDir = new File(dataDir, "data");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
@@ -1218,8 +1220,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- mAppInstallDir = new File(dataDir, "app");
- mAppLibInstallDir = new File(dataDir, "app-lib");
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
@@ -3576,22 +3576,22 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- private int createDataDirsLI(String packageName, int uid) {
- int[] users = sUserManager.getUserIds();
- int res = mInstaller.install(packageName, uid, uid);
- if (res < 0) {
- return res;
+ private int createDataDirForUserLI(String packageName, int uid, int userId) {
+ if (userId == 0) {
+ return mInstaller.install(packageName, uid, uid);
+ } else {
+ return mInstaller.createUserData(packageName, UserHandle.getUid(userId, uid), userId);
}
- for (int user : users) {
- if (user != 0) {
- res = mInstaller.createUserData(packageName,
- UserHandle.getUid(user, uid), user);
- if (res < 0) {
- return res;
- }
+ }
+
+ private int createDataDirsLI(String packageName, int uid) {
+ for (int userId : sUserManager.getUserIds()) {
+ int res = createDataDirForUserLI(packageName, uid, userId);
+ if (res < 0) {
+ return res;
}
}
- return res;
+ return 0;
}
private int removeDataDirsLI(String packageName) {
@@ -3930,134 +3930,49 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
// This is a normal package, need to make its data directory.
- dataPath = getDataPathForPackage(pkg.packageName, 0);
-
- boolean uidError = false;
+ dataPath = getDataPathForPackage(pkg.packageName, UserHandle.USER_OWNER);
- if (dataPath.exists()) {
- int currentUid = 0;
- try {
- StructStat stat = Libcore.os.stat(dataPath.getPath());
- currentUid = stat.st_uid;
- } catch (ErrnoException e) {
- Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
- }
-
- // If we have mismatched owners for the data path, we have a problem.
- if (currentUid != pkg.applicationInfo.uid) {
- boolean recovered = false;
- if (currentUid == 0) {
- // The directory somehow became owned by root. Wow.
- // This is probably because the system was stopped while
- // installd was in the middle of messing with its libs
- // directory. Ask installd to fix that.
- int ret = mInstaller.fixUid(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret >= 0) {
- recovered = true;
- String msg = "Package " + pkg.packageName
- + " unexpectedly changed to uid 0; recovered to " +
- + pkg.applicationInfo.uid;
- reportSettingsProblem(Log.WARN, msg);
- }
- }
- if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
- || (scanMode&SCAN_BOOTING) != 0)) {
- // If this is a system app, we can at least delete its
- // current data so the application will still work.
- int ret = removeDataDirsLI(pkgName);
- if (ret >= 0) {
- // TODO: Kill the processes first
- // Old data gone!
- String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
- ? "System package " : "Third party package ";
- String msg = prefix + pkg.packageName
- + " has changed from uid: "
- + currentUid + " to "
- + pkg.applicationInfo.uid + "; old data erased";
- reportSettingsProblem(Log.WARN, msg);
- recovered = true;
-
- // And now re-install the app.
- ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
- if (ret == -1) {
- // Ack should not happen!
- msg = prefix + pkg.packageName
- + " could not have data directory re-created after delete.";
- reportSettingsProblem(Log.WARN, msg);
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- }
- if (!recovered) {
- mHasSystemUidErrors = true;
- }
- } else if (!recovered) {
- // If we allow this install to proceed, we will be broken.
- // Abort, abort!
- mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
- return null;
- }
- if (!recovered) {
- pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
- + pkg.applicationInfo.uid + "/fs_"
- + currentUid;
- pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
- String msg = "Package " + pkg.packageName
- + " has mismatched uid: "
- + currentUid + " on disk, "
- + pkg.applicationInfo.uid + " in settings";
- // writer
- synchronized (mPackages) {
- mSettings.mReadMessages.append(msg);
- mSettings.mReadMessages.append('\n');
- uidError = true;
- if (!pkgSetting.uidError) {
- reportSettingsProblem(Log.ERROR, msg);
- }
- }
- }
- }
- pkg.applicationInfo.dataDir = dataPath.getPath();
- } else {
+ if (!ensureDataDirExistsForAllUsers(pkg.packageName, pkg.applicationInfo.uid)) {
if (DEBUG_PACKAGE_SCANNING) {
- if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) {
Log.v(TAG, "Want this data dir: " + dataPath);
- }
- //invoke installer to do the actual installation
- int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
- if (ret < 0) {
- // Error from installer
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
+ }
}
- if (dataPath.exists()) {
- pkg.applicationInfo.dataDir = dataPath.getPath();
- } else {
- Slog.w(TAG, "Unable to create data directory: " + dataPath);
- pkg.applicationInfo.dataDir = null;
- }
+ // Error from installer
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
+ } else {
+ pkg.applicationInfo.dataDir = dataPath.getPath();
}
+ final boolean isSystemApp = (parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0;
+ final boolean isBootScan = (scanMode & SCAN_BOOTING) != 0;
+
+ final boolean uidCorrect = ensureDataDirUidIsCorrectForAllUsers(pkg.packageName,
+ pkg.applicationInfo.uid, isSystemApp, isBootScan);
+ if (!uidCorrect) {
+ pkg.applicationInfo.dataDir = "/mismatched_uid/settings_" + pkg.applicationInfo.uid
+ + "/fs_mismatched";
+ pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
+ }
+
+ pkgSetting.uidError = !uidCorrect;
+
/*
- * Set the data dir to the default "/data/data/<package name>/lib"
- * if we got here without anyone telling us different (e.g., apps
- * stored on SD card have their native libraries stored in the ASEC
- * container with the APK).
- *
- * This happens during an upgrade from a package settings file that
- * doesn't have a native library path attribute at all.
+ * Set the native library dir to the default if we got here without
+ * anyone telling us different (e.g., apps stored on SD card have
+ * their native libraries stored in the ASEC container with the
+ * APK). This happens during an upgrade from a package settings file
+ * that doesn't have a native library path attribute at all.
*/
- if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
+ if (pkg.applicationInfo.nativeLibraryDir == null) {
if (pkgSetting.nativeLibraryPathString == null) {
setInternalAppNativeLibraryPath(pkg, pkgSetting);
} else {
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
}
}
-
- pkgSetting.uidError = uidError;
}
String path = scanFile.getPath();
@@ -4446,6 +4361,100 @@ public class PackageManagerService extends IPackageManager.Stub {
return pkg;
}
+ /**
+ * Checks to see whether a package data directory is owned by the correct
+ * user. If it isn't, it will attempt to fix it if it's a system application
+ * or if this is the boot scan.
+ *
+ * @return {@code true} if successful, {@code false} if recovery failed
+ */
+ private boolean ensureDataDirUidIsCorrectForAllUsers(String packageName, int appUid,
+ boolean isSystemApp, boolean isBootScan) {
+ boolean mismatch = false;
+
+ for (int userId : sUserManager.getUserIds()) {
+ final File dataPath = getDataPathForPackage(packageName, userId);
+
+ int currentUid = 0;
+ try {
+ final StructStat stat = Libcore.os.stat(dataPath.getPath());
+ currentUid = stat.st_uid;
+ } catch (ErrnoException e) {
+ Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
+ }
+
+ final int expectedUid = UserHandle.getUid(userId, appUid);
+
+ // If we have mismatched owners for the data path, we have a
+ // problem.
+ if (currentUid != expectedUid) {
+ if (currentUid == 0) {
+ // The directory somehow became owned by root. Wow.
+ // This is probably because the system was stopped while
+ // installd was in the middle of messing with its libs
+ // directory. Ask installd to fix that.
+ final int ret;
+ synchronized (mInstaller) {
+ ret = mInstaller.fixUid(packageName, expectedUid, userId);
+ }
+ if (ret >= 0) {
+ String msg = "Package " + packageName
+ + " unexpectedly changed to uid 0; recovered to " + expectedUid;
+ reportSettingsProblem(Log.WARN, msg);
+ } else {
+ mismatch = true;
+ String prefix = isSystemApp ? "System package " : "Third party package ";
+ String msg = prefix + packageName + " has changed from uid: " + currentUid
+ + " to " + expectedUid;
+ reportSettingsProblem(Log.WARN, msg);
+ }
+ }
+ }
+ }
+
+ if (mismatch) {
+ if (isSystemApp || isBootScan) {
+ // If this is a system app, we can at least delete its
+ // current data so the application will still work.
+ int ret;
+ synchronized (mInstallLock) {
+ ret = removeDataDirsLI(packageName);
+ }
+ if (ret >= 0) {
+ // TODO: Kill the processes first
+ // Old data gone!
+ String prefix = isSystemApp
+ ? "System package " : "Third party package ";
+ String msg = prefix + packageName + " old data erased";
+ reportSettingsProblem(Log.WARN, msg);
+
+ // And now re-install the app.
+ synchronized (mInstallLock) {
+ ret = createDataDirsLI(packageName, appUid);
+ }
+ if (ret == -1) {
+ // Ack should not happen!
+ msg = prefix + packageName
+ + " could not have data directory re-created after delete.";
+ reportSettingsProblem(Log.WARN, msg);
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return false;
+ }
+ } else {
+ mHasSystemUidErrors = true;
+ return false;
+ }
+ } else {
+ // If we allow this install to proceed, we will be broken.
+ // Abort, abort!
+ mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
PackageSetting pkgSetting) {
final String apkLibPath = getApkName(pkgSetting.codePathString);
@@ -7502,6 +7511,22 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageRemovedInfo removedInfo;
}
+ private boolean ensureDataDirExistsForAllUsers(String packageName, int uid) {
+ boolean exists = true;
+ for (int userId : sUserManager.getUserIds()) {
+ final File dataPath = getDataPathForPackage(packageName, userId);
+ if (!dataPath.exists()) {
+ synchronized (mInstallLock) {
+ if (createDataDirForUserLI(packageName, uid, userId) < 0) {
+ Slog.e(TAG, "Couldn't create data path " + dataPath.getPath());
+ }
+ }
+ exists &= dataPath.exists();
+ }
+ }
+ return exists;
+ }
+
/*
* Install a non-existing package.
*/
@@ -7511,7 +7536,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
- boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
+ boolean dataDirExists = ensureDataDirExistsForAllUsers(pkg.packageName,
+ pkg.applicationInfo.uid);
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though