coda: potential buffer overflow in coda_psdev_write()
authorJan Harkes <jaharkes@cs.cmu.edu>
Tue, 16 Jul 2019 23:28:16 +0000 (16:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jul 2019 02:23:23 +0000 (19:23 -0700)
Add checks to make sure the downcall message we got from the Coda cache
manager is large enough to contain the data it is supposed to have.
i.e.  when we get a CODA_ZAPDIR we can access &out->coda_zapdir.CodaFid.

Link: http://lkml.kernel.org/r/894fb6b250add09e4e3935f14649f21284a5cb18.1558117389.git.jaharkes@cs.cmu.edu
Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Fabian Frederick <fabf@skynet.be>
Cc: Mikko Rapeli <mikko.rapeli@iki.fi>
Cc: Sam Protsenko <semen.protsenko@linaro.org>
Cc: Yann Droneaud <ydroneaud@opteya.com>
Cc: Zhouyang Jia <jiazhouyang09@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/coda/psdev.c
fs/coda/upcall.c
include/linux/coda_psdev.h

index 241f7e04ad04d0674540e72b39c9911f72c23bcd..b4da2812499eb252f5f288b0984d17646001907e 100644 (file)
@@ -100,8 +100,12 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
        ssize_t retval = 0, count = 0;
        int error;
 
+       /* make sure there is enough to copy out the (opcode, unique) values */
+       if (nbytes < (2 * sizeof(u_int32_t)))
+               return -EINVAL;
+
         /* Peek at the opcode, uniquefier */
-       if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
+       if (copy_from_user(&hdr, buf, 2 * sizeof(u_int32_t)))
                return -EFAULT;
 
         if (DOWNCALL(hdr.opcode)) {
@@ -127,7 +131,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
                }
 
                /* what downcall errors does Venus handle ? */
-               error = coda_downcall(vcp, hdr.opcode, dcbuf);
+               error = coda_downcall(vcp, hdr.opcode, dcbuf, nbytes);
 
                CODA_FREE(dcbuf, nbytes);
                if (error) {
index 1175a1722411d353624c8b1548f054c5b13fc520..cf1e662681a5d128cef7f9c2735570a7a46123da 100644 (file)
@@ -804,12 +804,44 @@ exit:
  *
  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 
-int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
+                 size_t nbytes)
 {
        struct inode *inode = NULL;
        struct CodaFid *fid = NULL, *newfid;
        struct super_block *sb;
 
+       /*
+        * Make sure we have received enough data from the cache
+        * manager to populate the necessary fields in the buffer
+        */
+       switch (opcode) {
+       case CODA_PURGEUSER:
+               if (nbytes < sizeof(struct coda_purgeuser_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_ZAPDIR:
+               if (nbytes < sizeof(struct coda_zapdir_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_ZAPFILE:
+               if (nbytes < sizeof(struct coda_zapfile_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_PURGEFID:
+               if (nbytes < sizeof(struct coda_purgefid_out))
+                       return -EINVAL;
+               break;
+
+       case CODA_REPLACE:
+               if (nbytes < sizeof(struct coda_replace_out))
+                       return -EINVAL;
+               break;
+       }
+
        /* Handle invalidation requests. */
        mutex_lock(&vcp->vc_mutex);
        sb = vcp->vc_sb;
index 57d2b2faf6a3e13fce381dc963d57fba2d6e4f71..d1672fd5e6382f551986a035879b02ed317ab9bd 100644 (file)
@@ -71,7 +71,8 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask);
 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
                 unsigned int cmd, struct PioctlData *data);
-int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out);
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
+                 size_t nbytes);
 int venus_fsync(struct super_block *sb, struct CodaFid *fid);
 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);