Search in sources :

Example 16 with Location

use of com.android.tools.klint.detector.api.Location in project kotlin by JetBrains.

the class UnsafeBroadcastReceiverDetector method checkOnReceive.

private static void checkOnReceive(@NonNull JavaContext context, @NonNull PsiMethod method) {
    // Search for call to getAction but also search for references to aload_2,
    // which indicates that the method is making use of the received intent in
    // some way.
    //
    // If the onReceive method doesn't call getAction but does make use of
    // the received intent, it is possible that it is passing it to another
    // method that might be performing the getAction check, so we warn that the
    // finding may be a false positive. (An alternative option would be to not
    // report a finding at all in this case.)
    PsiParameter parameter = method.getParameterList().getParameters()[1];
    OnReceiveVisitor visitor = new OnReceiveVisitor(context.getEvaluator(), parameter);
    context.getUastContext().getMethodBody(method).accept(visitor);
    if (!visitor.getCallsGetAction()) {
        String report;
        if (!visitor.getUsesIntent()) {
            report = "This broadcast receiver declares an intent-filter for a protected " + "broadcast action string, which can only be sent by the system, " + "not third-party applications. However, the receiver's onReceive " + "method does not appear to call getAction to ensure that the " + "received Intent's action string matches the expected value, " + "potentially making it possible for another actor to send a " + "spoofed intent with no action string or a different action " + "string and cause undesired behavior.";
        } else {
            // An alternative implementation option is to not report a finding at all in
            // this case, if we are worried about false positives causing confusion or
            // resulting in developers ignoring other lint warnings.
            report = "This broadcast receiver declares an intent-filter for a protected " + "broadcast action string, which can only be sent by the system, " + "not third-party applications. However, the receiver's onReceive " + "method does not appear to call getAction to ensure that the " + "received Intent's action string matches the expected value, " + "potentially making it possible for another actor to send a " + "spoofed intent with no action string or a different action " + "string and cause undesired behavior. In this case, it is " + "possible that the onReceive method passed the received Intent " + "to another method that checked the action string. If so, this " + "finding can safely be ignored.";
        }
        Location location = context.getNameLocation(method);
        context.report(ACTION_STRING, method, location, report);
    }
}
Also used : PsiParameter(com.intellij.psi.PsiParameter) Location(com.android.tools.klint.detector.api.Location)

Example 17 with Location

use of com.android.tools.klint.detector.api.Location in project kotlin by JetBrains.

the class StringFormatDetector method checkArity.

/**
     * Check that the number of arguments in the format string is consistent
     * across translations, and that all arguments are used
     */
private static void checkArity(Context context, String name, List<Pair<Handle, String>> list) {
    // Check to make sure that the argument counts and types are consistent
    int prevCount = -1;
    for (Pair<Handle, String> pair : list) {
        Set<Integer> indices = new HashSet<Integer>();
        int count = getFormatArgumentCount(pair.getSecond(), indices);
        Handle handle = pair.getFirst();
        if (prevCount != -1 && prevCount != count) {
            Object clientData = handle.getClientData();
            if (clientData instanceof Node) {
                if (context.getDriver().isSuppressed(null, ARG_COUNT, (Node) clientData)) {
                    return;
                }
            }
            Location location = handle.resolve();
            Location secondary = list.get(0).getFirst().resolve();
            secondary.setMessage("Conflicting number of arguments here");
            location.setSecondary(secondary);
            String message = String.format("Inconsistent number of arguments in formatting string `%1$s`; " + "found both %2$d and %3$d", name, prevCount, count);
            context.report(ARG_COUNT, location, message);
            break;
        }
        for (int i = 1; i <= count; i++) {
            if (!indices.contains(i)) {
                Object clientData = handle.getClientData();
                if (clientData instanceof Node) {
                    if (context.getDriver().isSuppressed(null, ARG_COUNT, (Node) clientData)) {
                        return;
                    }
                }
                Set<Integer> all = new HashSet<Integer>();
                for (int j = 1; j < count; j++) {
                    all.add(j);
                }
                all.removeAll(indices);
                List<Integer> sorted = new ArrayList<Integer>(all);
                Collections.sort(sorted);
                Location location = handle.resolve();
                String message = String.format("Formatting string '`%1$s`' is not referencing numbered arguments %2$s", name, sorted);
                context.report(ARG_COUNT, location, message);
                break;
            }
        }
        prevCount = count;
    }
}
Also used : Node(org.w3c.dom.Node) ArrayList(java.util.ArrayList) Handle(com.android.tools.klint.detector.api.Location.Handle) HashSet(java.util.HashSet) Location(com.android.tools.klint.detector.api.Location)

