[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    Re: [oss-security] Linux kernel: off-by-one in fl_set_geneve_opt
From:       Salvatore Bonaccorso <carnil () debian ! org>
Date:       2023-06-17 5:17:52
Message-ID: ZI1CALKOZczi4lKI () eldamar ! lan
[Download RAW message or body]

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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic