Merge "Don't provide read logs for shell-initiated installations." into rvc-dev am: e0ba6d9dff

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11778056

Change-Id: I3449f64a8405e8e64d4e270277c226c6da64e5df
This commit is contained in:
TreeHugger Robot
2020-06-15 16:42:17 +00:00
committed by Automerger Merge Worker
11 changed files with 169 additions and 19 deletions

View File

@@ -205,6 +205,7 @@ public class PackageParser {
public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
public static final String TAG_USES_SDK = "uses-sdk"; public static final String TAG_USES_SDK = "uses-sdk";
public static final String TAG_USES_SPLIT = "uses-split"; public static final String TAG_USES_SPLIT = "uses-split";
public static final String TAG_PROFILEABLE = "profileable";
public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes"; public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
@@ -459,6 +460,9 @@ public class PackageParser {
public final SigningDetails signingDetails; public final SigningDetails signingDetails;
public final boolean coreApp; public final boolean coreApp;
public final boolean debuggable; public final boolean debuggable;
// This does not represent the actual manifest structure since the 'profilable' tag
// could be used with attributes other than 'shell'. Extend if necessary.
public final boolean profilableByShell;
public final boolean multiArch; public final boolean multiArch;
public final boolean use32bitAbi; public final boolean use32bitAbi;
public final boolean extractNativeLibs; public final boolean extractNativeLibs;
@@ -470,15 +474,13 @@ public class PackageParser {
public final int overlayPriority; public final int overlayPriority;
public ApkLite(String codePath, String packageName, String splitName, public ApkLite(String codePath, String packageName, String splitName,
boolean isFeatureSplit, boolean isFeatureSplit, String configForSplit, String usesSplitName,
String configForSplit, String usesSplitName, boolean isSplitRequired, boolean isSplitRequired, int versionCode, int versionCodeMajor, int revisionCode,
int versionCode, int versionCodeMajor, int installLocation, List<VerifierInfo> verifiers, SigningDetails signingDetails,
int revisionCode, int installLocation, List<VerifierInfo> verifiers, boolean coreApp, boolean debuggable, boolean profilableByShell, boolean multiArch,
SigningDetails signingDetails, boolean coreApp, boolean use32bitAbi, boolean useEmbeddedDex, boolean extractNativeLibs,
boolean debuggable, boolean multiArch, boolean use32bitAbi, boolean isolatedSplits, String targetPackageName, boolean overlayIsStatic,
boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits, int overlayPriority, int minSdkVersion, int targetSdkVersion) {
String targetPackageName, boolean overlayIsStatic, int overlayPriority,
int minSdkVersion, int targetSdkVersion) {
this.codePath = codePath; this.codePath = codePath;
this.packageName = packageName; this.packageName = packageName;
this.splitName = splitName; this.splitName = splitName;
@@ -493,6 +495,7 @@ public class PackageParser {
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
this.coreApp = coreApp; this.coreApp = coreApp;
this.debuggable = debuggable; this.debuggable = debuggable;
this.profilableByShell = profilableByShell;
this.multiArch = multiArch; this.multiArch = multiArch;
this.use32bitAbi = use32bitAbi; this.use32bitAbi = use32bitAbi;
this.useEmbeddedDex = useEmbeddedDex; this.useEmbeddedDex = useEmbeddedDex;
@@ -1573,6 +1576,7 @@ public class PackageParser {
int revisionCode = 0; int revisionCode = 0;
boolean coreApp = false; boolean coreApp = false;
boolean debuggable = false; boolean debuggable = false;
boolean profilableByShell = false;
boolean multiArch = false; boolean multiArch = false;
boolean use32bitAbi = false; boolean use32bitAbi = false;
boolean extractNativeLibs = true; boolean extractNativeLibs = true;
@@ -1638,6 +1642,10 @@ public class PackageParser {
final String attr = attrs.getAttributeName(i); final String attr = attrs.getAttributeName(i);
if ("debuggable".equals(attr)) { if ("debuggable".equals(attr)) {
debuggable = attrs.getAttributeBooleanValue(i, false); debuggable = attrs.getAttributeBooleanValue(i, false);
if (debuggable) {
// Debuggable implies profileable
profilableByShell = true;
}
} }
if ("multiArch".equals(attr)) { if ("multiArch".equals(attr)) {
multiArch = attrs.getAttributeBooleanValue(i, false); multiArch = attrs.getAttributeBooleanValue(i, false);
@@ -1690,6 +1698,13 @@ public class PackageParser {
minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION); minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
} }
} }
} else if (TAG_PROFILEABLE.equals(parser.getName())) {
for (int i = 0; i < attrs.getAttributeCount(); ++i) {
final String attr = attrs.getAttributeName(i);
if ("shell".equals(attr)) {
profilableByShell = attrs.getAttributeBooleanValue(i, profilableByShell);
}
}
} }
} }
@@ -1707,8 +1722,9 @@ public class PackageParser {
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor, configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor,
revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable, revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,
multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, isolatedSplits, profilableByShell, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
targetPackage, overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion); isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion,
targetSdkVersion);
} }
/** /**

View File

@@ -20,7 +20,6 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageParser; import android.content.pm.PackageParser;
@@ -303,6 +302,7 @@ public class ApkLiteParseUtils {
int revisionCode = 0; int revisionCode = 0;
boolean coreApp = false; boolean coreApp = false;
boolean debuggable = false; boolean debuggable = false;
boolean profilableByShell = false;
boolean multiArch = false; boolean multiArch = false;
boolean use32bitAbi = false; boolean use32bitAbi = false;
boolean extractNativeLibs = true; boolean extractNativeLibs = true;
@@ -379,6 +379,10 @@ public class ApkLiteParseUtils {
switch (attr) { switch (attr) {
case "debuggable": case "debuggable":
debuggable = attrs.getAttributeBooleanValue(i, false); debuggable = attrs.getAttributeBooleanValue(i, false);
if (debuggable) {
// Debuggable implies profileable
profilableByShell = true;
}
break; break;
case "multiArch": case "multiArch":
multiArch = attrs.getAttributeBooleanValue(i, false); multiArch = attrs.getAttributeBooleanValue(i, false);
@@ -431,6 +435,13 @@ public class ApkLiteParseUtils {
minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION); minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
} }
} }
} else if (PackageParser.TAG_PROFILEABLE.equals(parser.getName())) {
for (int i = 0; i < attrs.getAttributeCount(); ++i) {
final String attr = attrs.getAttributeName(i);
if ("shell".equals(attr)) {
profilableByShell = attrs.getAttributeBooleanValue(i, profilableByShell);
}
}
} }
} }
@@ -445,12 +456,13 @@ public class ApkLiteParseUtils {
overlayPriority = 0; overlayPriority = 0;
} }
return input.success(new PackageParser.ApkLite(codePath, packageSplit.first, return input.success(
packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
versionCode, versionCodeMajor, revisionCode, installLocation, verifiers, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
signingDetails, coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
minSdkVersion, targetSdkVersion)); useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion));
} }
public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input, public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,

View File

@@ -110,6 +110,11 @@ interface IIncrementalService {
*/ */
void deleteStorage(int storageId); void deleteStorage(int storageId);
/**
* Permanently disable readlogs reporting for a storage given its ID.
*/
void disableReadLogs(int storageId);
/** /**
* Setting up native library directories and extract native libs onto a storage if needed. * Setting up native library directories and extract native libs onto a storage if needed.
*/ */

