Commit c4a047272566b44b44222369d50a307c708c4f74

Authored by Al Viro
Committed by Arnd Bergmann
1 parent 9a181c5861

fix rawctl compat ioctls breakage on amd64 and itanic

RAW_SETBIND and RAW_GETBIND 32bit versions are fscked in interesting ways.

1) fs/compat_ioctl.c has COMPATIBLE_IOCTL(RAW_SETBIND) followed by
HANDLE_IOCTL(RAW_SETBIND, raw_ioctl).  The latter is ignored.

2) on amd64 (and itanic) the damn thing is broken - we have int + u64 + u64
and layouts on i386 and amd64 are _not_ the same.  raw_ioctl() would
work there, but it's never called due to (1).  As it is, i386 /sbin/raw
definitely doesn't work on amd64 boxen.

3) switching to raw_ioctl() as is would *not* work on e.g. sparc64 and ppc64,
which would be rather sad, seeing that normal userland there is 32bit.
The thing is, slapping __packed on the struct in question does not DTRT -
it eliminates *all* padding.  The real solution is to use compat_u64.

4) of course, all that stuff has no business being outside of raw.c in the
first place - there should be ->compat_ioctl() for /dev/rawctl instead of
messing with compat_ioctl.c.

[akpm@linux-foundation.org: coding-style fixes]
[arnd@arndb.de: port to 2.6.36]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Showing 2 changed files with 140 additions and 173 deletions Side-by-side Diff

... ... @@ -19,8 +19,8 @@
19 19 #include <linux/cdev.h>
20 20 #include <linux/device.h>
21 21 #include <linux/mutex.h>
22   -#include <linux/smp_lock.h>
23 22 #include <linux/gfp.h>
  23 +#include <linux/compat.h>
24 24  
25 25 #include <asm/uaccess.h>
26 26  
... ... @@ -55,7 +55,6 @@
55 55 return 0;
56 56 }
57 57  
58   - lock_kernel();
59 58 mutex_lock(&raw_mutex);
60 59  
61 60 /*
... ... @@ -82,7 +81,6 @@
82 81 bdev->bd_inode->i_mapping;
83 82 filp->private_data = bdev;
84 83 mutex_unlock(&raw_mutex);
85   - unlock_kernel();
86 84 return 0;
87 85  
88 86 out2:
... ... @@ -91,7 +89,6 @@
91 89 blkdev_put(bdev, filp->f_mode);
92 90 out:
93 91 mutex_unlock(&raw_mutex);
94   - unlock_kernel();
95 92 return err;
96 93 }
97 94  
98 95  
99 96  
100 97  
101 98  
... ... @@ -125,20 +122,84 @@
125 122 raw_ioctl(struct file *filp, unsigned int command, unsigned long arg)
126 123 {
127 124 struct block_device *bdev = filp->private_data;
128   - int ret;
  125 + return blkdev_ioctl(bdev, 0, command, arg);
  126 +}
129 127  
130   - lock_kernel();
131   - ret = blkdev_ioctl(bdev, 0, command, arg);
132   - unlock_kernel();
  128 +static int bind_set(int number, u64 major, u64 minor)
  129 +{
  130 + dev_t dev = MKDEV(major, minor);
  131 + struct raw_device_data *rawdev;
  132 + int err = 0;
133 133  
134   - return ret;
  134 + if (number <= 0 || number >= MAX_RAW_MINORS)
  135 + return -EINVAL;
  136 +
  137 + if (MAJOR(dev) != major || MINOR(dev) != minor)
  138 + return -EINVAL;
  139 +
  140 + rawdev = &raw_devices[number];
  141 +
  142 + /*
  143 + * This is like making block devices, so demand the
  144 + * same capability
  145 + */
  146 + if (!capable(CAP_SYS_ADMIN))
  147 + return -EPERM;
  148 +
  149 + /*
  150 + * For now, we don't need to check that the underlying
  151 + * block device is present or not: we can do that when
  152 + * the raw device is opened. Just check that the
  153 + * major/minor numbers make sense.
  154 + */
  155 +
  156 + if (MAJOR(dev) == 0 && dev != 0)
  157 + return -EINVAL;
  158 +
  159 + mutex_lock(&raw_mutex);
  160 + if (rawdev->inuse) {
  161 + mutex_unlock(&raw_mutex);
  162 + return -EBUSY;
  163 + }
  164 + if (rawdev->binding) {
  165 + bdput(rawdev->binding);
  166 + module_put(THIS_MODULE);
  167 + }
  168 + if (!dev) {
  169 + /* unbind */
  170 + rawdev->binding = NULL;
  171 + device_destroy(raw_class, MKDEV(RAW_MAJOR, number));
  172 + } else {
  173 + rawdev->binding = bdget(dev);
  174 + if (rawdev->binding == NULL) {
  175 + err = -ENOMEM;
  176 + } else {
  177 + dev_t raw = MKDEV(RAW_MAJOR, number);
  178 + __module_get(THIS_MODULE);
  179 + device_destroy(raw_class, raw);
  180 + device_create(raw_class, NULL, raw, NULL,
  181 + "raw%d", number);
  182 + }
  183 + }
  184 + mutex_unlock(&raw_mutex);
  185 + return err;
