@Override public int checkPermission(final String permName, final String pkgName) { return mCondom.proceed(OutboundType.CHECK_PERMISSION, pkgName, PERMISSION_DENIED, new CondomCore.WrappedValueProcedure<Integer>() { @Override public Integer proceed() { return CondomPackageManager.super.checkPermission(permName, pkgName); } }); }
return mCondom.proceed(OutboundType.QUERY_SERVICES, intent, null, new CondomCore.WrappedValueProcedureThrows<ResolveInfo, Throwable>() { @Override public ResolveInfo proceed() throws Throwable { if (! mCondom.mExcludeBackgroundServices && mCondom.mOutboundJudge == null) return (ResolveInfo) CondomProcessPackageManager.super.invoke(proxy, method, args);
@Override public ApplicationInfo getApplicationInfo(final String pkg, final int flags) throws NameNotFoundException { return mCondom.proceed(OutboundType.GET_APPLICATION_INFO, pkg, null, new CondomCore.WrappedValueProcedureThrows<ApplicationInfo, NameNotFoundException>() { @Override public ApplicationInfo proceed() throws NameNotFoundException { return CondomPackageManager.super.getApplicationInfo(pkg, flags); } }); }
return mCondom.proceed(OutboundType.QUERY_SERVICES, intent, null, new CondomCore.WrappedValueProcedureThrows<ResolveInfo, Exception>() { @Override public ResolveInfo proceed() throws Exception { if (! mCondom.mExcludeBackgroundServices) return (ResolveInfo) CondomProcessPackageManager.super.invoke(proxy, method, args);
@Override public ResolveInfo resolveService(final Intent intent, final int flags) { final int original_intent_flags = intent.getFlags(); // Intent flags could only filter background receivers, we have to deal with services by ourselves. return mCondom.proceed(OutboundType.QUERY_SERVICES, intent, null, new CondomCore.WrappedValueProcedure<ResolveInfo>() { @Override public ResolveInfo proceed() { if (! mCondom.mExcludeBackgroundServices && mCondom.mOutboundJudge == null) return CondomPackageManager.super.resolveService(intent, flags); // Shortcut for pass-through final List<ResolveInfo> candidates = CondomPackageManager.super.queryIntentServices(intent, flags); final Intent original_intent = intent.setFlags(original_intent_flags); // Restore the intent flags early before getFirstMatch(). return mCondom.filterCandidates(OutboundType.QUERY_SERVICES, original_intent, candidates, TAG, false); } }); }
@CheckResult <T, E extends Throwable> List<T> proceedQuery(final OutboundType type, final @Nullable Intent intent, final WrappedValueProcedureThrows<List<T>, E> procedure, final Function<T, String> pkg_getter) throws E { return proceed(type, intent, Collections.<T>emptyList(), new WrappedValueProcedureThrows<List<T>, E>() { @Override public List<T> proceed() throws E { final List<T> candidates = procedure.proceed(); if (candidates != null && mOutboundJudge != null && (intent == null || getTargetPackage(intent) == null)) { // Package-targeted intent is already filtered by OutboundJudge in proceed(). final Iterator<T> iterator = candidates.iterator(); while (iterator.hasNext()) { final T candidate = iterator.next(); final String pkg = pkg_getter.apply(candidate); if (pkg != null && shouldBlockRequestTarget(type, intent, pkg)) // Dry-run is checked inside shouldBlockRequestTarget() iterator.remove(); // TODO: Not safe to assume the list returned from PackageManager is modifiable. } } return candidates; }}); } interface Function<T, R> { R apply(T t); }
void proceedBroadcast(final Context context, final Intent intent, final WrappedValueProcedure<Boolean> procedure, final @Nullable BroadcastReceiver resultReceiver) { if (proceed(OutboundType.BROADCAST, intent, Boolean.FALSE, procedure) == Boolean.FALSE && resultReceiver != null) resultReceiver.onReceive(new ReceiverRestrictedContext(context), intent); }
@Override public boolean bindService(final Intent intent, final ServiceConnection conn, final int flags) { final boolean result = mCondom.proceed(OutboundType.BIND_SERVICE, intent, Boolean.FALSE, new CondomCore.WrappedValueProcedure<Boolean>() { @Override public Boolean proceed() { return mApplication.bindService(intent, conn, flags); }}); if (result) mCondom.logIfOutboundPass(TAG, intent, CondomCore.getTargetPackage(intent), CondomCore.CondomEvent.BIND_PASS); return result; }
@Override public ComponentName startService(final Intent intent) { final ComponentName component = mCondom.proceed(OutboundType.START_SERVICE, intent, null, new CondomCore.WrappedValueProcedure<ComponentName>() { @Override public ComponentName proceed() { return mApplication.startService(intent); }}); if (component != null) mCondom.logIfOutboundPass(TAG, intent, component.getPackageName(), CondomCore.CondomEvent.START_PASS); return component; }
@Override public ComponentName startService(final Intent intent) { final ComponentName component = mCondom.proceed(OutboundType.START_SERVICE, intent, null, new CondomCore.WrappedValueProcedure<ComponentName>() { @Override public ComponentName proceed() { return CondomContext.super.startService(intent); }}); if (component != null) mCondom.logIfOutboundPass(TAG, intent, component.getPackageName(), CondomCore.CondomEvent.START_PASS); return component; }
@Override public boolean bindService(final Intent intent, final ServiceConnection conn, final int flags) { final boolean result = mCondom.proceed(OutboundType.BIND_SERVICE, intent, Boolean.FALSE, new CondomCore.WrappedValueProcedure<Boolean>() { @Override public Boolean proceed() { return CondomContext.super.bindService(intent, conn, flags); }}); if (result) mCondom.logIfOutboundPass(TAG, intent, CondomCore.getTargetPackage(intent), CondomCore.CondomEvent.BIND_PASS); return result; }
@Override public PackageInfo getPackageInfo(final String pkg, final int flags) throws NameNotFoundException { final PackageInfo info = mCondom.proceed(OutboundType.GET_PACKAGE_INFO, pkg, null, new CondomCore.WrappedValueProcedureThrows<PackageInfo, NameNotFoundException>() { @Override public PackageInfo proceed() throws NameNotFoundException { return CondomPackageManager.super.getPackageInfo(pkg, flags); } }); if (info == null) throw new NameNotFoundException(pkg); if ((flags & PackageManager.GET_PERMISSIONS) != 0 && ! mCondom.getSpoofPermissions().isEmpty() && mCondom.getPackageName().equals(pkg)) { final List<String> requested_permissions = info.requestedPermissions == null ? new ArrayList<String>() : new ArrayList<>(Arrays.asList(info.requestedPermissions)); final List<String> missing_permissions = new ArrayList<>(mCondom.getSpoofPermissions()); missing_permissions.removeAll(requested_permissions); if (! missing_permissions.isEmpty()) { requested_permissions.addAll(missing_permissions); info.requestedPermissions = requested_permissions.toArray(new String[requested_permissions.size()]); } // Even if all permissions to spoof are already requested, the permission granted state still requires amending. if (SDK_INT >= JELLY_BEAN) { final int[] req_permissions_flags = info.requestedPermissionsFlags == null ? new int[requested_permissions.size()] : Arrays.copyOf(info.requestedPermissionsFlags, requested_permissions.size()); for (int i = 0; i < info.requestedPermissions.length; i++) if (mCondom.shouldSpoofPermission(info.requestedPermissions[i])) req_permissions_flags[i] = PackageInfo.REQUESTED_PERMISSION_GRANTED; info.requestedPermissionsFlags = req_permissions_flags; } } return info; }
switch (method_name) { case "broadcastIntent": // int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String/[23+] String[] requiredPermissions, [18+ int appOp], [23+ Bundle options], boolean serialized, boolean sticky, [16+ int userId]); result = mCondom.proceed(OutboundType.BROADCAST, (Intent) args[1], Integer.MIN_VALUE, new CondomCore.WrappedValueProcedureThrows<Integer, Throwable>() { @Override public Integer proceed() throws Throwable { return (Integer) CondomProcessActivityManager.super.invoke(proxy, method, args); }}); case "bindService": intent = (Intent) args[2]; result = mCondom.proceed(OutboundType.BIND_SERVICE, intent, 0, new CondomCore.WrappedValueProcedureThrows<Integer, Throwable>() { @Override public Integer proceed() throws Throwable { return (Integer) CondomProcessActivityManager.super.invoke(proxy, method, args); case "startService": intent = (Intent) args[1]; final ComponentName component = mCondom.proceed(OutboundType.START_SERVICE, intent, null, new CondomCore.WrappedValueProcedureThrows<ComponentName, Throwable>() { @Override public ComponentName proceed() throws Throwable { return (ComponentName) CondomProcessActivityManager.super.invoke(proxy, method, args); }});
@SuppressLint("CheckResult") void proceedBroadcast(final Intent intent, final CondomCore.WrappedProcedure procedure) { proceed(OutboundType.BROADCAST, intent, null, procedure); }
@Override public ResolveInfo resolveService(final Intent originalIntent, final int flags) { final Intent intent = applyRedirect(originalIntent); final int original_intent_flags = intent.getFlags(); // Intent flags could only filter background receivers, we have to deal with services by ourselves. return mCondom.proceed(OutboundType.QUERY_SERVICES, intent, null, new CondomCore.WrappedValueProcedure<ResolveInfo>() { @Override public ResolveInfo proceed() { if (! mCondom.mExcludeBackgroundServices && mCondom.mOutboundJudge == null) return CondomPackageManager.super.resolveService(intent, flags); // Shortcut for pass-through final List<ResolveInfo> candidates = CondomPackageManager.super.queryIntentServices(intent, flags); final Intent original_intent = intent.setFlags(original_intent_flags); // Restore the intent flags early before getFirstMatch(). return mCondom.filterCandidates(OutboundType.QUERY_SERVICES, original_intent, candidates, TAG, false); }}); }
@CheckResult <T extends Throwable> List<ResolveInfo> proceedQuery( final OutboundType type, final Intent intent, final CondomCore.WrappedValueProcedureThrows<List<ResolveInfo>, T> procedure) throws T { return proceed(type, intent, Collections.<ResolveInfo>emptyList(), new CondomCore.WrappedValueProcedureThrows<List<ResolveInfo>, T>() { @Override public List<ResolveInfo> proceed() throws T { final List<ResolveInfo> candidates = procedure.proceed(); if (mOutboundJudge != null && getTargetPackage(intent) == null) { // Package-targeted intent is already filtered by OutboundJudge in proceed(). final Iterator<ResolveInfo> iterator = candidates.iterator(); while (iterator.hasNext()) { final ResolveInfo candidate = iterator.next(); final String pkg = type == OutboundType.QUERY_SERVICES ? candidate.serviceInfo.packageName : (type == OutboundType.QUERY_RECEIVERS ? candidate.activityInfo.packageName : null); if (pkg != null && shouldBlockRequestTarget(type, intent, pkg)) // Dry-run is checked inside shouldBlockRequestTarget() iterator.remove(); // TODO: Not safe to assume the list returned from PackageManager is modifiable. } } return candidates; }}); }
@Override public boolean bindService(final Intent originalIntent, final ServiceConnection conn, final int flags) { final Intent intent = applyRedirect(originalIntent); final boolean result = mCondom.proceed(OutboundType.BIND_SERVICE, intent, Boolean.FALSE, new CondomCore.WrappedValueProcedure<Boolean>() { @Override public Boolean proceed() { return CondomContext.super.bindService(intent, conn, flags); }}); if (result) mCondom.logIfOutboundPass(TAG, intent, CondomCore.getTargetPackage(intent), CondomCore.CondomEvent.BIND_PASS); return result; }
@Override public ComponentName startService(final Intent originalIntent) { final Intent intent = applyRedirect(originalIntent); final ComponentName component = mCondom.proceed(OutboundType.START_SERVICE, intent, null, new CondomCore.WrappedValueProcedure<ComponentName>() { @Override public ComponentName proceed() { return CondomContext.super.startService(intent); }}); if (component != null) mCondom.logIfOutboundPass(TAG, intent, component.getPackageName(), CondomCore.CondomEvent.START_PASS); return component; }
private Object proceed(final Object proxy, final Method method, final Object[] args) throws Exception { final String method_name = method.getName(); final Intent intent; switch (method_name) { case "broadcastIntent": return mCondom.proceed(OutboundType.BROADCAST, (Intent) args[1], 0/* ActivityManager.BROADCAST_SUCCESS */, new CondomCore.WrappedValueProcedureThrows<Integer, Exception>() { @Override public Integer proceed() throws Exception { return (Integer) CondomProcessActivityManager.super.invoke(proxy, method, args); }}); case "bindService": intent = (Intent) args[2]; final Integer result = mCondom.proceed(OutboundType.BIND_SERVICE, intent, 0, new CondomCore.WrappedValueProcedureThrows<Integer, Exception>() { @Override public Integer proceed() throws Exception { return (Integer) CondomProcessActivityManager.super.invoke(proxy, method, args); }}); // Result: 0 - no match, >0 - succeed, <0 - SecurityException. if (result > 0) mCondom.logIfOutboundPass(FULL_TAG, intent, CondomCore.getTargetPackage(intent), CondomCore.CondomEvent.BIND_PASS); return result; case "startService": intent = (Intent) args[1]; final ComponentName component = mCondom.proceed(OutboundType.START_SERVICE, intent, null, new CondomCore.WrappedValueProcedureThrows<ComponentName, Exception>() { @Override public ComponentName proceed() throws Exception { return (ComponentName) CondomProcessActivityManager.super.invoke(proxy, method, args); }}); if (component != null) mCondom.logIfOutboundPass(FULL_TAG, intent, component.getPackageName(), CondomCore.CondomEvent.START_PASS); return component; case "getContentProvider": final String name = (String) args[1]; if (! mCondom.shouldAllowProvider(mCondom.mBase, name, PackageManager.GET_UNINSTALLED_PACKAGES)) return null; // Actually blocked by IPackageManager.resolveContentProvider() which is called in shouldAllowProvider() above. break; } return super.invoke(proxy, method, args); }