net: lwm2m: Improve content writers error handling in engine

Verify the restult of the content writer functions and return an error
if content writer fails to read/write field in the message.

This solves an issue when for example malformed packet was sent to the
server if the payload did not fit in the message.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2021-12-21 14:45:07 +01:00 committed by Carles Cufí
commit cb6c5f37ca

View file

@ -1097,7 +1097,10 @@ int lwm2m_register_payload_handler(struct lwm2m_message *msg)
struct lwm2m_engine_obj_inst *obj_inst; struct lwm2m_engine_obj_inst *obj_inst;
int ret; int ret;
engine_put_begin(&msg->out, NULL); ret = engine_put_begin(&msg->out, NULL);
if (ret < 0) {
return ret;
}
SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) { SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
/* Security obj MUST NOT be part of registration message */ /* Security obj MUST NOT be part of registration message */
@ -2228,6 +2231,7 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst,
uint16_t res_inst_id_tmp = 0U; uint16_t res_inst_id_tmp = 0U;
void *data_ptr = NULL; void *data_ptr = NULL;
size_t data_len = 0; size_t data_len = 0;
int ret = 0;
if (!obj_inst || !res || !obj_field || !msg) { if (!obj_inst || !res || !obj_field || !msg) {
return -EINVAL; return -EINVAL;
@ -2248,7 +2252,11 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst,
return -ENOENT; return -ENOENT;
} }
engine_put_begin_ri(&msg->out, &msg->path); ret = engine_put_begin_ri(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
res_inst_id_tmp = msg->path.res_inst_id; res_inst_id_tmp = msg->path.res_inst_id;
} }
@ -2282,65 +2290,65 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst,
switch (obj_field->data_type) { switch (obj_field->data_type) {
case LWM2M_RES_TYPE_OPAQUE: case LWM2M_RES_TYPE_OPAQUE:
engine_put_opaque(&msg->out, &msg->path, ret = engine_put_opaque(&msg->out, &msg->path,
(uint8_t *)data_ptr, (uint8_t *)data_ptr,
data_len); data_len);
break; break;
case LWM2M_RES_TYPE_STRING: case LWM2M_RES_TYPE_STRING:
engine_put_string(&msg->out, &msg->path, ret = engine_put_string(&msg->out, &msg->path,
(uint8_t *)data_ptr, (uint8_t *)data_ptr,
strlen((uint8_t *)data_ptr)); strlen((uint8_t *)data_ptr));
break; break;
case LWM2M_RES_TYPE_U32: case LWM2M_RES_TYPE_U32:
case LWM2M_RES_TYPE_TIME: case LWM2M_RES_TYPE_TIME:
engine_put_s64(&msg->out, &msg->path, ret = engine_put_s64(&msg->out, &msg->path,
(int64_t)*(uint32_t *)data_ptr); (int64_t)*(uint32_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_U16: case LWM2M_RES_TYPE_U16:
engine_put_s32(&msg->out, &msg->path, ret = engine_put_s32(&msg->out, &msg->path,
(int32_t)*(uint16_t *)data_ptr); (int32_t)*(uint16_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_U8: case LWM2M_RES_TYPE_U8:
engine_put_s16(&msg->out, &msg->path, ret = engine_put_s16(&msg->out, &msg->path,
(int16_t)*(uint8_t *)data_ptr); (int16_t)*(uint8_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_S64: case LWM2M_RES_TYPE_S64:
engine_put_s64(&msg->out, &msg->path, ret = engine_put_s64(&msg->out, &msg->path,
*(int64_t *)data_ptr); *(int64_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_S32: case LWM2M_RES_TYPE_S32:
engine_put_s32(&msg->out, &msg->path, ret = engine_put_s32(&msg->out, &msg->path,
*(int32_t *)data_ptr); *(int32_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_S16: case LWM2M_RES_TYPE_S16:
engine_put_s16(&msg->out, &msg->path, ret = engine_put_s16(&msg->out, &msg->path,
*(int16_t *)data_ptr); *(int16_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_S8: case LWM2M_RES_TYPE_S8:
engine_put_s8(&msg->out, &msg->path, ret = engine_put_s8(&msg->out, &msg->path,
*(int8_t *)data_ptr); *(int8_t *)data_ptr);
break; break;
case LWM2M_RES_TYPE_BOOL: case LWM2M_RES_TYPE_BOOL:
engine_put_bool(&msg->out, &msg->path, ret = engine_put_bool(&msg->out, &msg->path,
*(bool *)data_ptr); *(bool *)data_ptr);
break; break;
case LWM2M_RES_TYPE_FLOAT: case LWM2M_RES_TYPE_FLOAT:
engine_put_float(&msg->out, &msg->path, ret = engine_put_float(&msg->out, &msg->path,
(double *)data_ptr); (double *)data_ptr);
break; break;
case LWM2M_RES_TYPE_OBJLNK: case LWM2M_RES_TYPE_OBJLNK:
engine_put_objlnk(&msg->out, &msg->path, ret = engine_put_objlnk(&msg->out, &msg->path,
(struct lwm2m_objlnk *)data_ptr); (struct lwm2m_objlnk *)data_ptr);
break; break;
@ -2352,8 +2360,16 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst,
} }
} }
if (ret < 0) {
return ret;
}
if (res->multi_res_inst) { if (res->multi_res_inst) {
engine_put_end_ri(&msg->out, &msg->path); ret = engine_put_end_ri(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
msg->path.res_inst_id = res_inst_id_tmp; msg->path.res_inst_id = res_inst_id_tmp;
} }
@ -2397,7 +2413,7 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst,
struct lwm2m_message *msg, struct lwm2m_message *msg,
void *data_ptr, size_t data_len) void *data_ptr, size_t data_len)
{ {
size_t len = 1; int len = 1;
bool last_pkt_block = false; bool last_pkt_block = false;
int ret = 0; int ret = 0;
bool last_block = true; bool last_block = true;
@ -2432,9 +2448,8 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst,
len = engine_get_opaque(&msg->in, write_buf, len = engine_get_opaque(&msg->in, write_buf,
MIN(data_len, write_buf_len), MIN(data_len, write_buf_len),
&opaque_ctx, &last_pkt_block); &opaque_ctx, &last_pkt_block);
if (len == 0) { if (len <= 0) {
/* ignore empty content and continue */ return len;
return 0;
} }
#if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
@ -2545,71 +2560,92 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
ret = lwm2m_write_handler_opaque(obj_inst, res, ret = lwm2m_write_handler_opaque(obj_inst, res,
res_inst, msg, res_inst, msg,
data_ptr, data_len); data_ptr, data_len);
if (ret < 0) {
return ret;
}
len = ret; len = ret;
break; break;
case LWM2M_RES_TYPE_STRING: case LWM2M_RES_TYPE_STRING:
engine_get_string(&msg->in, write_buf, write_buf_len); ret = engine_get_string(&msg->in, write_buf,
write_buf_len);
if (ret < 0) {
break;
}
len = strlen((char *)write_buf); len = strlen((char *)write_buf);
break; break;
case LWM2M_RES_TYPE_U32: case LWM2M_RES_TYPE_U32:
case LWM2M_RES_TYPE_TIME: case LWM2M_RES_TYPE_TIME:
engine_get_s64(&msg->in, &temp64); ret = engine_get_s64(&msg->in, &temp64);
if (ret < 0) {
break;
}
*(uint32_t *)write_buf = temp64; *(uint32_t *)write_buf = temp64;
len = 4; len = 4;
break; break;
case LWM2M_RES_TYPE_U16: case LWM2M_RES_TYPE_U16:
engine_get_s32(&msg->in, &temp32); ret = engine_get_s32(&msg->in, &temp32);
if (ret < 0) {
break;
}
*(uint16_t *)write_buf = temp32; *(uint16_t *)write_buf = temp32;
len = 2; len = 2;
break; break;
case LWM2M_RES_TYPE_U8: case LWM2M_RES_TYPE_U8:
engine_get_s32(&msg->in, &temp32); ret = engine_get_s32(&msg->in, &temp32);
if (ret < 0) {
break;
}
*(uint8_t *)write_buf = temp32; *(uint8_t *)write_buf = temp32;
len = 1; len = 1;
break; break;
case LWM2M_RES_TYPE_S64: case LWM2M_RES_TYPE_S64:
engine_get_s64(&msg->in, (int64_t *)write_buf); ret = engine_get_s64(&msg->in, (int64_t *)write_buf);
len = 8; len = 8;
break; break;
case LWM2M_RES_TYPE_S32: case LWM2M_RES_TYPE_S32:
engine_get_s32(&msg->in, (int32_t *)write_buf); ret = engine_get_s32(&msg->in, (int32_t *)write_buf);
len = 4; len = 4;
break; break;
case LWM2M_RES_TYPE_S16: case LWM2M_RES_TYPE_S16:
engine_get_s32(&msg->in, &temp32); ret = engine_get_s32(&msg->in, &temp32);
if (ret < 0) {
break;
}
*(int16_t *)write_buf = temp32; *(int16_t *)write_buf = temp32;
len = 2; len = 2;
break; break;
case LWM2M_RES_TYPE_S8: case LWM2M_RES_TYPE_S8:
engine_get_s32(&msg->in, &temp32); ret = engine_get_s32(&msg->in, &temp32);
if (ret < 0) {
break;
}
*(int8_t *)write_buf = temp32; *(int8_t *)write_buf = temp32;
len = 1; len = 1;
break; break;
case LWM2M_RES_TYPE_BOOL: case LWM2M_RES_TYPE_BOOL:
engine_get_bool(&msg->in, (bool *)write_buf); ret = engine_get_bool(&msg->in, (bool *)write_buf);
len = 1; len = 1;
break; break;
case LWM2M_RES_TYPE_FLOAT: case LWM2M_RES_TYPE_FLOAT:
engine_get_float(&msg->in, (double *)write_buf); ret = engine_get_float(&msg->in, (double *)write_buf);
len = sizeof(double); len = sizeof(double);
break; break;
case LWM2M_RES_TYPE_OBJLNK: case LWM2M_RES_TYPE_OBJLNK:
engine_get_objlnk(&msg->in, ret = engine_get_objlnk(&msg->in,
(struct lwm2m_objlnk *)write_buf); (struct lwm2m_objlnk *)write_buf);
len = sizeof(struct lwm2m_objlnk); len = sizeof(struct lwm2m_objlnk);
break; break;
@ -2620,6 +2656,10 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
return -EINVAL; return -EINVAL;
} }
if (ret < 0) {
return ret;
}
} else { } else {
return -ENOENT; return -ENOENT;
} }
@ -3126,7 +3166,10 @@ int lwm2m_perform_read_op(struct lwm2m_message *msg, uint16_t content_format)
/* store original path values so we can change them during processing */ /* store original path values so we can change them during processing */
memcpy(&temp_path, &msg->path, sizeof(temp_path)); memcpy(&temp_path, &msg->path, sizeof(temp_path));
engine_put_begin(&msg->out, &msg->path); ret = engine_put_begin(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
while (obj_inst) { while (obj_inst) {
if (!obj_inst->resources || obj_inst->resource_count == 0U) { if (!obj_inst->resources || obj_inst->resource_count == 0U) {
@ -3138,7 +3181,10 @@ int lwm2m_perform_read_op(struct lwm2m_message *msg, uint16_t content_format)
if (msg->path.level <= 1U) { if (msg->path.level <= 1U) {
/* start instance formatting */ /* start instance formatting */
engine_put_begin_oi(&msg->out, &msg->path); ret = engine_put_begin_oi(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
} }
for (index = 0; index < obj_inst->resource_count; index++) { for (index = 0; index < obj_inst->resource_count; index++) {
@ -3164,12 +3210,20 @@ int lwm2m_perform_read_op(struct lwm2m_message *msg, uint16_t content_format)
ret = -EPERM; ret = -EPERM;
} else { } else {
/* start resource formatting */ /* start resource formatting */
engine_put_begin_r(&msg->out, &msg->path); ret = engine_put_begin_r(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
/* perform read operation on this resource */ /* perform read operation on this resource */
ret = lwm2m_read_handler(obj_inst, res, ret = lwm2m_read_handler(obj_inst, res,
obj_field, msg); obj_field, msg);
if (ret < 0) { if (ret == -ENOMEM) {
/* No point continuing if there's no
* memory left in a message.
*/
return ret;
} else if (ret < 0) {
/* ignore errors unless single read */ /* ignore errors unless single read */
if (msg->path.level > 2 && if (msg->path.level > 2 &&
!LWM2M_HAS_PERM(obj_field, !LWM2M_HAS_PERM(obj_field,
@ -3181,7 +3235,10 @@ int lwm2m_perform_read_op(struct lwm2m_message *msg, uint16_t content_format)
} }
/* end resource formatting */ /* end resource formatting */
engine_put_end_r(&msg->out, &msg->path); ret = engine_put_end_r(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
} }
/* on single read break if errors */ /* on single read break if errors */
@ -3196,7 +3253,10 @@ int lwm2m_perform_read_op(struct lwm2m_message *msg, uint16_t content_format)
move_forward: move_forward:
if (msg->path.level <= 1U) { if (msg->path.level <= 1U) {
/* end instance formatting */ /* end instance formatting */
engine_put_end_oi(&msg->out, &msg->path); ret = engine_put_end_oi(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
} }
if (msg->path.level <= 1U) { if (msg->path.level <= 1U) {
@ -3208,7 +3268,10 @@ move_forward:
} }
} }
engine_put_end(&msg->out, &msg->path); ret = engine_put_end(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
/* restore original path values */ /* restore original path values */
memcpy(&msg->path, &temp_path, sizeof(temp_path)); memcpy(&msg->path, &temp_path, sizeof(temp_path));
@ -3258,7 +3321,10 @@ int lwm2m_discover_handler(struct lwm2m_message *msg, bool is_bootstrap)
* Add required prefix for bootstrap discovery (5.2.7.3). * Add required prefix for bootstrap discovery (5.2.7.3).
* For device management discovery, `engine_put_begin()` adds nothing. * For device management discovery, `engine_put_begin()` adds nothing.
*/ */
engine_put_begin(&msg->out, &msg->path); ret = engine_put_begin(&msg->out, &msg->path);
if (ret < 0) {
return ret;
}
SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) { SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
/* Skip unrelated objects */ /* Skip unrelated objects */