.. | .. |
---|
46 | 46 | return 0; |
---|
47 | 47 | } |
---|
48 | 48 | |
---|
49 | | -static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
---|
| 49 | +static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp) |
---|
50 | 50 | { |
---|
51 | | - void __user *argp = (void __user *) arg; |
---|
52 | 51 | struct hidp_connadd_req ca; |
---|
53 | 52 | struct hidp_conndel_req cd; |
---|
54 | 53 | struct hidp_connlist_req cl; |
---|
.. | .. |
---|
57 | 56 | struct socket *isock; |
---|
58 | 57 | int err; |
---|
59 | 58 | |
---|
60 | | - BT_DBG("cmd %x arg %lx", cmd, arg); |
---|
| 59 | + BT_DBG("cmd %x arg %p", cmd, argp); |
---|
61 | 60 | |
---|
62 | 61 | switch (cmd) { |
---|
63 | 62 | case HIDPCONNADD: |
---|
.. | .. |
---|
123 | 122 | return -EINVAL; |
---|
124 | 123 | } |
---|
125 | 124 | |
---|
| 125 | +static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
---|
| 126 | +{ |
---|
| 127 | + return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg); |
---|
| 128 | +} |
---|
| 129 | + |
---|
126 | 130 | #ifdef CONFIG_COMPAT |
---|
127 | 131 | struct compat_hidp_connadd_req { |
---|
128 | 132 | int ctrl_sock; /* Connected control socket */ |
---|
.. | .. |
---|
142 | 146 | |
---|
143 | 147 | static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
---|
144 | 148 | { |
---|
| 149 | + void __user *argp = compat_ptr(arg); |
---|
| 150 | + int err; |
---|
| 151 | + |
---|
145 | 152 | if (cmd == HIDPGETCONNLIST) { |
---|
146 | 153 | struct hidp_connlist_req cl; |
---|
| 154 | + u32 __user *p = argp; |
---|
147 | 155 | u32 uci; |
---|
148 | | - int err; |
---|
149 | 156 | |
---|
150 | | - if (get_user(cl.cnum, (u32 __user *) arg) || |
---|
151 | | - get_user(uci, (u32 __user *) (arg + 4))) |
---|
| 157 | + if (get_user(cl.cnum, p) || get_user(uci, p + 1)) |
---|
152 | 158 | return -EFAULT; |
---|
153 | 159 | |
---|
154 | 160 | cl.ci = compat_ptr(uci); |
---|
.. | .. |
---|
158 | 164 | |
---|
159 | 165 | err = hidp_get_connlist(&cl); |
---|
160 | 166 | |
---|
161 | | - if (!err && put_user(cl.cnum, (u32 __user *) arg)) |
---|
| 167 | + if (!err && put_user(cl.cnum, p)) |
---|
162 | 168 | err = -EFAULT; |
---|
163 | 169 | |
---|
164 | 170 | return err; |
---|
165 | 171 | } else if (cmd == HIDPCONNADD) { |
---|
166 | | - struct compat_hidp_connadd_req ca; |
---|
167 | | - struct hidp_connadd_req __user *uca; |
---|
| 172 | + struct compat_hidp_connadd_req ca32; |
---|
| 173 | + struct hidp_connadd_req ca; |
---|
| 174 | + struct socket *csock; |
---|
| 175 | + struct socket *isock; |
---|
168 | 176 | |
---|
169 | | - uca = compat_alloc_user_space(sizeof(*uca)); |
---|
| 177 | + if (!capable(CAP_NET_ADMIN)) |
---|
| 178 | + return -EPERM; |
---|
170 | 179 | |
---|
171 | | - if (copy_from_user(&ca, (void __user *) arg, sizeof(ca))) |
---|
| 180 | + if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32))) |
---|
172 | 181 | return -EFAULT; |
---|
173 | 182 | |
---|
174 | | - if (put_user(ca.ctrl_sock, &uca->ctrl_sock) || |
---|
175 | | - put_user(ca.intr_sock, &uca->intr_sock) || |
---|
176 | | - put_user(ca.parser, &uca->parser) || |
---|
177 | | - put_user(ca.rd_size, &uca->rd_size) || |
---|
178 | | - put_user(compat_ptr(ca.rd_data), &uca->rd_data) || |
---|
179 | | - put_user(ca.country, &uca->country) || |
---|
180 | | - put_user(ca.subclass, &uca->subclass) || |
---|
181 | | - put_user(ca.vendor, &uca->vendor) || |
---|
182 | | - put_user(ca.product, &uca->product) || |
---|
183 | | - put_user(ca.version, &uca->version) || |
---|
184 | | - put_user(ca.flags, &uca->flags) || |
---|
185 | | - put_user(ca.idle_to, &uca->idle_to) || |
---|
186 | | - copy_to_user(&uca->name[0], &ca.name[0], 128)) |
---|
187 | | - return -EFAULT; |
---|
| 183 | + ca.ctrl_sock = ca32.ctrl_sock; |
---|
| 184 | + ca.intr_sock = ca32.intr_sock; |
---|
| 185 | + ca.parser = ca32.parser; |
---|
| 186 | + ca.rd_size = ca32.rd_size; |
---|
| 187 | + ca.rd_data = compat_ptr(ca32.rd_data); |
---|
| 188 | + ca.country = ca32.country; |
---|
| 189 | + ca.subclass = ca32.subclass; |
---|
| 190 | + ca.vendor = ca32.vendor; |
---|
| 191 | + ca.product = ca32.product; |
---|
| 192 | + ca.version = ca32.version; |
---|
| 193 | + ca.flags = ca32.flags; |
---|
| 194 | + ca.idle_to = ca32.idle_to; |
---|
| 195 | + ca32.name[sizeof(ca32.name) - 1] = '\0'; |
---|
| 196 | + memcpy(ca.name, ca32.name, 128); |
---|
188 | 197 | |
---|
189 | | - arg = (unsigned long) uca; |
---|
| 198 | + csock = sockfd_lookup(ca.ctrl_sock, &err); |
---|
| 199 | + if (!csock) |
---|
| 200 | + return err; |
---|
190 | 201 | |
---|
191 | | - /* Fall through. We don't actually write back any _changes_ |
---|
192 | | - to the structure anyway, so there's no need to copy back |
---|
193 | | - into the original compat version */ |
---|
| 202 | + isock = sockfd_lookup(ca.intr_sock, &err); |
---|
| 203 | + if (!isock) { |
---|
| 204 | + sockfd_put(csock); |
---|
| 205 | + return err; |
---|
| 206 | + } |
---|
| 207 | + |
---|
| 208 | + err = hidp_connection_add(&ca, csock, isock); |
---|
| 209 | + if (!err && copy_to_user(argp, &ca32, sizeof(ca32))) |
---|
| 210 | + err = -EFAULT; |
---|
| 211 | + |
---|
| 212 | + sockfd_put(csock); |
---|
| 213 | + sockfd_put(isock); |
---|
| 214 | + |
---|
| 215 | + return err; |
---|
194 | 216 | } |
---|
195 | 217 | |
---|
196 | 218 | return hidp_sock_ioctl(sock, cmd, arg); |
---|
.. | .. |
---|
211 | 233 | .recvmsg = sock_no_recvmsg, |
---|
212 | 234 | .listen = sock_no_listen, |
---|
213 | 235 | .shutdown = sock_no_shutdown, |
---|
214 | | - .setsockopt = sock_no_setsockopt, |
---|
215 | | - .getsockopt = sock_no_getsockopt, |
---|
216 | 236 | .connect = sock_no_connect, |
---|
217 | 237 | .socketpair = sock_no_socketpair, |
---|
218 | 238 | .accept = sock_no_accept, |
---|