2017-06-28 18:11:05 +03:00
/*
* Copyright ( C ) 2017 Josh Poimboeuf < jpoimboe @ redhat . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# ifndef _CHECK_H
# define _CHECK_H
# include <stdbool.h>
# include "elf.h"
2017-06-28 18:11:07 +03:00
# include "cfi.h"
2017-06-28 18:11:05 +03:00
# include "arch.h"
2017-07-11 18:33:42 +03:00
# include "orc.h"
2017-06-28 18:11:05 +03:00
# include <linux/hashtable.h>
2017-06-28 18:11:07 +03:00
struct insn_state {
struct cfi_reg cfa ;
struct cfi_reg regs [ CFI_NUM_REGS ] ;
int stack_size ;
2017-07-11 18:33:42 +03:00
unsigned char type ;
2017-06-28 18:11:07 +03:00
bool bp_scratch ;
2018-05-18 09:47:12 +03:00
bool drap , end ;
objtool: Track DRAP separately from callee-saved registers
When GCC realigns a function's stack, it sometimes uses %r13 as the DRAP
register, like:
push %r13
lea 0x10(%rsp), %r13
and $0xfffffffffffffff0, %rsp
pushq -0x8(%r13)
push %rbp
mov %rsp, %rbp
push %r13
...
mov -0x8(%rbp),%r13
leaveq
lea -0x10(%r13), %rsp
pop %r13
retq
Since %r13 was pushed onto the stack twice, its two stack locations need
to be stored separately. The first push of %r13 is its original value,
and the second push of %r13 is the caller's stack frame address.
Since %r13 is a callee-saved register, we need to track the stack
location of its original value separately from the DRAP register.
This fixes the following false positive warning:
lib/ubsan.o: warning: objtool: val_to_string.constprop.7()+0x97: leave instruction with modified stack frame
Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: baa41469a7b9 ("objtool: Implement stack validation 2.0")
Link: http://lkml.kernel.org/r/3da23a6d4c5b3c1e21fc2ccc21a73941b97ff20a.1502401017.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-08-11 00:37:26 +03:00
int drap_reg , drap_offset ;
2017-08-29 20:51:03 +03:00
struct cfi_reg vals [ CFI_NUM_REGS ] ;
2017-06-28 18:11:07 +03:00
} ;
2017-06-28 18:11:05 +03:00
struct instruction {
struct list_head list ;
struct hlist_node hash ;
struct section * sec ;
unsigned long offset ;
2017-06-28 18:11:07 +03:00
unsigned int len ;
2017-06-28 18:11:05 +03:00
unsigned char type ;
unsigned long immediate ;
2018-01-12 00:46:24 +03:00
bool alt_group , visited , dead_end , ignore , hint , save , restore , ignore_alts ;
2018-01-16 12:24:06 +03:00
bool retpoline_safe ;
2017-06-28 18:11:05 +03:00
struct symbol * call_dest ;
struct instruction * jump_dest ;
2018-02-08 16:02:32 +03:00
struct instruction * first_jump_src ;
2017-06-28 18:11:05 +03:00
struct list_head alts ;
struct symbol * func ;
2017-06-28 18:11:07 +03:00
struct stack_op stack_op ;
struct insn_state state ;
2017-07-11 18:33:42 +03:00
struct orc_entry orc ;
2017-06-28 18:11:05 +03:00
} ;
struct objtool_file {
struct elf * elf ;
struct list_head insn_list ;
DECLARE_HASHTABLE ( insn_hash , 16 ) ;
2018-09-07 16:12:01 +03:00
struct section * whitelist ;
bool ignore_unreachables , c_file , hints , rodata ;
2017-06-28 18:11:05 +03:00
} ;
2018-01-16 19:16:32 +03:00
int check ( const char * objname , bool orc ) ;
2017-07-11 18:33:42 +03:00
struct instruction * find_insn ( struct objtool_file * file ,
struct section * sec , unsigned long offset ) ;
2017-06-28 18:11:05 +03:00
2017-06-28 18:11:07 +03:00
# define for_each_insn(file, insn) \
list_for_each_entry ( insn , & file - > insn_list , list )
2017-07-11 18:33:42 +03:00
# define sec_for_each_insn(file, sec, insn) \
for ( insn = find_insn ( file , sec , 0 ) ; \
insn & & & insn - > list ! = & file - > insn_list & & \
insn - > sec = = sec ; \
insn = list_next_entry ( insn , list ) )
2017-06-28 18:11:05 +03:00
# endif /* _CHECK_H */