diff options
-rw-r--r-- | cmds/installd/commands.c | 33 | ||||
-rw-r--r-- | services/java/com/android/server/pm/Installer.java | 4 | ||||
-rw-r--r-- | services/java/com/android/server/pm/PackageManagerService.java | 284 |
3 files changed, 181 insertions, 140 deletions
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 59bcda1..8588975 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -143,39 +143,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 |