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 }