Skip to content

Commit

Permalink
coda: potential buffer overflow in coda_psdev_write()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reported-by: Dan Carpenter <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Colin Ian King <[email protected]>
Cc: David Howells <[email protected]>
Cc: Fabian Frederick <[email protected]>
Cc: Mikko Rapeli <[email protected]>
Cc: Sam Protsenko <[email protected]>
Cc: Yann Droneaud <[email protected]>
Cc: Zhouyang Jia <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
jaharkes authored and torvalds committed Jul 17, 2019
1 parent 02551c2 commit 6e51f8a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
8 changes: 6 additions & 2 deletions fs/coda/psdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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) {
Expand Down
34 changes: 33 additions & 1 deletion fs/coda/upcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,12 +804,44 @@ static int coda_upcall(struct venus_comm *vcp,
*
* 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;
Expand Down
3 changes: 2 additions & 1 deletion include/linux/coda_psdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 6e51f8a

Please sign in to comment.