Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Tencent is pleased to support the open source community by making Tinker available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.tinker.lib.patch;

import java.io.File;
import java.io.IOException;

public final class PatchEntryUtils {

private PatchEntryUtils() {
}

public static boolean isValidEntryName(String name) {
if (name == null || name.isEmpty()) {
return false;
}
if (name.contains("..")) {
return false;
}
if (name.startsWith("/") || name.startsWith("\\")) {
return false;
}
if (name.contains(":")) {
return false;
}
return true;
}

public static boolean isPathInDirectory(File file, File directory) throws IOException {
final String canonicalDir = directory.getCanonicalPath();
final String canonicalFile = file.getCanonicalPath();
return canonicalFile.equals(canonicalDir)
|| canonicalFile.startsWith(canonicalDir + File.separator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,37 @@ public class ResDiffPatchInternal extends BasePatchInternal {

protected static final String TAG = "Tinker.ResDiffPatchInternal";

private static boolean checkPatchZipEntriesSafe(File patchFile, File parentDir) {
TinkerZipFile zipFile = null;
try {
zipFile = new TinkerZipFile(patchFile);
final String parentCanonical = parentDir.getCanonicalFile().getCanonicalPath() + File.separator;
Enumeration<? extends TinkerZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
TinkerZipEntry entry = entries.nextElement();
if (entry == null) {
continue;
}
String name = entry.getName();
if (!isLegalEntryName(name)) {
ShareTinkerLog.e(TAG, "illegal entry name in patch zip: %s", name);
return false;
}
File extractedFile = new File(parentDir, name);
if (!extractedFile.getCanonicalPath().startsWith(parentCanonical)) {
ShareTinkerLog.e(TAG, "zip slip detected for entry: %s", name);
return false;
}
}
return true;
} catch (Throwable e) {
ShareTinkerLog.e(TAG, "checkPatchZipEntriesSafe failed: %s", e.getMessage());
return false;
} finally {
IOHelper.closeQuietly(zipFile);
}
}

protected static boolean tryRecoverResourceFiles(Tinker manager, ShareSecurityCheck checker, Context context,
String patchVersionDirectory, File patchFile, boolean useCustomPatcher, PatchResult patchResult) {

Expand Down Expand Up @@ -124,6 +155,11 @@ private static boolean extractResourceDiffInternals(Context context, String dir,
}
String apkPath = applicationInfo.sourceDir;

if (!checkPatchZipEntriesSafe(patchFile, directory)) {
ShareTinkerLog.e(TAG, "patch recover, illegal zip entry detected in patch file: %s", patchFile.getAbsolutePath());
manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
return false;
}

if (!checkAndExtractResourceLargeFile(context, apkPath, directory, tempResFileDirectory, patchFile, resPatchInfo, type, useCustomPatcher)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Tencent is pleased to support the open source community by making Tinker available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.tinker.lib.util;

import java.io.File;
import java.io.IOException;
import java.util.zip.ZipEntry;

public final class PatchEntryUtils {

private PatchEntryUtils() {
}

public static File validateZipEntry(ZipEntry entry, File targetDir) throws IOException {
if (entry == null) {
throw new IOException("zip entry is null");
}
if (targetDir == null) {
throw new IOException("target directory is null");
}
final File targetFile = new File(targetDir, entry.getName());
final String targetDirCanonical = targetDir.getCanonicalPath();
final String targetFileCanonical = targetFile.getCanonicalPath();
if (!targetFileCanonical.startsWith(targetDirCanonical + File.separator)
&& !targetFileCanonical.equals(targetDirCanonical)) {
throw new IOException("illegal zip entry path: " + entry.getName());
}
return targetFile;
}
}