1/*
2 * Copyright (C) 2014 Oracle.
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/*
19 * Looks for integers that we get from the user which can be attacked
20 * with an integer overflow.
21 *
22 */
23
24#include "smatch.h"
25#include "smatch_slist.h"
26
27static int my_id;
28
29static void match_condition(struct expression *expr)
30{
31	struct expression *left, *right;
32	struct symbol *type;
33	char *right_name;
34	char *left_name;
35
36	if (expr->type != EXPR_COMPARE)
37		return;
38	if (expr->op != '<')
39		return;
40
41	type = get_type(expr);
42	if (!type_signed(type))
43		return;
44
45	left = strip_expr(expr->left);
46	right = strip_expr(expr->right);
47
48	if (left->type != EXPR_BINOP) {
49		left = get_assigned_expr(left);
50		left = strip_expr(left);
51		if (!left || left->type != EXPR_BINOP)
52			return;
53	}
54
55	if (left->op != '+' && left->op != '*' && left->op != SPECIAL_LEFTSHIFT)
56		return;
57
58	if (has_variable(left, right) == 1) {
59		left_name = expr_to_str(left);
60		right_name = expr_to_str(right);
61		sm_warning("signed overflow undefined. '%s %s %s'", left_name, show_special(expr->op), right_name);
62		free_string(left_name);
63		free_string(right_name);
64	}
65}
66
67static void match_binop(struct expression *expr)
68{
69	sval_t left_val, right_min;
70	char *str;
71
72	if (expr->op != '-')
73		return;
74
75	if (!get_value(expr->left, &left_val))
76		return;
77
78	switch (left_val.uvalue) {
79	case SHRT_MAX:
80	case USHRT_MAX:
81	case INT_MAX:
82	case UINT_MAX:
83	case LLONG_MAX:
84	case ULLONG_MAX:
85		break;
86	default:
87		return;
88	}
89
90	get_absolute_min(expr->right, &right_min);
91	if (!sval_is_negative(right_min))
92		return;
93
94	str = expr_to_str(expr);
95	sm_warning("potential negative subtraction from max '%s'", str);
96	free_string(str);
97}
98
99void check_signed_integer_overflow_check(int id)
100{
101	my_id = id;
102
103	if (option_project == PROJ_KERNEL) {
104		/* The kernel uses -fno-strict-overflow so it's fine */
105		return;
106	}
107
108	add_hook(&match_condition, CONDITION_HOOK);
109	add_hook(&match_binop, BINOP_HOOK);
110}
111
112