Re: [PATCH 02/14] HID: provide a helper for validating hid reports

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 29, 2013 at 9:51 PM, Kees Cook <keescook@xxxxxxxxxxxx> wrote:
> On Thu, Aug 29, 2013 at 2:35 AM, Benjamin Tissoires
> <benjamin.tissoires@xxxxxxxxx> wrote:
>> Hi Kees,
>>
>> On Wed, Aug 28, 2013 at 10:30 PM, Jiri Kosina <jkosina@xxxxxxx> wrote:
>>> From: Kees Cook <keescook@xxxxxxxxxxxx>
>>>
>>> Many drivers need to validate the characteristics of their HID report
>>> during initialization to avoid misusing the reports. This adds a common
>>> helper to perform validation of the report, its field count, and the
>>> value count within the fields.
>>>
>>> Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
>>> Cc: stable@xxxxxxxxxx
>>> ---
>>>  drivers/hid/hid-core.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  include/linux/hid.h    |    4 ++++
>>>  2 files changed, 54 insertions(+)
>>>
>>> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
>>> index 5ea7d51..55798b2 100644
>>> --- a/drivers/hid/hid-core.c
>>> +++ b/drivers/hid/hid-core.c
>>> @@ -759,6 +759,56 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
>>>  }
>>>  EXPORT_SYMBOL_GPL(hid_parse_report);
>>>
>>> +static const char * const hid_report_names[] = {
>>> +       "HID_INPUT_REPORT",
>>> +       "HID_OUTPUT_REPORT",
>>> +       "HID_FEATURE_REPORT",
>>> +};
>>> +/**
>>> + * hid_validate_report - validate existing device report
>>> + *
>>> + * @device: hid device
>>> + * @type: which report type to examine
>>> + * @id: which report ID to examine (0 for first)
>>> + * @fields: expected number of fields
>>> + * @report_counts: expected number of values per field
>>> + *
>>> + * Validate the report details after parsing.
>>> + */
>>> +struct hid_report *hid_validate_report(struct hid_device *hid,
>>> +                                      unsigned int type, unsigned int id,
>>
>> You should consider having an u8 for id, or at least add a check
>> against id >= HID_MAX_IDS
>
> Right, as you saw in later email, I added this check globally in the
> first patch.
>

Yes, but still, a driver may call this with 257 as an id, leading to a
report pointer with garbage value. And here, the function is used once
after parsing, so the test can be added without any impact.

>>
>>> +                                      unsigned int fields,
>>> +                                      unsigned int report_counts)
>>> +{
>>> +       struct hid_report *report;
>>> +       unsigned int i;
>>> +
>>> +       if (type > HID_FEATURE_REPORT) {
>>> +               hid_err(hid, "invalid HID report %u\n", type);
>>> +               return NULL;
>>> +       }
>>> +
>>> +       report = hid->report_enum[type].report_id_hash[id];
>>
>> for code readability, and better checking, I'd prefer use
>> hid_get_report() here instead. Or just add an inlined accessor in
>> hid.h to retrieve the report from the id as many drivers are using the
>> report_id_hash directly.
>
> I did not do this because hid_get_report() examines ->numbered and I
> explicitly didn't want that limitation since most of these drivers are
> blinding accessing the arrays by id number. If the structure members
> were opaque and all the drivers were forced to use the access
> functions, sure, we'd be fine.
>

Well, what I have in mind is just to add the accessor, and to convert
all the drivers to use it. If a new driver try to not use it, we don't
allow him to be upstream :)

>>
>>> +       if (!report) {
>>> +               hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
>>> +               return NULL;
>>> +       }
>>> +       if (report->maxfield < fields) {
>>> +               hid_err(hid, "not enough fields in %s %u\n",
>>> +                       hid_report_names[type], id);
>>> +               return NULL;
>>> +       }
>>> +       for (i = 0; i < fields; i++) {
>>> +               if (report->field[i]->report_count < report_counts) {
>>
>> This is wrong.
>> you can have a per field different report_count, and it is perfectly
>> correct. So the only validate value for report_counts would be 1.
>> Otherwise, if you want to provide better checking, you need to provide
>> an array of report_counts, which start beeing a little bit annoying
>> for users.
>
> Well, nothing needs multiple differing report_counts in practice, so I
> opted to just do it this way since nothing calling the function needs
> more granular checking.
>

So I would recommend at least to add a comment somewhere that this is
the current implementation, and we may need to change it if we have
different devices which would need a different processing.

Cheers,
Benjamin

> -Kees
>
>>
>>> +                       hid_err(hid, "not enough values in %s %u fields\n",
>>> +                               hid_report_names[type], id);
>>> +                       return NULL;
>>> +               }
>>> +       }
>>> +       return report;
>>> +}
>>> +EXPORT_SYMBOL_GPL(hid_validate_report);
>>> +
>>>  /**
>>>   * hid_open_report - open a driver-specific device report
>>>   *
>>> diff --git a/include/linux/hid.h b/include/linux/hid.h
>>> index ff545cc..76e41d8 100644
>>> --- a/include/linux/hid.h
>>> +++ b/include/linux/hid.h
>>> @@ -749,6 +749,10 @@ void hid_output_report(struct hid_report *report, __u8 *data);
>>>  struct hid_device *hid_allocate_device(void);
>>>  struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
>>>  int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
>>> +struct hid_report *hid_validate_report(struct hid_device *hid,
>>> +                                      unsigned int type, unsigned int id,
>>> +                                      unsigned int fields,
>>> +                                      unsigned int report_counts);
>>>  int hid_open_report(struct hid_device *device);
>>>  int hid_check_keys_pressed(struct hid_device *hid);
>>>  int hid_connect(struct hid_device *hid, unsigned int connect_mask);
>>>
>>> --
>>> Jiri Kosina
>>> SUSE Labs
>>> --
>>
>> Cheers,
>> Benjamin
>
>
>
> --
> Kees Cook
> Chrome OS Security
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux