On Wed, Nov 02, 2022 at 05:56:21PM +0100, Martijn van Duren wrote:
> On Wed, 2022-11-02 at 17:47 +0100, Claudio Jeker wrote:
> > On Wed, Nov 02, 2022 at 05:25:12PM +0100, Martijn van Duren wrote:
> > > On Wed, 2022-11-02 at 17:00 +0100, Claudio Jeker wrote:
> > > > On Wed, Nov 02, 2022 at 07:33:14AM +0100, Martijn van Duren wrote:
> > > > > I found 2 minor issues in the handling of sequences/sets in
> > > > > ober_read_element():
> > > > > 1) An empty sequence/set (which is basically always) unconditionally
> > > > >    creates an (uninitialised) sub-element. Add the same length check
> > > > >    used to check the next element
> > > > > 2) For each sub-element r is only checked for -1, but not if it
> > > > >    overflows the length of the sequence itself. This is not a big risk
> > > > >    since each sub-element is length-checked against the buffer
> > > > >    availability and simply returns an ECANCELED, which would be no
> > > > >    worse memory-wise than sending an extremely large packet.
> > > > > 
> > > > > While here, only having the NULL of the comparison on the next line
> > > > > annoyed me.
> > > > > 
> > > > > OK?
> > > > 
> > > > See below.
> > > >  
> > > > > martijn@
> > > > > 
> > > > > Index: ber.c
> > > > > ===================================================================
> > > > > RCS file: /cvs/src/lib/libutil/ber.c,v
> > > > > retrieving revision 1.23
> > > > > diff -u -p -r1.23 ber.c
> > > > > --- ber.c     21 Oct 2021 08:17:33 -0000      1.23
> > > > > +++ ber.c     2 Nov 2022 06:28:33 -0000
> > > > > @@ -1375,7 +1375,7 @@ ober_read_element(struct ber *ber, struc
> > > > >               break;
> > > > >       case BER_TYPE_SEQUENCE:
> > > > >       case BER_TYPE_SET:
> > > > > -             if (elm->be_sub == NULL) {
> > > > > +             if (len > 0 && elm->be_sub == NULL) {
> > > > >                       if ((elm->be_sub = ober_get_element(0)) == NULL)
> > > > >                               return -1;
> > > > >               }
> > > > 
> > > > OK, be_sub == NULL is something checked and better than an empty object.
> > > 
> > > I'm not sure I understand what you mean here.
> > 
> > I just wanted to say that elm->be_sub == NULL is a condition that most
> > other code handles well. While having an empty element in elm->be_sub is
> > something other code may not handle well.
> 
> Ah ok, so confirming that the change is OK. Thanks.
> > 
> > > > 
> > > > > @@ -1390,13 +1390,21 @@ ober_read_element(struct ber *ber, struc
> > > > >                               return -1;
> > > > >                       }
> > > > >                       r = ober_read_element(ber, next);
> > > > > -                     if (r == -1)
> > > > > +                     if (r == -1) {
> > > > > +                             /* sub-element overflows sequence/set */
> > > > 
> > > > This comment is not quite right. I think the proper comment here is:
> > > 
> > > I'm not sure. Yes the sub-element overflows the buffer, so it is more
> > > accurate in the literal sense. However, since the sequence/set already
> > > has its entire length in the buffer it implies that an ECANCELED is an
> > > overflow of the sub-element of the sequence and therefore makes it
> > > clearer why the errno is overwritten.
> > 
> > Actually why do we need to reset the errno anyway?
> > Is anything in userland looking at ECANCELED and retries after receiving
> > more data?
> 
> Yes, aldap.c and snmpe.c do this. And even if it didn't, going with
> EINVAL is more concise than ECANCELED.

I really dislike such errno magic but fixing that is a much bigger
project.
 
> So is the comment OK as is, do you still want to go with your comment,
> or do you want to suggest something else?

My question is should we actually write this as:

                                if (r == -1 || r > len) {
                                        errno = EINVAL;
                                        return -1;
                                }

In the end any error of a subelement can be interpreted as an illegal seq/set.

> > > > 
> > > >                                 /* sub-element overflows buffer */
> > > > > +                             if (errno == ECANCELED)
> > > > > +                                     errno = EINVAL;
> > > > >                               return -1;
> > > > > +                     }
> > > > > +                     if (r > len) {
> > > > 
> > > > This check here is actually checking that the sub_element does not
> > > > overflow the sequence/set. So maybe move the abcve comment down here.
> > > 
> > > I think it does exactly the same thing, with the only difference that
> > > the ECANCELED case didn't reside fully in the buffer. The reason I
> > > didn't add the comment here was because I think it's clear from the
> > > context, where that context might be less obvious at ECANCELED.
> > 
> > Sure. It is kind of same same. The check is important though.
> 
> Yes, but the question still remains: Do I need to add a comment here?

No

> > 
> > > > 
> > > > > +                             errno = EINVAL;
> > > > > +                             return -1;
> > > > > +                     }
> > > > >                       elements++;
> > > > >                       len -= r;
> > > > >                       if (len > 0 && next->be_next == NULL) {
> > > > > -                             if ((next->be_next = 
> > > > > ober_get_element(0)) ==
> > > > > -                                 NULL)
> > > > > +                             next->be_next = ober_get_element(0);
> > > > > +                             if (next->be_next == NULL)
> > > > >                                       return -1;
> > > > >                       }
> > > > >                       next = next->be_next;
> > > > > 
> > > > 
> > > > Apart from that OK claudio@
> > > > 
> > > 
> > 
> 

-- 
:wq Claudio

Reply via email to