NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/59230: Bug in libmj, might effect netpgp
>Number: 59230
>Category: lib
>Synopsis: Bug in libmj, might effect netpgp
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Mar 28 17:35:00 +0000 2025
>Originator: brad%anduin.eldar.org@localhost
>Release: NetBSD 10.99.12
>Organization:
eldar.org
>Environment:
System: NetBSD bradtest.eot11.eldar.org 10.99.12 NetBSD 10.99.12 (GENERIC_TEST) #0: Sun Mar 9 09:02:09 EDT 2025 brad%samwise.nat.eldar.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC_TEST amd64
Architecture: x86_64
Machine: amd64
>Description:
libmj, a minimal JSON library, comes from the netpgp package which is
in base. It appears that libmj is a first class library with a man
page that describes it use. It was imported quite some time ago.While
using libmj for something other than netpgp, I noticed a bug.
If there is a JSON array inside of a JSON object, using the libmj
sense of "array" and "object", the resulting JSON superatom will not
print correctly with mj_asprintf(), but will with mj_snprintf().
Since mj_asprintf() is just a small wrapper that recursively finds the
size of the atom passed to it, callocs up some space with the
resulting size and then calls mj_snprintf(), the bug is probably in
the function mj_string_size(), which is used to calculate the JSON
atom sizes. It appears that mj_string_size() might not account for
some white space present in arrays.
A test program is included below that demostrates the problem, and a
possible patch.
>How-To-Repeat:
Call the following program z.c, and compile it like this:
cc -DDO_MJ_ASPRINTF -DDO_MJ_SNPRINTF -o z z.c -lmj
When executed, the program will generate this output:
{ "OUTER_OBJECT":{ "OBJECT_0":[ { "INNER_ARRAY_0":[ 0, 0 ]
, "INNER_ARRAY_1":[ 0, 0 ]
}
, { "INNER_ARRAY_0":[ 0, 0 ]
, "INNER_ARRAY_1":[ 1, 1 ]
}
]
, "OBJECT_1":[ { "INNER_ARRAY_0":[ 1, 1 ]
, "INNER_ARRAY_1":[ 1, 1 ]
}
, { "INNER_ARRAY_0":[ 1, 1 ]
, "INNER_ARRAY_1":[ 2, 2 ]
}
]
}
, "INCLUDE_INT":10191, "INCLUDE_INT_AGAIN
-----
{ "OUTER_OBJECT":{ "OBJECT_0":[ { "INNER_ARRAY_0":[ 0, 0 ]
, "INNER_ARRAY_1":[ 0, 0 ]
}
, { "INNER_ARRAY_0":[ 0, 0 ]
, "INNER_ARRAY_1":[ 1, 1 ]
}
]
, "OBJECT_1":[ { "INNER_ARRAY_0":[ 1, 1 ]
, "INNER_ARRAY_1":[ 1, 1 ]
}
, { "INNER_ARRAY_0":[ 1, 1 ]
, "INNER_ARRAY_1":[ 2, 2 ]
}
]
}
, "INCLUDE_INT":10191, "INCLUDE_INT_AGAIN":20382 }
Note that the first print of the main JSON atom clips off a number of
characters and resultes in invalid JSON. In fact, a character will be
lost for every array present. The second one has everything and is
correct.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mj.h>
void
main()
{
mj_t array;
mj_t obj;
mj_t inner_obj;
mj_t outer_obj;
char buf[10000];
char obuf[10000];
char *s;
int cc;
int anint = 10191;
(void) memset(&obj, 0x0, sizeof(obj));
(void) memset(&outer_obj, 0x0, sizeof(outer_obj));
mj_create(&obj, "object");
mj_create(&outer_obj, "object");
for(int k=0;k < 2;k++) {
(void) memset(&array, 0x0, sizeof(array));
mj_create(&array, "array");
for(int64_t j=0;j < 2;j++) {
(void) memset(&inner_obj, 0x0, sizeof(inner_obj));
mj_create(&inner_obj, "object");
for(int64_t i=0;i < 2;i++) {
sprintf(buf,"INNER_ARRAY_%d",i);
mj_t inner_array;
(void) memset(&inner_array, 0x0, sizeof(inner_array));
mj_create(&inner_array, "array");
for(int64_t l=0;l < 2;l++) {
mj_append(&inner_array,"integer", (i * j) + k);
}
mj_append_field(&inner_obj, buf, "array", &inner_array);
}
mj_append(&array,"object",&inner_obj);
mj_delete(&inner_obj);
}
sprintf(buf,"OBJECT_%d",k);
mj_append_field(&outer_obj, buf, "array", &array);
mj_delete(&array);
}
mj_append_field(&obj, "OUTER_OBJECT", "object", &outer_obj);
mj_append_field(&obj, "INCLUDE_INT", "integer", (int64_t)anint);
mj_append_field(&obj, "INCLUDE_INT_AGAIN", "integer", (int64_t)anint * 2);
#ifdef DO_MJ_ASPRINTF
cc = mj_asprint(&s, &obj, MJ_JSON_ENCODE);
printf("%s",s);
printf("\n\n");
#endif
printf("-----\n");
#ifdef DO_MJ_SNPRINTF
mj_snprint(obuf,sizeof(obuf),&obj,MJ_JSON_ENCODE);
printf("%s",obuf);
printf("\n\n");
#endif
}
>Fix:
This patch allows the test program to work as expected, but I don't
really know if it is the correct solution. The status and
dispensation of netpgp, as a imported package, is also unknown. While
a number of other atom combinations were tested, I did not test just
every possible way one might generate JSON. I mostly had a need to
put JSON arrays inside of JSON objects hopefully using a library that
was in the base system.
--- crypto/external/bsd/netpgp/dist/src/libmj/mj.c.ORIG3 2022-08-27 15:25:42.278799705 -0400
+++ crypto/external/bsd/netpgp/dist/src/libmj/mj.c 2025-03-28 12:42:23.590223734 -0400
@@ -502,7 +502,7 @@
cc += (i < atom->c - 1) ? 2 : 1;
}
/* end ']' */
- return cc + 1;
+ return cc + 2;
case MJ_OBJECT:
/* start '{ ' */
for (cc = 2, i = 0 ; i < atom->c ; i += 2) {
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index