oss-sec mailing list archives
Re: Linux kernel: off-by-one in fl_set_geneve_opt
From: Hangyu Hua <hbh25y () gmail com>
Date: Wed, 7 Jun 2023 18:41:34 +0800
On 7/6/2023 11:32, Hangyu Hua wrote:
Hi guys, I find a off-by-one bug in linux kernel's Flowerclassifier(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.
Hi guys,I decide not to publish the exp for ethical reasons. Please email me if any distribution's maintainers need the code.
Thanks, Hangyu
Thanks, Hangyu
Current thread:
- Linux kernel: off-by-one in fl_set_geneve_opt Hangyu Hua (Jun 06)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Hangyu Hua (Jun 07)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Hangyu Hua (Jun 08)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Solar Designer (Jun 08)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Hangyu Hua (Jun 12)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Hangyu Hua (Jun 08)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Salvatore Bonaccorso (Jun 16)
- Re: Linux kernel: off-by-one in fl_set_geneve_opt Hangyu Hua (Jun 07)