135 186 }
136 187  
137   -static void bind_device(struct raw_config_request *rq)
  188 +static int bind_get(int number, dev_t *dev)
138 189 {
139   - device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor));
140   - device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), NULL,
141   - "raw%d", rq->raw_minor);
  190 + struct raw_device_data *rawdev;
  191 + struct block_device *bdev;
  192 +
  193 + if (number <= 0 || number >= MAX_RAW_MINORS)
  194 + return -EINVAL;
  195 +
  196 + rawdev = &raw_devices[number];
  197 +
  198 + mutex_lock(&raw_mutex);
  199 + bdev = rawdev->binding;
  200 + *dev = bdev ? bdev->bd_dev : 0;
  201 + mutex_unlock(&raw_mutex);
  202 + return 0;
142 203 }
143 204  
144 205 /*
145 206  
146 207  
147 208  
148 209  
149 210  
150 211  
151 212  
152 213  
153 214  
154 215  
155 216  
156 217  
157 218  
158 219  
... ... @@ -149,105 +210,78 @@
149 210 unsigned long arg)
150 211 {
151 212 struct raw_config_request rq;
152   - struct raw_device_data *rawdev;
153   - int err = 0;
  213 + dev_t dev;
  214 + int err;
154 215  
155   - lock_kernel();
156 216 switch (command) {
157 217 case RAW_SETBIND:
  218 + if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
  219 + return -EFAULT;
  220 +
  221 + return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
  222 +
158 223 case RAW_GETBIND:
  224 + if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
  225 + return -EFAULT;
159 226  
160   - /* First, find out which raw minor we want */
  227 + err = bind_get(rq.raw_minor, &dev);
  228 + if (err)
  229 + return err;
161 230  
162   - if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) {
163   - err = -EFAULT;
164   - goto out;
165   - }
  231 + rq.block_major = MAJOR(dev);
  232 + rq.block_minor = MINOR(dev);
166 233  
167   - if (rq.raw_minor <= 0 || rq.raw_minor >= MAX_RAW_MINORS) {
168   - err = -EINVAL;
169   - goto out;
170   - }
171   - rawdev = &raw_devices[rq.raw_minor];
  234 + if (copy_to_user((void __user *)arg, &rq, sizeof(rq)))
  235 + return -EFAULT;
172 236  
173   - if (command == RAW_SETBIND) {
174   - dev_t dev;
  237 + return 0;
  238 + }
175 239  
176   - /*
177   - * This is like making block devices, so demand the
178   - * same capability
179   - */
180   - if (!capable(CAP_SYS_ADMIN)) {
181   - err = -EPERM;
182   - goto out;
183   - }
  240 + return -EINVAL;
  241 +}
