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);
}
}
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;
}
}
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);
}
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);
}
}
}
*/
}
}
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;
}
}
}
Aggregations