I take back my previous answer to this question:
> Are you sure the name always contain an underscore?  Can't it be
> "Button:Button42" ?

In my previous response I had only discovered three cases of usage -1.
I took another look and discovered that there indeed is a scenario as you
mention other then just "_%d".

In my efforts to resolve that scenario, I discovered a simple solution I
had not thought about earlier.

With the help of pages[k].page_contents[j].name I'm able to parse current
and
future versions " * %99[^\n]" lines the usb_hid_usages.

This patch is back to using sscanf again & I still haven't been able to
figure
out what could be unsafe about this use of it.


Index: usage.c
===================================================================
RCS file: /cvs/src/lib/libusbhid/usage.c,v
retrieving revision 1.16
diff -u -p -r1.16 usage.c
--- usage.c     8 Oct 2014 04:49:36 -0000       1.16
+++ usage.c     18 Jun 2018 18:38:04 -0000
@@ -266,7 +266,7 @@ hid_parse_usage_in_page(const char *name
 {
        const char *sep;
        unsigned int l;
-       int k, j;
+       int k, j, us, pu;

        sep = strchr(name, ':');
        if (sep == NULL)
@@ -278,9 +278,16 @@ hid_parse_usage_in_page(const char *name
        return -1;
  found:
        sep++;
-       for (j = 0; j < pages[k].pagesize; j++)
+       for (j = 0; j < pages[k].pagesize; j++) {
+               us = pages[k].page_contents[j].usage;
+               if (us == -1) {
+                       if (sscanf(sep, pages[k].page_contents[j].name,
&pu) > 0
+                           & 0x10000 > pu & pu > 0x0)
+                               return (pages[k].usage << 16) | pu;
+               }
                if (strcmp(pages[k].page_contents[j].name, sep) == 0)
                        return (pages[k].usage << 16) |
                            pages[k].page_contents[j].usage;
+       }
        return -1;
 }


2018-06-15 0:11 GMT+02:00 David Bern <david.ml.b...@gmail.com>:

> Thank you mpi for the response.
>
> I will try to answer to the best of my knowledge.
>
> > Are you sure the name always contain an underscore?  Can't it be
> > "Button:Button42" ?
> It depends. At the moment it is dictated by the default page
> /usr/share/misc/usb_hid_usages and the name looks more like "Button:Button
> 42".
>
> So if someone decides to create another table, he/she could decide to name
> it
> "Button:Button-42" instead.
> However if that would occur other things would break as well, this
> because of how the
> table is loaded by hid_start().
>
> The patch is made to handle lines defined as " * %99[^\n]". When a line
> with spaces
> is found, hid_start() will replace the spaces with "_".
>
> > You're passing the string directly to sscanf(3), is that safe?
>
> I was initially uncertain about the safety of sscanf, But when reading the
> man-page I could
> only identify scenarios using it to scan "%s" as unsafe if you don't
> supply a width as this
> could lead to buffer overflows.
>
> > Don't you want to parse only unsigned numbers?  Or is it possible to
> > have "Button:Button_-3" ?
>
> Yes. You are right, which has lead me to replace sscanf with strtonum
> instead.
> In that way I can do a simple check of input correctness.
> To be honest regarding input, I'm not certain about how high values the
> hid-specification
> allows, it does seem in the cases I have been able to identify, that it is
> possible to use
> the first two bytes.
>
> Thank you for the questions.
>
>
> Index: usage.c
> ===================================================================
> RCS file: /cvs/src/lib/libusbhid/usage.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 usage.c
> --- usage.c     8 Oct 2014 04:49:36 -0000       1.16
> +++ usage.c     14 Jun 2018 21:56:30 -0000
> @@ -265,8 +265,10 @@ int
>  hid_parse_usage_in_page(const char *name)
>  {
>         const char *sep;
> +       const char *usage_sep;
>         unsigned int l;
> -       int k, j;
> +       int k, j, us, parsed_usage;
> +       const char *errstr;
>
>         sep = strchr(name, ':');
>         if (sep == NULL)
> @@ -278,9 +280,21 @@ hid_parse_usage_in_page(const char *name
>         return -1;
>   found:
>         sep++;
> -       for (j = 0; j < pages[k].pagesize; j++)
> +       for (j = 0; j < pages[k].pagesize; j++) {
> +               us = pages[k].page_contents[j].usage;
> +               if (us == -1) {
> +                       usage_sep = strchr(sep, '_');
> +                       if (usage_sep == NULL)
> +                               return -1;
> +                       usage_sep++;
> +                       parsed_usage = strtonum(usage_sep, 0x1, 0xFFFF,
> &errstr);
> +                       if (errstr == NULL)
> +                               return (pages[k].usage << 16) |
> +                                   parsed_usage;
> +               }
>                 if (strcmp(pages[k].page_contents[j].name, sep) == 0)
>                         return (pages[k].usage << 16) |
>                             pages[k].page_contents[j].usage;
> +       }
>         return -1;
>  }
>
>
>
> 2018-06-14 14:54 GMT+02:00 Martin Pieuchot <m...@openbsd.org>:
>
>> On 29/05/18(Tue) 22:29, David Bern wrote:
>> > Sorry for the spamming.
>> > After some research and finding that my fix for issue nr: 2 (
>> > hid_usage_in_page() )
>> > will break the functionality inside /usr.bin/usbhidaction/usbhidac
>> tion.c
>> > https://goo.gl/1cWFtR (link to usbhidaction.c)
>> >
>> > I now change my patch to only include a fix for issue nr: 1
>> > More details is described in the previous mail
>>
>> Are you sure the name always contain an underscore?  Can't it be
>> "Button:Button42" ?
>>
>> You're passing the string directly to sscanf(3), is that safe?
>>
>> Don't you want to parse only unsigned numbers?  Or is it possible to
>> have "Button:Button_-3" ?
>>
>> > Index: usage.c
>> > ===================================================================
>> > RCS file: /cvs/src/lib/libusbhid/usage.c,v
>> > retrieving revision 1.16
>> > diff -u -p -r1.16 usage.c
>> > --- usage.c     8 Oct 2014 04:49:36 -0000       1.16
>> > +++ usage.c     29 May 2018 19:45:25 -0000
>> > @@ -265,8 +265,9 @@ int
>> >  hid_parse_usage_in_page(const char *name)
>> >  {
>> >         const char *sep;
>> > +       const char *usage_sep;
>> >         unsigned int l;
>> > -       int k, j;
>> > +       int k, j, us, parsed_usage;
>> >
>> >         sep = strchr(name, ':');
>> >         if (sep == NULL)
>> > @@ -278,9 +279,19 @@ hid_parse_usage_in_page(const char *name
>> >         return -1;
>> >   found:
>> >         sep++;
>> > -       for (j = 0; j < pages[k].pagesize; j++)
>> > +       for (j = 0; j < pages[k].pagesize; j++) {
>> > +               us = pages[k].page_contents[j].usage;
>> > +               if (us == -1) {
>> > +                       usage_sep = strchr(sep, '_');
>> > +                       if (usage_sep == NULL)
>> > +                               return -1;
>> > +                       if (sscanf(usage_sep, "_%d", &parsed_usage))
>> > +                               return (pages[k].usage << 16) |
>> > +                                   parsed_usage;
>> > +               }
>> >                 if (strcmp(pages[k].page_contents[j].name, sep) == 0)
>> >                         return (pages[k].usage << 16) |
>> >                             pages[k].page_contents[j].usage;
>> > +       }
>> >         return -1;
>> >  }
>> >
>> >
>> > comments? ok?
>> >
>> > 2018-05-28 13:01 GMT+02:00 David Bern <david.ml.b...@gmail.com>:
>> >
>> > > I was suggested off list to give an explanation on what the patch
>> does.
>> > >
>> > > So please, tell me if I need to clarify more, or make further changes
>> to
>> > > the code.
>> > >
>> > > The patch tries to fix two things.
>> > > 1. Changes in hid_parse_usage_in_page() fixes problems in parsing
>> usages
>> > > defined as:  *       Button %d
>> > >
>> > > hid_parse_usage_in_page():
>> > > Previously - With input "Button:Button_1" returns -1
>> > > Now - With input "Button:Button_1" returns 589825
>> > >
>> > > In the scenario of parsing Button:Button_1 we will not find a usage
>> name
>> > > matching that string. For example Button:Button_1 is defined as
>> > > Button %d in the table.
>> > >
>> > > We are still able to calculate the proper usage number in the same
>> way we
>> > > are
>> > > able to calculate the proper usage name in hid_usage_in_page().
>> > >
>> > > The first step is to identify if usage name is shortened. If it is,
>> > > usage will hold a value of -1. Then I try to locate a separator char
>> in
>> > > the name as "_".
>> > > If a separator char is found I use it to read the value as "_%d" to
>> get
>> > > the
>> > > corresponding usage number
>> > >
>> > > >+               us = pages[k].page_contents[j].usage;
>> > > >+               if (us == -1) {
>> > > >+                       usage_sep = strchr(sep, '_');
>> > > >+                       if (usage_sep == NULL)
>> > > >+                               return -1;
>> > > >+                       if (sscanf(usage_sep, "_%d", &parsed_usage))
>> > > >+                               return (pages[k].usage << 16) |
>> > > >+                                               parsed_usage;
>> > >
>> > >
>> > > 2. The text-string that is returned by hid_usage_in_page() misses page
>> > > information.
>> > > So the changes made in hid_usage_in_page() is to make it the inverse
>> of
>> > > hid_parse_usage_in_page()
>> > >
>> > > In details what the code previously did and now does.
>> > >
>> > > hid_usage_in_page():
>> > > Previously - With input 589825 returns Button_1
>> > > Now - With input 589825 returns Button:Button_1
>> > >
>> > >
>> > > The change just adds a pages[k].name to the string, a format that
>> > > hid_parse_usage_in_page() expects it to have.
>> > > I make formatting in two steps when us == -1 which it is when usage is
>> > > shortened
>> > > as for example: *       Button %d.
>> > >
>> > > >+                       snprintf(fmt, sizeof fmt,
>> > > >+                           "%%s:%s", pages[k].page_contents[j].name
>> );
>> > > >+                       snprintf(b, sizeof b, fmt, pages[k].name, i);
>> > >
>> > > The first step is to create a format string that will result in
>> something
>> > > like
>> > >  "%s:Button_%d".
>> > > The last step I use the fmt-string to create a complete string that
>> will
>> > > result in
>> > > "Button:Button_1"
>> > >
>> > >
>> > >
>> > >
>> > > 2018-05-24 18:44 GMT+02:00 David Bern <david.ml.b...@gmail.com>:
>> > >
>> > >> While I was waiting for comments and feedback I came up with some
>> > >> improvements.
>> > >> The "logic" is still the same, but the execution is hopefully more
>> sane.
>> > >>
>> > >> Index: usage.c
>> > >> ===================================================================
>> > >> RCS file: /cvs/src/lib/libusbhid/usage.c,v
>> > >> retrieving revision 1.16
>> > >> diff -u -p -r1.16 usage.c
>> > >> --- usage.c     8 Oct 2014 04:49:36 -0000       1.16
>> > >> +++ usage.c     24 May 2018 16:37:54 -0000
>> > >> @@ -224,6 +224,7 @@ hid_usage_in_page(unsigned int u)
>> > >>  {
>> > >>         int i = HID_USAGE(u), j, k, us;
>> > >>         int page = HID_PAGE(u);
>> > >> +       char fmt[100];
>> > >>         static char b[100];
>> > >>
>> > >>         for (k = 0; k < npages; k++)
>> > >> @@ -234,12 +235,16 @@ hid_usage_in_page(unsigned int u)
>> > >>         for (j = 0; j < pages[k].pagesize; j++) {
>> > >>                 us = pages[k].page_contents[j].usage;
>> > >>                 if (us == -1) {
>> > >> -                       snprintf(b, sizeof b,
>> > >> -                           pages[k].page_contents[j].name, i);
>> > >> +                       snprintf(fmt, sizeof fmt,
>> > >> +                           "%%s:%s", pages[k].page_contents[j].name
>> );
>> > >> +                       snprintf(b, sizeof b, fmt, pages[k].name, i);
>> > >> +                       return b;
>> > >> +               }
>> > >> +               if (us == i) {
>> > >> +                       snprintf(b, sizeof b, "%s:%s", pages[k].name,
>> > >> +                           pages[k].page_contents[j].name);
>> > >>                         return b;
>> > >>                 }
>> > >> -               if (us == i)
>> > >> -                       return pages[k].page_contents[j].name;
>> > >>         }
>> > >>   bad:
>> > >>         snprintf(b, sizeof b, "0x%04x", i);
>> > >> @@ -265,8 +270,9 @@ int
>> > >>  hid_parse_usage_in_page(const char *name)
>> > >>  {
>> > >>         const char *sep;
>> > >> +       const char *usage_sep;
>> > >>         unsigned int l;
>> > >> -       int k, j;
>> > >> +       int k, j, us, parsed_usage;
>> > >>
>> > >>         sep = strchr(name, ':');
>> > >>         if (sep == NULL)
>> > >> @@ -278,9 +284,19 @@ hid_parse_usage_in_page(const char *name
>> > >>         return -1;
>> > >>   found:
>> > >>         sep++;
>> > >> -       for (j = 0; j < pages[k].pagesize; j++)
>> > >> +       for (j = 0; j < pages[k].pagesize; j++) {
>> > >> +               us = pages[k].page_contents[j].usage;
>> > >> +               if (us == -1) {
>> > >> +                       usage_sep = strchr(sep, '_');
>> > >> +                       if (usage_sep == NULL)
>> > >> +                               return -1;
>> > >> +                       if (sscanf(usage_sep, "_%d", &parsed_usage))
>> > >> +                               return (pages[k].usage << 16) |
>> > >> +                                               parsed_usage;
>> > >> +               }
>> > >>                 if (strcmp(pages[k].page_contents[j].name, sep) ==
>> 0)
>> > >>                         return (pages[k].usage << 16) |
>> > >>                             pages[k].page_contents[j].usage;
>> > >> +       }
>> > >>         return -1;
>> > >>  }
>> > >>
>> > >>
>> > >>
>> > >> 2018-05-21 23:12 GMT+02:00 David Bern <david.ml.b...@gmail.com>:
>> > >>
>> > >>> First diff "solves" point 1 & 2. Second diff is on the parts of the
>> > >>> manual that does not match the usbhid.h
>> > >>>
>> > >>> Index: usage.c
>> > >>> ===================================================================
>> > >>> RCS file: /cvs/src/lib/libusbhid/usage.c,v
>> > >>> retrieving revision 1.16
>> > >>> diff -u -p -r1.16 usage.c
>> > >>> --- usage.c     8 Oct 2014 04:49:36 -0000       1.16
>> > >>> +++ usage.c     21 May 2018 21:06:24 -0000
>> > >>> @@ -224,6 +224,7 @@ hid_usage_in_page(unsigned int u)
>> > >>>  {
>> > >>>         int i = HID_USAGE(u), j, k, us;
>> > >>>         int page = HID_PAGE(u);
>> > >>> +       char usage_name[100];
>> > >>>         static char b[100];
>> > >>>
>> > >>>         for (k = 0; k < npages; k++)
>> > >>> @@ -234,12 +235,18 @@ hid_usage_in_page(unsigned int u)
>> > >>>         for (j = 0; j < pages[k].pagesize; j++) {
>> > >>>                 us = pages[k].page_contents[j].usage;
>> > >>>                 if (us == -1) {
>> > >>> -                       snprintf(b, sizeof b,
>> > >>> +                       snprintf(usage_name, sizeof usage_name,
>> > >>>                             pages[k].page_contents[j].name, i);
>> > >>> +                       snprintf(b, sizeof b,
>> > >>> +                           "%s:%s", pages[k].name, usage_name);
>> > >>> +                       return b;
>> > >>> +               }
>> > >>> +               if (us == i) {
>> > >>> +                       snprintf(b, sizeof b,
>> > >>> +                           "%s:%s", pages[k].name,
>> > >>> +                           pages[k].page_contents[j].name);
>> > >>>                         return b;
>> > >>>                 }
>> > >>> -               if (us == i)
>> > >>> -                       return pages[k].page_contents[j].name;
>> > >>>         }
>> > >>>   bad:
>> > >>>         snprintf(b, sizeof b, "0x%04x", i);
>> > >>> @@ -265,8 +272,9 @@ int
>> > >>>  hid_parse_usage_in_page(const char *name)
>> > >>>  {
>> > >>>         const char *sep;
>> > >>> +       const char *usage_sep;
>> > >>>         unsigned int l;
>> > >>> -       int k, j;
>> > >>> +       int k, j, us, parsed_usage;
>> > >>>
>> > >>>         sep = strchr(name, ':');
>> > >>>         if (sep == NULL)
>> > >>> @@ -277,10 +285,20 @@ hid_parse_usage_in_page(const char *name
>> > >>>                         goto found;
>> > >>>         return -1;
>> > >>>   found:
>> > >>> +       usage_sep = strchr(sep, '_');
>> > >>>         sep++;
>> > >>> -       for (j = 0; j < pages[k].pagesize; j++)
>> > >>> +       for (j = 0; j < pages[k].pagesize; j++) {
>> > >>> +               us = pages[k].page_contents[j].usage;
>> > >>> +               if (us == -1) {
>> > >>> +                       if (usage_sep == NULL)
>> > >>> +                               return -1;
>> > >>> +                       if (sscanf(usage_sep, "_%d", &parsed_usage))
>> > >>> +                               return (pages[k].usage << 16 |
>> > >>> +                                               parsed_usage);
>> > >>> +               }
>> > >>>                 if (strcmp(pages[k].page_contents[j].name, sep) ==
>> 0)
>> > >>>                         return (pages[k].usage << 16) |
>> > >>>                             pages[k].page_contents[j].usage;
>> > >>> +       }
>> > >>>         return -1;
>> > >>>  }
>> > >>>
>> > >>> Index: usbhid.3
>> > >>> ===================================================================
>> > >>> RCS file: /cvs/src/lib/libusbhid/usbhid.3,v
>> > >>> retrieving revision 1.17
>> > >>> diff -u -p -r1.17 usbhid.3
>> > >>> --- usbhid.3    13 May 2014 14:05:02 -0000      1.17
>> > >>> +++ usbhid.3    21 May 2018 21:02:21 -0000
>> > >>> @@ -65,22 +65,22 @@
>> > >>>  .Fn hid_report_size "report_desc_t d" "hid_kind_t k" "int id"
>> > >>>  .Ft int
>> > >>>  .Fn hid_locate "report_desc_t d" "u_int usage" "hid_kind_t k"
>> > >>> "hid_item_t *h" "int id"
>> > >>> -.Ft char *
>> > >>> +.Ft const char *
>> > >>>  .Fn hid_usage_page "int i"
>> > >>> -.Ft char *
>> > >>> +.Ft const char *
>> > >>>  .Fn hid_usage_in_page "u_int u"
>> > >>>  .Ft int
>> > >>>  .Fn hid_parse_usage_page "const char *"
>> > >>> -.Ft char *
>> > >>> +.Ft int
>> > >>>  .Fn hid_parse_usage_in_page "const char *"
>> > >>>  .Ft void
>> > >>>  .Fn hid_init "char *file"
>> > >>>  .Ft int
>> > >>>  .Fn hid_start "char *file"
>> > >>> -.Ft int
>> > >>> +.Ft int32_t
>> > >>>  .Fn hid_get_data "void *data" "hid_item_t *h"
>> > >>>  .Ft void
>> > >>> -.Fn hid_set_data "void *data" "hid_item_t *h" "u_int data"
>> > >>> +.Fn hid_set_data "void *data" "hid_item_t *h" "int32_t data"
>> > >>>  .Sh DESCRIPTION
>> > >>>  The
>> > >>>  .Nm
>> > >>>
>> > >>>
>> > >>>
>> > >>> 2018-05-21 12:07 GMT+02:00 Martin Pieuchot <m...@openbsd.org>:
>> > >>>
>> > >>>> On 18/05/18(Fri) 10:01, David Bern wrote:
>> > >>>> > Hello!
>> > >>>> >
>> > >>>> > Have been using libusbhid and discovered a couple of
>> discrepancies in
>> > >>>> > the man-page (libusbhid.3) and the source of usage.c
>> > >>>> >
>> > >>>> > Some are just factual misses, but I also got (what I think is) 2
>> > >>>> errors.
>> > >>>> > I will try to explain them;
>> > >>>> >
>> > >>>> > 1. (This is the I think is an error but not sure). The man-page
>> tells
>> > >>>> me
>> > >>>> > that hid_usage_in_page and hid_parse_usage_in_page are each
>> > >>>> > others inverse.
>> > >>>> > If I haven't misunderstood the practical meaning of inverse in
>> this
>> > >>>> > case then this should be true:
>> > >>>> > x == hid_parse_usage_in_page(hid_usage_in_page(x)).
>> > >>>> >
>> > >>>> > My observation:
>> > >>>> > The main reason to why this isnt true, is that
>> hid_usage_in_page()
>> > >>>> > returns the data of pages[k].page_contents[j].name
>> > >>>> > while hid_parse_usage_in_page() expects the data to
>> > >>>> > contain "%s:%s", pages[k].name, pages[k].page_contents[j].name
>> > >>>> >
>> > >>>> > The reason I ask instead of just posting working code is this:
>> > >>>> > Am I misunderstanding the manual? In that case, the solution I
>> want
>> > >>>> > to send in is a change in that sentence
>> > >>>> > Or Is the manual correct and the behavior of hid_usage_in_page()
>> > >>>> wrong,
>> > >>>> > is this something I can correct without breaking other systems?
>> > >>>> >
>> > >>>> >
>> > >>>> > 2. The second error I found is located in
>> hid_parse_usage_in_page().
>> > >>>> > It is unable to parse values found in page Button.
>> > >>>> >
>> > >>>> > My observation:
>> > >>>> > usage.c is using a standard table named usb_hid_pages. In that
>> table
>> > >>>> > we got a page called Buttons.
>> > >>>> > the usages in that page is shortened to "*  Button %d".
>> > >>>> > I believe this is the cause of why hid_parse_usage_in_page() is
>> > >>>> getting
>> > >>>> > the pagesize "wrong" and therefor unable to parse any button in
>> the
>> > >>>> > button page. I guess this is the case with other similar cases as
>> > >>>> well.
>> > >>>> >
>> > >>>> > my conclusion is that it would be possible to handle similar
>> cases in
>> > >>>> a
>> > >>>> > similar way as it is handled in hid_usage_in_page().
>> > >>>> >
>> > >>>> >
>> > >>>> > As this is my first "issue" I would love to get as much feedback
>> as
>> > >>>> > possible so I can work on delivering a desirable and usable
>> patch in
>> > >>>> > my first try.
>> > >>>>
>> > >>>> Just send a diff, then we'll look at it 8)
>> > >>>>
>> > >>>
>> > >>>
>> > >>
>> > >
>>
>
>

Reply via email to