View File

@@ -152,6 +152,13 @@ public final class IncrementalFileStorages {
} }
} }
/**
* Permanently disables readlogs.
*/
public void disableReadLogs() {
mDefaultStorage.disableReadLogs();
}
/** /**
* Resets the states and unbinds storage instances for an installation session. * Resets the states and unbinds storage instances for an installation session.
* TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept * TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept

View File

@@ -417,6 +417,17 @@ public final class IncrementalStorage {
private static final int INCFS_MAX_HASH_SIZE = 32; // SHA256 private static final int INCFS_MAX_HASH_SIZE = 32; // SHA256
private static final int INCFS_MAX_ADD_DATA_SIZE = 128; private static final int INCFS_MAX_ADD_DATA_SIZE = 128;
/**
* Permanently disable readlogs collection.
*/
public void disableReadLogs() {
try {
mService.disableReadLogs(mId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
/** /**
* Deserialize and validate v4 signature bytes. * Deserialize and validate v4 signature bytes.
*/ */

View File

@@ -2108,6 +2108,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
baseApk = apk; baseApk = apk;
} }
// Validate and add Dex Metadata (.dm).
final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile); final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
if (dexMetadataFile != null) { if (dexMetadataFile != null) {
if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) { if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
@@ -2295,6 +2296,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName); "Missing split for " + mPackageName);
} }
final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
if (!baseApk.debuggable && !baseApk.profilableByShell) {
mIncrementalFileStorages.disableReadLogs();
}
}
} }
private void resolveAndStageFile(File origFile, File targetFile) private void resolveAndStageFile(File origFile, File targetFile)

