1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dalvik.system; 18 19 import libcore.util.NonNull; 20 21 import java.util.Objects; 22 import java.util.zip.ZipException; 23 24 /** 25 * Enables validation of zip file entry paths to prevent exploitation of the path traversal 26 * vulnerability, e.g. zip path entries containing ".." or "/". For more details, read 27 * <a href="https://developer.android.com/topic/security/risks/zip-path-traversal">this</a>. 28 * <p> 29 * The default implementation accepts all zip file entry paths without raising any exceptions. 30 * <p> 31 * For custom validation rules, the core functionality should be implemented in a {@link Callback} 32 * interface and that instance should be set in {@link #setCallback(Callback)}. 33 * <p> 34 * Existing validation could be set to a default one by calling {@link #clearCallback()}. 35 */ 36 public final class ZipPathValidator { 37 38 /** 39 * Default implementation of the {@link Callback} interface which accepts all paths. 40 * 41 * @hide 42 */ 43 public static final Callback DEFAULT = new Callback() {}; 44 45 private static volatile Callback sInstance = DEFAULT; 46 47 /** 48 * Clears the current validation mechanism by setting the current callback instance to a default 49 * validation. 50 */ clearCallback()51 public static void clearCallback() { 52 sInstance = DEFAULT; 53 } 54 55 /** 56 * Sets the current callback implementation for zip paths. 57 * <p> 58 * The provided callback should not perform IO or any blocking operations, but only perform path 59 * validation. A typical implementation will validate String entries in a single pass and throw 60 * a {@link ZipException} if the path contains potentially hazardous components such as "..". 61 * 62 * @param callback An instance of {@link Callback}'s implementation. 63 */ setCallback(@onNull Callback callback)64 public static void setCallback(@NonNull Callback callback) { 65 sInstance = Objects.requireNonNull(callback); 66 } 67 68 /** 69 * Retrieves the current validator set by {@link #setCallback(Callback)}. 70 * 71 * @return Current callback. 72 * 73 * @hide 74 */ getInstance()75 public static @NonNull Callback getInstance() { 76 return sInstance; 77 } 78 79 /** 80 * Returns true if the current validator is the default implementation {@link DEFAULT}, 81 * otherwise false. 82 * 83 * @hide 84 */ isClear()85 public static boolean isClear() { 86 return sInstance.equals(DEFAULT); 87 } 88 89 /** 90 * Interface that defines the core validation mechanism when accessing zip file entry paths. 91 */ 92 public interface Callback { 93 /** 94 * Called to check the validity of the path of a zip entry. The default implementation 95 * accepts all paths without raising any exceptions. 96 * <p> 97 * This method will be called by {@link java.util.zip.ZipInputStream#getNextEntry} or 98 * {@link java.util.zip.ZipFile#ZipFile(String)}. 99 * 100 * @param path The name of the zip entry. 101 * @throws ZipException If the zip entry is invalid depending on the implementation. 102 */ onZipEntryAccess(@onNull String path)103 default void onZipEntryAccess(@NonNull String path) throws ZipException {} 104 } 105 ZipPathValidator()106 private ZipPathValidator() {} 107 } 108