| From cff89b190444a12b0af2c7046a9c8eeac1d7560a Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 5 Feb 2021 16:11:00 -0600 |
| Subject: net: ipa: avoid field overflow |
| |
| From: Alex Elder <elder@linaro.org> |
| |
| [ Upstream commit cd1150098f2cc7bd05740c105488c293f6761f5a ] |
| |
| It's possible that the length passed to ipa_header_size_encoded() |
| is larger than what can be represented by the HDR_LEN field alone |
| (starting with IPA v4.5). If we attempted that, u32_encode_bits() |
| would trigger a build-time error. |
| |
| Avoid this problem by masking off high-order bits of the value |
| encoded as the lower portion of the header length. |
| |
| The same sort of problem exists in ipa_metadata_offset_encoded(), |
| so implement the same fix there. |
| |
| Signed-off-by: Alex Elder <elder@linaro.org> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ipa/ipa_reg.h | 22 ++++++++++++++-------- |
| 1 file changed, 14 insertions(+), 8 deletions(-) |
| |
| diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h |
| index e6b0827a244e..732e691e9aa6 100644 |
| --- a/drivers/net/ipa/ipa_reg.h |
| +++ b/drivers/net/ipa/ipa_reg.h |
| @@ -408,15 +408,18 @@ enum ipa_cs_offload_en { |
| static inline u32 ipa_header_size_encoded(enum ipa_version version, |
| u32 header_size) |
| { |
| + u32 size = header_size & field_mask(HDR_LEN_FMASK); |
| u32 val; |
| |
| - val = u32_encode_bits(header_size, HDR_LEN_FMASK); |
| - if (version < IPA_VERSION_4_5) |
| + val = u32_encode_bits(size, HDR_LEN_FMASK); |
| + if (version < IPA_VERSION_4_5) { |
| + /* ipa_assert(header_size == size); */ |
| return val; |
| + } |
| |
| /* IPA v4.5 adds a few more most-significant bits */ |
| - header_size >>= hweight32(HDR_LEN_FMASK); |
| - val |= u32_encode_bits(header_size, HDR_LEN_MSB_FMASK); |
| + size = header_size >> hweight32(HDR_LEN_FMASK); |
| + val |= u32_encode_bits(size, HDR_LEN_MSB_FMASK); |
| |
| return val; |
| } |
| @@ -425,15 +428,18 @@ static inline u32 ipa_header_size_encoded(enum ipa_version version, |
| static inline u32 ipa_metadata_offset_encoded(enum ipa_version version, |
| u32 offset) |
| { |
| + u32 off = offset & field_mask(HDR_OFST_METADATA_FMASK); |
| u32 val; |
| |
| - val = u32_encode_bits(offset, HDR_OFST_METADATA_FMASK); |
| - if (version < IPA_VERSION_4_5) |
| + val = u32_encode_bits(off, HDR_OFST_METADATA_FMASK); |
| + if (version < IPA_VERSION_4_5) { |
| + /* ipa_assert(offset == off); */ |
| return val; |
| + } |
| |
| /* IPA v4.5 adds a few more most-significant bits */ |
| - offset >>= hweight32(HDR_OFST_METADATA_FMASK); |
| - val |= u32_encode_bits(offset, HDR_OFST_METADATA_MSB_FMASK); |
| + off = offset >> hweight32(HDR_OFST_METADATA_FMASK); |
| + val |= u32_encode_bits(off, HDR_OFST_METADATA_MSB_FMASK); |
| |
| return val; |
| } |
| -- |
| 2.30.1 |
| |