aboutsummaryrefslogtreecommitdiffstats
path: root/net/atm
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2008-12-04 01:12:38 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 01:12:38 -0500
commit8865c418caf4e9dd2c24bdfae3a5a4106e143e60 (patch)
tree4d7fac2c74af56c6aaf83b324b349b76c5f949d9 /net/atm
parentdcd39c90290297f6e6ed8a04bb20da7ac2b043c5 (diff)
atm: 32-bit ioctl compatibility
We lack compat ioctl support through most of the ATM code. This patch deals with most of it, and I can now at least use BR2684 and PPPoATM with 32-bit userspace. I haven't added a .compat_ioctl method to struct atm_ioctl, because AFAICT none of the current users need any conversion -- so we can just call the ->ioctl() method in every case. I looked at br2684, clip, lec, mpc, pppoatm and atmtcp. In svc_compat_ioctl() the only mangling which is needed is to change COMPAT_ATM_ADDPARTY to ATM_ADDPARTY. Although it's defined as _IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf) it doesn't actually _take_ a struct atm_iobuf as an argument -- it takes a struct sockaddr_atmsvc, which _is_ the same between 32-bit and 64-bit code, so doesn't need conversion. Almost all of vcc_ioctl() would have been identical, so I converted that into a core do_vcc_ioctl() function with an 'int compat' argument. I've done the same with atm_dev_ioctl(), where there _are_ a few differences, but still it's relatively contained and there would otherwise have been a lot of duplication. I haven't done any of the actual device-specific ioctls, although I've added a compat_ioctl method to struct atmdev_ops. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/common.h1
-rw-r--r--net/atm/ioctl.c49
-rw-r--r--net/atm/pvc.c3
-rw-r--r--net/atm/resources.c88
-rw-r--r--net/atm/resources.h2
-rw-r--r--net/atm/svc.c19
6 files changed, 135 insertions, 27 deletions
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);
20unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait); 20unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait);
21int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); 21int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
22int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
22int vcc_setsockopt(struct socket *sock, int level, int optname, 23int vcc_setsockopt(struct socket *sock, int level, int optname,
23 char __user *optval, int optlen); 24 char __user *optval, int optlen);
24int vcc_getsockopt(struct socket *sock, int level, int optname, 25int 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)
46EXPORT_SYMBOL(register_atm_ioctl); 47EXPORT_SYMBOL(register_atm_ioctl);
47EXPORT_SYMBOL(deregister_atm_ioctl); 48EXPORT_SYMBOL(deregister_atm_ioctl);
48 49
49int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 50static 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
160done: 184done:
161 return error; 185 return error;
162} 186}
187
188
189int 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
195int 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
198int atm_dev_ioctl(unsigned int cmd, void __user *arg) 198int 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 @@
13extern struct list_head atm_devs; 13extern struct list_head atm_devs;
14extern struct mutex atm_dev_mutex; 14extern struct mutex atm_dev_mutex;
15 15
16int atm_dev_ioctl(unsigned int cmd, void __user *arg); 16int 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
608static 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
607static const struct proto_ops svc_proto_ops = { 623static 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,