Commit 7c503df2 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] smbfs fixes

Fixes for various smbfs data leak bugs from Alan, Chuck Ebbert and various
people on various mailing lists.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 96eddffb
...@@ -1427,9 +1427,9 @@ smb_proc_readX_data(struct smb_request *req) ...@@ -1427,9 +1427,9 @@ smb_proc_readX_data(struct smb_request *req)
* So we must first calculate the amount of padding used by the server. * So we must first calculate the amount of padding used by the server.
*/ */
data_off -= hdrlen; data_off -= hdrlen;
if (data_off > SMB_READX_MAX_PAD) { if (data_off > SMB_READX_MAX_PAD || data_off < 0) {
PARANOIA("offset is larger than max pad!\n"); PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n");
PARANOIA("%d > %d\n", data_off, SMB_READX_MAX_PAD); PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off);
req->rq_rlen = req->rq_bufsize + 1; req->rq_rlen = req->rq_bufsize + 1;
return; return;
} }
......
...@@ -590,8 +590,18 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) ...@@ -590,8 +590,18 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
data_count = WVAL(inbuf, smb_drcnt); data_count = WVAL(inbuf, smb_drcnt);
/* Modify offset for the split header/buffer we use */ /* Modify offset for the split header/buffer we use */
data_offset -= hdrlen; if (data_count || data_offset) {
parm_offset -= hdrlen; if (unlikely(data_offset < hdrlen))
goto out_bad_data;
else
data_offset -= hdrlen;
}
if (parm_count || parm_offset) {
if (unlikely(parm_offset < hdrlen))
goto out_bad_parm;
else
parm_offset -= hdrlen;
}
if (parm_count == parm_tot && data_count == data_tot) { if (parm_count == parm_tot && data_count == data_tot) {
/* /*
...@@ -602,18 +612,22 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) ...@@ -602,18 +612,22 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
* response that fits. * response that fits.
*/ */
VERBOSE("single trans2 response " VERBOSE("single trans2 response "
"dcnt=%d, pcnt=%d, doff=%d, poff=%d\n", "dcnt=%u, pcnt=%u, doff=%u, poff=%u\n",
data_count, parm_count, data_count, parm_count,
data_offset, parm_offset); data_offset, parm_offset);
req->rq_ldata = data_count; req->rq_ldata = data_count;
req->rq_lparm = parm_count; req->rq_lparm = parm_count;
req->rq_data = req->rq_buffer + data_offset; req->rq_data = req->rq_buffer + data_offset;
req->rq_parm = req->rq_buffer + parm_offset; req->rq_parm = req->rq_buffer + parm_offset;
if (unlikely(parm_offset + parm_count > req->rq_rlen))
goto out_bad_parm;
if (unlikely(data_offset + data_count > req->rq_rlen))
goto out_bad_data;
return 0; return 0;
} }
VERBOSE("multi trans2 response " VERBOSE("multi trans2 response "
"frag=%d, dcnt=%d, pcnt=%d, doff=%d, poff=%d\n", "frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n",
req->rq_fragment, req->rq_fragment,
data_count, parm_count, data_count, parm_count,
data_offset, parm_offset); data_offset, parm_offset);
...@@ -640,13 +654,15 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) ...@@ -640,13 +654,15 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
req->rq_parm = req->rq_trans2buffer; req->rq_parm = req->rq_trans2buffer;
req->rq_data = req->rq_trans2buffer + parm_tot; req->rq_data = req->rq_trans2buffer + parm_tot;
} else if (req->rq_total_data < data_tot || } else if (unlikely(req->rq_total_data < data_tot ||
req->rq_total_parm < parm_tot) req->rq_total_parm < parm_tot))
goto out_data_grew; goto out_data_grew;
if (parm_disp + parm_count > req->rq_total_parm) if (unlikely(parm_disp + parm_count > req->rq_total_parm ||
parm_offset + parm_count > req->rq_rlen))
goto out_bad_parm; goto out_bad_parm;
if (data_disp + data_count > req->rq_total_data) if (unlikely(data_disp + data_count > req->rq_total_data ||
data_offset + data_count > req->rq_rlen))
goto out_bad_data; goto out_bad_data;
inbuf = req->rq_buffer; inbuf = req->rq_buffer;
...@@ -668,10 +684,9 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) ...@@ -668,10 +684,9 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
return 1; return 1;
out_too_long: out_too_long:
printk(KERN_ERR "smb_trans2: data/param too long, data=%d, parm=%d\n", printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n",
data_tot, parm_tot); data_tot, parm_tot);
req->rq_errno = -EIO; goto out_EIO;
goto out;
out_no_mem: out_no_mem:
printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n", printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n",
req->rq_trans2bufsize); req->rq_trans2bufsize);
...@@ -679,16 +694,15 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) ...@@ -679,16 +694,15 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
goto out; goto out;
out_data_grew: out_data_grew:
printk(KERN_ERR "smb_trans2: data/params grew!\n"); printk(KERN_ERR "smb_trans2: data/params grew!\n");
req->rq_errno = -EIO; goto out_EIO;
goto out;
out_bad_parm: out_bad_parm:
printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n", printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n",
parm_disp, parm_count, parm_tot); parm_disp, parm_count, parm_tot, parm_offset);
req->rq_errno = -EIO; goto out_EIO;
goto out;
out_bad_data: out_bad_data:
printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n", printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n",
data_disp, data_count, data_tot); data_disp, data_count, data_tot, data_offset);
out_EIO:
req->rq_errno = -EIO; req->rq_errno = -EIO;
out: out:
return req->rq_errno; return req->rq_errno;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment