Merge "Move initZipPathValidator() into ActivityThread"

This commit is contained in:
Azhara Assanova 2023-03-01 15:52:09 +00:00 committed by Gerrit Code Review
commit ceb138df5e
3 changed files with 22 additions and 270 deletions

View File

@ -36,6 +36,7 @@ import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
import android.annotation.NonNull;
import android.annotation.Nullable;
@ -48,6 +49,7 @@ import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermis
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.BackupAgent;
import android.app.compat.CompatChanges;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
import android.app.servertransaction.ActivityRelaunchItem;
@ -202,6 +204,7 @@ import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BinderCallsStats;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SafeZipPathValidatorCallback;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.DecorView;
import com.android.internal.util.ArrayUtils;
@ -216,6 +219,7 @@ import dalvik.system.AppSpecializationHooks;
import dalvik.system.CloseGuard;
import dalvik.system.VMDebug;
import dalvik.system.VMRuntime;
import dalvik.system.ZipPathValidator;
import libcore.io.ForwardingOs;
import libcore.io.IoUtils;
@ -6466,6 +6470,11 @@ public final class ActivityThread extends ClientTransactionHandler
// Let libcore handle any compat changes after installing the list of compat changes.
AppSpecializationHooks.handleCompatChangesBeforeBindingApplication();
// Initialize the zip path validator callback depending on the targetSdk.
// This has to be after AppCompatCallbacks#install() so that the Compat
// checks work accordingly.
initZipPathValidatorCallback();
mBoundApplication = data;
mConfigurationController.setConfiguration(data.config);
mConfigurationController.setCompatConfiguration(data.config);
@ -6795,6 +6804,19 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
/**
* If targetSDK >= U: set the safe zip path validator callback which disallows dangerous zip
* entry names.
* Otherwise: clear the callback to the default validation.
*/
private void initZipPathValidatorCallback() {
if (CompatChanges.isChangeEnabled(VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL)) {
ZipPathValidator.setCallback(new SafeZipPathValidatorCallback());
} else {
ZipPathValidator.clearCallback();
}
}
private void handleSetContentCaptureOptionsCallback(String packageName) {
if (mContentCaptureOptionsCallback != null) {
return;

View File

@ -16,14 +16,10 @@
package com.android.internal.os;
import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.app.IActivityManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.type.DefaultMimeMapFactory;
import android.net.TrafficStats;
@ -40,7 +36,6 @@ import com.android.internal.logging.AndroidConfig;
import dalvik.system.RuntimeHooks;
import dalvik.system.VMRuntime;
import dalvik.system.ZipPathValidator;
import libcore.content.type.MimeMap;
@ -265,30 +260,9 @@ public class RuntimeInit {
*/
TrafficStats.attachSocketTagger();
/*
* Initialize the zip path validator callback depending on the targetSdk.
*/
initZipPathValidatorCallback();
initialized = true;
}
/**
* If targetSDK >= U: set the safe zip path validator callback which disallows dangerous zip
* entry names.
* Otherwise: clear the callback to the default validation.
*
* @hide
*/
@TestApi
public static void initZipPathValidatorCallback() {
if (CompatChanges.isChangeEnabled(VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL)) {
ZipPathValidator.setCallback(new SafeZipPathValidatorCallback());
} else {
ZipPathValidator.clearCallback();
}
}
/**
* Returns an HTTP user agent of the form
* "Dalvik/1.1.0 (Linux; U; Android Eclair Build/MAIN)".

View File

@ -1,244 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.os;
import static org.junit.Assert.assertThrows;
import android.compat.testing.PlatformCompatChangeRule;
import androidx.test.runner.AndroidJUnit4;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* Test SafeZipPathCallback.
*/
@RunWith(AndroidJUnit4.class)
public class SafeZipPathValidatorCallbackTest {
@Rule
public TestRule mCompatChangeRule = new PlatformCompatChangeRule();
@Before
public void setUp() {
RuntimeInit.initZipPathValidatorCallback();
}
@Test
@EnableCompatChanges({SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL})
public void testNewZipFile_whenZipFileHasDangerousEntriesAndChangeEnabled_throws()
throws Exception {
final String[] dangerousEntryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
};
for (String entryName : dangerousEntryNames) {
final File tempFile = File.createTempFile("smdc", "zip");
try {
writeZipFileOutputStreamWithEmptyEntry(tempFile, entryName);
assertThrows(
"ZipException expected for entry: " + entryName,
ZipException.class,
() -> {
new ZipFile(tempFile);
});
} finally {
tempFile.delete();
}
}
}
@Test
@EnableCompatChanges({SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL})
public void
testZipInputStreamGetNextEntry_whenZipFileHasDangerousEntriesAndChangeEnabled_throws()
throws Exception {
final String[] dangerousEntryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
};
for (String entryName : dangerousEntryNames) {
byte[] badZipBytes = getZipBytesFromZipOutputStreamWithEmptyEntry(entryName);
try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(badZipBytes))) {
assertThrows(
"ZipException expected for entry: " + entryName,
ZipException.class,
() -> {
zis.getNextEntry();
});
}
}
}
@Test
@EnableCompatChanges({SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL})
public void testNewZipFile_whenZipFileHasNormalEntriesAndChangeEnabled_doesNotThrow()
throws Exception {
final String[] normalEntryNames = {
"foo", "foo.bar", "foo..bar",
};
for (String entryName : normalEntryNames) {
final File tempFile = File.createTempFile("smdc", "zip");
try {
writeZipFileOutputStreamWithEmptyEntry(tempFile, entryName);
try {
new ZipFile((tempFile));
} catch (ZipException e) {
throw new AssertionError("ZipException not expected for entry: " + entryName);
}
} finally {
tempFile.delete();
}
}
}
@Test
@DisableCompatChanges({SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL})
public void
testZipInputStreamGetNextEntry_whenZipFileHasNormalEntriesAndChangeEnabled_doesNotThrow()
throws Exception {
final String[] normalEntryNames = {
"foo", "foo.bar", "foo..bar",
};
for (String entryName : normalEntryNames) {
byte[] zipBytes = getZipBytesFromZipOutputStreamWithEmptyEntry(entryName);
try {
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes));
zis.getNextEntry();
} catch (ZipException e) {
throw new AssertionError("ZipException not expected for entry: " + entryName);
}
}
}
@Test
@DisableCompatChanges({SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL})
public void
testNewZipFile_whenZipFileHasNormalAndDangerousEntriesAndChangeDisabled_doesNotThrow()
throws Exception {
final String[] entryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
"foo",
"foo.bar",
"foo..bar",
};
for (String entryName : entryNames) {
final File tempFile = File.createTempFile("smdc", "zip");
try {
writeZipFileOutputStreamWithEmptyEntry(tempFile, entryName);
try {
new ZipFile((tempFile));
} catch (ZipException e) {
throw new AssertionError("ZipException not expected for entry: " + entryName);
}
} finally {
tempFile.delete();
}
}
}
@Test
@DisableCompatChanges({SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL})
public void
testZipInputStreamGetNextEntry_whenZipFileHasNormalAndDangerousEntriesAndChangeDisabled_doesNotThrow()
throws Exception {
final String[] entryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
"foo",
"foo.bar",
"foo..bar",
};
for (String entryName : entryNames) {
byte[] zipBytes = getZipBytesFromZipOutputStreamWithEmptyEntry(entryName);
try {
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes));
zis.getNextEntry();
} catch (ZipException e) {
throw new AssertionError("ZipException not expected for entry: " + entryName);
}
}
}
private void writeZipFileOutputStreamWithEmptyEntry(File tempFile, String entryName)
throws IOException {
FileOutputStream tempFileStream = new FileOutputStream(tempFile);
writeZipOutputStreamWithEmptyEntry(tempFileStream, entryName);
tempFileStream.close();
}
private byte[] getZipBytesFromZipOutputStreamWithEmptyEntry(String entryName)
throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
writeZipOutputStreamWithEmptyEntry(bos, entryName);
return bos.toByteArray();
}
private void writeZipOutputStreamWithEmptyEntry(OutputStream os, String entryName)
throws IOException {
ZipOutputStream zos = new ZipOutputStream(os);
ZipEntry entry = new ZipEntry(entryName);
zos.putNextEntry(entry);
zos.write(new byte[2]);
zos.closeEntry();
zos.close();
}
}