On Thu, Oct 03, 2019 at 10:42:42AM +0200, Martijn van Duren wrote:
> On 10/3/19 10:19 AM, Claudio Jeker wrote:
> > On Thu, Oct 03, 2019 at 10:01:06AM +0200, Martijn van Duren wrote:
> >> On 10/3/19 9:21 AM, Sebastien Marie wrote:
> >>> On Thu, Sep 26, 2019 at 02:33:11PM +0200, Martijn van Duren wrote:
> >>>> On 9/26/19 9:54 AM, Martijn van Duren wrote:
> >>>>> Hello,
> >>>>>
> >>>>> I reckon this will be on of the last major additions.
> >>>>> Adding "snmp set" allows us to run snmpd's regress without installing
> >>>>> netsnmp. :-)
> >>>>>
> >>>>> Tested with snmpd's regress test.
> >>>>>
> >>>>> Majority of diff is moving oid/value parsing from snmp trap to a
> >>>>> separate function.
> >>>>>
> >>>>> OK?
> >>>>>
> >>>>> martijn@
> >>>
> >>> few comments.
> >>>
> >>> thanks.
> >>>
> >>>> Index: snmpc.c
> >>>> ===================================================================
> >>>> RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
> >>>> retrieving revision 1.11
> >>>> diff -u -p -r1.11 snmpc.c
> >>>> --- snmpc.c      18 Sep 2019 09:54:36 -0000      1.11
> >>>> +++ snmpc.c      26 Sep 2019 12:32:38 -0000
> >>>> @@ -666,19 +669,54 @@ snmpc_walk(int argc, char *argv[])
> >>>>  }
> >>>>  
> >>>>  int
> >>>> +snmpc_set(int argc, char *argv[])
> >>>> +{
> >>>> +        struct snmp_agent *agent;
> >>>> +        struct ber_element *pdu, *varbind;
> >>>> +        int errorstatus, errorindex;
> >>>> +        int class;
> >>>> +        unsigned type;
> >>>> +
> >>>> +        if (argc < 4)
> >>>> +                usage();
> >>>> +        if ((agent = snmpc_connect(argv[0], "161")) == NULL)
> >>>> +                err(1, "%s", snmp_app->name);
> >>>> +        argc--;
> >>>> +        argv++;
> >>>> +
> >>>> +        if (argc < 3 || argc % 3 != 0)
> >>>> +                usage();
> >>>> +
> >>>> +        if (pledge("stdio", NULL) == -1)
> >>>> +                err(1, "pledge");
> >>>> +
> >>>> +        pdu = snmp_set(agent, snmpc_varbindparse(argc, argv));
> >>>> +
> >>>> +        (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, 
> >>>> &errorstatus,
> >>>> +            &errorindex, &varbind);
> >>>> +        if (errorstatus != 0)
> >>>> +                snmpc_printerror((enum snmp_error) errorstatus,
> >>>> +                    argv[errorindex - 1]);
> >>>
> >>> is "errorindex - 1" the right index ?
> >>
> >> Yes: RFC 3416 section 4.1:
> >> A variable binding is identified by its index value.  The first variable
> >> binding in a variable-binding list is index one, the second is index 
> >> two, etc.
> >>
> >> I choose to use argv, because it's easier for the end user to see his
> >> own input for where he mistyped instead of a double parsed oid to -O
> >> based output.
> >>
> >>>
> >>> $ ./obj/snmp set 192.168.1.5 sysContact.0 s "test"
> >>> snmp: Can't parse oid 192.168.1.5: Not writable
> >>>
> >>> Note that the same pattern is used in others commands.
> >>
> >> Somehow the machines I test against don't return a not writable message.
> >> Tested against snmpd, net-snmpd, HP Laserjet.
> >> Could you show me a tcpdump -v output on this output?
> >>>
> >>
> >>>> +struct ber_element *
> >>>> +snmpc_varbindparse(int argc, char *argv[])
> >>>> +{
> >>>> +        struct ber_oid oid, oidval;
> >>>> +        struct in_addr addr4;
> >>>> +        char *addr = (char *)&addr4;
> >>>> +        char *str = NULL, *tmpstr, *endstr;
> >>>> +        const char *errstr = NULL;
> >>>> +        struct ber_element *varbind = NULL, *vblist = NULL;
> >>>> +        int i, ret;
> >>>> +        size_t strl, byte;
> >>>> +        long long lval;
> >>>> +
> >>>> +        if (argc % 3 != 0)
> >>>> +                usage();
> >>>
> >>> if I don't mess myself, callers already checks that 'argc % 3 != 0'. So I 
> >>> think
> >>> the condition is more a defense for programmer error that user error, and 
> >>> I
> >>> would use an assert(argc % 3 == 0) or abort().
> >>
> >> I removed these checks from snmpc_{set,trap}. Even less code. :-)
> >>
> >> Index: snmp.c
> >> ===================================================================
> >> RCS file: /cvs/src/usr.bin/snmp/snmp.c,v
> >> retrieving revision 1.6
> >> diff -u -p -r1.6 snmp.c
> >> --- snmp.c 18 Sep 2019 09:54:36 -0000      1.6
> >> +++ snmp.c 3 Oct 2019 07:59:07 -0000
> >> @@ -249,6 +249,22 @@ fail:
> >>    return NULL;
> >>  }
> >>  
> >> +struct ber_element *
> >> +snmp_set(struct snmp_agent *agent, struct ber_element *vblist)
> >> +{
> >> +  struct ber_element *pdu;
> >> +
> >> +  if ((pdu = ber_add_sequence(NULL)) == NULL)
> >> +          return NULL;
> >> +  if (ber_printf_elements(pdu, "tddd{e", BER_CLASS_CONTEXT,
> >> +      SNMP_C_SETREQ, arc4random() & 0x7fffffff, 0, 0, vblist) == NULL) {
> >> +          ber_free_elements(pdu);
> > 
> > Shouldn't this be ber_free_elements(vblist)?
> > If ber_printf_elements() fails pdu was already freed there.
> 
> Nope, the pdu has already been allocated and is the root of this
> endeavour. So that needs to be freed.

But you pass the pdu to ber_printf_elements() and there this happens:

struct ber_element *
ber_printf_elements(struct ber_element *ber, char *fmt, ...)
{
....
 fail:
        ber_free_elements(ber);
        return (NULL);
}

So when ber_printf_elements() returns NULL the passed pdu was already
freed up in ber_free_elements() and so the code is doing a double free.
 
> vblist is most likely not linked into the pdu, so we can argue if it
> should be freed separately.
> 
> It's a minor leak, since we most likely are heading for the exit
> path, but it's worth thinking how we want to properly handle this (same
> for snmp_get, snmp_getnext, snmp_trap, and snmp_bulkget).

I'm fine with this and I agree that the error behaviour of
ber_printf_elements() is less than ideal since it is unclear what needs to
be cleared up and what not. This is actually a much bigger issue for the
daemons.
 
> I'd say we leave this for a different patch.
> > 
> > Apart from that OK claudio@
> > 
> 

-- 
:wq Claudio

Reply via email to