Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/smc: check v2_ext_offset/eid_cnt/ism_gid_cnt when receiving proposal msg

When receiving proposal msg in server, the fields v2_ext_offset/
eid_cnt/ism_gid_cnt in proposal msg are from the remote client
and can not be fully trusted. Especially the field v2_ext_offset,
once exceed the max value, there has the chance to access wrong
address, and crash may happen.

This patch checks the fields v2_ext_offset/eid_cnt/ism_gid_cnt
before using them.

Fixes: 8c3dca341aea ("net/smc: build and send V2 CLC proposal")
Signed-off-by: Guangguan Wang <guangguan.wang@linux.alibaba.com>
Reviewed-by: Wen Gu <guwen@linux.alibaba.com>
Reviewed-by: D. Wythe <alibuda@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Guangguan Wang and committed by
David S. Miller
7863c9f3 a29e220d

+16 -3
+2 -1
net/smc/af_smc.c
··· 2276 2276 goto not_found; 2277 2277 2278 2278 smc_v2_ext = smc_get_clc_v2_ext(pclc); 2279 - if (!smc_clc_match_eid(ini->negotiated_eid, smc_v2_ext, NULL, NULL)) 2279 + if (!smc_v2_ext || 2280 + !smc_clc_match_eid(ini->negotiated_eid, smc_v2_ext, NULL, NULL)) 2280 2281 goto not_found; 2281 2282 2282 2283 /* prepare RDMA check */
+7 -1
net/smc/smc_clc.c
··· 352 352 struct smc_clc_msg_hdr *hdr = &pclc->hdr; 353 353 struct smc_clc_v2_extension *v2_ext; 354 354 355 - v2_ext = smc_get_clc_v2_ext(pclc); 356 355 pclc_prfx = smc_clc_proposal_get_prefix(pclc); 357 356 if (!pclc_prfx || 358 357 pclc_prfx->ipv6_prefixes_cnt > SMC_CLC_MAX_V6_PREFIX) ··· 368 369 sizeof(struct smc_clc_msg_trail)) 369 370 return false; 370 371 } else { 372 + v2_ext = smc_get_clc_v2_ext(pclc); 373 + if ((hdr->typev2 != SMC_TYPE_N && 374 + (!v2_ext || v2_ext->hdr.eid_cnt > SMC_CLC_MAX_UEID)) || 375 + (smcd_indicated(hdr->typev2) && 376 + v2_ext->hdr.ism_gid_cnt > SMCD_CLC_MAX_V2_GID_ENTRIES)) 377 + return false; 378 + 371 379 if (ntohs(hdr->length) != 372 380 sizeof(*pclc) + 373 381 sizeof(struct smc_clc_msg_smcd) +
+7 -1
net/smc/smc_clc.h
··· 380 380 smc_get_clc_v2_ext(struct smc_clc_msg_proposal *prop) 381 381 { 382 382 struct smc_clc_msg_smcd *prop_smcd = smc_get_clc_msg_smcd(prop); 383 + u16 max_offset; 383 384 384 - if (!prop_smcd || !ntohs(prop_smcd->v2_ext_offset)) 385 + max_offset = offsetof(struct smc_clc_msg_proposal_area, pclc_v2_ext) - 386 + offsetof(struct smc_clc_msg_proposal_area, pclc_smcd) - 387 + offsetofend(struct smc_clc_msg_smcd, v2_ext_offset); 388 + 389 + if (!prop_smcd || !ntohs(prop_smcd->v2_ext_offset) || 390 + ntohs(prop_smcd->v2_ext_offset) > max_offset) 385 391 return NULL; 386 392 387 393 return (struct smc_clc_v2_extension *)