Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3045070c authored by Sami Tolvanen's avatar Sami Tolvanen Committed by Alistair Delva
Browse files

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: default avatarSami Tolvanen <samitolvanen@google.com>
parent 5bcde4a4
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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)