Merge "Sealed sessions need to be destroyed or validated" into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-09-09 01:04:14 +00:00
committed by Android (Google) Code Review
3 changed files with 58 additions and 20 deletions

View File

@@ -319,9 +319,15 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
if (type == START_TAG) { if (type == START_TAG) {
final String tag = in.getName(); final String tag = in.getName();
if (PackageInstallerSession.TAG_SESSION.equals(tag)) { if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
final PackageInstallerSession session = PackageInstallerSession. final PackageInstallerSession session;
readFromXml(in, mInternalCallback, mContext, mPm, try {
mInstallThread.getLooper(), mSessionsDir); session = PackageInstallerSession.readFromXml(in, mInternalCallback,
mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
} catch (Exception e) {
Slog.e(TAG, "Could not read session", e);
continue;
}
final long age = System.currentTimeMillis() - session.createdMillis; final long age = System.currentTimeMillis() - session.createdMillis;
final boolean valid; final boolean valid;

View File

@@ -351,7 +351,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
} }
mPrepared = prepared; mPrepared = prepared;
mSealed = sealed;
if (sealed) {
synchronized (mLock) {
try {
sealAndValidateLocked();
} catch (PackageManagerException | IOException e) {
destroyInternal();
throw new IllegalArgumentException(e);
}
}
}
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
@@ -667,11 +677,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) { public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver); Preconditions.checkNotNull(statusReceiver);
// Cache package manager data without the lock held
final PackageInfo installedPkgInfo = mPm.getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
final boolean wasSealed; final boolean wasSealed;
synchronized (mLock) { synchronized (mLock) {
assertCallerIsOwnerOrRootLocked(); assertCallerIsOwnerOrRootLocked();
@@ -696,7 +701,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
wasSealed = mSealed; wasSealed = mSealed;
if (!mSealed) { if (!mSealed) {
try { try {
sealAndValidateLocked(installedPkgInfo); sealAndValidateLocked();
} catch (IOException e) {
throw new IllegalArgumentException(e);
} catch (PackageManagerException e) { } catch (PackageManagerException e) {
// Do now throw an exception here to stay compatible with O and older // Do now throw an exception here to stay compatible with O and older
destroyInternal(); destroyInternal();
@@ -730,18 +737,33 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
* *
* <p>The session will be sealed after calling this method even if it failed. * <p>The session will be sealed after calling this method even if it failed.
* *
* @param pkgInfo The package info for {@link #params}.packagename * @throws PackageManagerException if the session was sealed but something went wrong. If the
* session was sealed this is the only possible exception.
*/ */
private void sealAndValidateLocked(@Nullable PackageInfo pkgInfo) private void sealAndValidateLocked() throws PackageManagerException, IOException {
throws PackageManagerException {
assertNoWriteFileTransfersOpenLocked(); assertNoWriteFileTransfersOpenLocked();
assertPreparedAndNotDestroyedLocked("sealing of session");
final PackageInfo pkgInfo = mPm.getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
resolveStageDirLocked();
mSealed = true; mSealed = true;
// Verify that stage looks sane with respect to existing application. // Verify that stage looks sane with respect to existing application.
// This currently only ensures packageName, versionCode, and certificate // This currently only ensures packageName, versionCode, and certificate
// consistency. // consistency.
try {
validateInstallLocked(pkgInfo); validateInstallLocked(pkgInfo);
} catch (PackageManagerException e) {
throw e;
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above
throw new PackageManagerException(e);
}
// Read transfers from the original owner stay open, but as the session's data // Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information. // cannot be modified anymore, there is no leak of information.
@@ -762,11 +784,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
+ "the " + Manifest.permission.INSTALL_PACKAGES + " permission"); + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
} }
// Cache package manager data without the lock held
final PackageInfo installedPkgInfo = mPm.getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
// Only install flags that can be verified by the app the session is transferred to are // Only install flags that can be verified by the app the session is transferred to are
// allowed. The parameters can be read via PackageInstaller.SessionInfo. // allowed. The parameters can be read via PackageInstaller.SessionInfo.
if (!params.areHiddenOptionsSet()) { if (!params.areHiddenOptionsSet()) {
@@ -778,8 +795,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertPreparedAndNotSealedLocked("transfer"); assertPreparedAndNotSealedLocked("transfer");
try { try {
sealAndValidateLocked(installedPkgInfo); sealAndValidateLocked();
} catch (IOException e) {
throw new IllegalStateException(e);
} catch (PackageManagerException e) { } catch (PackageManagerException e) {
// Session is sealed but could not be verified, we need to destroy it
destroyInternal();
dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
throw new IllegalArgumentException("Package is not valid", e); throw new IllegalArgumentException("Package is not valid", e);
} }
@@ -1539,6 +1562,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
*/ */
void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException { void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
synchronized (mLock) { synchronized (mLock) {
if (mDestroyed) {
return;
}
out.startTag(null, TAG_SESSION); out.startTag(null, TAG_SESSION);
writeIntAttribute(out, ATTR_SESSION_ID, sessionId); writeIntAttribute(out, ATTR_SESSION_ID, sessionId);

View File

@@ -40,6 +40,11 @@ public class PackageManagerException extends Exception {
this.error = error; this.error = error;
} }
public PackageManagerException(Throwable e) {
super(e);
this.error = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
public static PackageManagerException from(PackageParserException e) public static PackageManagerException from(PackageParserException e)
throws PackageManagerException { throws PackageManagerException {
throw new PackageManagerException(e.error, e.getMessage(), e.getCause()); throw new PackageManagerException(e.error, e.getMessage(), e.getCause());