]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Input: cs40l50-vibra - validate custom data from user space
authorHyeongJun An <sammiee5311@gmail.com>
Sat, 18 Jul 2026 07:40:32 +0000 (16:40 +0900)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 24 Jul 2026 23:47:47 +0000 (16:47 -0700)
cs40l50_add() copies the custom data of an FF_PERIODIC/FF_CUSTOM effect
straight from the ff_effect the user passed to EVIOCSFF, without
requiring it to hold anything:

    work_data.custom_data = memdup_array_user(periodic->custom_data,
                                              periodic->custom_len,
                                              sizeof(s16));
    work_data.custom_len = periodic->custom_len;

The driver then reads two words out of that buffer: custom_data[0] as the
waveform bank in cs40l50_effect_bank_set(), and custom_data[1] as the
index within the bank in cs40l50_effect_index_set().  Neither read is
covered by a length check, and custom_len is fully user controlled:

  - custom_len == 0 makes memdup_array_user() call memdup_user() with a
    length of zero, which returns ZERO_SIZE_PTR rather than an error, so
    custom_data[0] dereferences it.

  - custom_len == 1 allocates two bytes.  A bank of ROM or RAM keeps
    effect->type out of the OWT case, and custom_data[1] is then read one
    word past the allocation.

The bank value itself is also mishandled.  It is masked with
CS40L50_CUSTOM_DATA_MASK (0xffff) but stored in an s16, so a
custom_data[0] of 0x8000 or above wraps to a negative value that passes
the "bank_type >= CS40L50_WVFRM_BANK_NUM" test.
cs40l50_effect_index_set() indexes vib->dsp.banks[] with it before the
switch statement's default case gets a chance to reject it:

    base_index = vib->dsp.banks[effect->type].base_index;
    max_index = vib->dsp.banks[effect->type].max_index;

Require the two words the driver reads to be present, and hold the masked
bank in a u32 so the existing upper-bound test covers the whole range.
The da7280 haptic driver already range checks custom_len this way.

Fixes: c38fe1bb5d21 ("Input: cs40l50 - Add support for the CS40L50 haptic driver")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: HyeongJun An <sammiee5311@gmail.com>
Link: https://patch.msgid.link/20260718074032.1864861-1-sammiee5311@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/misc/cs40l50-vibra.c

index 996d6c38cca4397148687d8b118eac723e679c8c..7ef4534fea2fb0b105aeb0a2d38aacc9a1e94a5e 100644 (file)
@@ -139,10 +139,10 @@ static struct cs40l50_effect *cs40l50_find_effect(int id, struct list_head *effe
 static int cs40l50_effect_bank_set(struct cs40l50_work *work_data,
                                   struct cs40l50_effect *effect)
 {
-       s16 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
+       u32 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
 
        if (bank_type >= CS40L50_WVFRM_BANK_NUM) {
-               dev_err(work_data->vib->dev, "Invalid bank (%d)\n", bank_type);
+               dev_err(work_data->vib->dev, "Invalid bank (%u)\n", bank_type);
                return -EINVAL;
        }
 
@@ -326,6 +326,12 @@ static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect,
                return -EINVAL;
        }
 
+       if (periodic->custom_len < CS40L50_OWT_CUSTOM_DATA_SIZE) {
+               dev_err(vib->dev, "Invalid custom data length (%u)\n",
+                       periodic->custom_len);
+               return -EINVAL;
+       }
+
        work_data.custom_data = memdup_array_user(effect->u.periodic.custom_data,
                                                  effect->u.periodic.custom_len,
                                                  sizeof(s16));