oss-sec mailing list archives
Re: Linux kernel: off-by-one in fl_set_geneve_opt
From: Salvatore Bonaccorso <carnil () debian org>
Date: Sat, 17 Jun 2023 07:17:52 +0200
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
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)