Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da2509c4 authored by Kenny Root's avatar Kenny Root Committed by Android (Google) Code Review
Browse files

Merge "Check non-primary user dirs during package scan" into jb-mr1-dev

parents 6757572b 4525f5b6
Loading
Loading
Loading
Loading
+24 −9
Original line number Diff line number Diff line
@@ -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;
}
+2 −2
Original line number Diff line number Diff line
@@ -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());
    }

+155 −129
Original line number Diff line number Diff line
@@ -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);
    }

    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;

            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;
            dataPath = getDataPathForPackage(pkg.packageName, UserHandle.USER_OWNER);

                            // 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;
                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