Now that the davinci drivers can be enabled in compile tests on other
architectures, I ran into this warning on a 64-bit build:

drivers/media/platform/davinci/dm644x_ccdc.c: In function 
'ccdc_update_raw_params':
drivers/media/platform/davinci/dm644x_ccdc.c:279:7: error: cast to pointer from 
integer of different size [-Werror=int-to-pointer-cast]

While that looks fairly harmless (it would be fine on 32-bit), it was
just the tip of the iceberg:

- The function constantly mixes up pointers and phys_addr_t numbers
- This is part of a 'VPFE_CMD_S_CCDC_RAW_PARAMS' ioctl command that is
  described as an 'experimental ioctl that will change in future kernels',
  but if we have users that probably won't happen.
- The code to allocate the table never gets called after we copy_from_user
  the user input over the kernel settings, and then compare them
  for inequality.
- We then go on to use an address provided by user space as both the
  __user pointer for input and pass it through phys_to_virt to come up
  with a kernel pointer to copy the data to. This looks like a trivially
  exploitable root hole.

This patch disables all the obviously broken code, by zeroing out the
sensitive data provided by user space. I also fix the type confusion
here. If we think the ioctl has no stable users, we could consider
just removing it instead.

Fixes: 5f15fbb68fd7 ("V4L/DVB (12251): v4l: dm644x ccdc module for vpfe capture 
driver")
Signed-off-by: Arnd Bergmann <a...@arndb.de>
---
 drivers/media/platform/davinci/dm644x_ccdc.c | 40 +++++++++++++++++-----------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c 
b/drivers/media/platform/davinci/dm644x_ccdc.c
index 740fbc7a8c14..1b42f50cad38 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -236,10 +236,22 @@ static int ccdc_update_raw_params(struct 
ccdc_config_params_raw *raw_params)
 {
        struct ccdc_config_params_raw *config_params =
                                &ccdc_cfg.bayer.config_params;
-       unsigned int *fpc_virtaddr = NULL;
-       unsigned int *fpc_physaddr = NULL;
+       unsigned int *fpc_virtaddr;
+       phys_addr_t fpc_physaddr;
 
        memcpy(config_params, raw_params, sizeof(*raw_params));
+
+       /*
+        * FIXME: the code to copy the fault_pxl settings was present
+        *        in the original version but clearly could never
+        *        work and will interpret user-provided data in
+        *        dangerous ways. Let's disable it completely to be
+        *        on the safe side.
+        */
+       config_params->fault_pxl.enable = 0;
+       config_params->fault_pxl.fp_num = 0;
+       config_params->fault_pxl.fpc_table_addr = 0;
+
        /*
         * allocate memory for fault pixel table and copy the user
         * values to the table
@@ -247,16 +259,15 @@ static int ccdc_update_raw_params(struct 
ccdc_config_params_raw *raw_params)
        if (!config_params->fault_pxl.enable)
                return 0;
 
-       fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
-       fpc_virtaddr = (unsigned int *)phys_to_virt(
-                               (unsigned long)fpc_physaddr);
+       fpc_physaddr = config_params->fault_pxl.fpc_table_addr;
+       fpc_virtaddr = (unsigned int *)phys_to_virt(fpc_physaddr);
        /*
         * Allocate memory for FPC table if current
         * FPC table buffer is not big enough to
         * accommodate FPC Number requested
         */
        if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
-               if (fpc_physaddr != NULL) {
+               if (fpc_physaddr) {
                        free_pages((unsigned long)fpc_virtaddr,
                                   get_order
                                   (config_params->fault_pxl.fp_num *
@@ -270,13 +281,12 @@ static int ccdc_update_raw_params(struct 
ccdc_config_params_raw *raw_params)
                                                         fault_pxl.fp_num *
                                                         FP_NUM_BYTES));
 
-               if (fpc_virtaddr == NULL) {
+               if (fpc_virtaddr) {
                        dev_dbg(ccdc_cfg.dev,
                                "\nUnable to allocate memory for FPC");
                        return -EFAULT;
                }
-               fpc_physaddr =
-                   (unsigned int *)virt_to_phys((void *)fpc_virtaddr);
+               fpc_physaddr = virt_to_phys(fpc_virtaddr);
        }
 
        /* Copy number of fault pixels and FPC table */
@@ -287,7 +297,7 @@ static int ccdc_update_raw_params(struct 
ccdc_config_params_raw *raw_params)
                dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
                return -EFAULT;
        }
-       config_params->fault_pxl.fpc_table_addr = (unsigned long)fpc_physaddr;
+       config_params->fault_pxl.fpc_table_addr = fpc_physaddr;
        return 0;
 }
 
@@ -295,13 +305,13 @@ static int ccdc_close(struct device *dev)
 {
        struct ccdc_config_params_raw *config_params =
                                &ccdc_cfg.bayer.config_params;
-       unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
+       phys_addr_t fpc_physaddr;
+       unsigned int *fpc_virtaddr;
 
-       fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+       fpc_physaddr = config_params->fault_pxl.fpc_table_addr;
 
-       if (fpc_physaddr != NULL) {
-               fpc_virtaddr = (unsigned int *)
-                   phys_to_virt((unsigned long)fpc_physaddr);
+       if (fpc_physaddr) {
+               fpc_virtaddr = phys_to_virt(fpc_physaddr);
                free_pages((unsigned long)fpc_virtaddr,
                           get_order(config_params->fault_pxl.fp_num *
                           FP_NUM_BYTES));
-- 
2.9.0

Reply via email to