This one has been irking me for some time. At the moment when decoding a
ber message there is no way for br_application to indicate that the
tag/type is unrecognised and if br_application is not set we default to
BER_TYPE_NULL. In basically all cases any wrong encoding should be
caught by ober_scanf_elements and friends, but I'd rather fail sooner
than later.
By scanning the tree I found BER_TYPE_DEFAULT only used by ber.c, so I
decided to rename it to BER_TYPE_UNKNOWN so that it can be used as a
failure return value from br_application. The value of -1 can safely be
used here, since get_id() allows max sizeof(unsigned int) iterations and
each iteration adds 7 bits to the value, so we never reach negative
numbers through natural means.
In a similar fashion: don't simply ignore elements in
ober_write_elements() if the encoding is not recognised.
ober_set_application() is currently not documented, so on this front
there is no update, I think this should be done as a separate endeavour.
I've put this diff through snmp, snmpd, ldapd, libutil regress without
problems, but I can't fully rule out any fallout (valid, or invalid).
thoughts? OK?
martijn@
Index: ber.c
===================================================================
RCS file: /cvs/src/lib/libutil/ber.c,v
retrieving revision 1.24
diff -u -p -r1.24 ber.c
--- ber.c 3 Nov 2022 17:58:10 -0000 1.24
+++ ber.c 23 Dec 2022 11:42:38 -0000
@@ -64,7 +64,7 @@ ober_get_element(unsigned int encoding)
return NULL;
elm->be_encoding = encoding;
- ober_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
+ ober_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_UNKNOWN);
return elm;
}
@@ -73,7 +73,7 @@ void
ober_set_header(struct ber_element *elm, int class, unsigned int type)
{
elm->be_class = class & BER_CLASS_MASK;
- if (type == BER_TYPE_DEFAULT)
+ if (type == BER_TYPE_UNKNOWN)
type = elm->be_encoding;
elm->be_type = type;
}
@@ -899,7 +899,7 @@ ober_read_elements(struct ber *ber, stru
struct ber_element *root = elm;
if (root == NULL) {
- if ((root = ober_get_element(0)) == NULL)
+ if ((root = ober_get_element(BER_TYPE_UNKNOWN)) == NULL)
return NULL;
}
@@ -1078,6 +1078,9 @@ ober_dump_element(struct ber *ber, struc
if (root->be_sub && ober_dump_element(ber, root->be_sub) == -1)
return -1;
break;
+ default:
+ errno = EINVAL;
+ return -1;
}
if (root->be_next == NULL)
@@ -1291,7 +1294,7 @@ ober_read_element(struct ber *ber, struc
elm->be_offs = ber->br_offs; /* element position within stream */
elm->be_class = class;
- if (elm->be_encoding == 0) {
+ if (elm->be_encoding == BER_TYPE_UNKNOWN) {
/* try to figure out the encoding via class, type and cstruct */
if (cstruct)
elm->be_encoding = BER_TYPE_SEQUENCE;
@@ -1304,9 +1307,12 @@ ober_read_element(struct ber *ber, struc
* type is defined as 4 byte OCTET STRING.
*/
elm->be_encoding = (*ber->br_application)(elm);
- } else
- /* last resort option */
- elm->be_encoding = BER_TYPE_NULL;
+ }
+
+ if (elm->be_encoding == BER_TYPE_UNKNOWN) {
+ errno = EINVAL;
+ return -1;
+ }
}
switch (elm->be_encoding) {
@@ -1376,7 +1382,8 @@ ober_read_element(struct ber *ber, struc
case BER_TYPE_SEQUENCE:
case BER_TYPE_SET:
if (len > 0 && elm->be_sub == NULL) {
- if ((elm->be_sub = ober_get_element(0)) == NULL)
+ elm->be_sub = ober_get_element(BER_TYPE_UNKNOWN);
+ if (elm->be_sub == NULL)
return -1;
}
next = elm->be_sub;
@@ -1403,7 +1410,8 @@ ober_read_element(struct ber *ber, struc
elements++;
len -= r;
if (len > 0 && next->be_next == NULL) {
- next->be_next = ober_get_element(0);
+ next->be_next =
+ ober_get_element(BER_TYPE_UNKNOWN);
if (next->be_next == NULL)
return -1;
}
Index: ber.h
===================================================================
RCS file: /cvs/src/lib/libutil/ber.h,v
retrieving revision 1.5
diff -u -p -r1.5 ber.h
--- ber.h 31 Oct 2021 16:42:08 -0000 1.5
+++ ber.h 23 Dec 2022 11:42:38 -0000
@@ -58,7 +58,7 @@ struct ber {
};
/* well-known ber_element types */
-#define BER_TYPE_DEFAULT ((unsigned int)-1)
+#define BER_TYPE_UNKNOWN ((unsigned int)-1)
#define BER_TYPE_EOC 0
#define BER_TYPE_BOOLEAN 1
#define BER_TYPE_INTEGER 2