Example 18 with Location

use of com.android.tools.klint.detector.api.Location in project kotlin by JetBrains.

the class StringFormatDetector method checkNotFormattedHandle.

/**
     * Checks a String.format call that is using a string that doesn't contain format placeholders.
     * @param context the context to report errors to
     * @param call the AST node for the {@link String#format}
     * @param name the string name
     * @param handle the string location
     */
private static void checkNotFormattedHandle(JavaContext context, UCallExpression call, String name, Handle handle) {
    Object clientData = handle.getClientData();
    if (clientData instanceof Node) {
        if (context.getDriver().isSuppressed(null, INVALID, (Node) clientData)) {
            return;
        }
    }
    Location location = context.getUastLocation(call);
    Location secondary = handle.resolve();
    secondary.setMessage("This definition does not require arguments");
    location.setSecondary(secondary);
    String message = String.format("Format string '`%1$s`' is not a valid format string so it should not be " + "passed to `String.format`", name);
    context.report(INVALID, call, location, message);
}
Also used : Node(org.w3c.dom.Node) Location(com.android.tools.klint.detector.api.Location)

Example 19 with Location

use of com.android.tools.klint.detector.api.Location in project kotlin by JetBrains.

the class StringFormatDetector method checkTypes.

private static void checkTypes(Context context, boolean checkValid, boolean checkTypes, String name, List<Pair<Handle, String>> list) {
    Map<Integer, String> types = new HashMap<Integer, String>();
    Map<Integer, Handle> typeDefinition = new HashMap<Integer, Handle>();
    for (Pair<Handle, String> pair : list) {
        Handle handle = pair.getFirst();
        String formatString = pair.getSecond();
        //boolean warned = false;
        Matcher matcher = FORMAT.matcher(formatString);
        int index = 0;
        int prevIndex = 0;
        int nextNumber = 1;
        while (true) {
            if (matcher.find(index)) {
                int matchStart = matcher.start();
                // Make sure this is not an escaped '%'
                for (; prevIndex < matchStart; prevIndex++) {
                    char c = formatString.charAt(prevIndex);
                    if (c == '\\') {
                        prevIndex++;
                    }
                }
                if (prevIndex > matchStart) {
                    // We're in an escape, ignore this result
                    index = prevIndex;
                    continue;
                }
                // Ensure loop proceeds
                index = matcher.end();
                String str = formatString.substring(matchStart, matcher.end());
                if (str.equals("%%") || str.equals("%n")) {
                    // Just an escaped %
                    continue;
                }
                if (checkValid) {
                    // Make sure it's a valid format string
                    if (str.length() > 2 && str.charAt(str.length() - 2) == ' ') {
                        char last = str.charAt(str.length() - 1);
                        // dedicated error message
                        if (last != 'd' && last != 'o' && last != 'x' && last != 'X') {
                            Object clientData = handle.getClientData();
                            if (clientData instanceof Node) {
                                if (context.getDriver().isSuppressed(null, INVALID, (Node) clientData)) {
                                    return;
                                }
                            }
                            Location location = handle.resolve();
                            String message = String.format("Incorrect formatting string `%1$s`; missing conversion " + "character in '`%2$s`' ?", name, str);
                            context.report(INVALID, location, message);
                            //warned = true;
                            continue;
                        }
                    }
                }
                if (!checkTypes) {
                    continue;
                }
                // Shouldn't throw a number format exception since we've already
                // matched the pattern in the regexp
                int number;
                String numberString = matcher.group(1);
                if (numberString != null) {
                    // Strip off trailing $
                    numberString = numberString.substring(0, numberString.length() - 1);
                    number = Integer.parseInt(numberString);
                    nextNumber = number + 1;
                } else {
                    number = nextNumber++;
                }
                String format = matcher.group(6);
                String currentFormat = types.get(number);
                if (currentFormat == null) {
                    types.put(number, format);
                    typeDefinition.put(number, handle);
                } else if (!currentFormat.equals(format) && isIncompatible(currentFormat.charAt(0), format.charAt(0))) {
                    Object clientData = handle.getClientData();
                    if (clientData instanceof Node) {
                        if (context.getDriver().isSuppressed(null, ARG_TYPES, (Node) clientData)) {
                            return;
                        }
                    }
                    Location location = handle.resolve();
                    // Attempt to limit the location range to just the formatting
                    // string in question
                    location = refineLocation(context, location, formatString, matcher.start(), matcher.end());
                    Location otherLocation = typeDefinition.get(number).resolve();
                    otherLocation.setMessage("Conflicting argument type here");
                    location.setSecondary(otherLocation);
                    File f = otherLocation.getFile();
                    String message = String.format("Inconsistent formatting types for argument #%1$d in " + "format string `%2$s` ('%3$s'): Found both '`%4$s`' and '`%5$s`' " + "(in %6$s)", number, name, str, currentFormat, format, f.getParentFile().getName() + File.separator + f.getName());
                    //warned = true;
                    context.report(ARG_TYPES, location, message);
                    break;
                }
            } else {
                break;
            }
        }
    // Check that the format string is valid by actually attempting to instantiate
    // it. We only do this if we haven't already complained about this string
    // for other reasons.
    /* Check disabled for now: it had many false reports due to conversion
             * errors (which is expected since we just pass in strings), but once those
             * are eliminated there aren't really any other valid error messages returned
             * (for example, calling the formatter with bogus formatting flags always just
             * returns a "conversion" error. It looks like we'd need to actually pass compatible
             * arguments to trigger other types of formatting errors such as precision errors.
            if (!warned && checkValid) {
                try {
                    formatter.format(formatString, "", "", "", "", "", "", "",
                            "", "", "", "", "", "", "");

                } catch (IllegalFormatException t) { // TODO: UnknownFormatConversionException
                    if (!t.getLocalizedMessage().contains(" != ")
                            && !t.getLocalizedMessage().contains("Conversion")) {
                        Location location = handle.resolve();
                        context.report(INVALID, location,
                                String.format("Wrong format for %1$s: %2$s",
                                        name, t.getLocalizedMessage()), null);
                    }
                }
            }
            */
    }
}
Also used : HashMap(java.util.HashMap) Matcher(java.util.regex.Matcher) Node(org.w3c.dom.Node) Handle(com.android.tools.klint.detector.api.Location.Handle) File(java.io.File) Location(com.android.tools.klint.detector.api.Location)

