On Tue, 2023-08-22 at 13:27 +0200, Martijn van Duren wrote:
> On Tue, 2023-08-22 at 10:16 +0000, Gerhard Roth wrote:
> > On Tue, 2023-08-22 at 11:16 +0200, Martijn van Duren wrote:
> > > On Mon, 2023-08-21 at 07:35 +0000, Gerhard Roth wrote:
> > > > Hi Martijn,
> > > > 
> > > > last November you fixed ber.c so that sequences won't generate
> > > > an uninitialized subelement.
> > > > 
> > > > This revealed another bug in ober_scanf_elements(): it couldn't
> > > > process sequences with an empty list of subelements. The following
> > > > code failed in ober_scanf_elements():
> > > > 
> > > >         struct ber_element      *root;
> > > >         struct ber_element      *sub;
> > > > 
> > > >         if ((root = ober_add_sequence(NULL)) == NULL)
> > > >                 err(1, "ober_add_sequence() failed");
> > > > 
> > > >         errno = 0;
> > > >         if (ober_scanf_elements(root, "{e", &sub))
> > > >                 err(1, "ober_scanf_elements() failed");
> > > > 
> > > >         printf("sub = %p\n", sub);
> > > > 
> > > > 
> > > > The patch below fixes that.
> > > > 
> > > > Gerhard
> > > > 
> > > > 
> > > > Index: lib/libutil/ber.c
> > > > ===================================================================
> > > > RCS file: /cvs/src/lib/libutil/ber.c,v
> > > > retrieving revision 1.24
> > > > diff -u -p -u -p -r1.24 ber.c
> > > > --- lib/libutil/ber.c   3 Nov 2022 17:58:10 -0000       1.24
> > > > +++ lib/libutil/ber.c   21 Aug 2023 07:24:21 -0000
> > > > @@ -700,7 +700,8 @@ ober_scanf_elements(struct ber_element *
> > > >  
> > > >         va_start(ap, fmt);
> > > >         while (*fmt) {
> > > > -               if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt 
> > > > != ')')
> > > > +               if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt 
> > > > != ')' &&
> > > > +                   *fmt != 'e')
> > > >                         goto fail;
> > > 
> > > I'm not sure about this part. An ober_scanf_elements of "{}e" on your
> > > example above also fails. The 'e' element might not increment the ber
> > > pointer, but I do think it should fail if an expected element is
> > > missing.
> > 
> > You're right. And digging into it, only makes it look worse.
> > 
> > I think, the 'e' format should behave differently.
> > 
> > 1) in case of '{e' it is the first element of a sequence.
> >         Empty sequences are allowed and we should not fail but
> >         set the argument to NULL instead.
> > 
> > 2) in all other cases, 'e' is the next element in the list.
> >         And here we should fail if there are less elements in the
> >         list than expected.
> > 
> > Below is an updated diff that fixes the problem by remembering
> > whether the last traversal was via 'be_sub' (fsub == 1) or 'be_next'
> > and then behaves differently. Not very elegant although.
> 
> I'm not sure yet. Do you have a particular usecase for this?
> Usually you would just do something like
> ober_scanf_elements(elm, "e{", seq);
> if (seq->be_sub != NULL) ...

In my use-case the format contained more elements that followed.
I wanted to scan them all with a single ober_scanf_elements().
But I can just as well split that up into two separate call.

So let's forget about this patch.

Many thanks for looking into this!

Gerhard


> 
> > 
> > > 
> > > >                 switch (*fmt++) {
> > > >                 case '$':
> > > > @@ -797,7 +798,7 @@ ober_scanf_elements(struct ber_element *
> > > >                         if (ber->be_encoding != BER_TYPE_SEQUENCE &&
> > > >                             ber->be_encoding != BER_TYPE_SET)
> > > >                                 goto fail;
> > > > -                       if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
> > > > +                       if (level >= _MAX_SEQ-1)
> > > 
> > > This part is OK martijn@
> > > 
> > > >                                 goto fail;
> > > >                         parent[++level] = ber;
> > > >                         ber = ber->be_sub;
> > > > 
> > > 
> > 
> > Index: lib/libutil/ber.c
> > ===================================================================
> > RCS file: /cvs/src/lib/libutil/ber.c,v
> > retrieving revision 1.24
> > diff -u -p -u -p -r1.24 ber.c
> > --- lib/libutil/ber.c   3 Nov 2022 17:58:10 -0000       1.24
> > +++ lib/libutil/ber.c   22 Aug 2023 10:10:43 -0000
> > @@ -695,12 +695,14 @@ ober_scanf_elements(struct ber_element *
> >         off_t                   *pos;
> >         struct ber_oid          *o;
> >         struct ber_element      *parent[_MAX_SEQ], **e;
> > +       int                      fsub = 0;
> >  
> >         memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ);
> >  
> >         va_start(ap, fmt);
> >         while (*fmt) {
> > -               if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt != 
> > ')')
> > +               if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt != 
> > ')' &&
> > +                   *fmt != 'e')
> >                         goto fail;
> >                 switch (*fmt++) {
> >                 case '$':
> > @@ -732,6 +734,8 @@ ober_scanf_elements(struct ber_element *
> >                 case 'e':
> >                         e = va_arg(ap, struct ber_element **);
> >                         *e = ber;
> > +                       if (fsub)
> > +                               goto fail;
> >                         ret++;
> >                         continue;
> >                 case 'E':
> > @@ -797,10 +801,11 @@ ober_scanf_elements(struct ber_element *
> >                         if (ber->be_encoding != BER_TYPE_SEQUENCE &&
> >                             ber->be_encoding != BER_TYPE_SET)
> >                                 goto fail;
> > -                       if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
> > +                       if (level >= _MAX_SEQ-1)
> >                                 goto fail;
> >                         parent[++level] = ber;
> >                         ber = ber->be_sub;
> > +                       fsub = 1;
> >                         ret++;
> >                         continue;
> >                 case '}':
> > @@ -808,6 +813,7 @@ ober_scanf_elements(struct ber_element *
> >                         if (level < 0 || parent[level] == NULL)
> >                                 goto fail;
> >                         ber = parent[level--];
> > +                       fsub = 0;
> >                         ret++;
> >                         break;
> >                 default:
> > 
> > 
> 

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to