Browse Source

qcacmn: Fix CFI failure caused by dfs_remove_from_nol

The parameter of callback of kernel struct hrtimer is itself, not
qdf_hrtimer_data_t. CFI failure happens if the function pointers
does not have the same type as the function that's called.
Add a new API __qdf_hrtimer_cb and assign it to hrtimer->function.

Change-Id: I9cf753272dd37635e82defac6cf7258c7a70425d
CRs-Fixed: 3245385
Bing Sun 2 years ago
parent
commit
d0385d035d
3 changed files with 23 additions and 10 deletions
  1. 20 3
      qdf/linux/src/i_qdf_hrtimer.h
  2. 2 4
      umac/dfs/core/src/misc/dfs_cac.c
  3. 1 3
      umac/dfs/core/src/misc/dfs_nol.c

+ 20 - 3
qdf/linux/src/i_qdf_hrtimer.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014-2019,2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -31,8 +32,9 @@
 #include <qdf_types.h>
 #include <i_qdf_trace.h>
 
+struct __qdf_hrtimer_data_internal_t;
 /* hrtimer data type */
-typedef struct {
+typedef struct __qdf_hrtimer_data_internal_t {
 	union {
 		struct hrtimer hrtimer;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
@@ -40,6 +42,9 @@ typedef struct {
 #endif
 	} u;
 	enum qdf_context_mode ctx;
+	struct __qdf_hrtimer_data_internal_t *cb_ctx;
+	enum qdf_hrtimer_restart_status (*callback)
+				(struct __qdf_hrtimer_data_internal_t *);
 } __qdf_hrtimer_data_t;
 
 /**
@@ -120,6 +125,14 @@ int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer)
 }
 #endif
 
+static enum hrtimer_restart __qdf_hrtimer_cb(struct hrtimer *arg)
+{
+	__qdf_hrtimer_data_t *timer = container_of(arg, __qdf_hrtimer_data_t,
+						   u.hrtimer);
+
+	return (enum hrtimer_restart)timer->callback(timer->cb_ctx);
+}
+
 /**
  * __qdf_hrtimer_init() - init hrtimer in a given context
  * @timer: pointer to the hrtimer object
@@ -142,10 +155,12 @@ static inline void  __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
 	enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
 
 	timer->ctx = ctx;
+	timer->callback = cback;
+	timer->cb_ctx = timer;
 
 	if (timer->ctx == QDF_CONTEXT_HARDWARE) {
 		hrtimer_init(hrtimer, clock, hrt_mode);
-		hrtimer->function = cback;
+		hrtimer->function = __qdf_hrtimer_cb;
 	} else if (timer->ctx == QDF_CONTEXT_TASKLET) {
 		QDF_BUG(0);
 	}
@@ -162,10 +177,12 @@ static inline void  __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
 	enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
 
 	timer->ctx = ctx;
+	timer->callback = cback;
+	timer->cb_ctx = timer;
 
 	if (timer->ctx == QDF_CONTEXT_HARDWARE) {
 		hrtimer_init(hrtimer, clock, hrt_mode);
-		hrtimer->function = cback;
+		hrtimer->function = __qdf_hrtimer_cb;
 	} else if (timer->ctx == QDF_CONTEXT_TASKLET) {
 		tasklet_hrtimer_init(tasklet_hrtimer, cback, clock, hrt_mode);
 	}

+ 2 - 4
umac/dfs/core/src/misc/dfs_cac.c

@@ -168,11 +168,9 @@ void dfs_process_cac_completion(void *context)
 static enum qdf_hrtimer_restart_status
 dfs_cac_timeout(qdf_hrtimer_data_t *arg)
 {
-	struct wlan_dfs *dfs = NULL;
-	void *ptr = (void *)arg;
-	qdf_hrtimer_data_t *thr = container_of(ptr, qdf_hrtimer_data_t, u);
+	struct wlan_dfs *dfs;
 
-	dfs = container_of(thr, struct wlan_dfs, dfs_cac_timer);
+	dfs = container_of(arg, struct wlan_dfs, dfs_cac_timer);
 
 	if (dfs_is_hw_mode_switch_in_progress(dfs))
 		dfs->dfs_defer_params.is_cac_completed = true;

+ 1 - 3
umac/dfs/core/src/misc/dfs_nol.c

@@ -235,10 +235,8 @@ static enum qdf_hrtimer_restart_status
 dfs_remove_from_nol(qdf_hrtimer_data_t *arg)
 {
 	struct dfs_nolelem *nol_arg;
-	void *ptr = (void *)arg;
-	qdf_hrtimer_data_t *thr = container_of(ptr, qdf_hrtimer_data_t, u);
 
-	nol_arg = container_of(thr, struct dfs_nolelem, nol_timer);
+	nol_arg = container_of(arg, struct dfs_nolelem, nol_timer);
 
 	qdf_sched_work(NULL, &nol_arg->nol_timer_completion_work);