Commit 779d8521 authored by Robert Lubos's avatar Robert Lubos Committed by Fabio Baltieri
Browse files

net: lwm2m: oma_tlv: Fix UBSAN warnings about signed integers



* Simplify the logic of the get_number() function to address the corner
  cases reported by UBSAN regarding byte-swapping signed integer values.

  The existing logic was actually only valid for little-endian systems,
  as it expected that the bytes written from the packet buffer will be
  stored at the beginning of the int64_t memory, plus the actual
  byte-swapping with signed integer casts inside was hard to follow.
  Switch to a plain uint8_t buffer for integer readout, and use
  dedicated system function to convert the big-endian data in the buffer
  into unsigned integer in the system endianness, followed by the final
  cast to a signed value.

* Add explicit cast to uint32_t in put_objlnk() to prevent warning about
  not-fitting integer after byte shift, and update the result type to
  uint32_t as well.

* Switch to buffer with sys_put_be16/32/64 when writing integers due to
  similar warnings about byte-swapping signed values.

Signed-off-by: default avatarRobert Lubos <robert.lubos@nordicsemi.no>
parent a09fae57
Loading
Loading
Loading
Loading
+17 −18
Original line number Diff line number Diff line
@@ -425,7 +425,7 @@ static int put_s16(struct lwm2m_output_context *out,
	struct tlv_out_formatter_data *fd;
	int len;
	struct oma_tlv tlv;
	int16_t net_value;
	uint8_t net_value[sizeof(int16_t)];

	if (INT8_MIN <= value && value <= INT8_MAX) {
		return put_s8(out, path, (int8_t)value);
@@ -436,11 +436,11 @@ static int put_s16(struct lwm2m_output_context *out,
		return -EINVAL;
	}

	net_value = sys_cpu_to_be16(value);
	sys_put_be16(value, net_value);
	tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
		  tlv_calc_id(fd->writer_flags, path), sizeof(net_value));

	len = oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
	len = oma_tlv_put(&tlv, out, net_value, false);
	return len;
}

@@ -450,7 +450,7 @@ static int put_s32(struct lwm2m_output_context *out,
	struct tlv_out_formatter_data *fd;
	int len;
	struct oma_tlv tlv;
	int32_t net_value;
	uint8_t net_value[sizeof(int32_t)];

	if (INT16_MIN <= value && value <= INT16_MAX) {
		return put_s16(out, path, (int16_t)value);
@@ -461,11 +461,11 @@ static int put_s32(struct lwm2m_output_context *out,
		return -EINVAL;
	}

	net_value = sys_cpu_to_be32(value);
	sys_put_be32(value, net_value);
	tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
		  tlv_calc_id(fd->writer_flags, path), sizeof(net_value));

	len = oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
	len = oma_tlv_put(&tlv, out, net_value, false);

	return len;
}
@@ -476,7 +476,7 @@ static int put_s64(struct lwm2m_output_context *out,
	struct tlv_out_formatter_data *fd;
	int len;
	struct oma_tlv tlv;
	int64_t net_value;
	uint8_t net_value[sizeof(int64_t)];

	if (INT32_MIN <= value && value <= INT32_MAX) {
		return put_s32(out, path, (int32_t)value);
@@ -487,11 +487,11 @@ static int put_s64(struct lwm2m_output_context *out,
		return -EINVAL;
	}

	net_value = sys_cpu_to_be64(value);
	sys_put_be64(value, net_value);
	tlv_setup(&tlv, tlv_calc_type(fd->writer_flags),
		  tlv_calc_id(fd->writer_flags, path), sizeof(net_value));

	len = oma_tlv_put(&tlv, out, (uint8_t *)&net_value, false);
	len = oma_tlv_put(&tlv, out, net_value, false);
	return len;
}

@@ -564,8 +564,8 @@ static int put_objlnk(struct lwm2m_output_context *out,
{
	struct tlv_out_formatter_data *fd;
	struct oma_tlv tlv;
	int32_t net_value = sys_cpu_to_be32(
				((value->obj_id) << 16) | value->obj_inst);
	uint32_t net_value = sys_cpu_to_be32(
				((uint32_t)value->obj_id << 16) | value->obj_inst);

	fd = engine_get_out_user_data(out);
	if (!fd) {
@@ -583,7 +583,7 @@ static int get_number(struct lwm2m_input_context *in, int64_t *value,
{
	struct oma_tlv tlv;
	int size;
	int64_t temp;
	uint8_t temp[sizeof(int64_t)];
	int ret;

	size = oma_tlv_get(&tlv, in, false);
@@ -596,24 +596,23 @@ static int get_number(struct lwm2m_input_context *in, int64_t *value,
		return -ENOMEM;
	}

	ret = buf_read((uint8_t *)&temp, tlv.length,
		       CPKT_BUF_READ(in->in_cpkt), &in->offset);
	ret = buf_read(temp, tlv.length, CPKT_BUF_READ(in->in_cpkt), &in->offset);
	if (ret < 0) {
		return ret;
	}

	switch (tlv.length) {
	case 1:
		*value = (int8_t)temp;
		*value = (int8_t)temp[0];
		break;
	case 2:
		*value = sys_cpu_to_be16((int16_t)temp);
		*value = (int16_t)sys_get_be16(temp);
		break;
	case 4:
		*value = sys_cpu_to_be32((int32_t)temp);
		*value = (int32_t)sys_get_be32(temp);
		break;
	case 8:
		*value = sys_cpu_to_be64(temp);
		*value = (int64_t)sys_get_be64(temp);
		break;
	default:
		LOG_ERR("invalid length: %u", tlv.length);