Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: pcf50633-adc: Fix potential race in pcf50633_adc_sync_read

Currently it's not guaranteed that request struct is not already freed when
reading from it. Fix this by moving synced request related fields from the
pcf50633_adc_request struct to its own struct and store it on the functions
stack.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Lars-Peter Clausen and committed by
Samuel Ortiz
6438a694 0aeee5d4

+15 -24
+15 -24
drivers/mfd/pcf50633-adc.c
··· 30 30 struct pcf50633_adc_request { 31 31 int mux; 32 32 int avg; 33 - int result; 34 33 void (*callback)(struct pcf50633 *, void *, int); 35 34 void *callback_param; 35 + }; 36 36 37 - /* Used in case of sync requests */ 37 + struct pcf50633_adc_sync_request { 38 + int result; 38 39 struct completion completion; 39 - 40 40 }; 41 41 42 42 #define PCF50633_MAX_ADC_FIFO_DEPTH 8 ··· 109 109 return 0; 110 110 } 111 111 112 - static void 113 - pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) 112 + static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, 113 + int result) 114 114 { 115 - struct pcf50633_adc_request *req = param; 115 + struct pcf50633_adc_sync_request *req = param; 116 116 117 117 req->result = result; 118 118 complete(&req->completion); ··· 120 120 121 121 int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) 122 122 { 123 - struct pcf50633_adc_request *req; 124 - int err; 123 + struct pcf50633_adc_sync_request req; 124 + int ret; 125 125 126 - /* req is freed when the result is ready, in interrupt handler */ 127 - req = kzalloc(sizeof(*req), GFP_KERNEL); 128 - if (!req) 129 - return -ENOMEM; 126 + init_completion(&req.completion); 130 127 131 - req->mux = mux; 132 - req->avg = avg; 133 - req->callback = pcf50633_adc_sync_read_callback; 134 - req->callback_param = req; 128 + ret = pcf50633_adc_async_read(pcf, mux, avg, 129 + pcf50633_adc_sync_read_callback, &req); 130 + if (ret) 131 + return ret; 135 132 136 - init_completion(&req->completion); 137 - err = adc_enqueue_request(pcf, req); 138 - if (err) 139 - return err; 133 + wait_for_completion(&req.completion); 140 134 141 - wait_for_completion(&req->completion); 142 - 143 - /* FIXME by this time req might be already freed */ 144 - return req->result; 135 + return req.result; 145 136 } 146 137 EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read); 147 138