plist handling of invalid input and keyhashes

This fixes some issues with the new discovery data ("plist" topics)
discovered on interoperating with some other DDS implementations:

* The interpretation of a keyhash as if it were a valid sample was wrong
  in various ways: inconsistent endianness, incorrect encoding
  identifier and a missing sentinel.  As Cyclone follows the spec and
  always provides a well-formed payload, the problem only surfaces when
  interoperating with implementations that expect the recipient to make
  do with a keyhash.

* Various paths failed to check for failure causing potential null
  pointer dereferences.

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2020-04-08 11:35:49 +02:00 committed by eboasson
parent eb7e5e3a87
commit 52edbe94e9
2 changed files with 19 additions and 4 deletions

View file

@ -102,6 +102,8 @@ static struct ddsi_serdata *serdata_plist_from_ser (const struct ddsi_sertopic *
{ {
const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn; const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn;
struct ddsi_serdata_plist *d = serdata_plist_new (tp, kind, size, NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain))); struct ddsi_serdata_plist *d = serdata_plist_new (tp, kind, size, NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain)));
if (d == NULL)
return NULL;
uint32_t off = 4; /* must skip the CDR header */ uint32_t off = 4; /* must skip the CDR header */
assert (fragchain->min == 0); assert (fragchain->min == 0);
assert (fragchain->maxp1 >= off); /* CDR header must be in first fragment */ assert (fragchain->maxp1 >= off); /* CDR header must be in first fragment */
@ -128,6 +130,8 @@ static struct ddsi_serdata *serdata_plist_from_ser_iov (const struct ddsi_sertop
const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn; const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn;
assert (niov >= 1); assert (niov >= 1);
struct ddsi_serdata_plist *d = serdata_plist_new (tp, kind, size, iov[0].iov_base); struct ddsi_serdata_plist *d = serdata_plist_new (tp, kind, size, iov[0].iov_base);
if (d == NULL)
return NULL;
memcpy (d->data + d->pos, (const char *) iov[0].iov_base + 4, iov[0].iov_len - 4); memcpy (d->data + d->pos, (const char *) iov[0].iov_base + 4, iov[0].iov_len - 4);
d->pos += (uint32_t) iov[0].iov_len - 4; d->pos += (uint32_t) iov[0].iov_len - 4;
for (ddsrt_msg_iovlen_t i = 1; i < niov; i++) for (ddsrt_msg_iovlen_t i = 1; i < niov; i++)
@ -141,14 +145,18 @@ static struct ddsi_serdata *serdata_plist_from_ser_iov (const struct ddsi_sertop
static struct ddsi_serdata *serdata_plist_from_keyhash (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash) static struct ddsi_serdata *serdata_plist_from_keyhash (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash)
{ {
const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn; const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn;
const struct { uint16_t identifier, options; nn_parameter_t par; ddsi_keyhash_t kh; } in = { const struct { uint16_t identifier, options; nn_parameter_t par; ddsi_keyhash_t kh; nn_parameter_t sentinel; } in = {
.identifier = CDR_BE, .identifier = PL_CDR_BE,
.options = 0, .options = 0,
.par = { .par = {
.parameterid = ddsrt_toBE2u (tp->keyparam), .parameterid = ddsrt_toBE2u (tp->keyparam),
.length = sizeof (*keyhash) .length = ddsrt_toBE2u ((uint16_t) sizeof (*keyhash))
}, },
*keyhash .kh = *keyhash,
.sentinel = {
.parameterid = ddsrt_toBE2u (PID_SENTINEL),
.length = 0
}
}; };
const ddsrt_iovec_t iov = { .iov_base = (void *) &in, .iov_len = sizeof (in) }; const ddsrt_iovec_t iov = { .iov_base = (void *) &in, .iov_len = sizeof (in) };
return serdata_plist_from_ser_iov (tpcmn, SDK_KEY, 1, &iov, sizeof (in) - 4); return serdata_plist_from_ser_iov (tpcmn, SDK_KEY, 1, &iov, sizeof (in) - 4);

View file

@ -1534,6 +1534,13 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
PGUID (srcguid), sampleinfo->seq); PGUID (srcguid), sampleinfo->seq);
goto done_upd_deliv; goto done_upd_deliv;
} }
if (d == NULL)
{
GVLOG (DDS_LC_DISCOVERY | DDS_LC_WARNING, "data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": deserialization failed\n",
sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
PGUID (srcguid), sampleinfo->seq);
goto done_upd_deliv;
}
d->timestamp = (sampleinfo->timestamp.v != DDSRT_WCTIME_INVALID.v) ? sampleinfo->timestamp : ddsrt_time_wallclock (); d->timestamp = (sampleinfo->timestamp.v != DDSRT_WCTIME_INVALID.v) ? sampleinfo->timestamp : ddsrt_time_wallclock ();
d->statusinfo = statusinfo; d->statusinfo = statusinfo;