2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

ofp-actions: Use aligned structures when decoding ofp actions.

Some openflow actions can be misaligned, e.g., actions whithin OF 1.0
replies to statistics reply messages which have a header of 12 bytes
and no additional padding.

Also, buggy controllers might incorrectly encode actions.

When decoding multiple actions in ofpacts_decode(), make sure that
when advancing to the next action it will be properly aligned
(multiple of OFPACT_ALIGNTO).

Detected by UB Sanitizer when running one of the fuzz tests:

  lib/ofp-actions.c:5347:12:
  runtime error: member access within misaligned address 0x0000016ba274
  for type 'const struct nx_action_learn', which requires 8 byte alignment
  0x0000016ba274: note: pointer points here
    20 20 20 20 ff ff 00 38  00 00 23 20 00 10 20 20
                ^
    20 20 20 20 20 20 20 20  20 20 20 20 00 03 20 00

  0 0x52cece in decode_LEARN_common lib/ofp-actions.c:5347
  1 0x52dcf6 in decode_NXAST_RAW_LEARN lib/ofp-actions.c:5463
  2 0x548604 in ofpact_decode lib/ofp-actions.inc2:4723
  3 0x53ee43 in ofpacts_decode lib/ofp-actions.c:7781
  4 0x53efc1 in ofpacts_pull_openflow_actions__ lib/ofp-actions.c:7820
  5 0x5409e1 in ofpacts_pull_openflow_instructions lib/ofp-actions.c:8396
  6 0x5608a8 in ofputil_decode_flow_stats_reply lib/ofp-flow.c:1100

Acked-by: Adrian Moreno <amorenoz@redhat.com>
Acked-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
Dumitru Ceara
2022-04-11 13:38:44 +02:00
committed by Ilya Maximets
parent 08c3e5e37e
commit a5cc859a42
4 changed files with 110 additions and 23 deletions

View File

@@ -424,7 +424,8 @@ static void put_reg_load(struct ofpbuf *openflow,
const struct mf_subfield *, uint64_t value);
static enum ofperr ofpact_pull_raw(struct ofpbuf *, enum ofp_version,
enum ofp_raw_action_type *, uint64_t *arg);
enum ofp_raw_action_type *, uint64_t *arg,
size_t *raw_len);
static void *ofpact_put_raw(struct ofpbuf *, enum ofp_version,
enum ofp_raw_action_type, uint64_t arg);
@@ -7773,45 +7774,87 @@ check_GOTO_TABLE(const struct ofpact_goto_table *a,
static void
log_bad_action(const struct ofp_action_header *actions, size_t actions_len,
const struct ofp_action_header *bad_action, enum ofperr error)
size_t action_offset, enum ofperr error)
{
if (!VLOG_DROP_WARN(&rl)) {
struct ds s;
ds_init(&s);
ds_put_hex_dump(&s, actions, actions_len, 0, false);
VLOG_WARN("bad action at offset %#"PRIxPTR" (%s):\n%s",
(char *)bad_action - (char *)actions,
VLOG_WARN("bad action at offset %"PRIuSIZE" (%s):\n%s", action_offset,
ofperr_get_name(error), ds_cstr(&s));
ds_destroy(&s);
}
}
static enum ofperr
ofpacts_decode_aligned(struct ofpbuf *openflow, enum ofp_version ofp_version,
const struct vl_mff_map *vl_mff_map,
uint64_t *ofpacts_tlv_bitmap, struct ofpbuf *ofpacts,
size_t *bad_action_offset)
{
size_t decoded_len = 0;
enum ofperr error = 0;
ovs_assert(OFPACT_IS_ALIGNED(openflow->data));
while (openflow->size) {
/* Ensure the next action data is properly aligned before decoding it.
* Some times it's valid to have to decode actions that are not
* properly aligned (e.g., when processing OF 1.0 statistics reply
* messages which have a header of 12 bytes - struct ofp10_stats_msg).
* In other cases the encoder might be buggy.
*/
if (!OFPACT_IS_ALIGNED(openflow->data)) {
ofpbuf_align(openflow);
}
const struct ofp_action_header *action = openflow->data;
enum ofp_raw_action_type raw;
size_t act_len = 0;
uint64_t arg;
error = ofpact_pull_raw(openflow, ofp_version, &raw, &arg, &act_len);
if (!error) {
error = ofpact_decode(action, raw, ofp_version, arg, vl_mff_map,
ofpacts_tlv_bitmap, ofpacts);
}
if (error) {
*bad_action_offset = decoded_len;
goto done;
}
decoded_len += act_len;
}
done:
return error;
}
static enum ofperr
ofpacts_decode(const void *actions, size_t actions_len,
enum ofp_version ofp_version,
const struct vl_mff_map *vl_mff_map,
uint64_t *ofpacts_tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpbuf openflow = ofpbuf_const_initializer(actions, actions_len);
while (openflow.size) {
const struct ofp_action_header *action = openflow.data;
enum ofp_raw_action_type raw;
enum ofperr error;
uint64_t arg;
size_t bad_action_offset = 0;
struct ofpbuf aligned_buf;
error = ofpact_pull_raw(&openflow, ofp_version, &raw, &arg);
if (!error) {
error = ofpact_decode(action, raw, ofp_version, arg, vl_mff_map,
ofpacts_tlv_bitmap, ofpacts);
}
if (error) {
log_bad_action(actions, actions_len, action, error);
return error;
}
if (!OFPACT_IS_ALIGNED(actions)) {
ofpbuf_init(&aligned_buf, actions_len);
ofpbuf_put(&aligned_buf, actions, actions_len);
} else {
ofpbuf_use_data(&aligned_buf, actions, actions_len);
}
return 0;
enum ofperr error
= ofpacts_decode_aligned(&aligned_buf, ofp_version, vl_mff_map,
ofpacts_tlv_bitmap, ofpacts,
&bad_action_offset);
if (error) {
log_bad_action(actions, actions_len, bad_action_offset, error);
}
ofpbuf_uninit(&aligned_buf);
return error;
}
static enum ofperr
@@ -9664,14 +9707,15 @@ ofpact_decode_raw(enum ofp_version ofp_version,
static enum ofperr
ofpact_pull_raw(struct ofpbuf *buf, enum ofp_version ofp_version,
enum ofp_raw_action_type *raw, uint64_t *arg)
enum ofp_raw_action_type *raw, uint64_t *arg,
size_t *raw_len)
{
const struct ofp_action_header *oah = buf->data;
const struct ofpact_raw_instance *action;
unsigned int length;
enum ofperr error;
*raw = *arg = 0;
*raw = *arg = *raw_len = 0;
error = ofpact_decode_raw(ofp_version, oah, buf->size, &action);
if (error) {
return error;
@@ -9714,6 +9758,7 @@ ofpact_pull_raw(struct ofpbuf *buf, enum ofp_version ofp_version,
}
ofpbuf_pull(buf, length);
*raw_len = length;
return 0;
}