/* * Copyright (C) 2012 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.tools.lint.checks; import static com.android.SdkConstants.ANDROID_MANIFEST_XML; import static com.android.SdkConstants.ANDROID_URI; import static com.android.SdkConstants.ATTR_NAME; import static com.android.SdkConstants.TAG_USES_PERMISSION; import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Implementation; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.Scope; import com.android.tools.lint.detector.api.Severity; import com.android.tools.lint.detector.api.Speed; import com.android.tools.lint.detector.api.XmlContext; import org.w3c.dom.Attr; import org.w3c.dom.Element; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; /** * Checks if an application wants to use permissions that can only be used by * system applications. */ public class SystemPermissionsDetector extends Detector implements Detector.XmlScanner { /** The main issue discovered by this detector */ public static final Issue ISSUE = Issue.create( "ProtectedPermissions", //$NON-NLS-1$ "Using system app permission", "Permissions with the protection level signature or signatureOrSystem are only " + "granted to system apps. If an app is a regular non-system app, it will never be " + "able to use these permissions.", Category.CORRECTNESS, 5, Severity.ERROR, new Implementation( SystemPermissionsDetector.class, EnumSet.of(Scope.MANIFEST))); // List of permissions have the protection levels signature or systemOrSignature. // This list must be sorted alphabetically. private static final String[] SYSTEM_PERMISSIONS = new String[] { "android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE", "android.permission.ACCESS_CACHE_FILESYSTEM", "android.permission.ACCESS_CHECKIN_PROPERTIES", "android.permission.ACCESS_MTP", "android.permission.ACCESS_SURFACE_FLINGER", "android.permission.ACCOUNT_MANAGER", "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK", "android.permission.ASEC_ACCESS", "android.permission.ASEC_CREATE", "android.permission.ASEC_DESTROY", "android.permission.ASEC_MOUNT_UNMOUNT", "android.permission.ASEC_RENAME", "android.permission.BACKUP", "android.permission.BIND_APPWIDGET", "android.permission.BIND_DEVICE_ADMIN", "android.permission.BIND_INPUT_METHOD", "android.permission.BIND_PACKAGE_VERIFIER", "android.permission.BIND_REMOTEVIEWS", "android.permission.BIND_TEXT_SERVICE", "android.permission.BIND_VPN_SERVICE", "android.permission.BIND_WALLPAPER", "android.permission.BRICK", "android.permission.BROADCAST_PACKAGE_REMOVED", "android.permission.BROADCAST_SMS", "android.permission.BROADCAST_WAP_PUSH", "android.permission.CALL_PRIVILEGED", "android.permission.CHANGE_BACKGROUND_DATA_SETTING", "android.permission.CHANGE_COMPONENT_ENABLED_STATE", "android.permission.CLEAR_APP_USER_DATA", "android.permission.CONFIRM_FULL_BACKUP", "android.permission.CONNECTIVITY_INTERNAL", "android.permission.CONTROL_LOCATION_UPDATES", "android.permission.COPY_PROTECTED_DATA", "android.permission.CRYPT_KEEPER", "android.permission.DELETE_CACHE_FILES", "android.permission.DELETE_PACKAGES", "android.permission.DEVICE_POWER", "android.permission.DIAGNOSTIC", "android.permission.DUMP", "android.permission.FACTORY_TEST", "android.permission.FORCE_BACK", "android.permission.FORCE_STOP_PACKAGES", "android.permission.GLOBAL_SEARCH", "android.permission.GLOBAL_SEARCH_CONTROL", "android.permission.HARDWARE_TEST", "android.permission.INJECT_EVENTS", "android.permission.INSTALL_LOCATION_PROVIDER", "android.permission.INSTALL_PACKAGES", "android.permission.INTERNAL_SYSTEM_WINDOW", "android.permission.MANAGE_APP_TOKENS", "android.permission.MANAGE_NETWORK_POLICY", "android.permission.MANAGE_USB", "android.permission.MASTER_CLEAR", "android.permission.MODIFY_NETWORK_ACCOUNTING", "android.permission.MODIFY_PHONE_STATE", "android.permission.MOVE_PACKAGE", "android.permission.NET_ADMIN", "android.permission.MODIFY_PHONE_STATE", "android.permission.PACKAGE_USAGE_STATS", "android.permission.PACKAGE_VERIFICATION_AGENT", "android.permission.PERFORM_CDMA_PROVISIONING", "android.permission.READ_FRAME_BUFFER", "android.permission.READ_INPUT_STATE", "android.permission.READ_NETWORK_USAGE_HISTORY", "android.permission.READ_PRIVILEGED_PHONE_STATE", "android.permission.REBOOT", "android.permission.RECEIVE_EMERGENCY_BROADCAST", "android.permission.REMOVE_TASKS", "android.permission.RETRIEVE_WINDOW_CONTENT", "android.permission.SEND_SMS_NO_CONFIRMATION", "android.permission.SET_ACTIVITY_WATCHER", "android.permission.SET_ORIENTATION", "android.permission.SET_POINTER_SPEED", "android.permission.SET_PREFERRED_APPLICATIONS", "android.permission.SET_SCREEN_COMPATIBILITY", "android.permission.SET_TIME", "android.permission.SET_WALLPAPER_COMPONENT", "android.permission.SHUTDOWN", "android.permission.STATUS_BAR", "android.permission.STATUS_BAR_SERVICE", "android.permission.STOP_APP_SWITCHES", "android.permission.UPDATE_DEVICE_STATS", "android.permission.WRITE_APN_SETTINGS", "android.permission.WRITE_GSERVICES", "android.permission.WRITE_MEDIA_STORAGE", "android.permission.WRITE_SECURE_SETTINGS" }; /** Constructs a new {@link SystemPermissionsDetector} check */ public SystemPermissionsDetector() { } @NonNull @Override public Speed getSpeed() { return Speed.FAST; } @Override public boolean appliesTo(@NonNull Context context, @NonNull File file) { return file.getName().equals(ANDROID_MANIFEST_XML); } // ---- Implements Detector.XmlScanner ---- @Override public Collection<String> getApplicableElements() { return Collections.singletonList(TAG_USES_PERMISSION); } @Override public void visitElement(@NonNull XmlContext context, @NonNull Element element) { Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); if (nameNode != null) { String permissionName = nameNode.getValue(); if (Arrays.binarySearch(SYSTEM_PERMISSIONS, permissionName) >= 0) { context.report(ISSUE, element, context.getLocation(nameNode), "Permission is only granted to system apps"); } } } }