Skip to content

Commit fd6c3d5

Browse files
committed
compat_ioctl: move SG_GET_REQUEST_TABLE handling
SG_GET_REQUEST_TABLE is now the last ioctl command that needs a conversion handler. This is only used in a single file, so the implementation should be there. I'm trying to simplify it in the process, to get rid of the compat_alloc_user_space() and extra copy, by adding a put_compat_request_table() function instead, which copies the data in the right format to user space. Cc: [email protected] Cc: Doug Gilbert <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: "Martin K. Petersen" <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
1 parent 8f5d9f2 commit fd6c3d5

File tree

2 files changed

+36
-61
lines changed

2 files changed

+36
-61
lines changed

drivers/scsi/sg.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,33 @@ sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
889889
}
890890
}
891891

892+
#ifdef CONFIG_COMPAT
893+
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
894+
char req_state;
895+
char orphan;
896+
char sg_io_owned;
897+
char problem;
898+
int pack_id;
899+
compat_uptr_t usr_ptr;
900+
unsigned int duration;
901+
int unused;
902+
};
903+
904+
static int put_compat_request_table(struct compat_sg_req_info __user *o,
905+
struct sg_req_info *rinfo)
906+
{
907+
int i;
908+
for (i = 0; i < SG_MAX_QUEUE; i++) {
909+
if (copy_to_user(o + i, rinfo + i, offsetof(sg_req_info_t, usr_ptr)) ||
910+
put_user((uintptr_t)rinfo[i].usr_ptr, &o[i].usr_ptr) ||
911+
put_user(rinfo[i].duration, &o[i].duration) ||
912+
put_user(rinfo[i].unused, &o[i].unused))
913+
return -EFAULT;
914+
}
915+
return 0;
916+
}
917+
#endif
918+
892919
static long
893920
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
894921
{
@@ -1069,9 +1096,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
10691096
val = (sdp->device ? 1 : 0);
10701097
return put_user(val, ip);
10711098
case SG_GET_REQUEST_TABLE:
1072-
if (!access_ok(p, SZ_SG_REQ_INFO * SG_MAX_QUEUE))
1073-
return -EFAULT;
1074-
else {
1099+
{
10751100
sg_req_info_t *rinfo;
10761101

10771102
rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO,
@@ -1081,8 +1106,13 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
10811106
read_lock_irqsave(&sfp->rq_list_lock, iflags);
10821107
sg_fill_request_table(sfp, rinfo);
10831108
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
1084-
result = __copy_to_user(p, rinfo,
1085-
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
1109+
#ifdef CONFIG_COMPAT
1110+
if (in_compat_syscall())
1111+
result = put_compat_request_table(p, rinfo);
1112+
else
1113+
#endif
1114+
result = copy_to_user(p, rinfo,
1115+
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
10861116
result = result ? -EFAULT : 0;
10871117
kfree(rinfo);
10881118
return result;

fs/compat_ioctl.c

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -52,53 +52,6 @@
5252

5353
#include <linux/sort.h>
5454

55-
#ifdef CONFIG_BLOCK
56-
static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
57-
{
58-
int err;
59-
60-
err = security_file_ioctl(file, cmd, arg);
61-
if (err)
62-
return err;
63-
64-
return vfs_ioctl(file, cmd, arg);
65-
}
66-
67-
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
68-
char req_state;
69-
char orphan;
70-
char sg_io_owned;
71-
char problem;
72-
int pack_id;
73-
compat_uptr_t usr_ptr;
74-
unsigned int duration;
75-
int unused;
76-
};
77-
78-
static int sg_grt_trans(struct file *file,
79-
unsigned int cmd, struct compat_sg_req_info __user *o)
80-
{
81-
int err, i;
82-
sg_req_info_t __user *r;
83-
r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE);
84-
err = do_ioctl(file, cmd, (unsigned long)r);
85-
if (err < 0)
86-
return err;
87-
for (i = 0; i < SG_MAX_QUEUE; i++) {
88-
void __user *ptr;
89-
int d;
90-
91-
if (copy_in_user(o + i, r + i, offsetof(sg_req_info_t, usr_ptr)) ||
92-
get_user(ptr, &r[i].usr_ptr) ||
93-
get_user(d, &r[i].duration) ||
94-
put_user((u32)(unsigned long)(ptr), &o[i].usr_ptr) ||
95-
put_user(d, &o[i].duration))
96-
return -EFAULT;
97-
}
98-
return err;
99-
}
100-
#endif /* CONFIG_BLOCK */
101-
10255
/*
10356
* simple reversible transform to make our table more evenly
10457
* distributed after sorting.
@@ -121,6 +74,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
12174
#ifdef CONFIG_BLOCK
12275
/* SG stuff */
12376
COMPATIBLE_IOCTL(SG_IO)
77+
COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
12478
COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
12579
COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
12680
COMPATIBLE_IOCTL(SG_EMULATED_HOST)
@@ -156,15 +110,6 @@ COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
156110
static long do_ioctl_trans(unsigned int cmd,
157111
unsigned long arg, struct file *file)
158112
{
159-
#ifdef CONFIG_BLOCK
160-
void __user *argp = compat_ptr(arg);
161-
162-
switch (cmd) {
163-
case SG_GET_REQUEST_TABLE:
164-
return sg_grt_trans(file, cmd, argp);
165-
}
166-
#endif
167-
168113
return -ENOIOCTLCMD;
169114
}
170115

0 commit comments

Comments
 (0)