Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <ZI1CALKOZczi4lKI@eldamar.lan>
Date: Sat, 17 Jun 2023 07:17:52 +0200
From: Salvatore Bonaccorso <carnil@...ian.org>
To: oss-security@...ts.openwall.com
Subject: Re: Linux kernel: off-by-one in fl_set_geneve_opt

Hi,

On Wed, Jun 07, 2023 at 11:32:31AM +0800, Hangyu Hua wrote:
> 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.

CVE-2023-35788 has been assigned for this issue:
https://www.cve.org/CVERecord?id=CVE-2023-35788

Regards,
Salvatore

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.