diff options
-rw-r--r-- | include/linux/atm.h | 17 | ||||
-rw-r--r-- | include/linux/atmdev.h | 15 | ||||
-rw-r--r-- | net/atm/common.h | 1 | ||||
-rw-r--r-- | net/atm/ioctl.c | 49 | ||||
-rw-r--r-- | net/atm/pvc.c | 3 | ||||
-rw-r--r-- | net/atm/resources.c | 88 | ||||
-rw-r--r-- | net/atm/resources.h | 2 | ||||
-rw-r--r-- | net/atm/svc.c | 19 |
8 files changed, 164 insertions, 30 deletions
diff --git a/include/linux/atm.h b/include/linux/atm.h index c791ddd96939..d3b292174aeb 100644 --- a/include/linux/atm.h +++ b/include/linux/atm.h | |||
@@ -231,10 +231,21 @@ static __inline__ int atmpvc_addr_in_use(struct sockaddr_atmpvc addr) | |||
231 | */ | 231 | */ |
232 | 232 | ||
233 | struct atmif_sioc { | 233 | struct atmif_sioc { |
234 | int number; | 234 | int number; |
235 | int length; | 235 | int length; |
236 | void __user *arg; | 236 | void __user *arg; |
237 | }; | 237 | }; |
238 | 238 | ||
239 | #ifdef __KERNEL__ | ||
240 | #ifdef CONFIG_COMPAT | ||
241 | #include <linux/compat.h> | ||
242 | struct compat_atmif_sioc { | ||
243 | int number; | ||
244 | int length; | ||
245 | compat_uptr_t arg; | ||
246 | }; | ||
247 | #endif | ||
248 | #endif | ||
249 | |||
239 | typedef unsigned short atm_backend_t; | 250 | typedef unsigned short atm_backend_t; |
240 | #endif | 251 | #endif |
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index a3d07c29d16c..086e5c362d3a 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h | |||
@@ -100,6 +100,10 @@ struct atm_dev_stats { | |||
100 | /* use backend to make new if */ | 100 | /* use backend to make new if */ |
101 | #define ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf) | 101 | #define ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf) |
102 | /* add party to p2mp call */ | 102 | /* add party to p2mp call */ |
103 | #ifdef CONFIG_COMPAT | ||
104 | /* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */ | ||
105 | #define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL+4,struct compat_atm_iobuf) | ||
106 | #endif | ||
103 | #define ATM_DROPPARTY _IOW('a', ATMIOC_SPECIAL+5,int) | 107 | #define ATM_DROPPARTY _IOW('a', ATMIOC_SPECIAL+5,int) |
104 | /* drop party from p2mp call */ | 108 | /* drop party from p2mp call */ |
105 | 109 | ||
@@ -224,6 +228,13 @@ struct atm_cirange { | |||
224 | extern struct proc_dir_entry *atm_proc_root; | 228 | extern struct proc_dir_entry *atm_proc_root; |
225 | #endif | 229 | #endif |
226 | 230 | ||
231 | #ifdef CONFIG_COMPAT | ||
232 | #include <linux/compat.h> | ||
233 | struct compat_atm_iobuf { | ||
234 | int length; | ||
235 | compat_uptr_t buffer; | ||
236 | }; | ||
237 | #endif | ||
227 | 238 | ||
228 | struct k_atm_aal_stats { | 239 | struct k_atm_aal_stats { |
229 | #define __HANDLE_ITEM(i) atomic_t i | 240 | #define __HANDLE_ITEM(i) atomic_t i |
@@ -379,6 +390,10 @@ struct atmdev_ops { /* only send is required */ | |||
379 | int (*open)(struct atm_vcc *vcc); | 390 | int (*open)(struct atm_vcc *vcc); |
380 | void (*close)(struct atm_vcc *vcc); | 391 | void (*close)(struct atm_vcc *vcc); |
381 | int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void __user *arg); | 392 | int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void __user *arg); |
393 | #ifdef CONFIG_COMPAT | ||
394 | int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd, | ||
395 | void __user *arg); | ||
396 | #endif | ||
382 | int (*getsockopt)(struct atm_vcc *vcc,int level,int optname, | 397 | int (*getsockopt)(struct atm_vcc *vcc,int level,int optname, |
383 | void __user *optval,int optlen); | 398 | void __user *optval,int optlen); |
384 | int (*setsockopt)(struct atm_vcc *vcc,int level,int optname, | 399 | int (*setsockopt)(struct atm_vcc *vcc,int level,int optname, |
diff --git a/net/atm/common.h b/net/atm/common.h index 16f32c1fa1c9..92e2981f479f 100644 --- a/net/atm/common.h +++ b/net/atm/common.h | |||
@@ -19,6 +19,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, | |||
19 | size_t total_len); | 19 | size_t total_len); |
20 | unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait); | 20 | unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait); |
21 | int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); | 21 | int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); |
22 | int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); | ||
22 | int vcc_setsockopt(struct socket *sock, int level, int optname, | 23 | int vcc_setsockopt(struct socket *sock, int level, int optname, |
23 | char __user *optval, int optlen); | 24 | char __user *optval, int optlen); |
24 | int vcc_getsockopt(struct socket *sock, int level, int optname, | 25 | int vcc_getsockopt(struct socket *sock, int level, int optname, |
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 7afd8e7754fd..76ed3c8d26e6 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/atmlec.h> | 19 | #include <linux/atmlec.h> |
20 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
21 | #include <asm/ioctls.h> | 21 | #include <asm/ioctls.h> |
22 | #include <net/compat.h> | ||
22 | 23 | ||
23 | #include "resources.h" | 24 | #include "resources.h" |
24 | #include "signaling.h" /* for WAITING and sigd_attach */ | 25 | #include "signaling.h" /* for WAITING and sigd_attach */ |
@@ -46,7 +47,7 @@ void deregister_atm_ioctl(struct atm_ioctl *ioctl) | |||
46 | EXPORT_SYMBOL(register_atm_ioctl); | 47 | EXPORT_SYMBOL(register_atm_ioctl); |
47 | EXPORT_SYMBOL(deregister_atm_ioctl); | 48 | EXPORT_SYMBOL(deregister_atm_ioctl); |
48 | 49 | ||
49 | int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | 50 | static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat) |
50 | { | 51 | { |
51 | struct sock *sk = sock->sk; | 52 | struct sock *sk = sock->sk; |
52 | struct atm_vcc *vcc; | 53 | struct atm_vcc *vcc; |
@@ -80,13 +81,25 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
80 | goto done; | 81 | goto done; |
81 | } | 82 | } |
82 | case SIOCGSTAMP: /* borrowed from IP */ | 83 | case SIOCGSTAMP: /* borrowed from IP */ |
83 | error = sock_get_timestamp(sk, argp); | 84 | #ifdef CONFIG_COMPAT |
85 | if (compat) | ||
86 | error = compat_sock_get_timestamp(sk, argp); | ||
87 | else | ||
88 | #endif | ||
89 | error = sock_get_timestamp(sk, argp); | ||
84 | goto done; | 90 | goto done; |
85 | case SIOCGSTAMPNS: /* borrowed from IP */ | 91 | case SIOCGSTAMPNS: /* borrowed from IP */ |
86 | error = sock_get_timestampns(sk, argp); | 92 | #ifdef CONFIG_COMPAT |
93 | if (compat) | ||
94 | error = compat_sock_get_timestampns(sk, argp); | ||
95 | else | ||
96 | #endif | ||
97 | error = sock_get_timestampns(sk, argp); | ||
87 | goto done; | 98 | goto done; |
88 | case ATM_SETSC: | 99 | case ATM_SETSC: |
89 | printk(KERN_WARNING "ATM_SETSC is obsolete\n"); | 100 | if (net_ratelimit()) |
101 | printk(KERN_WARNING "ATM_SETSC is obsolete; used by %s:%d\n", | ||
102 | current->comm, task_pid_nr(current)); | ||
90 | error = 0; | 103 | error = 0; |
91 | goto done; | 104 | goto done; |
92 | case ATMSIGD_CTRL: | 105 | case ATMSIGD_CTRL: |
@@ -99,12 +112,23 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
99 | * info uses kernel pointers as opaque references, | 112 | * info uses kernel pointers as opaque references, |
100 | * so the holder of the file descriptor can scribble | 113 | * so the holder of the file descriptor can scribble |
101 | * on the kernel... so we should make sure that we | 114 | * on the kernel... so we should make sure that we |
102 | * have the same privledges that /proc/kcore needs | 115 | * have the same privileges that /proc/kcore needs |
103 | */ | 116 | */ |
104 | if (!capable(CAP_SYS_RAWIO)) { | 117 | if (!capable(CAP_SYS_RAWIO)) { |
105 | error = -EPERM; | 118 | error = -EPERM; |
106 | goto done; | 119 | goto done; |
107 | } | 120 | } |
121 | #ifdef CONFIG_COMPAT | ||
122 | /* WTF? I don't even want to _think_ about making this | ||
123 | work for 32-bit userspace. TBH I don't really want | ||
124 | to think about it at all. dwmw2. */ | ||
125 | if (compat) { | ||
126 | if (net_ratelimit()) | ||
127 | printk(KERN_WARNING "32-bit task cannot be atmsigd\n"); | ||
128 | error = -EINVAL; | ||
129 | goto done; | ||
130 | } | ||
131 | #endif | ||
108 | error = sigd_attach(vcc); | 132 | error = sigd_attach(vcc); |
109 | if (!error) | 133 | if (!error) |
110 | sock->state = SS_CONNECTED; | 134 | sock->state = SS_CONNECTED; |
@@ -155,8 +179,21 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
155 | if (error != -ENOIOCTLCMD) | 179 | if (error != -ENOIOCTLCMD) |
156 | goto done; | 180 | goto done; |
157 | 181 | ||
158 | error = atm_dev_ioctl(cmd, argp); | 182 | error = atm_dev_ioctl(cmd, argp, compat); |
159 | 183 | ||
160 | done: | 184 | done: |
161 | return error; | 185 | return error; |
162 | } | 186 | } |
187 | |||
188 | |||
189 | int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
190 | { | ||
191 | return do_vcc_ioctl(sock, cmd, arg, 0); | ||
192 | } | ||
193 | |||
194 | #ifdef CONFIG_COMPAT | ||
195 | int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
196 | { | ||
197 | return do_vcc_ioctl(sock, cmd, arg, 1); | ||
198 | } | ||
199 | #endif | ||
diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 43e8bf5ed001..e1d22d9430dd 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c | |||
@@ -113,6 +113,9 @@ static const struct proto_ops pvc_proto_ops = { | |||
113 | .getname = pvc_getname, | 113 | .getname = pvc_getname, |
114 | .poll = vcc_poll, | 114 | .poll = vcc_poll, |
115 | .ioctl = vcc_ioctl, | 115 | .ioctl = vcc_ioctl, |
116 | #ifdef CONFIG_COMPAT | ||
117 | .compat_ioctl = vcc_compat_ioctl, | ||
118 | #endif | ||
116 | .listen = sock_no_listen, | 119 | .listen = sock_no_listen, |
117 | .shutdown = pvc_shutdown, | 120 | .shutdown = pvc_shutdown, |
118 | .setsockopt = pvc_setsockopt, | 121 | .setsockopt = pvc_setsockopt, |
diff --git a/net/atm/resources.c b/net/atm/resources.c index a34ba948af96..56b7322ff461 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -195,20 +195,39 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in | |||
195 | } | 195 | } |
196 | 196 | ||
197 | 197 | ||
198 | int atm_dev_ioctl(unsigned int cmd, void __user *arg) | 198 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) |
199 | { | 199 | { |
200 | void __user *buf; | 200 | void __user *buf; |
201 | int error, len, number, size = 0; | 201 | int error, len, number, size = 0; |
202 | struct atm_dev *dev; | 202 | struct atm_dev *dev; |
203 | struct list_head *p; | 203 | struct list_head *p; |
204 | int *tmp_buf, *tmp_p; | 204 | int *tmp_buf, *tmp_p; |
205 | struct atm_iobuf __user *iobuf = arg; | 205 | int __user *sioc_len; |
206 | struct atmif_sioc __user *sioc = arg; | 206 | int __user *iobuf_len; |
207 | |||
208 | #ifndef CONFIG_COMPAT | ||
209 | compat = 0; /* Just so the compiler _knows_ */ | ||
210 | #endif | ||
211 | |||
207 | switch (cmd) { | 212 | switch (cmd) { |
208 | case ATM_GETNAMES: | 213 | case ATM_GETNAMES: |
209 | if (get_user(buf, &iobuf->buffer)) | 214 | |
210 | return -EFAULT; | 215 | if (compat) { |
211 | if (get_user(len, &iobuf->length)) | 216 | #ifdef CONFIG_COMPAT |
217 | struct compat_atm_iobuf __user *ciobuf = arg; | ||
218 | compat_uptr_t cbuf; | ||
219 | iobuf_len = &ciobuf->length; | ||
220 | if (get_user(cbuf, &ciobuf->buffer)) | ||
221 | return -EFAULT; | ||
222 | buf = compat_ptr(cbuf); | ||
223 | #endif | ||
224 | } else { | ||
225 | struct atm_iobuf __user *iobuf = arg; | ||
226 | iobuf_len = &iobuf->length; | ||
227 | if (get_user(buf, &iobuf->buffer)) | ||
228 | return -EFAULT; | ||
229 | } | ||
230 | if (get_user(len, iobuf_len)) | ||
212 | return -EFAULT; | 231 | return -EFAULT; |
213 | mutex_lock(&atm_dev_mutex); | 232 | mutex_lock(&atm_dev_mutex); |
214 | list_for_each(p, &atm_devs) | 233 | list_for_each(p, &atm_devs) |
@@ -229,7 +248,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
229 | } | 248 | } |
230 | mutex_unlock(&atm_dev_mutex); | 249 | mutex_unlock(&atm_dev_mutex); |
231 | error = ((copy_to_user(buf, tmp_buf, size)) || | 250 | error = ((copy_to_user(buf, tmp_buf, size)) || |
232 | put_user(size, &iobuf->length)) | 251 | put_user(size, iobuf_len)) |
233 | ? -EFAULT : 0; | 252 | ? -EFAULT : 0; |
234 | kfree(tmp_buf); | 253 | kfree(tmp_buf); |
235 | return error; | 254 | return error; |
@@ -237,13 +256,32 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
237 | break; | 256 | break; |
238 | } | 257 | } |
239 | 258 | ||
240 | if (get_user(buf, &sioc->arg)) | 259 | if (compat) { |
241 | return -EFAULT; | 260 | #ifdef CONFIG_COMPAT |
242 | if (get_user(len, &sioc->length)) | 261 | struct compat_atmif_sioc __user *csioc = arg; |
243 | return -EFAULT; | 262 | compat_uptr_t carg; |
244 | if (get_user(number, &sioc->number)) | 263 | |
245 | return -EFAULT; | 264 | sioc_len = &csioc->length; |
246 | 265 | if (get_user(carg, &csioc->arg)) | |
266 | return -EFAULT; | ||
267 | buf = compat_ptr(carg); | ||
268 | |||
269 | if (get_user(len, &csioc->length)) | ||
270 | return -EFAULT; | ||
271 | if (get_user(number, &csioc->number)) | ||
272 | return -EFAULT; | ||
273 | #endif | ||
274 | } else { | ||
275 | struct atmif_sioc __user *sioc = arg; | ||
276 | |||
277 | sioc_len = &sioc->length; | ||
278 | if (get_user(buf, &sioc->arg)) | ||
279 | return -EFAULT; | ||
280 | if (get_user(len, &sioc->length)) | ||
281 | return -EFAULT; | ||
282 | if (get_user(number, &sioc->number)) | ||
283 | return -EFAULT; | ||
284 | } | ||
247 | if (!(dev = try_then_request_module(atm_dev_lookup(number), | 285 | if (!(dev = try_then_request_module(atm_dev_lookup(number), |
248 | "atm-device-%d", number))) | 286 | "atm-device-%d", number))) |
249 | return -ENODEV; | 287 | return -ENODEV; |
@@ -358,7 +396,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
358 | size = error; | 396 | size = error; |
359 | /* may return 0, but later on size == 0 means "don't | 397 | /* may return 0, but later on size == 0 means "don't |
360 | write the length" */ | 398 | write the length" */ |
361 | error = put_user(size, &sioc->length) | 399 | error = put_user(size, sioc_len) |
362 | ? -EFAULT : 0; | 400 | ? -EFAULT : 0; |
363 | goto done; | 401 | goto done; |
364 | case ATM_SETLOOP: | 402 | case ATM_SETLOOP: |
@@ -380,11 +418,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
380 | } | 418 | } |
381 | /* fall through */ | 419 | /* fall through */ |
382 | default: | 420 | default: |
383 | if (!dev->ops->ioctl) { | 421 | if (compat) { |
384 | error = -EINVAL; | 422 | #ifdef CONFIG_COMPAT |
385 | goto done; | 423 | if (!dev->ops->compat_ioctl) { |
424 | error = -EINVAL; | ||
425 | goto done; | ||
426 | } | ||
427 | size = dev->ops->compat_ioctl(dev, cmd, buf); | ||
428 | #endif | ||
429 | } else { | ||
430 | if (!dev->ops->ioctl) { | ||
431 | error = -EINVAL; | ||
432 | goto done; | ||
433 | } | ||
434 | size = dev->ops->ioctl(dev, cmd, buf); | ||
386 | } | 435 | } |
387 | size = dev->ops->ioctl(dev, cmd, buf); | ||
388 | if (size < 0) { | 436 | if (size < 0) { |
389 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); | 437 | error = (size == -ENOIOCTLCMD ? -EINVAL : size); |
390 | goto done; | 438 | goto done; |
@@ -392,7 +440,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
392 | } | 440 | } |
393 | 441 | ||
394 | if (size) | 442 | if (size) |
395 | error = put_user(size, &sioc->length) | 443 | error = put_user(size, sioc_len) |
396 | ? -EFAULT : 0; | 444 | ? -EFAULT : 0; |
397 | else | 445 | else |
398 | error = 0; | 446 | error = 0; |
diff --git a/net/atm/resources.h b/net/atm/resources.h index 1d004aaaeec1..126fb1840dfb 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h | |||
@@ -13,7 +13,7 @@ | |||
13 | extern struct list_head atm_devs; | 13 | extern struct list_head atm_devs; |
14 | extern struct mutex atm_dev_mutex; | 14 | extern struct mutex atm_dev_mutex; |
15 | 15 | ||
16 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); | 16 | int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat); |
17 | 17 | ||
18 | 18 | ||
19 | #ifdef CONFIG_PROC_FS | 19 | #ifdef CONFIG_PROC_FS |
diff --git a/net/atm/svc.c b/net/atm/svc.c index de1e4f2f3a43..e9c65500f84e 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c | |||
@@ -604,6 +604,22 @@ static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
604 | return error; | 604 | return error; |
605 | } | 605 | } |
606 | 606 | ||
607 | #ifdef CONFIG_COMPAT | ||
608 | static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
609 | { | ||
610 | /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf. | ||
611 | But actually it takes a struct sockaddr_atmsvc, which doesn't need | ||
612 | compat handling. So all we have to do is fix up cmd... */ | ||
613 | if (cmd == COMPAT_ATM_ADDPARTY) | ||
614 | cmd = ATM_ADDPARTY; | ||
615 | |||
616 | if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY) | ||
617 | return svc_ioctl(sock, cmd, arg); | ||
618 | else | ||
619 | return vcc_compat_ioctl(sock, cmd, arg); | ||
620 | } | ||
621 | #endif /* CONFIG_COMPAT */ | ||
622 | |||
607 | static const struct proto_ops svc_proto_ops = { | 623 | static const struct proto_ops svc_proto_ops = { |
608 | .family = PF_ATMSVC, | 624 | .family = PF_ATMSVC, |
609 | .owner = THIS_MODULE, | 625 | .owner = THIS_MODULE, |
@@ -616,6 +632,9 @@ static const struct proto_ops svc_proto_ops = { | |||
616 | .getname = svc_getname, | 632 | .getname = svc_getname, |
617 | .poll = vcc_poll, | 633 | .poll = vcc_poll, |
618 | .ioctl = svc_ioctl, | 634 | .ioctl = svc_ioctl, |
635 | #ifdef CONFIG_COMPAT | ||
636 | .compat_ioctl = svc_compat_ioctl, | ||
637 | #endif | ||
619 | .listen = svc_listen, | 638 | .listen = svc_listen, |
620 | .shutdown = svc_shutdown, | 639 | .shutdown = svc_shutdown, |
621 | .setsockopt = svc_setsockopt, | 640 | .setsockopt = svc_setsockopt, |