package biz.bokhorst.xprivacy; import java.io.FileNotFoundException; import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.os.Binder; import android.os.Process; import android.text.TextUtils; import android.util.Log; public class XIoBridge extends XHook { private Methods mMethod; private String mFileName; private static String mExternalStorage = null; private static String mEmulatedSource = null; private static String mEmulatedTarget = null; private static String mMediaStorage = null; private static String mSecondaryStorage = null; private XIoBridge(Methods method, String restrictionName) { super(restrictionName, method.name(), null); mMethod = method; mFileName = null; } private XIoBridge(Methods method, String restrictionName, String fileName) { super(restrictionName, method.name(), fileName); mMethod = method; mFileName = fileName; } public String getClassName() { return "libcore.io.IoBridge"; } // @formatter:off // public static void connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException // public static void connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException // public static FileDescriptor open(String path, int flags) throws FileNotFoundException // public static FileDescriptor socket(boolean stream) throws SocketException // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Environment.java // https://android.googlesource.com/platform/libcore/+/android-5.0.1_r1/luni/src/main/java/libcore/io/IoBridge.java // @formatter:on private enum Methods { open, connect }; public static List<XHook> getInstances() { List<XHook> listHook = new ArrayList<XHook>(); listHook.add(new XIoBridge(Methods.connect, PrivacyManager.cInternet)); listHook.add(new XIoBridge(Methods.open, PrivacyManager.cStorage)); listHook.add(new XIoBridge(Methods.open, PrivacyManager.cIdentification, "/proc")); listHook.add(new XIoBridge(Methods.open, PrivacyManager.cIdentification, "/system/build.prop")); listHook.add(new XIoBridge(Methods.open, PrivacyManager.cIdentification, "/sys/block/.../cid")); listHook.add(new XIoBridge(Methods.open, PrivacyManager.cIdentification, "/sys/class/.../cid")); return listHook; } @Override @SuppressLint("SdCardPath") protected void before(XParam param) throws Throwable { if (mMethod == Methods.connect) { if (param.args.length > 2 && param.args[1] instanceof InetAddress && param.args[2] instanceof Integer) { InetAddress address = (InetAddress) param.args[1]; int port = (Integer) param.args[2]; String hostName; int uid = Binder.getCallingUid(); boolean resolve = PrivacyManager.getSettingBool(uid, PrivacyManager.cSettingResolve, false); boolean noresolve = PrivacyManager.getSettingBool(-uid, PrivacyManager.cSettingNoResolve, false); if (resolve && !noresolve) try { hostName = address.getHostName(); } catch (Throwable ignored) { hostName = address.toString(); } else hostName = address.toString(); if (isRestrictedExtra(param, hostName + ":" + port)) param.setThrowable(new SocketException("XPrivacy")); } } else if (mMethod == Methods.open) { if (param.args.length > 0) { String fileName = (String) param.args[0]; if (mFileName == null && fileName != null) { // Get storage folders if (mExternalStorage == null) { mExternalStorage = System.getenv("EXTERNAL_STORAGE"); mEmulatedSource = System.getenv("EMULATED_STORAGE_SOURCE"); mEmulatedTarget = System.getenv("EMULATED_STORAGE_TARGET"); mMediaStorage = System.getenv("MEDIA_STORAGE"); mSecondaryStorage = System.getenv("SECONDARY_STORAGE"); if (TextUtils.isEmpty(mMediaStorage)) mMediaStorage = "/data/media"; } // Check storage folders if (fileName.startsWith("/sdcard") || (mExternalStorage != null && fileName.startsWith(mExternalStorage)) || (mEmulatedSource != null && fileName.startsWith(mEmulatedSource)) || (mEmulatedTarget != null && fileName.startsWith(mEmulatedTarget)) || (mMediaStorage != null && fileName.startsWith(mMediaStorage)) || (mSecondaryStorage != null && fileName.startsWith(mSecondaryStorage))) if (isRestrictedExtra(param, fileName)) param.setThrowable(new FileNotFoundException("XPrivacy")); } else if (fileName.startsWith(mFileName) || mFileName.contains("...")) { // Zygote, Android if (Util.getAppId(Process.myUid()) == Process.SYSTEM_UID) return; // Proc white list if (mFileName.equals("/proc")) if ("/proc/self/cmdline".equals(fileName)) return; // Check if restricted if (mFileName.contains("...")) { String[] component = mFileName.split("\\.\\.\\."); if (fileName.startsWith(component[0]) && fileName.endsWith(component[1])) if (isRestricted(param, mFileName)) param.setThrowable(new FileNotFoundException("XPrivacy")); } else if (mFileName.equals("/proc")) { if (isRestrictedExtra(param, mFileName, fileName)) param.setThrowable(new FileNotFoundException("XPrivacy")); } else { if (isRestricted(param, mFileName)) param.setThrowable(new FileNotFoundException("XPrivacy")); } } } } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName()); } @Override protected void after(XParam param) throws Throwable { // Do nothing } }