|
@@ -600,9 +600,35 @@ struct v4l2_ext_controls32 {
|
|
|
compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
|
|
|
};
|
|
|
|
|
|
+struct v4l2_ext_control32 {
|
|
|
+ __u32 id;
|
|
|
+ __u32 size;
|
|
|
+ __u32 reserved2[1];
|
|
|
+ union {
|
|
|
+ __s32 value;
|
|
|
+ __s64 value64;
|
|
|
+ compat_caddr_t string; /* actually char * */
|
|
|
+ };
|
|
|
+} __attribute__ ((packed));
|
|
|
+
|
|
|
+/* The following function really belong in v4l2-common, but that causes
|
|
|
+ a circular dependency between modules. We need to think about this, but
|
|
|
+ for now this will do. */
|
|
|
+
|
|
|
+/* Return non-zero if this control is a pointer type. Currently only
|
|
|
+ * type STRING is a pointer type.
|
|
|
+ *
|
|
|
+ * Note that there are currently no controls of this type, but at least the
|
|
|
+ * compat32 code is in place to properly handle such controls. Please
|
|
|
+ * remove this note once the first pointer controls are added. */
|
|
|
+static inline int ctrl_is_pointer(u32 id)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
|
|
|
{
|
|
|
- struct v4l2_ext_control __user *ucontrols;
|
|
|
+ struct v4l2_ext_control32 __user *ucontrols;
|
|
|
struct v4l2_ext_control __user *kcontrols;
|
|
|
int n;
|
|
|
compat_caddr_t p;
|
|
@@ -626,15 +652,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
|
|
|
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
|
|
|
kp->controls = kcontrols;
|
|
|
while (--n >= 0) {
|
|
|
- if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
|
|
|
- return -EFAULT;
|
|
|
- if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
|
|
|
- return -EFAULT;
|
|
|
- /* Note: if the void * part of the union ever becomes relevant
|
|
|
- then we need to know the type of the control in order to do
|
|
|
- the right thing here. Luckily, that is not yet an issue. */
|
|
|
- if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
|
|
|
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
|
|
|
return -EFAULT;
|
|
|
+ if (ctrl_is_pointer(kcontrols->id)) {
|
|
|
+ void __user *s;
|
|
|
+
|
|
|
+ if (get_user(p, &ucontrols->string))
|
|
|
+ return -EFAULT;
|
|
|
+ s = compat_ptr(p);
|
|
|
+ if (put_user(s, &kcontrols->string))
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
ucontrols++;
|
|
|
kcontrols++;
|
|
|
}
|
|
@@ -643,7 +671,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
|
|
|
|
|
|
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
|
|
|
{
|
|
|
- struct v4l2_ext_control __user *ucontrols;
|
|
|
+ struct v4l2_ext_control32 __user *ucontrols;
|
|
|
struct v4l2_ext_control __user *kcontrols = kp->controls;
|
|
|
int n = kp->count;
|
|
|
compat_caddr_t p;
|
|
@@ -664,15 +692,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
|
|
|
return -EFAULT;
|
|
|
|
|
|
while (--n >= 0) {
|
|
|
- if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
|
|
|
- return -EFAULT;
|
|
|
- if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
|
|
|
- sizeof(ucontrols->reserved2)))
|
|
|
- return -EFAULT;
|
|
|
- /* Note: if the void * part of the union ever becomes relevant
|
|
|
- then we need to know the type of the control in order to do
|
|
|
- the right thing here. Luckily, that is not yet an issue. */
|
|
|
- if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
|
|
|
+ unsigned size = sizeof(*ucontrols);
|
|
|
+
|
|
|
+ /* Do not modify the pointer when copying a pointer control.
|
|
|
+ The contents of the pointer was changed, not the pointer
|
|
|
+ itself. */
|
|
|
+ if (ctrl_is_pointer(kcontrols->id))
|
|
|
+ size -= sizeof(ucontrols->value64);
|
|
|
+ if (copy_in_user(ucontrols, kcontrols, size))
|
|
|
return -EFAULT;
|
|
|
ucontrols++;
|
|
|
kcontrols++;
|