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 | } |
