Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <ee226490-51c6-f8e9-821a-6061202c01b1@gmail.com>
Date: Wed, 7 Jun 2023 11:32:31 +0800
From: Hangyu Hua <hbh25y@...il.com>
To: oss-security@...ts.openwall.com
Subject: Linux kernel: off-by-one in fl_set_geneve_opt

Hi guys,

I find a off-by-one bug in linux kernel's Flower
classifier(NET_CLS_FLOWER). It can cause denial-of-service and privilege 
escalation.

# Details:

static int fl_set_geneve_opt(const struct nlattr *nla, struct 
fl_flow_key *key,
      int depth, int option_len,
      struct netlink_ext_ack *extack)
{
struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
struct nlattr *class = NULL, *type = NULL, *data = NULL;
struct geneve_opt *opt;
int err, data_len = 0;

if (option_len > sizeof(struct geneve_opt))
data_len = option_len - sizeof(struct geneve_opt);

opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len]; <--- [1]
memset(opt, 0xff, option_len);
opt->length = data_len / 4;
opt->r1 = 0;
opt->r2 = 0;
opt->r3 = 0;

...
if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
int new_len = key->enc_opts.len;

data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
data_len = nla_len(data);
if (data_len < 4) {
NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4
bytes long");
return -ERANGE;
}
if (data_len % 4) {
NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a
multiple of 4 bytes long");
return -ERANGE;
}

new_len += sizeof(struct geneve_opt) + data_len;
BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
if (new_len > FLOW_DIS_TUN_OPTS_MAX) { <--- [2]
NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
return -ERANGE;
}
opt->length = data_len / 4;
memcpy(opt->opt_data, nla_data(data), data_len); <--- [3]
}
...
}

We can see that opt use key->enc_opts.len to get its pointer from
key->enc_opts.data[] in [1]. Then length will be set to "data_len /
4". The bug is that if we send two TCA_FLOWER_KEY_ENC_OPTS_GENEVE
packets and their total size is 252 bytes(key->enc_opts.len = 252)
then key->enc_opts.len = opt->length = data_len / 4 when the third
TCA_FLOWER_KEY_ENC_OPTS_GENEVE packet enters fl_set_geneve_opt. This
can bypass the check in [2] and cause out of bound write in
[3](opt->opt_data = key->enc_opts.data[257]).

# Patch

I already contacted the linux security team and made a patch:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/sched?id=4d56304e5827c8cc8cc18c75343d283af7c4825c

# CVE

Pending

# EXP

In order to avoid confusion i will publish it after I get CVE.

Thanks,
Hangyu

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.