184 242  
185   - /*
186   - * For now, we don't need to check that the underlying
187   - * block device is present or not: we can do that when
188   - * the raw device is opened. Just check that the
189   - * major/minor numbers make sense.
190   - */
  243 +#ifdef CONFIG_COMPAT
  244 +struct raw32_config_request {
  245 + compat_int_t raw_minor;
  246 + compat_u64 block_major;
  247 + compat_u64 block_minor;
  248 +};
191 249  
192   - dev = MKDEV(rq.block_major, rq.block_minor);
193   - if ((rq.block_major == 0 && rq.block_minor != 0) ||
194   - MAJOR(dev) != rq.block_major ||
195   - MINOR(dev) != rq.block_minor) {
196   - err = -EINVAL;
197   - goto out;
198   - }
  250 +static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
  251 + unsigned long arg)
  252 +{
  253 + struct raw32_config_request __user *user_req = compat_ptr(arg);
  254 + struct raw32_config_request rq;
  255 + dev_t dev;
  256 + int err = 0;
199 257  
200   - mutex_lock(&raw_mutex);
201   - if (rawdev->inuse) {
202   - mutex_unlock(&raw_mutex);
203   - err = -EBUSY;
204   - goto out;
205   - }
206   - if (rawdev->binding) {
207   - bdput(rawdev->binding);
208   - module_put(THIS_MODULE);
209   - }
210   - if (rq.block_major == 0 && rq.block_minor == 0) {
211   - /* unbind */
212   - rawdev->binding = NULL;
213   - device_destroy(raw_class,
214   - MKDEV(RAW_MAJOR, rq.raw_minor));
215   - } else {
216   - rawdev->binding = bdget(dev);
217   - if (rawdev->binding == NULL)
218   - err = -ENOMEM;
219   - else {
220   - __module_get(THIS_MODULE);
221   - bind_device(&rq);
222   - }
223   - }
224   - mutex_unlock(&raw_mutex);
225   - } else {
226   - struct block_device *bdev;
  258 + switch (cmd) {
  259 + case RAW_SETBIND:
  260 + if (copy_from_user(&rq, user_req, sizeof(rq)))
  261 + return -EFAULT;
227 262  
228   - mutex_lock(&raw_mutex);
229   - bdev = rawdev->binding;
230   - if (bdev) {
231   - rq.block_major = MAJOR(bdev->bd_dev);
232   - rq.block_minor = MINOR(bdev->bd_dev);
233   - } else {
234   - rq.block_major = rq.block_minor = 0;
235   - }
236   - mutex_unlock(&raw_mutex);
237   - if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) {
238   - err = -EFAULT;
239   - goto out;
240   - }
241   - }
242   - break;
243   - default:
244   - err = -EINVAL;
245   - break;
  263 + return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
  264 +
  265 + case RAW_GETBIND:
  266 + if (copy_from_user(&rq, user_req, sizeof(rq)))
  267 + return -EFAULT;
  268 +
  269 + err = bind_get(rq.raw_minor, &dev);
  270 + if (err)
  271 + return err;
  272 +
  273 + rq.block_major = MAJOR(dev);
  274 + rq.block_minor = MINOR(dev);
  275 +
  276 + if (copy_to_user(user_req, &rq, sizeof(rq)))
  277 + return -EFAULT;
  278 +
  279 + return 0;
246 280 }
247   -out:
248   - unlock_kernel();
249   - return err;
  281 +
  282 + return -EINVAL;
250 283 }
  284 +#endif
