OSDN Git Service

Check non-primary user dirs during package scan
authorKenny Root <kroot@google.com>
Mon, 22 Oct 2012 21:24:23 +0000 (14:24 -0700)
committerKenny Root <kroot@google.com>
Tue, 23 Oct 2012 01:48:24 +0000 (18:48 -0700)
During package scan, only the primary user data directories were
checked. If the secondary user didn't have an application directory, it
would happily ignore it. The app would then crash upon startup.

Bug: 7391882
Change-Id: I1fa92aa27386104d4ac6bc5dc92bfbf2e7dfac9f

cmds/installd/commands.c
services/java/com/android/server/pm/Installer.java
services/java/com/android/server/pm/PackageManagerService.java

index 8e4d7ed..e3acad9 100644 (file)
@@ -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;
 }
index 71a6a01..0247911 100644 (file)
@@ -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());
     }
 
index 4c6f589..66d2f24 100644 (file)
@@ -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