From a669ce68cd8ee67ebfe37844bf7de81e23219842 Mon Sep 17 00:00:00 2001 From: Yurii Zubrytskyi Date: Mon, 12 Dec 2022 15:11:41 -0800 Subject: [PATCH] Disallow everyone to list files in the package dir Only the system and the owner should be able to list the app directory, both levels of it. Our code used the default mode for them, making Incremental installations vulnerable to any app that can see mounted filesystems: enumerating files in the mounted incfs instance would give away the app package name. This CL explicitly changes the mode to only allow reading individual files in directory, but not listing them. Also now we have code that fixes any originally installed packages to make sure their mode is set properly as well Bug: 261766355 Test: manual + an incremental CTS case Change-Id: Ib084a3da95bd3e45463ee9e85e5b626495fd5486 --- .../os/incremental/IncrementalManager.java | 19 +++++++++++++- .../com/android/server/pm/InitAppsHelper.java | 26 +++++++++++++++++++ .../server/pm/InstallPackageHelper.java | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java index 9c8ee562849cd..80041437d6b82 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -25,6 +25,9 @@ import android.content.pm.DataLoaderParams; import android.content.pm.IPackageLoadingProgressCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructStat; import android.util.Slog; import android.util.SparseArray; @@ -146,15 +149,29 @@ public final class IncrementalManager { @Nullable public IncrementalStorage createStorage(@NonNull String path, @NonNull IncrementalStorage linkedStorage, @CreateMode int createMode) { + int id = -1; try { - final int id = mService.createLinkedStorage( + // Incremental service mounts its newly created storage on top of the supplied path, + // ensure that the original mode remains the same after mounting. + StructStat st = Os.stat(path); + id = mService.createLinkedStorage( path, linkedStorage.getId(), createMode); if (id < 0) { return null; } + Os.chmod(path, st.st_mode & 07777); return new IncrementalStorage(mService, id); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (ErrnoException e) { + if (id >= 0) { + try { + mService.deleteStorage(id); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + throw new RuntimeException(e); } } diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java index 12b5ab8a3160c..823bc71229438 100644 --- a/services/core/java/com/android/server/pm/InitAppsHelper.java +++ b/services/core/java/com/android/server/pm/InitAppsHelper.java @@ -39,6 +39,8 @@ import android.annotation.Nullable; import android.os.Environment; import android.os.SystemClock; import android.os.Trace; +import android.system.ErrnoException; +import android.system.Os; import android.util.ArrayMap; import android.util.EventLog; import android.util.Slog; @@ -55,6 +57,7 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.utils.WatchedArrayMap; import java.io.File; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -226,6 +229,24 @@ final class InitAppsHelper { } } + /** + * Fix up the previously-installed app directory mode - they can't be readable by non-system + * users to prevent them from listing the dir to discover installed package names. + */ + void fixInstalledAppDirMode() { + try (var files = Files.newDirectoryStream(mPm.getAppInstallDir().toPath())) { + files.forEach(dir -> { + try { + Os.chmod(dir.toString(), 0771); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to fix an installed app dir mode", e); + } + }); + } catch (Exception e) { + Slog.w(TAG, "Failed to walk the app install directory to fix the modes", e); + } + } + /** * Install apps/updates from data dir and fix system apps that are affected. */ @@ -234,6 +255,11 @@ final class InitAppsHelper { long startTime) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); + + if ((mScanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == SCAN_FIRST_BOOT_OR_UPGRADE) { + fixInstalledAppDirMode(); + } + scanDirTracedLI(mPm.getAppInstallDir(), 0, mScanFlags | SCAN_REQUIRE_KNOWN, packageParser, mExecutorService); diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 7553370bf4c62..c959b4724b93a 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -1719,7 +1719,7 @@ final class InstallPackageHelper { final boolean onIncremental = mPm.mIncrementalManager != null && isIncrementalPath(beforeCodeFile.getAbsolutePath()); try { - makeDirRecursive(afterCodeFile.getParentFile(), 0775); + makeDirRecursive(afterCodeFile.getParentFile(), 0771); if (onIncremental) { // Just link files here. The stage dir will be removed when the installation // session is completed.