Now that we have the flow-mod validation with the action/instructions
support we can extend the usage of this functions for the packet-out
validation.
This diff increases the packet-out validation coverage by also doing
instructions and packet truncation checks.
ok?
Index: ofp13.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/ofp13.c,v
retrieving revision 1.25
diff -u -p -r1.25 ofp13.c
--- ofp13.c 7 Nov 2016 13:27:11 -0000 1.25
+++ ofp13.c 7 Nov 2016 13:33:34 -0000
@@ -462,10 +462,9 @@ ofp13_validate_packet_out(struct switchd
struct ofp_header *oh, struct ibuf *ibuf)
{
struct ofp_packet_out *pout;
- size_t len;
- off_t off;
+ size_t len, plen, diff;
+ off_t off, noff;
struct ofp_action_header *ah;
- struct ofp_action_output *ao;
off = 0;
if ((pout = ibuf_seek(ibuf, off, sizeof(*pout))) == NULL) {
@@ -474,36 +473,43 @@ ofp13_validate_packet_out(struct switchd
return (-1);
}
- log_debug("\tbuffer %d port %s "
- "actions length %u",
+ off += sizeof(*pout);
+ len = ntohs(pout->pout_actions_len);
+ log_debug("\tbuffer %d in_port %s actions_len %lu",
ntohl(pout->pout_buffer_id),
- print_map(ntohl(pout->pout_in_port), ofp_port_map),
- ntohs(pout->pout_actions_len));
- len = ntohl(pout->pout_actions_len);
+ print_map(ntohl(pout->pout_in_port), ofp_port_map), len);
- off += sizeof(*pout);
- while ((ah = ibuf_seek(ibuf, off, len)) != NULL &&
- ntohs(ah->ah_len) >= (uint16_t)sizeof(*ah)) {
- switch (ntohs(ah->ah_type)) {
- case OFP_ACTION_OUTPUT:
- ao = (struct ofp_action_output *)ah;
- log_debug("\t\taction type %s length %d "
- "port %s max length %d",
- print_map(ntohs(ao->ao_type), ofp_action_map),
- ntohs(ao->ao_len),
- print_map(ntohs(ao->ao_port), ofp_port_map),
- ntohs(ao->ao_max_len));
- break;
- default:
- log_debug("\t\taction type %s length %d",
- print_map(ntohs(ah->ah_type), ofp_action_map),
- ntohs(ah->ah_len));
- break;
- }
- if (pout->pout_buffer_id == (uint32_t)-1)
- break;
- off += ntohs(ah->ah_len);
+parse_next_action:
+ if ((ah = ibuf_seek(ibuf, off, sizeof(*ah))) == NULL)
+ return (-1);
+
+ noff = off;
+ ofp13_validate_action(sc, oh, ibuf, &off, ah);
+
+ diff = off - noff;
+ /* Loop prevention. */
+ if (off < noff || diff == 0)
+ return (-1);
+
+ len -= diff;
+ if (len)
+ goto parse_next_action;
+
+ /* Check for encapsulated packet truncation. */
+ len = ntohs(oh->oh_length) - off;
+ plen = ibuf_length(ibuf) - off;
+
+ if (plen < len) {
+ log_debug("\ttruncated packet %lu < %lu", plen, len);
+
+ /* Buffered packets can be truncated */
+ if (pout->pout_buffer_id != OFP_PKTOUT_NO_BUFFER)
+ len = plen;
+ else
+ return (-1);
}
+ if (ibuf_seek(ibuf, off, len) == NULL)
+ return (-1);
return (0);
}