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 <stdlib.h> 19 #include "parse.h" 20 #include "smatch.h" 21 #include "smatch_slist.h" 22 #include "smatch_extra.h" 23 24 struct limiter { 25 int buf_arg; 26 int limit_arg; 27 }; 28 static struct limiter b0_l2 = {0, 2}; 29 static struct limiter b1_l2 = {1, 2}; 30 31 struct string_list *ignored_structs; 32 33 static int get_the_max(struct expression *expr, sval_t *sval) 34 { 35 struct range_list *rl; 36 37 if (get_hard_max(expr, sval)) 38 return 1; 39 if (!option_spammy) 40 return 0; 41 if (get_fuzzy_max(expr, sval)) 42 return 1; 43 if (!get_user_rl(expr, &rl)) 44 return 0; 45 *sval = rl_max(rl); 46 return 1; 47 } 48 49 static int bytes_to_end_of_struct(struct expression *expr) 50 { 51 struct expression *deref; 52 struct symbol *type; 53 int struct_bytes; 54 int offset; 55 56 if (expr->type == EXPR_PREOP && expr->op == '&') 57 expr = strip_parens(expr->unop); 58 else { 59 type = get_type(expr); 60 if (!type || type->type != SYM_ARRAY) 61 return 0; 62 } 63 if (expr->type != EXPR_DEREF || !expr->member) 64 return 0; 65 deref = expr->deref; 66 if (deref->type == EXPR_PREOP && deref->op == '*') 67 deref = deref->unop; 68 struct_bytes = get_array_size_bytes_max(deref); 69 if (struct_bytes <= 0) { 70 type = get_type(expr->deref); 71 struct_bytes = type_bytes(type); 72 } 73 offset = get_member_offset_from_deref(expr); 74 if (offset <= 0) 75 return 0; 76 return struct_bytes - expr->member_offset; 77 } 78 79 static int size_of_union(struct expression *expr) 80 { 81 struct symbol *type; 82 83 if (expr->type != EXPR_PREOP || expr->op != '&') 84 return 0; 85 expr = strip_parens(expr->unop); 86 if (expr->type != EXPR_DEREF || !expr->member) 87 return 0; 88 expr = expr->unop; 89 type = get_type(expr); 90 if (!type || type->type != SYM_UNION) 91 return 0; 92 return type_bytes(type); 93 } 94 95 static int is_likely_multiple(int has, int needed, struct expression *limit) 96 { 97 sval_t mult; 98 99 limit = strip_parens(limit); 100 if (limit->type != EXPR_BINOP || limit->op != '*') 101 return 0; 102 if (!get_value(limit->left, &mult)) 103 return 0; 104 if (has * mult.value == needed) 105 return 1; 106 if (!get_value(limit->right, &mult)) 107 return 0; 108 if (has * mult.value == needed) 109 return 1; 110 111 return 0; 112 } 113 114 static int name_in_union(struct symbol *type, const char *name) 115 { 116 struct symbol *tmp; 117 118 if (type->type == SYM_NODE) 119 type = get_real_base_type(type); 120 if (!type || type->type != SYM_UNION) 121 return 0; 122 123 FOR_EACH_PTR(type->symbol_list, tmp) { 124 if (tmp->ident && 125 strcmp(name, tmp->ident->name) == 0) 126 return 1; 127 } END_FOR_EACH_PTR(tmp); 128 129 return 0; 130 } 131 132 static int ends_on_struct_member_boundary(struct expression *expr, int needed) 133 { 134 struct symbol *type, *tmp; 135 int offset; 136 int size; 137 int found = 0; 138 139 expr = strip_expr(expr); 140 if (expr->type == EXPR_PREOP && expr->op == '&') { 141 expr = strip_parens(expr->unop); 142 } else { 143 type = get_type(expr); 144 if (!type || type->type != SYM_ARRAY) 145 return 0; 146 } 147 if (expr->type != EXPR_DEREF || !expr->member) 148 return 0; 149 150 type = get_type(expr->unop); 151 if (!type) 152 return 0; 153 if (type->type == SYM_UNION) { 154 struct expression *unop = strip_expr(expr->unop); 155 156 if (unop->type != EXPR_DEREF) 157 return 0; 158 type = get_type(unop->unop); 159 if (!type) 160 return 0; 161 } 162 if (type->type != SYM_STRUCT) 163 return 0; 164 165 offset = 0; 166 FOR_EACH_PTR(type->symbol_list, tmp) { 167 if (!found) { 168 if ((tmp->ident && 169 strcmp(expr->member->name, tmp->ident->name) == 0) || 170 name_in_union(tmp, expr->member->name)) 171 found = 1; 172 173 offset = ALIGN(offset, tmp->ctype.alignment); 174 175 offset += type_bytes(tmp); 176 size = type_bytes(tmp); 177 continue; 178 } 179 180 /* if there is a hole then fail. */ 181 if (offset != ALIGN(offset, tmp->ctype.alignment)) 182 return 0; 183 offset += type_bytes(tmp); 184 size += type_bytes(tmp); 185 186 if (size == needed) 187 return 1; 188 if (size > needed) 189 return 0; 190 } END_FOR_EACH_PTR(tmp); 191 return 0; 192 } 193 194 static int is_one_element_array(struct expression *expr) 195 { 196 struct symbol *type; 197 sval_t sval; 198 199 if (expr->type == EXPR_PREOP && expr->op == '&') 200 expr = expr->unop; 201 if (expr->type == EXPR_BINOP) /* array elements foo[5] */ 202 return 0; 203 204 type = get_type(expr); 205 if (!type) 206 return 0; 207 if (!type || type->type != SYM_ARRAY) 208 return 0; 209 210 if (!get_implied_value(type->array_size, &sval)) 211 return 0; 212 213 if (sval.value == 1) 214 return 1; 215 return 0; 216 } 217 218 static int is_ignored_struct(struct expression *expr) 219 { 220 struct symbol *type; 221 222 type = get_type(expr); 223 if (!type) 224 return 0; 225 if (type->type == SYM_PTR) 226 type = get_real_base_type(type); 227 if (type->type != SYM_STRUCT) 228 return 0; 229 if (!type->ident) 230 return 0; 231 if (list_has_string(ignored_structs, type->ident->name)) 232 return 1; 233 return 0; 234 } 235 236 static void match_limited(const char *fn, struct expression *expr, void *_limiter) 237 { 238 struct limiter *limiter = (struct limiter *)_limiter; 239 struct expression *dest; 240 struct expression *limit; 241 char *dest_name = NULL; 242 sval_t needed; 243 int has; 244 245 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg); 246 limit = get_argument_from_call_expr(expr->args, limiter->limit_arg); 247 if (!get_the_max(limit, &needed)) 248 return; 249 has = get_array_size_bytes_max(dest); 250 if (!has) 251 return; 252 if (has >= needed.value) 253 return; 254 255 if (needed.value == bytes_to_end_of_struct(dest)) 256 return; 257 258 if (needed.value <= size_of_union(dest)) 259 return; 260 261 if (is_likely_multiple(has, needed.value, limit)) 262 return; 263 264 if (ends_on_struct_member_boundary(dest, needed.value)) 265 return; 266 267 if (is_one_element_array(dest)) 268 return; 269 270 if (is_ignored_struct(dest)) 271 return; 272 273 dest_name = expr_to_str(dest); 274 sm_error("%s() '%s' too small (%d vs %s)", fn, dest_name, has, sval_to_str(needed)); 275 free_string(dest_name); 276 } 277 278 static void register_funcs_from_file(void) 279 { 280 char name[256]; 281 struct token *token; 282 const char *func; 283 int size, buf; 284 struct limiter *limiter; 285 286 snprintf(name, 256, "%s.sizeof_param", option_project_str); 287 name[255] = '\0'; 288 token = get_tokens_file(name); 289 if (!token) 290 return; 291 if (token_type(token) != TOKEN_STREAMBEGIN) 292 return; 293 token = token->next; 294 while (token_type(token) != TOKEN_STREAMEND) { 295 if (token_type(token) != TOKEN_IDENT) 296 break; 297 func = show_ident(token->ident); 298 299 token = token->next; 300 if (token_type(token) != TOKEN_NUMBER) 301 break; 302 size = atoi(token->number); 303 304 token = token->next; 305 if (token_type(token) == TOKEN_SPECIAL) { 306 if (token->special != '-') 307 break; 308 token = token->next; 309 if (token_type(token) != TOKEN_NUMBER) 310 break; 311 token = token->next; 312 continue; 313 314 } 315 if (token_type(token) != TOKEN_NUMBER) 316 break; 317 buf = atoi(token->number); 318 319 limiter = malloc(sizeof(*limiter)); 320 limiter->limit_arg = size; 321 limiter->buf_arg = buf; 322 323 add_function_hook(func, &match_limited, limiter); 324 325 token = token->next; 326 } 327 if (token_type(token) != TOKEN_STREAMEND) 328 sm_perror("parsing '%s'", name); 329 clear_token_alloc(); 330 } 331 332 static void register_ignored_structs_from_file(void) 333 { 334 char name[256]; 335 struct token *token; 336 const char *struct_type; 337 338 snprintf(name, 256, "%s.ignore_memcpy_struct_overflows", option_project_str); 339 name[255] = '\0'; 340 token = get_tokens_file(name); 341 if (!token) 342 return; 343 if (token_type(token) != TOKEN_STREAMBEGIN) 344 return; 345 token = token->next; 346 while (token_type(token) != TOKEN_STREAMEND) { 347 if (token_type(token) != TOKEN_IDENT) 348 return; 349 350 struct_type = show_ident(token->ident); 351 insert_string(&ignored_structs, alloc_string(struct_type)); 352 353 token = token->next; 354 } 355 clear_token_alloc(); 356 } 357 358 void check_memcpy_overflow(int id) 359 { 360 register_funcs_from_file(); 361 register_ignored_structs_from_file(); 362 add_function_hook("memcmp", &match_limited, &b0_l2); 363 add_function_hook("memcmp", &match_limited, &b1_l2); 364 if (option_project == PROJ_KERNEL) { 365 add_function_hook("copy_to_user", &match_limited, &b1_l2); 366 add_function_hook("_copy_to_user", &match_limited, &b1_l2); 367 add_function_hook("__copy_to_user", &match_limited, &b1_l2); 368 add_function_hook("copy_from_user", &match_limited, &b0_l2); 369 add_function_hook("_copy_from_user", &match_limited, &b0_l2); 370 add_function_hook("__copy_from_user", &match_limited, &b0_l2); 371 } 372 } 373