ANDROID: timer: fix timer_setup with CFI

timer_setup casts the callback function to an incompatible type, which
trips CFI for all users of the API:

  CFI failure (target: [<ffffff8da5b6bc88>] nf_ct_frag6_expire+0x0/0x4):
  ...
  Call trace:
    __cfi_check_fail+0x1c/0x24
    ...
    call_timer_fn+0x304/0x308

Note that this only affects 4.14, the timer code was refactored in the
later upstream releases.

Bug: 130800382
Bug: 156058713
Change-Id: If7d706dcbe08ca0001d025606e5d3f3ca1559a7b
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
This commit is contained in:
Sami Tolvanen
2019-04-18 12:44:31 -07:00
committed by Alistair Delva
parent 5bcde4a44d
commit 3045070cf5

View File

@@ -21,6 +21,9 @@ struct timer_list {
unsigned long data;
u32 flags;
#ifdef CONFIG_CFI_CLANG
void (*__function)(struct timer_list *);
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
@@ -172,6 +175,30 @@ static inline void init_timer_on_stack_key(struct timer_list *timer,
#define TIMER_DATA_TYPE unsigned long
#define TIMER_FUNC_TYPE void (*)(TIMER_DATA_TYPE)
#ifdef CONFIG_CFI_CLANG
/*
* With CFI_CLANG, we cannot cast the callback function to TIMER_FUNC_TYPE
* without tripping an indirect call check in call_timer_fn. Therefore, we
* add a new field to struct timer_list and use __timer_callback to perform
* the indirect call using the correct function pointer.
*/
static inline void __timer_callback(unsigned long data)
{
struct timer_list *timer = (struct timer_list *)data;
timer->__function(timer);
}
static inline void timer_setup(struct timer_list *timer,
void (*callback)(struct timer_list *),
unsigned int flags)
{
timer->__function = callback;
__setup_timer(timer, __timer_callback,
(TIMER_DATA_TYPE)timer, flags);
}
#else
static inline void timer_setup(struct timer_list *timer,
void (*callback)(struct timer_list *),
unsigned int flags)
@@ -179,6 +206,7 @@ static inline void timer_setup(struct timer_list *timer,
__setup_timer(timer, (TIMER_FUNC_TYPE)callback,
(TIMER_DATA_TYPE)timer, flags);
}
#endif
#define from_timer(var, callback_timer, timer_fieldname) \
container_of(callback_timer, typeof(*var), timer_fieldname)