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 com.google.android.lint.aidl 18 19 import com.android.tools.lint.detector.api.Category 20 import com.android.tools.lint.detector.api.Implementation 21 import com.android.tools.lint.detector.api.Incident 22 import com.android.tools.lint.detector.api.Issue 23 import com.android.tools.lint.detector.api.JavaContext 24 import com.android.tools.lint.detector.api.Scope 25 import com.android.tools.lint.detector.api.Severity 26 import org.jetbrains.uast.UBlockExpression 27 import org.jetbrains.uast.UMethod 28 29 /** 30 * Looks for methods implementing generated AIDL interface stubs 31 * that can have simple permission checks migrated to 32 * @EnforcePermission annotations 33 */ 34 @Suppress("UnstableApiUsage") 35 class SimpleManualPermissionEnforcementDetector : AidlImplementationDetector() { 36 override fun visitAidlMethod( 37 context: JavaContext, 38 node: UMethod, 39 interfaceName: String, 40 body: UBlockExpression 41 ) { 42 val enforcePermissionFix = EnforcePermissionFix.fromBlockExpression(context, body) ?: return 43 val lintFix = enforcePermissionFix.toLintFix(context, node) 44 val message = 45 "$interfaceName permission check ${ 46 if (enforcePermissionFix.errorLevel) "should" else "can" 47 } be converted to @EnforcePermission annotation" 48 49 val incident = Incident( 50 ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT, 51 enforcePermissionFix.manualCheckLocations.last(), 52 message, 53 lintFix 54 ) 55 56 // TODO(b/265014041): turn on errors once all code that would cause one is fixed 57 // if (enforcePermissionFix.errorLevel) { 58 // incident.overrideSeverity(Severity.ERROR) 59 // } 60 61 context.report(incident) 62 } 63 64 companion object { 65 66 private val EXPLANATION = """ 67 Whenever possible, method implementations of AIDL interfaces should use the @EnforcePermission 68 annotation to declare the permissions to be enforced. The verification code is then 69 generated by the AIDL compiler, which also takes care of annotating the generated java 70 code. 71 72 This reduces the risk of bugs around these permission checks (that often become vulnerabilities). 73 It also enables easier auditing and review. 74 75 Please migrate to an @EnforcePermission annotation. (See: go/aidl-enforce-howto) 76 """.trimIndent() 77 78 @JvmField 79 val ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT = Issue.create( 80 id = "SimpleManualPermissionEnforcement", 81 briefDescription = "Manual permission check can be @EnforcePermission annotation", 82 explanation = EXPLANATION, 83 category = Category.SECURITY, 84 priority = 5, 85 severity = Severity.WARNING, 86 implementation = Implementation( 87 SimpleManualPermissionEnforcementDetector::class.java, 88 Scope.JAVA_FILE_SCOPE 89 ), 90 ) 91 } 92 } 93