mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-05 22:29:49 +00:00
Improved message parse robustness. Rejecting 'error requests'. Removed invalid genError return on varbindlist parse error, changed badValue into noSuchName error for non-writeable objects.
This commit is contained in:
parent
25ed4e9d16
commit
f7881e58bb
@ -550,19 +550,27 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
|||||||
en = msg_ps->ext_mib_node;
|
en = msg_ps->ext_mib_node;
|
||||||
np = msg_ps->ext_name_ptr;
|
np = msg_ps->ext_name_ptr;
|
||||||
|
|
||||||
if ((msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE) &&
|
if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
|
||||||
(msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
|
|
||||||
(en->set_test_a(request_id,&msg_ps->ext_object_def,
|
|
||||||
msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
|
|
||||||
{
|
{
|
||||||
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
|
if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
|
||||||
msg_ps->vb_idx += 1;
|
(en->set_test_a(request_id,&msg_ps->ext_object_def,
|
||||||
|
msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
|
||||||
|
{
|
||||||
|
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
|
||||||
|
msg_ps->vb_idx += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
en->set_test_pc(request_id,&msg_ps->ext_object_def);
|
||||||
|
/* bad value */
|
||||||
|
snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
en->set_test_pc(request_id,&msg_ps->ext_object_def);
|
en->set_test_pc(request_id,&msg_ps->ext_object_def);
|
||||||
/* bad value */
|
/* object not available for set */
|
||||||
snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
|
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
|
else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
|
||||||
@ -661,17 +669,24 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
|||||||
{
|
{
|
||||||
msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
|
msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
|
||||||
|
|
||||||
if ((object_def.access == MIB_OBJECT_READ_WRITE) &&
|
if (object_def.access == MIB_OBJECT_READ_WRITE)
|
||||||
(object_def.asn_type == msg_ps->vb_ptr->value_type) &&
|
|
||||||
(mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
|
|
||||||
{
|
{
|
||||||
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
|
if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
|
||||||
msg_ps->vb_idx += 1;
|
(mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
|
||||||
|
{
|
||||||
|
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
|
||||||
|
msg_ps->vb_idx += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* bad value */
|
||||||
|
snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* bad value */
|
/* object not available for set */
|
||||||
snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
|
snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -831,16 +846,18 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr,
|
|||||||
|
|
||||||
/* check total length, version, community, pdu type */
|
/* check total length, version, community, pdu type */
|
||||||
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
|
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
|
||||||
if ((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
|
if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
|
||||||
(msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
|
(msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
|
||||||
(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ))
|
(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
|
||||||
|
((msg_ps->error_status == SNMP_ES_NOERROR) &&
|
||||||
|
(msg_ps->error_index == 0)) )
|
||||||
{
|
{
|
||||||
/* Only accept requests. (be robust) */
|
/* Only accept requests and requests without error (be robust) */
|
||||||
err_ret = err_ret;
|
err_ret = err_ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Reject response and trap headers as input! */
|
/* Reject response and trap headers or error requests as input! */
|
||||||
err_ret = ERR_ARG;
|
err_ret = ERR_ARG;
|
||||||
}
|
}
|
||||||
if (err_ret == ERR_OK)
|
if (err_ret == ERR_OK)
|
||||||
@ -869,22 +886,17 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* varbind-list decode failed, or varbind list empty (silly cmd for agent) */
|
/* varbind-list decode failed, or varbind list empty.
|
||||||
|
drop request silently, do not return error!
|
||||||
|
(errors are only returned for a specific varbind failure) */
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
|
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
|
||||||
msg_ps->error_status = SNMP_ES_GENERROR;
|
|
||||||
msg_ps->error_index = 0;
|
|
||||||
msg_ps->outvb.head = NULL;
|
|
||||||
msg_ps->outvb.tail = NULL;
|
|
||||||
msg_ps->outvb.count = 0;
|
|
||||||
msg_ps->outvb.seqlen = 0;
|
|
||||||
msg_ps->outvb.seqlenlen = 1;
|
|
||||||
snmp_send_response(msg_ps);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* header check failed! */
|
/* header check failed
|
||||||
|
drop request silently, do not return error! */
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
|
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
|
||||||
}
|
}
|
||||||
@ -918,11 +930,12 @@ static err_t
|
|||||||
snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
|
snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
|
||||||
{
|
{
|
||||||
err_t derr;
|
err_t derr;
|
||||||
u16_t len;
|
u16_t len, ofs_base;
|
||||||
u8_t len_octets;
|
u8_t len_octets;
|
||||||
u8_t type;
|
u8_t type;
|
||||||
s32_t version;
|
s32_t version;
|
||||||
|
|
||||||
|
ofs_base = ofs;
|
||||||
snmp_asn1_dec_type(p, ofs, &type);
|
snmp_asn1_dec_type(p, ofs, &type);
|
||||||
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
||||||
if ((derr != ERR_OK) ||
|
if ((derr != ERR_OK) ||
|
||||||
@ -1022,11 +1035,17 @@ snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret,
|
|||||||
}
|
}
|
||||||
if (derr != ERR_OK)
|
if (derr != ERR_OK)
|
||||||
{
|
{
|
||||||
/* unsupported input PDU for this agent */
|
/* unsupported input PDU for this agent (no parse error) */
|
||||||
return ERR_ARG;
|
return ERR_ARG;
|
||||||
}
|
}
|
||||||
m_stat->rt = type & 0x1F;
|
m_stat->rt = type & 0x1F;
|
||||||
ofs += (1 + len_octets);
|
ofs += (1 + len_octets);
|
||||||
|
if (len != (pdu_len - (ofs - ofs_base)))
|
||||||
|
{
|
||||||
|
/* decoded PDU length does not equal actual payload length */
|
||||||
|
snmp_inc_snmpinasnparseerrs();
|
||||||
|
return ERR_ARG;
|
||||||
|
}
|
||||||
snmp_asn1_dec_type(p, ofs, &type);
|
snmp_asn1_dec_type(p, ofs, &type);
|
||||||
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
||||||
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
|
if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
|
||||||
@ -1051,8 +1070,8 @@ snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret,
|
|||||||
snmp_inc_snmpinasnparseerrs();
|
snmp_inc_snmpinasnparseerrs();
|
||||||
return ERR_ARG;
|
return ERR_ARG;
|
||||||
}
|
}
|
||||||
/* usually noError (0) for incoming messages but log errors
|
/* must be noError (0) for incoming requests.
|
||||||
for mib-2 completeness and for debug purposes */
|
log errors for mib-2 completeness and for debug purposes */
|
||||||
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
|
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
|
||||||
if (derr != ERR_OK)
|
if (derr != ERR_OK)
|
||||||
{
|
{
|
||||||
@ -1087,7 +1106,15 @@ snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret,
|
|||||||
snmp_inc_snmpinasnparseerrs();
|
snmp_inc_snmpinasnparseerrs();
|
||||||
return ERR_ARG;
|
return ERR_ARG;
|
||||||
}
|
}
|
||||||
/* skip 'error-index', usually 0 for incoming requests */
|
/* must be 0 for incoming requests.
|
||||||
|
decode anyway to catch bad integers (and dirty tricks) */
|
||||||
|
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
|
||||||
|
if (derr != ERR_OK)
|
||||||
|
{
|
||||||
|
/* can't decode */
|
||||||
|
snmp_inc_snmpinasnparseerrs();
|
||||||
|
return ERR_ARG;
|
||||||
|
}
|
||||||
ofs += (1 + len_octets + len);
|
ofs += (1 + len_octets + len);
|
||||||
*ofs_ret = ofs;
|
*ofs_ret = ofs;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
@ -1125,7 +1152,8 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
|||||||
snmp_asn1_dec_type(p, ofs, &type);
|
snmp_asn1_dec_type(p, ofs, &type);
|
||||||
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
||||||
if ((derr != ERR_OK) ||
|
if ((derr != ERR_OK) ||
|
||||||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
|
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
|
||||||
|
(len <= 0) || (len > vb_len))
|
||||||
{
|
{
|
||||||
snmp_inc_snmpinasnparseerrs();
|
snmp_inc_snmpinasnparseerrs();
|
||||||
/* free varbinds (if available) */
|
/* free varbinds (if available) */
|
||||||
|
Loading…
Reference in New Issue
Block a user