On Thu, 2020-09-03 at 09:49 +0200, Martijn van Duren wrote:
> At the moment it's not wise to run "snmp df" against untrusted
> instances, since it outputs the hrStorageDescr without checking the
> bytes being printed.
> 
> Make use of the new DISPLAY-HINT functionality of smi.c to make sure
> the string is actually DisplayHint compliant.
> 
> While here add the extra continuity-check in the second loop.
> 
> OK?
> 
> martijn@
> 
There was still a minor alignment issue in the previous diff, since
printf looks at the bytes printed and not the width of the characters,
which gives a wrong result if there's a replacement character in use.

Diff below fixes this.

All other fields should be printable ascii only and thus safe to use
in this way.

Index: mib.h
===================================================================
RCS file: /cvs/src/usr.bin/snmp/mib.h,v
retrieving revision 1.7
diff -u -p -r1.7 mib.h
--- mib.h       8 Aug 2020 14:01:31 -0000       1.7
+++ mib.h       3 Sep 2020 08:54:12 -0000
@@ -961,7 +961,7 @@
        { MIBDECL(hrStorageEntry) },                    \
        { MIBDECL(hrStorageIndex) },                    \
        { MIBDECL(hrStorageType) },                     \
-       { MIBDECL(hrStorageDescr) },                    \
+       { MIBDECL(hrStorageDescr), "DisplayString" },   \
        { MIBDECL(hrStorageAllocationUnits) },          \
        { MIBDECL(hrStorageSize) },                     \
        { MIBDECL(hrStorageUsed) },                     \
Index: snmpc.c
===================================================================
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.28
diff -u -p -r1.28 snmpc.c
--- snmpc.c     3 Aug 2020 14:45:54 -0000       1.28
+++ snmpc.c     3 Sep 2020 08:54:12 -0000
@@ -39,6 +39,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <util.h>
+#include <wchar.h>
 
 #include "smi.h"
 #include "snmp.h"
@@ -58,6 +59,7 @@ int snmpc_print(struct ber_element *);
 __dead void snmpc_printerror(enum snmp_error, struct ber_element *, int,
     const char *);
 char *snmpc_hex2bin(char *, size_t *);
+ssize_t snmpc_mbswidth(char *);
 struct ber_element *snmpc_varbindparse(int, char *[]);
 void usage(void);
 
@@ -820,8 +822,8 @@ snmpc_df(int argc, char *argv[])
 {
        struct snmpc_df {
                uint32_t index;
-               /* DisplayString is 255a DISPLAY-HINT */
-               char descr[256];
+               char *descr;
+               int descrwidth;
                /* Theoretical maximum for 2 32 bit values multiplied */
                char size[21];
                char used[21];
@@ -833,7 +835,8 @@ snmpc_df(int argc, char *argv[])
        struct ber_oid sizeoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 5 }, 11};
        struct ber_oid usedoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 6 }, 11};
        struct ber_oid oid, *reqoid;
-       struct ber_element *pdu, *varbind;
+       char oids[SNMP_MAX_OID_STRLEN];
+       struct ber_element *pdu, *varbind, *elm;
        struct snmp_agent *agent;
        int errorstatus, errorindex;
        int class;
@@ -890,8 +893,9 @@ snmpc_df(int argc, char *argv[])
                        return 1;
                }
                for (; varbind != NULL; varbind = varbind->be_next) {
-                       (void) ober_scanf_elements(varbind, "{oS", &oid);
-                       if (ober_oid_cmp(&descroid, &oid) != 2)
+                       if (ober_scanf_elements(varbind, "{os", &oid,
+                           &string) == -1 ||
+                           ober_oid_cmp(&descroid, &oid) != 2)
                                break;
                        rows++;
                } 
@@ -899,19 +903,29 @@ snmpc_df(int argc, char *argv[])
                        err(1, "malloc");
                (void) ober_scanf_elements(pdu, "{SSS{e", &varbind);
                for (; i < rows; varbind = varbind->be_next, i++) {
-                       if (ober_scanf_elements(varbind, "{os", &oid,
-                           &string) == -1) {
+                       if (ober_scanf_elements(varbind, "{oe", &oid,
+                           &elm) == -1) {
                                i--;
                                rows--;
                                continue;
                        }
+                       if (ober_oid_cmp(&descroid, &oid) != 2)
+                               break;
                        df[i].index = oid.bo_id[oid.bo_n - 1];
-                       len = strlcpy(df[i].descr, string,
-                           sizeof(df[i].descr));
-                       if (len > (int) sizeof(df[i].descr))
-                               len = (int) sizeof(df[i].descr) - 1;
-                       if (len > descrlen)
-                               descrlen = len;
+                       if ((df[i].descr = smi_print_element(&oid, elm, 0,
+                           smi_os_ascii, 0, utf8)) == NULL) {
+                               smi_oid2string(&oid, oids, sizeof(oids),
+                                   oid_lookup);
+                               warn("df: can't print oid %s", oids);
+                               i--;
+                               rows--;
+                               continue;
+                       }
+                       if ((df[i].descrwidth =
+                           (int) snmpc_mbswidth(df[i].descr)) == -1)
+                               err(1, "df: invalid hrStorageDescr");
+                       if (df[i].descrwidth > descrlen)
+                               descrlen = df[i].descrwidth;
                } 
                ober_free_elements(pdu);
                if (varbind != NULL)
@@ -1031,8 +1045,8 @@ snmpc_df(int argc, char *argv[])
            NEXTTAB(usedlen) + availlen, "Available",
            NEXTTAB(availlen) + proclen, "Used%");
        for (i = 0; i < rows; i++) {
-               printf("%-*s%*s%*s%*s%*s\n",
-                   descrlen, df[i].descr,
+               printf("%s%*s%*s%*s%*s%*s\n",
+                   df[i].descr, descrlen - df[i].descrwidth, "",
                    NEXTTAB(descrlen) + sizelen, df[i].size,
                    NEXTTAB(sizelen) + usedlen, df[i].used,
                    NEXTTAB(usedlen) + availlen, df[i].avail,
@@ -1325,6 +1339,24 @@ fail:
        errno = EINVAL;
        free(decstr);
        return NULL;
+}
+
+ssize_t
+snmpc_mbswidth(char *str)
+{
+       wchar_t wc;
+       size_t width = 0;
+       size_t i;
+       int len;
+
+       for (i = 0; (len = mbtowc(&wc, &(str[i]), MB_CUR_MAX)) != 0; i += len) {
+               if (len == -1) {
+                       mbtowc(NULL, NULL, MB_CUR_MAX);
+                       return -1;
+               }
+               width += wcwidth(wc);
+       }
+       return width;
 }
 
 struct ber_element *

Reply via email to