nubus: Avoid array underflow and overflow
authorFinn Thain <fthain@telegraphics.com.au>
Sat, 13 Jan 2018 22:37:13 +0000 (17:37 -0500)
committerGeert Uytterhoeven <geert@linux-m68k.org>
Tue, 16 Jan 2018 15:47:29 +0000 (16:47 +0100)
Check array indices. Avoid sprintf. Use buffers of sufficient size.
Use appropriate types for array length parameters.

Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
drivers/nubus/nubus.c
drivers/nubus/proc.c
include/linux/nubus.h

index b793727cd4f74b99713957fec6a2a111746236fa..b6c97e07f15e72ffbc889be723f6f395a4483959 100644 (file)
@@ -161,7 +161,7 @@ static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
    pointed to with offsets) out of the card ROM. */
 
 void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
-                       int len)
+                       unsigned int len)
 {
        unsigned char *t = (unsigned char *)dest;
        unsigned char *p = nubus_dirptr(dirent);
@@ -173,18 +173,22 @@ void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
 }
 EXPORT_SYMBOL(nubus_get_rsrc_mem);
 
-void nubus_get_rsrc_str(void *dest, const struct nubus_dirent *dirent,
-                       int len)
+void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
+                       unsigned int len)
 {
-       unsigned char *t = (unsigned char *)dest;
+       char *t = dest;
        unsigned char *p = nubus_dirptr(dirent);
 
-       while (len) {
-               *t = nubus_get_rom(&p, 1, dirent->mask);
-               if (!*t++)
+       while (len > 1) {
+               unsigned char c = nubus_get_rom(&p, 1, dirent->mask);
+
+               if (!c)
                        break;
+               *t++ = c;
                len--;
        }
+       if (len > 0)
+               *t = '\0';
 }
 EXPORT_SYMBOL(nubus_get_rsrc_str);
 
@@ -468,7 +472,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot,
                }
                case NUBUS_RESID_NAME:
                {
-                       nubus_get_rsrc_str(dev->name, &ent, 64);
+                       nubus_get_rsrc_str(dev->name, &ent, sizeof(dev->name));
                        pr_info("    name: %s\n", dev->name);
                        break;
                }
@@ -528,7 +532,7 @@ static int __init nubus_get_vidnames(struct nubus_board *board,
                /* Don't know what this is yet */
                u16 id;
                /* Longest one I've seen so far is 26 characters */
-               char name[32];
+               char name[36];
        };
 
        pr_info("    video modes supported:\n");
@@ -598,8 +602,8 @@ static int __init nubus_get_vendorinfo(struct nubus_board *board,
                char name[64];
 
                /* These are all strings, we think */
-               nubus_get_rsrc_str(name, &ent, 64);
-               if (ent.type > 5)
+               nubus_get_rsrc_str(name, &ent, sizeof(name));
+               if (ent.type < 1 || ent.type > 5)
                        ent.type = 5;
                pr_info("    %s: %s\n", vendor_fields[ent.type - 1], name);
        }
@@ -633,7 +637,8 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
                        break;
                }
                case NUBUS_RESID_NAME:
-                       nubus_get_rsrc_str(board->name, &ent, 64);
+                       nubus_get_rsrc_str(board->name, &ent,
+                                          sizeof(board->name));
                        pr_info("    name: %s\n", board->name);
                        break;
                case NUBUS_RESID_ICON:
index 004a122ac0ff21cfc6a05781e7510554f3e33cf3..fc20dbcd3b9a7da595dbc9eaae970f7c789e2986 100644 (file)
@@ -73,10 +73,10 @@ static void nubus_proc_subdir(struct nubus_dev* dev,
 
        /* Some of these are directories, others aren't */
        while (nubus_readdir(dir, &ent) != -1) {
-               char name[8];
+               char name[9];
                struct proc_dir_entry* e;
                
-               sprintf(name, "%x", ent.type);
+               snprintf(name, sizeof(name), "%x", ent.type);
                e = proc_create(name, S_IFREG | S_IRUGO | S_IWUSR, parent,
                                &nubus_proc_subdir_fops);
                if (!e)
@@ -95,11 +95,11 @@ static void nubus_proc_populate(struct nubus_dev* dev,
        /* We know these are all directories (board resource + one or
           more functional resources) */
        while (nubus_readdir(root, &ent) != -1) {
-               char name[8];
+               char name[9];
                struct proc_dir_entry* e;
                struct nubus_dir dir;
                
-               sprintf(name, "%x", ent.type);
+               snprintf(name, sizeof(name), "%x", ent.type);
                e = proc_mkdir(name, parent);
                if (!e) return;
 
@@ -119,7 +119,7 @@ int nubus_proc_attach_device(struct nubus_dev *dev)
 {
        struct proc_dir_entry *e;
        struct nubus_dir root;
-       char name[8];
+       char name[9];
 
        if (dev == NULL) {
                printk(KERN_ERR
@@ -135,7 +135,7 @@ int nubus_proc_attach_device(struct nubus_dev *dev)
        }
                
        /* Create a directory */
-       sprintf(name, "%x", dev->board->slot);
+       snprintf(name, sizeof(name), "%x", dev->board->slot);
        e = dev->procdir = proc_mkdir(name, proc_bus_nubus_dir);
        if (!e)
                return -ENOMEM;
index 11ce6b1117a8e58946af6587772a1029ca536d93..d8d63370a28c120c19f9be7f2dac336f2130c072 100644 (file)
@@ -126,10 +126,8 @@ int nubus_rewinddir(struct nubus_dir* dir);
 /* Things to do with directory entries */
 int nubus_get_subdir(const struct nubus_dirent* ent,
                     struct nubus_dir* dir);
-void nubus_get_rsrc_mem(void* dest,
-                       const struct nubus_dirent *dirent,
-                       int len);
-void nubus_get_rsrc_str(void* dest,
-                       const struct nubus_dirent *dirent,
-                       int maxlen);
+void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
+                       unsigned int len);
+void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
+                       unsigned int maxlen);
 #endif /* LINUX_NUBUS_H */