[SCSI] sg: return EFAULT for an invalid user address

blk_rq_unmap_user() returns EFAULT if a program passes an invalid
address to kernel (the kernel fails to copy data to user space). sg
needs to pass the returned value to user space instead of ignoring
it. Before the block layer conversion, sg returns EFAULT
properly. This restores the old behavior.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
FUJITA Tomonori 2009-04-04 00:35:42 +09:00 committed by James Bottomley
parent 96bcc722c4
commit e7ee4cc04b
1 changed files with 8 additions and 5 deletions

View File

@ -179,7 +179,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
/* tasklet or soft irq callback */ /* tasklet or soft irq callback */
static void sg_rq_end_io(struct request *rq, int uptodate); static void sg_rq_end_io(struct request *rq, int uptodate);
static int sg_start_req(Sg_request *srp, unsigned char *cmd); static int sg_start_req(Sg_request *srp, unsigned char *cmd);
static void sg_finish_rem_req(Sg_request * srp); static int sg_finish_rem_req(Sg_request * srp);
static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
Sg_request * srp); Sg_request * srp);
@ -518,7 +518,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
goto err_out; goto err_out;
} }
err_out: err_out:
sg_finish_rem_req(srp); err = sg_finish_rem_req(srp);
return (0 == err) ? count : err; return (0 == err) ? count : err;
} }
@ -1696,9 +1696,10 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
return res; return res;
} }
static void static int sg_finish_rem_req(Sg_request * srp)
sg_finish_rem_req(Sg_request * srp)
{ {
int ret = 0;
Sg_fd *sfp = srp->parentfp; Sg_fd *sfp = srp->parentfp;
Sg_scatter_hold *req_schp = &srp->data; Sg_scatter_hold *req_schp = &srp->data;
@ -1710,12 +1711,14 @@ sg_finish_rem_req(Sg_request * srp)
if (srp->rq) { if (srp->rq) {
if (srp->bio) if (srp->bio)
blk_rq_unmap_user(srp->bio); ret = blk_rq_unmap_user(srp->bio);
blk_put_request(srp->rq); blk_put_request(srp->rq);
} }
sg_remove_request(sfp, srp); sg_remove_request(sfp, srp);
return ret;
} }
static int static int