251 285  
252 286 static const struct file_operations raw_fops = {
253 287 .read = do_sync_read,
... ... @@ -263,6 +297,9 @@
263 297  
264 298 static const struct file_operations raw_ctl_fops = {
265 299 .unlocked_ioctl = raw_ctl_ioctl,
  300 +#ifdef CONFIG_COMPAT
  301 + .compat_ioctl = raw_ctl_compat_ioctl,
  302 +#endif
266 303 .open = raw_open,
267 304 .owner = THIS_MODULE,
268 305 };
... ... @@ -599,70 +599,7 @@
599 599 #define HIDPGETCONNLIST _IOR('H', 210, int)
600 600 #define HIDPGETCONNINFO _IOR('H', 211, int)
601 601  
602   -#ifdef CONFIG_BLOCK
603   -struct raw32_config_request
604   -{
605   - compat_int_t raw_minor;
606   - __u64 block_major;
607   - __u64 block_minor;
608   -} __attribute__((packed));
609 602  
610   -static int get_raw32_request(struct raw_config_request *req, struct raw32_config_request __user *user_req)
611   -{
612   - int ret;
613   -
614   - if (!access_ok(VERIFY_READ, user_req, sizeof(struct raw32_config_request)))
615   - return -EFAULT;
616   -
617   - ret = __get_user(req->raw_minor, &user_req->raw_minor);
618   - ret |= __get_user(req->block_major, &user_req->block_major);
619   - ret |= __get_user(req->block_minor, &user_req->block_minor);
620   -
621   - return ret ? -EFAULT : 0;
622   -}
623   -
624   -static int set_raw32_request(struct raw_config_request *req, struct raw32_config_request __user *user_req)
625   -{
626   - int ret;
627   -
628   - if (!access_ok(VERIFY_WRITE, user_req, sizeof(struct raw32_config_request)))
629   - return -EFAULT;
630   -
631   - ret = __put_user(req->raw_minor, &user_req->raw_minor);
632   - ret |= __put_user(req->block_major, &user_req->block_major);
633   - ret |= __put_user(req->block_minor, &user_req->block_minor);
634   -
635   - return ret ? -EFAULT : 0;
636   -}
637   -
638   -static int raw_ioctl(unsigned fd, unsigned cmd,
639   - struct raw32_config_request __user *user_req)
640   -{
641   - int ret;
642   -
643   - switch (cmd) {
644   - case RAW_SETBIND:
645   - default: { /* RAW_GETBIND */
646   - struct raw_config_request req;
647   - mm_segment_t oldfs = get_fs();
648   -
649   - if ((ret = get_raw32_request(&req, user_req)))
650   - return ret;
651   -
652   - set_fs(KERNEL_DS);
653   - ret = sys_ioctl(fd,cmd,(unsigned long)&req);
654   - set_fs(oldfs);
655   -
656   - if ((!ret) && (cmd == RAW_GETBIND)) {
657   - ret = set_raw32_request(&req, user_req);
658   - }
659   - break;
660   - }
661   - }
662   - return ret;
663   -}
664   -#endif /* CONFIG_BLOCK */
665   -
666 603 struct serial_struct32 {
667 604 compat_int_t type;
668 605 compat_int_t line;
... ... @@ -1262,9 +1199,6 @@
1262 1199 COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
1263 1200 COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
1264 1201 COMPATIBLE_IOCTL(OSS_GETVERSION)
1265   -/* Raw devices */
1266   -COMPATIBLE_IOCTL(RAW_SETBIND)
1267   -COMPATIBLE_IOCTL(RAW_GETBIND)
1268 1202 /* SMB ioctls which do not need any translations */
1269 1203 COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
1270 1204 /* Watchdog */
... ... @@ -1523,10 +1457,6 @@
1523 1457 case MTIOCGET32:
1524 1458 case MTIOCPOS32:
1525 1459 return mt_ioctl_trans(fd, cmd, argp);
1526   - /* Raw devices */
1527   - case RAW_SETBIND:
1528   - case RAW_GETBIND:
1529   - return raw_ioctl(fd, cmd, argp);
1530 1460 #endif
1531 1461 /* One SMB ioctl needs translations. */
1532 1462 #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)