Re: Format-string sanity checks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If you use linearized code instead of the symbol tree. That will
save you a lot of trouble. The best example is sparse.c. Please take
a look at check_call_instruction() and check_memset().

You can add your printk check in similar ways.

Chris

On 10/10/07, Vegard Nossum <vegard.nossum@xxxxxxxxx> wrote:
> Hey,
>
> As part of my project to make printk() in the kernel a bit safer, I've
> written this program using sparse to detect unsafe/unwise uses of
> printk.
>
> Basically, I want all format strings of printk() to be literal strings.
>
> This is a very early version. It can probably be written a bit nicer,
> for instance by including it in evaluate_call(), dropping a few of the
> checks (I am not so familiar with sparse, and wanted to be on the safe
> side), and also check all functions marked with the gcc printf attribute
> instead of just "printk". But it works for my purposes.
>
> This code is under the same license as sparse itself.
>
> Kind regards,
> Vegard
>
>
>
> /* Copyright (C) 2007  Vegard Nossum <vegard.nossum@xxxxxxxxx> */
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> #include "lib.h"
> #include "allocate.h"
> #include "token.h"
> #include "parse.h"
> #include "symbol.h"
> #include "expression.h"
> #include "linearize.h"
>
> static void check_stmt(struct statement *stmt);
> static void check_stmts(struct statement_list *stmts);
> static void check_sym(struct symbol *sym);
> static void check_syms(struct symbol_list *syms);
> static void check_expr(struct expression *expr);
> static void check_exprs(struct expression_list *exprs);
>
> static void
> check_printk(struct position pos, struct expression *expr)
> {
>         struct expression_list *args = expr->args;
>         struct expression *format;
>         struct symbol *symbol;
>         struct symbol *base;
>         struct expression *initializer;
>         struct string *string;
>         unsigned int i;
>
>         format = first_ptr_list(args);
>         if(!format) {
>                 warning(pos, "function call has no arguments");
>                 return;
>         }
>
>         if(format->type != EXPR_SYMBOL) {
>                 warning(pos, "format string has wrong type");
>                 return;
>         }
>
>         if(format->symbol_name) {
>                 warning(pos, "format string is a named symbol");
>                 return;
>         }
>
>         symbol = format->symbol;
>         if(symbol->namespace == NS_SYMBOL) {
>                 warning(pos, "format string is not a string literal");
>                 return;
>         }
>
>         if(!symbol->string) {
>                 warning(pos, "format string is not a string");
>                 return;
>         }
>
>         base = symbol->ctype.base_type;
>         if(base->type != SYM_ARRAY) {
>                 warning(pos, "format string is not an array");
>                 return;
>         }
>
>         initializer = symbol->initializer;
>         if(!initializer) {
>                 warning(pos, "format string does not have an initializer");
>                 return;
>         }
>
>         if(initializer->type != EXPR_STRING) {
>                 warning(pos, "format string is not a string literal");
>                 return;
>         }
>
>         string = initializer->string;
>         for(i = 0; i < string->length; ++i) {
>                 if(string->data[i] == '\n'
>                         && i != string->length - 2)
>                 {
>                         warning(pos, "format string contains newline");
>                         return;
>                 }
>         }
> }
>
> static void
> check_expr(struct expression *expr)
> {
>         if(!expr)
>                 return;
>
>         /* XXX: This needs some work... Maybe use evaluate? */
>         switch(expr->type) {
>         case EXPR_VALUE:
>         case EXPR_FVALUE:
>         case EXPR_STRING:
>                 break;
>         case EXPR_SYMBOL:
>         case EXPR_TYPE:
>                 //check_sym(expr->symbol);
>                 break;
>         case EXPR_BINOP:
>         case EXPR_ASSIGNMENT:
>         case EXPR_LOGICAL:
>         case EXPR_COMMA:
>         case EXPR_COMPARE:
>                 check_expr(expr->left);
>                 check_expr(expr->right);
>                 break;
>         case EXPR_DEREF:
>                 check_expr(expr->deref);
>                 break;
>         case EXPR_PREOP:
>         case EXPR_POSTOP:
>                 check_expr(expr->unop);
>                 break;
>         case EXPR_CAST:
>         case EXPR_FORCE_CAST:
>         case EXPR_IMPLIED_CAST:
>                 /* XXX: Hmm? */
>                 check_expr(expr->cast_expression);
>                 break;
>         case EXPR_SIZEOF:
>                 break;
>         case EXPR_ALIGNOF:
>                 break;
>         case EXPR_PTRSIZEOF:
>                 break;
>         case EXPR_CONDITIONAL:
>         case EXPR_SELECT:
>                 check_expr(expr->conditional);
>                 check_expr(expr->cond_true);
>                 check_expr(expr->cond_false);
>                 break;
>         case EXPR_STATEMENT:
>                 check_stmt(expr->statement);
>                 break;
>         case EXPR_CALL:
>                 check_expr(expr->fn);
>                 check_exprs(expr->args);
>                 break;
>         case EXPR_LABEL:
>                 //check_sym(expr->label_symbol);
>                 break;
>         case EXPR_INITIALIZER:
>                 check_exprs(expr->expr_list);
>                 break;
>         case EXPR_IDENTIFIER:
>                 check_expr(expr->ident_expression);
>                 break;
>         case EXPR_INDEX:
>                 check_expr(expr->idx_expression);
>                 break;
>         case EXPR_POS:
>                 check_expr(expr->init_expr);
>                 break;
>         case EXPR_SLICE:
>                 check_expr(expr->base);
>                 break;
>         case EXPR_OFFSETOF:
>                 check_expr(expr->down);
>                 break;
>         }
>
>         if(expr->type == EXPR_CALL) {
>                 struct expression *fn = expr->fn;
>
>                 if(fn->type == EXPR_PREOP)
>                         fn = fn->unop;
>
>                 if(fn->type == EXPR_SYMBOL) {
>                         if(!strcmp(fn->symbol_name->name, "printk"))
>                                 check_printk(fn->pos, expr);
>                 } else {
> #if 0
>                         printf("%d: Function in call expression has "
>                                 "unhandled type %d\n",
>                                 fn->pos.line,
>                                 fn->type);
> #endif
>                 }
>         }
> }
>
> static void
> check_exprs(struct expression_list *exprs)
> {
>         struct expression *expr;
>
>         if(!exprs)
>                 return;
>
>         FOR_EACH_PTR(exprs, expr) {
>                 check_expr(expr);
>         } END_FOR_EACH_PTR(expr);
> }
>
> static void
> check_stmt(struct statement *stmt)
> {
>         if(!stmt)
>                 return;
>
>         switch(stmt->type) {
>         case STMT_NONE:
>                 break;
>         case STMT_DECLARATION:
>                 break;
>         case STMT_EXPRESSION:
>                 check_expr(stmt->expression);
>                 break;
>         case STMT_COMPOUND:
>                 check_stmts(stmt->stmts);
>                 break;
>         case STMT_IF:
>                 check_expr(stmt->if_conditional);
>                 check_stmt(stmt->if_true);
>                 check_stmt(stmt->if_false);
>                 break;
>         case STMT_RETURN:
>                 check_expr(stmt->ret_value);
>                 break;
>         case STMT_CASE:
>                 check_expr(stmt->case_expression);
>                 break;
>         case STMT_SWITCH:
>                 check_expr(stmt->switch_expression);
>                 check_stmt(stmt->switch_statement);
>                 break;
>         case STMT_ITERATOR:
>                 check_stmt(stmt->iterator_pre_statement);
>                 check_expr(stmt->iterator_pre_condition);
>                 check_stmt(stmt->iterator_statement);
>                 check_stmt(stmt->iterator_post_statement);
>                 check_expr(stmt->iterator_post_condition);
>                 break;
>         case STMT_LABEL:
>                 break;
>         case STMT_GOTO:
>                 check_expr(stmt->goto_expression);
>                 break;
>         case STMT_ASM:
>                 check_expr(stmt->asm_string);
>                 check_exprs(stmt->asm_outputs);
>                 check_exprs(stmt->asm_inputs);
>                 check_exprs(stmt->asm_clobbers);
>                 break;
>         case STMT_CONTEXT:
>                 break;
>         case STMT_RANGE:
>                 check_expr(stmt->range_expression);
>                 check_expr(stmt->range_low);
>                 check_expr(stmt->range_high);
>                 break;
>         }
> }
>
> static void
> check_stmts(struct statement_list *stmts)
> {
>         struct statement *stmt;
>
>         if(!stmts)
>                 return;
>
>         FOR_EACH_PTR(stmts, stmt) {
>                 check_stmt(stmt);
>         } END_FOR_EACH_PTR(stmt);
> }
>
> static void
> check_sym(struct symbol *sym)
> {
>         if(sym->ctype.base_type)
>                 sym = sym->ctype.base_type;
>
>         if(sym->type == SYM_FN)
>                 check_stmt(sym->stmt);
> }
>
> static void
> check_syms(struct symbol_list *syms)
> {
>         struct symbol *sym;
>
>         FOR_EACH_PTR_NOTAG(syms, sym) {
>                 check_sym(sym);
>         } END_FOR_EACH_PTR_NOTAG(sym);
> }
>
> int
> main(int argc, char *argv[])
> {
>         struct string_list *files = NULL;
>         char *file;
>
>         sparse_initialize(argc, argv, &files);
>
>         FOR_EACH_PTR_NOTAG(files, file) {
>                 check_syms(sparse(file));
>         } END_FOR_EACH_PTR_NOTAG(file);
>
>         return 0;
> }
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
-
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux