1 /* 2 * Copyright (C) 2010 Dan Carpenter. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 16 */ 17 18 #include "smatch.h" 19 20 static int my_id; 21 22 static int can_overflow(struct expression *expr) 23 { 24 sval_t max; 25 int uncapped = 0; 26 27 expr = strip_expr(expr); 28 29 if (expr->type == EXPR_BINOP) { 30 uncapped += can_overflow(expr->left); 31 uncapped += can_overflow(expr->right); 32 33 if (uncapped && 34 (expr->op == '+' || expr->op == '*' || expr->op == SPECIAL_LEFTSHIFT)) 35 return 1; 36 37 return 0; 38 } 39 40 if (get_implied_max(expr, &max)) 41 return 0; 42 if (get_absolute_max(expr, &max) && sval_cmp_val(max, 4096) <= 0) 43 return 0; 44 return 1; 45 } 46 47 static void match_size(struct expression *size_expr) 48 { 49 char *name; 50 51 size_expr = strip_expr(size_expr); 52 if (!size_expr) 53 return; 54 if (size_expr->type != EXPR_BINOP) { 55 size_expr = get_assigned_expr(size_expr); 56 if (!size_expr || size_expr->type != EXPR_BINOP) 57 return; 58 } 59 if (!can_overflow(size_expr)) 60 return; 61 62 name = expr_to_str(size_expr); 63 sm_warning("math in access_ok() is dangerous '%s'", name); 64 65 free_string(name); 66 } 67 68 static void match_access_ok(const char *fn, struct expression *expr, void *data) 69 { 70 struct expression *size_expr; 71 72 size_expr = get_argument_from_call_expr(expr->args, 1); 73 match_size(size_expr); 74 } 75 76 static void split_asm_constraints(struct expression_list *expr_list) 77 { 78 struct expression *expr; 79 int i; 80 81 i = 0; 82 FOR_EACH_PTR(expr_list, expr) { 83 i++; 84 if (expr->type != EXPR_ASM_OPERAND) 85 continue; 86 if (i == 1) 87 match_size(expr->expr); 88 } END_FOR_EACH_PTR(expr); 89 } 90 91 static void match_asm_stmt(struct statement *stmt) 92 { 93 char *name; 94 95 name = get_macro_name(stmt->pos); 96 if (!name || strcmp(name, "access_ok") != 0) 97 return; 98 split_asm_constraints(stmt->asm_inputs); 99 } 100 101 void check_access_ok_math(int id) 102 { 103 my_id = id; 104 if (option_project != PROJ_KERNEL) 105 return; 106 if (!option_spammy) 107 return; 108 add_function_hook("__access_ok", &match_access_ok, NULL); 109 add_hook(&match_asm_stmt, ASM_HOOK); 110 } 111