Example 20 with Location

use of com.android.tools.klint.detector.api.Location in project kotlin by JetBrains.

the class BadHostnameVerifierDetector method checkClass.

@Override
public void checkClass(@NonNull JavaContext context, @NonNull UClass declaration) {
    JavaEvaluator evaluator = context.getEvaluator();
    for (PsiMethod method : declaration.findMethodsByName("verify", false)) {
        if (evaluator.methodMatches(method, null, false, TYPE_STRING, "javax.net.ssl.SSLSession")) {
            ComplexVisitor visitor = new ComplexVisitor(context);
            declaration.accept(visitor);
            if (visitor.isComplex()) {
                return;
            }
            Location location = context.getNameLocation(method);
            String message = String.format("`%1$s` always returns `true`, which " + "could cause insecure network traffic due to trusting " + "TLS/SSL server certificates for wrong hostnames", method.getName());
            context.report(ISSUE, location, message);
            break;
        }
    }
}
Also used : PsiMethod(com.intellij.psi.PsiMethod) JavaEvaluator(com.android.tools.klint.client.api.JavaEvaluator) Location(com.android.tools.klint.detector.api.Location)

Aggregations

Location (com.android.tools.klint.detector.api.Location)38 UExpression (org.jetbrains.uast.UExpression)8 JavaEvaluator (com.android.tools.klint.client.api.JavaEvaluator)7 File (java.io.File)7 PsiElement (com.intellij.psi.PsiElement)4 PsiMethod (com.intellij.psi.PsiMethod)4 ArrayList (java.util.ArrayList)4 Attr (org.w3c.dom.Attr)4 Node (org.w3c.dom.Node)4 Handle (com.android.tools.klint.detector.api.Location.Handle)3 XmlContext (com.android.tools.klint.detector.api.XmlContext)3 PsiClassType (com.intellij.psi.PsiClassType)3 PsiType (com.intellij.psi.PsiType)3 List (java.util.List)3 UAnonymousClass (org.jetbrains.uast.UAnonymousClass)3 NodeList (org.w3c.dom.NodeList)3 NonNull (com.android.annotations.NonNull)2 ResourceType (com.android.resources.ResourceType)2 ClassContext (com.android.tools.klint.detector.api.ClassContext)2 Context (com.android.tools.klint.detector.api.Context)2