View File

@@ -165,6 +165,11 @@ binder::Status BinderIncrementalService::deleteStorage(int32_t storageId) {
return ok(); return ok();
} }
binder::Status BinderIncrementalService::disableReadLogs(int32_t storageId) {
mImpl.disableReadLogs(storageId);
return ok();
}
binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path, binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path,
int32_t* _aidl_return) { int32_t* _aidl_return) {
*_aidl_return = mImpl.makeDir(storageId, path); *_aidl_return = mImpl.makeDir(storageId, path);

View File

@@ -74,7 +74,7 @@ public:
std::vector<uint8_t>* _aidl_return) final; std::vector<uint8_t>* _aidl_return) final;
binder::Status startLoading(int32_t storageId, bool* _aidl_return) final; binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
binder::Status deleteStorage(int32_t storageId) final; binder::Status deleteStorage(int32_t storageId) final;
binder::Status disableReadLogs(int32_t storageId) final;
binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath, binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
const std::string& libDirRelativePath, const std::string& libDirRelativePath,
const std::string& abi, bool extractNativeLibs, const std::string& abi, bool extractNativeLibs,

View File

@@ -60,6 +60,7 @@ struct Constants {
static constexpr auto storagePrefix = "st"sv; static constexpr auto storagePrefix = "st"sv;
static constexpr auto mountpointMdPrefix = ".mountpoint."sv; static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
static constexpr auto infoMdName = ".info"sv; static constexpr auto infoMdName = ".info"sv;
static constexpr auto readLogsDisabledMarkerName = ".readlogs_disabled"sv;
static constexpr auto libDir = "lib"sv; static constexpr auto libDir = "lib"sv;
static constexpr auto libSuffix = ".so"sv; static constexpr auto libSuffix = ".so"sv;
static constexpr auto blockSize = 4096; static constexpr auto blockSize = 4096;
@@ -172,6 +173,13 @@ std::string makeBindMdName() {
return name; return name;
} }
static bool checkReadLogsDisabledMarker(std::string_view root) {
const auto markerPath = path::c_str(path::join(root, constants().readLogsDisabledMarkerName));
struct stat st;
return (::stat(markerPath, &st) == 0);
}
} // namespace } // namespace
IncrementalService::IncFsMount::~IncFsMount() { IncrementalService::IncFsMount::~IncFsMount() {
@@ -618,6 +626,32 @@ StorageId IncrementalService::findStorageId(std::string_view path) const {
return it->second->second.storage; return it->second->second.storage;
} }
void IncrementalService::disableReadLogs(StorageId storageId) {
std::unique_lock l(mLock);
const auto ifs = getIfsLocked(storageId);
if (!ifs) {
LOG(ERROR) << "disableReadLogs failed, invalid storageId: " << storageId;
return;
}
if (!ifs->readLogsEnabled()) {
return;
}
ifs->disableReadLogs();
l.unlock();
const auto metadata = constants().readLogsDisabledMarkerName;
if (auto err = mIncFs->makeFile(ifs->control,
path::join(ifs->root, constants().mount,
constants().readLogsDisabledMarkerName),
0777, idFromMetadata(metadata), {})) {
//{.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
LOG(ERROR) << "Failed to make marker file for storageId: " << storageId;
return;
}
setStorageParams(storageId, /*enableReadLogs=*/false);
}
int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) { int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) {
const auto ifs = getIfs(storageId); const auto ifs = getIfs(storageId);
if (!ifs) { if (!ifs) {
@@ -627,6 +661,11 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog
const auto& params = ifs->dataLoaderStub->params(); const auto& params = ifs->dataLoaderStub->params();
if (enableReadLogs) { if (enableReadLogs) {
if (!ifs->readLogsEnabled()) {
LOG(ERROR) << "setStorageParams failed, readlogs disabled for storageId: " << storageId;
return -EPERM;
}
if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage, if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage,
params.packageName.c_str()); params.packageName.c_str());
!status.isOk()) { !status.isOk()) {
@@ -1072,6 +1111,11 @@ std::unordered_set<std::string_view> IncrementalService::adoptMountedInstances()
std::move(control), *this); std::move(control), *this);
cleanupFiles.release(); // ifs will take care of that now cleanupFiles.release(); // ifs will take care of that now
// Check if marker file present.
if (checkReadLogsDisabledMarker(root)) {
ifs->disableReadLogs();
}
std::vector<std::pair<std::string, metadata::BindPoint>> permanentBindPoints; std::vector<std::pair<std::string, metadata::BindPoint>> permanentBindPoints;
auto d = openDir(root); auto d = openDir(root);
while (auto e = ::readdir(d.get())) { while (auto e = ::readdir(d.get())) {
@@ -1243,6 +1287,11 @@ bool IncrementalService::mountExistingImage(std::string_view root) {
ifs->mountId = mount.storage().id(); ifs->mountId = mount.storage().id();
mNextId = std::max(mNextId, ifs->mountId + 1); mNextId = std::max(mNextId, ifs->mountId + 1);
// Check if marker file present.
if (checkReadLogsDisabledMarker(mountTarget)) {
ifs->disableReadLogs();
}
// DataLoader params // DataLoader params
DataLoaderParamsParcel dataLoaderParams; DataLoaderParamsParcel dataLoaderParams;
{ {

View File

@@ -94,6 +94,10 @@ public:
Permanent = 1, Permanent = 1,
}; };
enum StorageFlags {
ReadLogsEnabled = 1,
};
static FileId idFromMetadata(std::span<const uint8_t> metadata); static FileId idFromMetadata(std::span<const uint8_t> metadata);
static inline FileId idFromMetadata(std::span<const char> metadata) { static inline FileId idFromMetadata(std::span<const char> metadata) {
return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()}); return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()});
@@ -116,6 +120,7 @@ public:
int unbind(StorageId storage, std::string_view target); int unbind(StorageId storage, std::string_view target);
void deleteStorage(StorageId storage); void deleteStorage(StorageId storage);
void disableReadLogs(StorageId storage);
int setStorageParams(StorageId storage, bool enableReadLogs); int setStorageParams(StorageId storage, bool enableReadLogs);
int makeFile(StorageId storage, std::string_view path, int mode, FileId id, int makeFile(StorageId storage, std::string_view path, int mode, FileId id,
@@ -264,6 +269,7 @@ private:
const std::string root; const std::string root;
Control control; Control control;
/*const*/ MountId mountId; /*const*/ MountId mountId;
int32_t flags = StorageFlags::ReadLogsEnabled;
StorageMap storages; StorageMap storages;
BindMap bindPoints; BindMap bindPoints;
DataLoaderStubPtr dataLoaderStub; DataLoaderStubPtr dataLoaderStub;
@@ -282,6 +288,9 @@ private:
StorageMap::iterator makeStorage(StorageId id); StorageMap::iterator makeStorage(StorageId id);
void disableReadLogs() { flags &= ~StorageFlags::ReadLogsEnabled; }
int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); }
static void cleanupFilesystem(std::string_view root); static void cleanupFilesystem(std::string_view root);
}; };

View File

@@ -929,6 +929,34 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
ASSERT_GE(mDataLoader->setStorageParams(true), 0); ASSERT_GE(mDataLoader->setStorageParams(true), 0);
} }
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
mDataLoaderManager->bindToDataLoaderSuccess();
mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
// After setIncFsMountOptions succeeded expecting to start watching.
EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
// Not expecting callback removal.
EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
ASSERT_GE(storageId, 0);
ASSERT_GE(mDataLoader->setStorageParams(true), 0);
// Now disable.
mIncrementalService->disableReadLogs(storageId);
ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) { TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
mVold->mountIncFsSuccess(); mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess(); mIncFs->makeFileSuccess();