diff options
author | Guy Martin <gmsoft@tuxicoman.be> | 2006-01-11 20:40:51 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@brturbo.com.br> | 2006-01-11 21:11:55 -0500 |
commit | a113bc787e9b0e792f316e803b619d31af1397ad (patch) | |
tree | 872361a49a080925729c0d0b6b686d894c69a4f6 | |
parent | f8bf134d5f697311c04e867b6733d047a4b55a12 (diff) |
V4L/DVB (3352): Some fixes to compat_ioctl32
- Adds suppport or fix support for VIDIOC_ENUMSTD, VIDIOC_ENUMINPUT,
VIDIOC_G_TUNER and VIDIOC_S_TUNER.
- Fix the warnings at compile time and add checks for the pointer validity
using access_ok().
- v4l_print_ioctl() has also be added to identify possible missing ioctls.
- Has been tested on sparc64 and amd64. Other arches such as mips and hppa
are expected to work as sparc, but not tested yet.
Signed-off-by: Guy Martin <gmsoft@tuxicoman.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/compat_ioctl32.c | 371 |
1 files changed, 259 insertions, 112 deletions
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 6194b0125576..297c32ab51e3 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c | |||
@@ -18,8 +18,11 @@ | |||
18 | #include <linux/videodev2.h> | 18 | #include <linux/videodev2.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
21 | #include <media/v4l2-common.h> | ||
21 | 22 | ||
22 | #ifdef CONFIG_COMPAT | 23 | #ifdef CONFIG_COMPAT |
24 | |||
25 | |||
23 | struct video_tuner32 { | 26 | struct video_tuner32 { |
24 | compat_int_t tuner; | 27 | compat_int_t tuner; |
25 | char name[32]; | 28 | char name[32]; |
@@ -30,27 +33,29 @@ struct video_tuner32 { | |||
30 | 33 | ||
31 | static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) | 34 | static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) |
32 | { | 35 | { |
33 | if(get_user(kp->tuner, &up->tuner)) | 36 | if(!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) || |
37 | get_user(kp->tuner, &up->tuner) || | ||
38 | copy_from_user(kp->name, up->name, 32) || | ||
39 | get_user(kp->rangelow, &up->rangelow) || | ||
40 | get_user(kp->rangehigh, &up->rangehigh) || | ||
41 | get_user(kp->flags, &up->flags) || | ||
42 | get_user(kp->mode, &up->mode) || | ||
43 | get_user(kp->signal, &up->signal)) | ||
34 | return -EFAULT; | 44 | return -EFAULT; |
35 | __copy_from_user(kp->name, up->name, 32); | ||
36 | __get_user(kp->rangelow, &up->rangelow); | ||
37 | __get_user(kp->rangehigh, &up->rangehigh); | ||
38 | __get_user(kp->flags, &up->flags); | ||
39 | __get_user(kp->mode, &up->mode); | ||
40 | __get_user(kp->signal, &up->signal); | ||
41 | return 0; | 45 | return 0; |
42 | } | 46 | } |
43 | 47 | ||
44 | static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) | 48 | static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) |
45 | { | 49 | { |
46 | if(put_user(kp->tuner, &up->tuner)) | 50 | if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) || |
47 | return -EFAULT; | 51 | put_user(kp->tuner, &up->tuner) || |
48 | __copy_to_user(up->name, kp->name, 32); | 52 | copy_to_user(up->name, kp->name, 32) || |
49 | __put_user(kp->rangelow, &up->rangelow); | 53 | put_user(kp->rangelow, &up->rangelow) || |
50 | __put_user(kp->rangehigh, &up->rangehigh); | 54 | put_user(kp->rangehigh, &up->rangehigh) || |
51 | __put_user(kp->flags, &up->flags); | 55 | put_user(kp->flags, &up->flags) || |
52 | __put_user(kp->mode, &up->mode); | 56 | put_user(kp->mode, &up->mode) || |
53 | __put_user(kp->signal, &up->signal); | 57 | put_user(kp->signal, &up->signal)) |
58 | return -EFAULT; | ||
54 | return 0; | 59 | return 0; |
55 | } | 60 | } |
56 | 61 | ||
@@ -63,18 +68,19 @@ static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u | |||
63 | { | 68 | { |
64 | u32 tmp; | 69 | u32 tmp; |
65 | 70 | ||
66 | if (get_user(tmp, &up->base)) | 71 | if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) || |
67 | return -EFAULT; | 72 | get_user(tmp, &up->base) || |
73 | get_user(kp->height, &up->height) || | ||
74 | get_user(kp->width, &up->width) || | ||
75 | get_user(kp->depth, &up->depth) || | ||
76 | get_user(kp->bytesperline, &up->bytesperline)) | ||
77 | return -EFAULT; | ||
68 | 78 | ||
69 | /* This is actually a physical address stored | 79 | /* This is actually a physical address stored |
70 | * as a void pointer. | 80 | * as a void pointer. |
71 | */ | 81 | */ |
72 | kp->base = (void *)(unsigned long) tmp; | 82 | kp->base = (void *)(unsigned long) tmp; |
73 | 83 | ||
74 | __get_user(kp->height, &up->height); | ||
75 | __get_user(kp->width, &up->width); | ||
76 | __get_user(kp->depth, &up->depth); | ||
77 | __get_user(kp->bytesperline, &up->bytesperline); | ||
78 | return 0; | 84 | return 0; |
79 | } | 85 | } |
80 | 86 | ||
@@ -82,12 +88,13 @@ static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u | |||
82 | { | 88 | { |
83 | u32 tmp = (u32)((unsigned long)kp->base); | 89 | u32 tmp = (u32)((unsigned long)kp->base); |
84 | 90 | ||
85 | if(put_user(tmp, &up->base)) | 91 | if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) || |
86 | return -EFAULT; | 92 | put_user(tmp, &up->base) || |
87 | __put_user(kp->height, &up->height); | 93 | put_user(kp->height, &up->height) || |
88 | __put_user(kp->width, &up->width); | 94 | put_user(kp->width, &up->width) || |
89 | __put_user(kp->depth, &up->depth); | 95 | put_user(kp->depth, &up->depth) || |
90 | __put_user(kp->bytesperline, &up->bytesperline); | 96 | put_user(kp->bytesperline, &up->bytesperline)) |
97 | return -EFAULT; | ||
91 | return 0; | 98 | return 0; |
92 | } | 99 | } |
93 | 100 | ||
@@ -121,14 +128,15 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
121 | /* You get back everything except the clips... */ | 128 | /* You get back everything except the clips... */ |
122 | static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) | 129 | static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) |
123 | { | 130 | { |
124 | if(put_user(kp->x, &up->x)) | 131 | if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) || |
125 | return -EFAULT; | 132 | put_user(kp->x, &up->x) || |
126 | __put_user(kp->y, &up->y); | 133 | put_user(kp->y, &up->y) || |
127 | __put_user(kp->width, &up->width); | 134 | put_user(kp->width, &up->width) || |
128 | __put_user(kp->height, &up->height); | 135 | put_user(kp->height, &up->height) || |
129 | __put_user(kp->chromakey, &up->chromakey); | 136 | put_user(kp->chromakey, &up->chromakey) || |
130 | __put_user(kp->flags, &up->flags); | 137 | put_user(kp->flags, &up->flags) || |
131 | __put_user(kp->clipcount, &up->clipcount); | 138 | put_user(kp->clipcount, &up->clipcount)) |
139 | return -EFAULT; | ||
132 | return 0; | 140 | return 0; |
133 | } | 141 | } |
134 | 142 | ||
@@ -150,11 +158,12 @@ struct v4l2_window32 | |||
150 | 158 | ||
151 | static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) | 159 | static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) |
152 | { | 160 | { |
153 | if (copy_from_user(&kp->w, &up->w, sizeof(up->w))) | 161 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || |
154 | return -EFAULT; | 162 | copy_from_user(&kp->w, &up->w, sizeof(up->w)) || |
155 | __get_user(kp->field, &up->field); | 163 | get_user(kp->field, &up->field) || |
156 | __get_user(kp->chromakey, &up->chromakey); | 164 | get_user(kp->chromakey, &up->chromakey) || |
157 | __get_user(kp->clipcount, &up->clipcount); | 165 | get_user(kp->clipcount, &up->clipcount)) |
166 | return -EFAULT; | ||
158 | if (kp->clipcount > 2048) | 167 | if (kp->clipcount > 2048) |
159 | return -EINVAL; | 168 | return -EINVAL; |
160 | if (kp->clipcount) { | 169 | if (kp->clipcount) { |
@@ -165,7 +174,9 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user | |||
165 | kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); | 174 | kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); |
166 | kp->clips = kclips; | 175 | kp->clips = kclips; |
167 | while (--n >= 0) { | 176 | while (--n >= 0) { |
168 | copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c)); | 177 | if (!access_ok(VERIFY_READ, &uclips->c, sizeof(uclips->c)) || |
178 | copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c))) | ||
179 | return -EFAULT; | ||
169 | kclips->next = n ? kclips + 1 : 0; | 180 | kclips->next = n ? kclips + 1 : 0; |
170 | uclips += 1; | 181 | uclips += 1; |
171 | kclips += 1; | 182 | kclips += 1; |
@@ -177,32 +188,45 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user | |||
177 | 188 | ||
178 | static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) | 189 | static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) |
179 | { | 190 | { |
180 | if (copy_to_user(&up->w, &kp->w, sizeof(up->w))) | 191 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_window32)) || |
181 | return -EFAULT; | 192 | copy_to_user(&up->w, &kp->w, sizeof(up->w)) || |
182 | __put_user(kp->field, &up->field); | 193 | put_user(kp->field, &up->field) || |
183 | __put_user(kp->chromakey, &up->chromakey); | 194 | put_user(kp->chromakey, &up->chromakey) || |
184 | __put_user(kp->clipcount, &up->clipcount); | 195 | put_user(kp->clipcount, &up->clipcount)) |
196 | return -EFAULT; | ||
185 | return 0; | 197 | return 0; |
186 | } | 198 | } |
187 | 199 | ||
188 | static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) | 200 | static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) |
189 | { | 201 | { |
190 | return copy_from_user(kp, up, sizeof(struct v4l2_pix_format)); | 202 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_pix_format)) || |
203 | copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) | ||
204 | return -EFAULT; | ||
205 | return 0; | ||
191 | } | 206 | } |
192 | 207 | ||
193 | static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) | 208 | static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) |
194 | { | 209 | { |
195 | return copy_to_user(up, kp, sizeof(struct v4l2_pix_format)); | 210 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_pix_format)) || |
211 | copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) | ||
212 | return -EFAULT; | ||
213 | return 0; | ||
196 | } | 214 | } |
197 | 215 | ||
198 | static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) | 216 | static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) |
199 | { | 217 | { |
200 | return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)); | 218 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_vbi_format)) || |
219 | copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) | ||
220 | return -EFAULT; | ||
221 | return 0; | ||
201 | } | 222 | } |
202 | 223 | ||
203 | static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) | 224 | static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) |
204 | { | 225 | { |
205 | return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)); | 226 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_vbi_format)) || |
227 | copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) | ||
228 | return -EFAULT; | ||
229 | return 0; | ||
206 | } | 230 | } |
207 | 231 | ||
208 | struct v4l2_format32 | 232 | struct v4l2_format32 |
@@ -219,8 +243,9 @@ struct v4l2_format32 | |||
219 | 243 | ||
220 | static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | 244 | static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) |
221 | { | 245 | { |
222 | if(get_user(kp->type, &up->type)) | 246 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || |
223 | return -EFAULT; | 247 | get_user(kp->type, &up->type)) |
248 | return -EFAULT; | ||
224 | switch (kp->type) { | 249 | switch (kp->type) { |
225 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 250 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
226 | return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); | 251 | return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); |
@@ -237,7 +262,8 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
237 | 262 | ||
238 | static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | 263 | static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) |
239 | { | 264 | { |
240 | if(put_user(kp->type, &up->type)) | 265 | if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || |
266 | put_user(kp->type, &up->type)) | ||
241 | return -EFAULT; | 267 | return -EFAULT; |
242 | switch (kp->type) { | 268 | switch (kp->type) { |
243 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 269 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
@@ -251,6 +277,23 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
251 | } | 277 | } |
252 | } | 278 | } |
253 | 279 | ||
280 | static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up) | ||
281 | { | ||
282 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard)) || | ||
283 | copy_from_user(kp, up, sizeof(struct v4l2_standard))) | ||
284 | return -EFAULT; | ||
285 | return 0; | ||
286 | |||
287 | } | ||
288 | |||
289 | static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up) | ||
290 | { | ||
291 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard)) || | ||
292 | copy_to_user(up, kp, sizeof(struct v4l2_standard))) | ||
293 | return -EFAULT; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
254 | struct v4l2_standard32 | 297 | struct v4l2_standard32 |
255 | { | 298 | { |
256 | __u32 index; | 299 | __u32 index; |
@@ -264,18 +307,39 @@ struct v4l2_standard32 | |||
264 | static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) | 307 | static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) |
265 | { | 308 | { |
266 | /* other fields are not set by the user, nor used by the driver */ | 309 | /* other fields are not set by the user, nor used by the driver */ |
267 | return get_user(kp->index, &up->index); | 310 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || |
311 | get_user(kp->index, &up->index)) | ||
312 | return -EFAULT; | ||
313 | return 0; | ||
268 | } | 314 | } |
269 | 315 | ||
270 | static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) | 316 | static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) |
271 | { | 317 | { |
272 | if(put_user(kp->index, &up->index)) | 318 | if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || |
273 | return -EFAULT; | 319 | put_user(kp->index, &up->index) || |
274 | __copy_to_user(up->id, &kp->id, sizeof(__u64)); | 320 | copy_to_user(up->id, &kp->id, sizeof(__u64)) || |
275 | __copy_to_user(up->name, kp->name, 24); | 321 | copy_to_user(up->name, kp->name, 24) || |
276 | __put_user(kp->frameperiod, &up->frameperiod); | 322 | copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || |
277 | __put_user(kp->framelines, &up->framelines); | 323 | put_user(kp->framelines, &up->framelines) || |
278 | __copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)); | 324 | copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) |
325 | return -EFAULT; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up) | ||
330 | { | ||
331 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_tuner)) || | ||
332 | copy_from_user(kp, up, sizeof(struct v4l2_tuner))) | ||
333 | return -EFAULT; | ||
334 | return 0; | ||
335 | |||
336 | } | ||
337 | |||
338 | static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up) | ||
339 | { | ||
340 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_tuner)) || | ||
341 | copy_to_user(up, kp, sizeof(struct v4l2_tuner))) | ||
342 | return -EFAULT; | ||
279 | return 0; | 343 | return 0; |
280 | } | 344 | } |
281 | 345 | ||
@@ -304,12 +368,13 @@ struct v4l2_buffer32 | |||
304 | static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) | 368 | static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) |
305 | { | 369 | { |
306 | 370 | ||
307 | if (get_user(kp->index, &up->index)) | 371 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || |
308 | return -EFAULT; | 372 | get_user(kp->index, &up->index) || |
309 | __get_user(kp->type, &up->type); | 373 | get_user(kp->type, &up->type) || |
310 | __get_user(kp->flags, &up->flags); | 374 | get_user(kp->flags, &up->flags) || |
311 | __get_user(kp->memory, &up->memory); | 375 | get_user(kp->memory, &up->memory) || |
312 | __get_user(kp->input, &up->input); | 376 | get_user(kp->input, &up->input)) |
377 | return -EFAULT; | ||
313 | switch(kp->memory) { | 378 | switch(kp->memory) { |
314 | case V4L2_MEMORY_MMAP: | 379 | case V4L2_MEMORY_MMAP: |
315 | break; | 380 | break; |
@@ -317,12 +382,14 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user | |||
317 | { | 382 | { |
318 | unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr); | 383 | unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr); |
319 | 384 | ||
320 | __get_user(kp->length, &up->length); | 385 | if(get_user(kp->length, &up->length) || |
321 | __get_user(kp->m.userptr, &tmp); | 386 | get_user(kp->m.userptr, &tmp)) |
387 | return -EFAULT; | ||
322 | } | 388 | } |
323 | break; | 389 | break; |
324 | case V4L2_MEMORY_OVERLAY: | 390 | case V4L2_MEMORY_OVERLAY: |
325 | __get_user(kp->m.offset, &up->m.offset); | 391 | if(get_user(kp->m.offset, &up->m.offset)) |
392 | return -EFAULT; | ||
326 | break; | 393 | break; |
327 | } | 394 | } |
328 | return 0; | 395 | return 0; |
@@ -330,32 +397,37 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user | |||
330 | 397 | ||
331 | static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) | 398 | static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) |
332 | { | 399 | { |
333 | if (put_user(kp->index, &up->index)) | 400 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || |
334 | return -EFAULT; | 401 | put_user(kp->index, &up->index) || |
335 | __put_user(kp->type, &up->type); | 402 | put_user(kp->type, &up->type) || |
336 | __put_user(kp->flags, &up->flags); | 403 | put_user(kp->flags, &up->flags) || |
337 | __put_user(kp->memory, &up->memory); | 404 | put_user(kp->memory, &up->memory) || |
338 | __put_user(kp->input, &up->input); | 405 | put_user(kp->input, &up->input)) |
406 | return -EFAULT; | ||
339 | switch(kp->memory) { | 407 | switch(kp->memory) { |
340 | case V4L2_MEMORY_MMAP: | 408 | case V4L2_MEMORY_MMAP: |
341 | __put_user(kp->length, &up->length); | 409 | if (put_user(kp->length, &up->length) || |
342 | __put_user(kp->m.offset, &up->m.offset); | 410 | put_user(kp->m.offset, &up->m.offset)) |
411 | return -EFAULT; | ||
343 | break; | 412 | break; |
344 | case V4L2_MEMORY_USERPTR: | 413 | case V4L2_MEMORY_USERPTR: |
345 | __put_user(kp->length, &up->length); | 414 | if (put_user(kp->length, &up->length) || |
346 | __put_user(kp->m.userptr, &up->m.userptr); | 415 | put_user(kp->m.userptr, &up->m.userptr)) |
416 | return -EFAULT; | ||
347 | break; | 417 | break; |
348 | case V4L2_MEMORY_OVERLAY: | 418 | case V4L2_MEMORY_OVERLAY: |
349 | __put_user(kp->m.offset, &up->m.offset); | 419 | if (put_user(kp->m.offset, &up->m.offset)) |
420 | return -EFAULT; | ||
350 | break; | 421 | break; |
351 | } | 422 | } |
352 | __put_user(kp->bytesused, &up->bytesused); | 423 | if (put_user(kp->bytesused, &up->bytesused) || |
353 | __put_user(kp->field, &up->field); | 424 | put_user(kp->field, &up->field) || |
354 | __put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec); | 425 | put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || |
355 | __put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec); | 426 | put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || |
356 | __copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)); | 427 | copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || |
357 | __put_user(kp->sequence, &up->sequence); | 428 | put_user(kp->sequence, &up->sequence) || |
358 | __put_user(kp->reserved, &up->reserved); | 429 | put_user(kp->reserved, &up->reserved)) |
430 | return -EFAULT; | ||
359 | return 0; | 431 | return 0; |
360 | } | 432 | } |
361 | 433 | ||
@@ -371,11 +443,12 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame | |||
371 | { | 443 | { |
372 | u32 tmp; | 444 | u32 tmp; |
373 | 445 | ||
374 | if (get_user(tmp, &up->base)) | 446 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || |
375 | return -EFAULT; | 447 | get_user(tmp, &up->base) || |
448 | get_user(kp->capability, &up->capability) || | ||
449 | get_user(kp->flags, &up->flags)) | ||
450 | return -EFAULT; | ||
376 | kp->base = compat_ptr(tmp); | 451 | kp->base = compat_ptr(tmp); |
377 | __get_user(kp->capability, &up->capability); | ||
378 | __get_user(kp->flags, &up->flags); | ||
379 | get_v4l2_pix_format(&kp->fmt, &up->fmt); | 452 | get_v4l2_pix_format(&kp->fmt, &up->fmt); |
380 | return 0; | 453 | return 0; |
381 | } | 454 | } |
@@ -384,25 +457,46 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame | |||
384 | { | 457 | { |
385 | u32 tmp = (u32)((unsigned long)kp->base); | 458 | u32 tmp = (u32)((unsigned long)kp->base); |
386 | 459 | ||
387 | if(put_user(tmp, &up->base)) | 460 | if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || |
388 | return -EFAULT; | 461 | put_user(tmp, &up->base) || |
389 | __put_user(kp->capability, &up->capability); | 462 | put_user(kp->capability, &up->capability) || |
390 | __put_user(kp->flags, &up->flags); | 463 | put_user(kp->flags, &up->flags)) |
464 | return -EFAULT; | ||
391 | put_v4l2_pix_format(&kp->fmt, &up->fmt); | 465 | put_v4l2_pix_format(&kp->fmt, &up->fmt); |
392 | return 0; | 466 | return 0; |
393 | } | 467 | } |
394 | 468 | ||
395 | struct v4l2_input32 /* identical layout, but different size */ | 469 | static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up) |
396 | { | 470 | { |
397 | __u32 index; /* Which input */ | 471 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_input) - 4) || |
398 | __u8 name[32]; /* Label */ | 472 | copy_from_user(kp, up, sizeof(struct v4l2_input) - 4)) |
399 | __u32 type; /* Type of input */ | 473 | return -EFAULT; |
400 | __u32 audioset; /* Associated audios (bitfield) */ | 474 | return 0; |
401 | __u32 tuner; /* Associated tuner */ | 475 | } |
402 | __u32 std[2]; /* __u64 would get the padding wrong */ | 476 | |
403 | __u32 status; | 477 | static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up) |
404 | __u32 reserved[4]; | 478 | { |
405 | }; | 479 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_input) - 4) || |
480 | copy_to_user(up, kp, sizeof(struct v4l2_input) - 4)) | ||
481 | return -EFAULT; | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up) | ||
486 | { | ||
487 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_input)) || | ||
488 | copy_from_user(kp, up, sizeof(struct v4l2_input))) | ||
489 | return -EFAULT; | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up) | ||
494 | { | ||
495 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_input)) || | ||
496 | copy_to_user(up, kp, sizeof(struct v4l2_input))) | ||
497 | return -EFAULT; | ||
498 | return 0; | ||
499 | } | ||
406 | 500 | ||
407 | #define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) | 501 | #define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) |
408 | #define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) | 502 | #define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) |
@@ -413,6 +507,8 @@ struct v4l2_input32 /* identical layout, but different size */ | |||
413 | #define VIDIOCGFREQ32 _IOR('v',14, u32) | 507 | #define VIDIOCGFREQ32 _IOR('v',14, u32) |
414 | #define VIDIOCSFREQ32 _IOW('v',15, u32) | 508 | #define VIDIOCSFREQ32 _IOW('v',15, u32) |
415 | 509 | ||
510 | /* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */ | ||
511 | #define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4) | ||
416 | #define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32) | 512 | #define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32) |
417 | #define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32) | 513 | #define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32) |
418 | #define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32) | 514 | #define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32) |
@@ -425,7 +521,6 @@ struct v4l2_input32 /* identical layout, but different size */ | |||
425 | #define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t) | 521 | #define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t) |
426 | #define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t) | 522 | #define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t) |
427 | #define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32) | 523 | #define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32) |
428 | #define VIDIOC_ENUMINPUT32 _IOWR ('V', 26, struct v4l2_input32) | ||
429 | /* VIDIOC_S_CTRL is now _IOWR, but was _IOW */ | 524 | /* VIDIOC_S_CTRL is now _IOWR, but was _IOW */ |
430 | #define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control) | 525 | #define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control) |
431 | #define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t) | 526 | #define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t) |
@@ -444,6 +539,9 @@ static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg) | |||
444 | int nclips; | 539 | int nclips; |
445 | u32 n; | 540 | u32 n; |
446 | 541 | ||
542 | if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32))) | ||
543 | return -EFAULT; | ||
544 | |||
447 | if (get_user(nclips, &up->clipcount)) | 545 | if (get_user(nclips, &up->clipcount)) |
448 | return -EFAULT; | 546 | return -EFAULT; |
449 | 547 | ||
@@ -476,7 +574,9 @@ static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg) | |||
476 | return -EINVAL; | 574 | return -EINVAL; |
477 | for (i = 0; i < nclips; i++, u++, p++) { | 575 | for (i = 0; i < nclips; i++, u++, p++) { |
478 | s32 v; | 576 | s32 v; |
479 | if (get_user(v, &u->x) || | 577 | if (!access_ok(VERIFY_READ, u, sizeof(struct video_clip32)) || |
578 | !access_ok(VERIFY_WRITE, p, sizeof(struct video_clip32)) || | ||
579 | get_user(v, &u->x) || | ||
480 | put_user(v, &p->x) || | 580 | put_user(v, &p->x) || |
481 | get_user(v, &u->y) || | 581 | get_user(v, &u->y) || |
482 | put_user(v, &p->y) || | 582 | put_user(v, &p->y) || |
@@ -502,11 +602,14 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
502 | struct v4l2_buffer v2b; | 602 | struct v4l2_buffer v2b; |
503 | struct v4l2_framebuffer v2fb; | 603 | struct v4l2_framebuffer v2fb; |
504 | struct v4l2_standard v2s; | 604 | struct v4l2_standard v2s; |
605 | struct v4l2_input v2i; | ||
606 | struct v4l2_tuner v2t; | ||
505 | unsigned long vx; | 607 | unsigned long vx; |
506 | } karg; | 608 | } karg; |
507 | void __user *up = compat_ptr(arg); | 609 | void __user *up = compat_ptr(arg); |
508 | int compatible_arg = 1; | 610 | int compatible_arg = 1; |
509 | int err = 0; | 611 | int err = 0; |
612 | int realcmd = cmd; | ||
510 | 613 | ||
511 | /* First, convert the command. */ | 614 | /* First, convert the command. */ |
512 | switch(cmd) { | 615 | switch(cmd) { |
@@ -527,8 +630,8 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
527 | case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break; | 630 | case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break; |
528 | case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break; | 631 | case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break; |
529 | case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; | 632 | case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; |
530 | case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break; | 633 | case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break; |
531 | case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break; | 634 | case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break; |
532 | case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break; | 635 | case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break; |
533 | case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; | 636 | case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; |
534 | case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; | 637 | case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; |
@@ -577,10 +680,31 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
577 | break; | 680 | break; |
578 | 681 | ||
579 | case VIDIOC_ENUMSTD: | 682 | case VIDIOC_ENUMSTD: |
683 | err = get_v4l2_standard(&karg.v2s, up); | ||
684 | compatible_arg = 0; | ||
685 | break; | ||
686 | |||
687 | case VIDIOC_ENUMSTD32: | ||
580 | err = get_v4l2_standard32(&karg.v2s, up); | 688 | err = get_v4l2_standard32(&karg.v2s, up); |
581 | compatible_arg = 0; | 689 | compatible_arg = 0; |
582 | break; | 690 | break; |
583 | 691 | ||
692 | case VIDIOC_ENUMINPUT: | ||
693 | err = get_v4l2_input(&karg.v2i, up); | ||
694 | compatible_arg = 0; | ||
695 | break; | ||
696 | |||
697 | case VIDIOC_ENUMINPUT32: | ||
698 | err = get_v4l2_input32(&karg.v2i, up); | ||
699 | compatible_arg = 0; | ||
700 | break; | ||
701 | |||
702 | case VIDIOC_G_TUNER: | ||
703 | case VIDIOC_S_TUNER: | ||
704 | err = get_v4l2_tuner(&karg.v2t, up); | ||
705 | compatible_arg = 0; | ||
706 | break; | ||
707 | |||
584 | case VIDIOCGWIN: | 708 | case VIDIOCGWIN: |
585 | case VIDIOCGFBUF: | 709 | case VIDIOCGFBUF: |
586 | case VIDIOCGFREQ: | 710 | case VIDIOCGFREQ: |
@@ -593,12 +717,12 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
593 | goto out; | 717 | goto out; |
594 | 718 | ||
595 | if(compatible_arg) | 719 | if(compatible_arg) |
596 | err = native_ioctl(file, cmd, (unsigned long)up); | 720 | err = native_ioctl(file, realcmd, (unsigned long)up); |
597 | else { | 721 | else { |
598 | mm_segment_t old_fs = get_fs(); | 722 | mm_segment_t old_fs = get_fs(); |
599 | 723 | ||
600 | set_fs(KERNEL_DS); | 724 | set_fs(KERNEL_DS); |
601 | err = native_ioctl(file, cmd, (unsigned long)&karg); | 725 | err = native_ioctl(file, realcmd, (unsigned long)&karg); |
602 | set_fs(old_fs); | 726 | set_fs(old_fs); |
603 | } | 727 | } |
604 | if(err == 0) { | 728 | if(err == 0) { |
@@ -632,9 +756,26 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
632 | break; | 756 | break; |
633 | 757 | ||
634 | case VIDIOC_ENUMSTD: | 758 | case VIDIOC_ENUMSTD: |
759 | err = put_v4l2_standard(&karg.v2s, up); | ||
760 | break; | ||
761 | |||
762 | case VIDIOC_ENUMSTD32: | ||
635 | err = put_v4l2_standard32(&karg.v2s, up); | 763 | err = put_v4l2_standard32(&karg.v2s, up); |
636 | break; | 764 | break; |
637 | 765 | ||
766 | case VIDIOC_G_TUNER: | ||
767 | case VIDIOC_S_TUNER: | ||
768 | err = put_v4l2_tuner(&karg.v2t, up); | ||
769 | break; | ||
770 | |||
771 | case VIDIOC_ENUMINPUT: | ||
772 | err = put_v4l2_input(&karg.v2i, up); | ||
773 | break; | ||
774 | |||
775 | case VIDIOC_ENUMINPUT32: | ||
776 | err = put_v4l2_input32(&karg.v2i, up); | ||
777 | break; | ||
778 | |||
638 | case VIDIOCGFREQ: | 779 | case VIDIOCGFREQ: |
639 | case VIDIOC_G_INPUT: | 780 | case VIDIOC_G_INPUT: |
640 | err = put_user(((u32)karg.vx), (u32 __user *)up); | 781 | err = put_user(((u32)karg.vx), (u32 __user *)up); |
@@ -679,7 +820,11 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
679 | case VIDIOC_G_PARM: | 820 | case VIDIOC_G_PARM: |
680 | case VIDIOC_G_STD: | 821 | case VIDIOC_G_STD: |
681 | case VIDIOC_S_STD: | 822 | case VIDIOC_S_STD: |
823 | case VIDIOC_G_TUNER: | ||
824 | case VIDIOC_S_TUNER: | ||
825 | case VIDIOC_ENUMSTD: | ||
682 | case VIDIOC_ENUMSTD32: | 826 | case VIDIOC_ENUMSTD32: |
827 | case VIDIOC_ENUMINPUT: | ||
683 | case VIDIOC_ENUMINPUT32: | 828 | case VIDIOC_ENUMINPUT32: |
684 | case VIDIOC_G_CTRL: | 829 | case VIDIOC_G_CTRL: |
685 | case VIDIOC_S_CTRL32: | 830 | case VIDIOC_S_CTRL32: |
@@ -718,6 +863,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
718 | case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): | 863 | case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): |
719 | ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); | 864 | ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
720 | break; | 865 | break; |
866 | default: | ||
867 | v4l_print_ioctl("compat_ioctl32", cmd); | ||
721 | } | 868 | } |
722 | return ret; | 869 | return ret; |
723 | } | 870 | } |