* [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT @ 2020-07-07 21:16 Nick Desaulniers 2020-07-07 21:49 ` Sami Tolvanen 2020-07-07 22:43 ` Alex Elder 0 siblings, 2 replies; 7+ messages in thread From: Nick Desaulniers @ 2020-07-07 21:16 UTC (permalink / raw) To: David S . Miller Cc: Jakub Kicinski, stable, Masahiro Yamada, Sami Tolvanen, Nick Desaulniers, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, Alex Elder, linux-kernel, netdev, bpf From: Jakub Kicinski <kuba@kernel.org> When ur_load_imm_any() is inlined into jeq_imm(), it's possible for the compiler to deduce a case where _val can only have the value of -1 at compile time. Specifically, /* struct bpf_insn: _s32 imm */ u64 imm = insn->imm; /* sign extend */ if (imm >> 32) { /* non-zero only if insn->imm is negative */ /* inlined from ur_load_imm_any */ u32 __imm = imm >> 32; /* therefore, always 0xffffffff */ if (__builtin_constant_p(__imm) && __imm > 255) compiletime_assert_XXX() This can result in tripping a BUILD_BUG_ON() in __BF_FIELD_CHECK() that checks that a given value is representable in one byte (interpreted as unsigned). FIELD_FIT() should return true or false at runtime for whether a value can fit for not. Don't break the build over a value that's too large for the mask. We'd prefer to keep the inlining and compiler optimizations though we know this case will always return false. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/kernel-hardening/CAK7LNASvb0UDJ0U5wkYYRzTAdnEs64HjXpEUL7d=V0CXiAXcNw@mail.gmail.com/ Reported-by: Masahiro Yamada <masahiroy@kernel.org> Debugged-by: Sami Tolvanen <samitolvanen@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> --- include/linux/bitfield.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 48ea093ff04c..4e035aca6f7e 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -77,7 +77,7 @@ */ #define FIELD_FIT(_mask, _val) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \ !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ }) -- 2.27.0.383.g050319c2ae-goog ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT 2020-07-07 21:16 [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT Nick Desaulniers @ 2020-07-07 21:49 ` Sami Tolvanen 2020-07-07 22:43 ` Alex Elder 1 sibling, 0 replies; 7+ messages in thread From: Sami Tolvanen @ 2020-07-07 21:49 UTC (permalink / raw) To: Nick Desaulniers Cc: David S . Miller, Jakub Kicinski, stable, Masahiro Yamada, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, Alex Elder, linux-kernel, netdev, bpf On Tue, Jul 07, 2020 at 02:16:41PM -0700, Nick Desaulniers wrote: > From: Jakub Kicinski <kuba@kernel.org> > > When ur_load_imm_any() is inlined into jeq_imm(), it's possible for the > compiler to deduce a case where _val can only have the value of -1 at > compile time. Specifically, > > /* struct bpf_insn: _s32 imm */ > u64 imm = insn->imm; /* sign extend */ > if (imm >> 32) { /* non-zero only if insn->imm is negative */ > /* inlined from ur_load_imm_any */ > u32 __imm = imm >> 32; /* therefore, always 0xffffffff */ > if (__builtin_constant_p(__imm) && __imm > 255) > compiletime_assert_XXX() > > This can result in tripping a BUILD_BUG_ON() in __BF_FIELD_CHECK() that > checks that a given value is representable in one byte (interpreted as > unsigned). > > FIELD_FIT() should return true or false at runtime for whether a value > can fit for not. Don't break the build over a value that's too large for > the mask. We'd prefer to keep the inlining and compiler optimizations > though we know this case will always return false. > > Cc: stable@vger.kernel.org > Link: https://lore.kernel.org/kernel-hardening/CAK7LNASvb0UDJ0U5wkYYRzTAdnEs64HjXpEUL7d=V0CXiAXcNw@mail.gmail.com/ > Reported-by: Masahiro Yamada <masahiroy@kernel.org> > Debugged-by: Sami Tolvanen <samitolvanen@google.com> > Signed-off-by: Jakub Kicinski <kuba@kernel.org> > Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> > --- > include/linux/bitfield.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h > index 48ea093ff04c..4e035aca6f7e 100644 > --- a/include/linux/bitfield.h > +++ b/include/linux/bitfield.h > @@ -77,7 +77,7 @@ > */ > #define FIELD_FIT(_mask, _val) \ > ({ \ > - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ > + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \ > !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ > }) > I confirmied that this fixes the issue. Thanks for sending the patch! Sami ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT 2020-07-07 21:16 [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT Nick Desaulniers 2020-07-07 21:49 ` Sami Tolvanen @ 2020-07-07 22:43 ` Alex Elder 2020-07-08 17:10 ` Nick Desaulniers 1 sibling, 1 reply; 7+ messages in thread From: Alex Elder @ 2020-07-07 22:43 UTC (permalink / raw) To: Nick Desaulniers, David S . Miller Cc: Jakub Kicinski, stable, Masahiro Yamada, Sami Tolvanen, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, linux-kernel, netdev, bpf On 7/7/20 4:16 PM, Nick Desaulniers wrote: > From: Jakub Kicinski <kuba@kernel.org> > > When ur_load_imm_any() is inlined into jeq_imm(), it's possible for the > compiler to deduce a case where _val can only have the value of -1 at > compile time. Specifically, > > /* struct bpf_insn: _s32 imm */ > u64 imm = insn->imm; /* sign extend */ > if (imm >> 32) { /* non-zero only if insn->imm is negative */ > /* inlined from ur_load_imm_any */ > u32 __imm = imm >> 32; /* therefore, always 0xffffffff */ > if (__builtin_constant_p(__imm) && __imm > 255) > compiletime_assert_XXX() > > This can result in tripping a BUILD_BUG_ON() in __BF_FIELD_CHECK() that > checks that a given value is representable in one byte (interpreted as > unsigned). Why does FIELD_FIT() pass an unsigned long long value as the second argument to __BF_FIELD_CHECK()? Could it pass (typeof(_mask))0 instead? It wouldn't fix this particular case, because UR_REG_IMM_MAX is also defined with that type. But (without working through this in more detail) it seems like there might be a solution that preserves the compile-time checking. A second comment about this is that it might be nice to break __BF_FIELD_CHECK() into the parts that verify the mask (which could be used by FIELD_FIT() here) and the parts that verify other things. That's all--just questions, I have no problem with the patch... -Alex > FIELD_FIT() should return true or false at runtime for whether a value > can fit for not. Don't break the build over a value that's too large for > the mask. We'd prefer to keep the inlining and compiler optimizations > though we know this case will always return false. > > Cc: stable@vger.kernel.org > Link: https://lore.kernel.org/kernel-hardening/CAK7LNASvb0UDJ0U5wkYYRzTAdnEs64HjXpEUL7d=V0CXiAXcNw@mail.gmail.com/ > Reported-by: Masahiro Yamada <masahiroy@kernel.org> > Debugged-by: Sami Tolvanen <samitolvanen@google.com> > Signed-off-by: Jakub Kicinski <kuba@kernel.org> > Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> > --- > include/linux/bitfield.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h > index 48ea093ff04c..4e035aca6f7e 100644 > --- a/include/linux/bitfield.h > +++ b/include/linux/bitfield.h > @@ -77,7 +77,7 @@ > */ > #define FIELD_FIT(_mask, _val) \ > ({ \ > - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ > + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \ > !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ > }) > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT 2020-07-07 22:43 ` Alex Elder @ 2020-07-08 17:10 ` Nick Desaulniers 2020-07-08 17:34 ` Alex Elder 0 siblings, 1 reply; 7+ messages in thread From: Nick Desaulniers @ 2020-07-08 17:10 UTC (permalink / raw) To: Alex Elder, Jakub Kicinski Cc: David S . Miller, # 3.4.x, Masahiro Yamada, Sami Tolvanen, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, LKML, Network Development, bpf On Tue, Jul 7, 2020 at 3:43 PM Alex Elder <elder@linaro.org> wrote: > > On 7/7/20 4:16 PM, Nick Desaulniers wrote: > > From: Jakub Kicinski <kuba@kernel.org> > > > > When ur_load_imm_any() is inlined into jeq_imm(), it's possible for the > > compiler to deduce a case where _val can only have the value of -1 at > > compile time. Specifically, > > > > /* struct bpf_insn: _s32 imm */ > > u64 imm = insn->imm; /* sign extend */ > > if (imm >> 32) { /* non-zero only if insn->imm is negative */ > > /* inlined from ur_load_imm_any */ > > u32 __imm = imm >> 32; /* therefore, always 0xffffffff */ > > if (__builtin_constant_p(__imm) && __imm > 255) > > compiletime_assert_XXX() > > > > This can result in tripping a BUILD_BUG_ON() in __BF_FIELD_CHECK() that > > checks that a given value is representable in one byte (interpreted as > > unsigned). Hi Alex, Thanks for taking a look. They're good and fair questions. > > Why does FIELD_FIT() pass an unsigned long long value as the second > argument to __BF_FIELD_CHECK()? Was Jakub's suggestion; I don't feel strongly against it either way, though... > Could it pass (typeof(_mask))0 instead? ...might be nice to avoid implicit promotions and conversions if _mask is not the same sizeof _val. > It wouldn't fix this particular case, because UR_REG_IMM_MAX is also > defined with that type. But (without working through this in more > detail) it seems like there might be a solution that preserves the > compile-time checking. I'd argue the point of the patch is to not check at compile time for FIELD_FIT, since we have a case in drivers/net/ethernet/netronome/nfp/bpf/jit.c (jeq_imm()) that will always pass -1 (unintentionally due to compiler optimization). > A second comment about this is that it might be nice to break > __BF_FIELD_CHECK() into the parts that verify the mask (which > could be used by FIELD_FIT() here) and the parts that verify > other things. Like so? Jakub, WDYT? Or do you prefer v1+Alex's suggestion about using `(typeof(_mask))0` in place of 0ULL? diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 311a5be25acb..938fc733fccb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -492,11 +492,12 @@ nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx, return 0; } -#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \ - ({ \ - __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \ - nfp_eth_set_bit_config(nsp, raw_idx, mask, __bf_shf(mask), \ - val, ctrl_bit); \ +#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, "NFP_ETH_SET_BIT_CONFIG: "); \ + __BF_FIELD_CHECK_VAL(mask, val, "NFP_ETH_SET_BIT_CONFIG: "); \ + nfp_eth_set_bit_config(nsp, raw_idx, mask, __bf_shf(mask), \ + val, ctrl_bit); \ }) /** diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 48ea093ff04c..79651867beb3 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -41,18 +41,26 @@ #define __bf_shf(x) (__builtin_ffsll(x) - 1) -#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ +#define __BF_FIELD_CHECK_MASK(_mask, _pfx) \ ({ \ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ _pfx "mask is not constant"); \ BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \ + __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ + (1ULL << __bf_shf(_mask))); \ + }) + +#define __BF_FIELD_CHECK_VAL(_mask, _val, _pfx) \ + ({ \ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ _pfx "value too large for the field"); \ - BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ + }) + +#define __BF_FIELD_CHECK_REG(_mask, _reg, _pfx) \ + ({ \ + BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ULL, \ _pfx "type of reg too small for mask"); \ - __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ - (1ULL << __bf_shf(_mask))); \ }) /** @@ -64,7 +72,7 @@ */ #define FIELD_MAX(_mask) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: "); \ + __BF_FIELD_CHECK_MASK(_mask, "FIELD_MAX: "); \ (typeof(_mask))((_mask) >> __bf_shf(_mask)); \ }) @@ -77,7 +85,7 @@ */ #define FIELD_FIT(_mask, _val) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ + __BF_FIELD_CHECK_MASK(_mask, "FIELD_FIT: "); \ !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ }) @@ -91,7 +99,8 @@ */ #define FIELD_PREP(_mask, _val) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ + __BF_FIELD_CHECK_MASK(_mask, "FIELD_PREP: "); \ + __BF_FIELD_CHECK_VAL(_mask, _val, "FIELD_PREP: "); \ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ }) @@ -105,7 +114,8 @@ */ #define FIELD_GET(_mask, _reg) \ ({ \ - __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ + __BF_FIELD_CHECK_MASK(_mask, "FIELD_GET: "); \ + __BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ }) > > That's all--just questions, I have no problem with the patch... > > -Alex > > > > > > FIELD_FIT() should return true or false at runtime for whether a value > > can fit for not. Don't break the build over a value that's too large for > > the mask. We'd prefer to keep the inlining and compiler optimizations > > though we know this case will always return false. > > > > Cc: stable@vger.kernel.org > > Link: https://lore.kernel.org/kernel-hardening/CAK7LNASvb0UDJ0U5wkYYRzTAdnEs64HjXpEUL7d=V0CXiAXcNw@mail.gmail.com/ > > Reported-by: Masahiro Yamada <masahiroy@kernel.org> > > Debugged-by: Sami Tolvanen <samitolvanen@google.com> > > Signed-off-by: Jakub Kicinski <kuba@kernel.org> > > Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> > > --- > > include/linux/bitfield.h | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h > > index 48ea093ff04c..4e035aca6f7e 100644 > > --- a/include/linux/bitfield.h > > +++ b/include/linux/bitfield.h > > @@ -77,7 +77,7 @@ > > */ > > #define FIELD_FIT(_mask, _val) \ > > ({ \ > > - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ > > + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \ > > !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ > > }) > > > > > -- Thanks, ~Nick Desaulniers ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT 2020-07-08 17:10 ` Nick Desaulniers @ 2020-07-08 17:34 ` Alex Elder 2020-07-08 17:56 ` Nick Desaulniers 0 siblings, 1 reply; 7+ messages in thread From: Alex Elder @ 2020-07-08 17:34 UTC (permalink / raw) To: Nick Desaulniers, Jakub Kicinski Cc: David S . Miller, # 3.4.x, Masahiro Yamada, Sami Tolvanen, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, LKML, Network Development, bpf On 7/8/20 12:10 PM, Nick Desaulniers wrote: > On Tue, Jul 7, 2020 at 3:43 PM Alex Elder <elder@linaro.org> wrote: >> >> On 7/7/20 4:16 PM, Nick Desaulniers wrote: >>> From: Jakub Kicinski <kuba@kernel.org> >>> >>> When ur_load_imm_any() is inlined into jeq_imm(), it's possible for the >>> compiler to deduce a case where _val can only have the value of -1 at >>> compile time. Specifically, >>> >>> /* struct bpf_insn: _s32 imm */ >>> u64 imm = insn->imm; /* sign extend */ >>> if (imm >> 32) { /* non-zero only if insn->imm is negative */ >>> /* inlined from ur_load_imm_any */ >>> u32 __imm = imm >> 32; /* therefore, always 0xffffffff */ >>> if (__builtin_constant_p(__imm) && __imm > 255) >>> compiletime_assert_XXX() >>> >>> This can result in tripping a BUILD_BUG_ON() in __BF_FIELD_CHECK() that >>> checks that a given value is representable in one byte (interpreted as >>> unsigned). > > Hi Alex, > Thanks for taking a look. They're good and fair questions. > >> >> Why does FIELD_FIT() pass an unsigned long long value as the second >> argument to __BF_FIELD_CHECK()? > > Was Jakub's suggestion; I don't feel strongly against it either way, though... > >> Could it pass (typeof(_mask))0 instead? > > ...might be nice to avoid implicit promotions and conversions if _mask > is not the same sizeof _val. > >> It wouldn't fix this particular case, because UR_REG_IMM_MAX is also >> defined with that type. But (without working through this in more >> detail) it seems like there might be a solution that preserves the >> compile-time checking. > > I'd argue the point of the patch is to not check at compile time for > FIELD_FIT, since we have a case in > drivers/net/ethernet/netronome/nfp/bpf/jit.c (jeq_imm()) that will > always pass -1 (unintentionally due to compiler optimization). I understand why something needs to be done to handle that case. There's fancy macro gymnastics in "bitfield.h" to add convenient build-time checks for usage problems; I just thought there might be something we could do to preserve the checking--even in this case. But figuring that out takes more time than I was willing to spend on it yesterday... >> A second comment about this is that it might be nice to break >> __BF_FIELD_CHECK() into the parts that verify the mask (which >> could be used by FIELD_FIT() here) and the parts that verify >> other things. > > Like so? Jakub, WDYT? Or do you prefer v1+Alex's suggestion about > using `(typeof(_mask))0` in place of 0ULL? Yes, very much like that! But you could do that as a follow-on instead, so as not to delay or confuse things. Thanks. -Alex > diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c > b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c > index 311a5be25acb..938fc733fccb 100644 > --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c > +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c > @@ -492,11 +492,12 @@ nfp_eth_set_bit_config(struct nfp_nsp *nsp, > unsigned int raw_idx, > return 0; > } > > -#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \ > - ({ \ > - __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \ > - nfp_eth_set_bit_config(nsp, raw_idx, mask, __bf_shf(mask), \ > - val, ctrl_bit); \ > +#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) > \ > + ({ > \ > + __BF_FIELD_CHECK_MASK(mask, "NFP_ETH_SET_BIT_CONFIG: > "); \ > + __BF_FIELD_CHECK_VAL(mask, val, > "NFP_ETH_SET_BIT_CONFIG: "); \ > + nfp_eth_set_bit_config(nsp, raw_idx, mask, > __bf_shf(mask), \ > + val, ctrl_bit); > \ > }) > > /** > diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h > index 48ea093ff04c..79651867beb3 100644 > --- a/include/linux/bitfield.h > +++ b/include/linux/bitfield.h > @@ -41,18 +41,26 @@ > > #define __bf_shf(x) (__builtin_ffsll(x) - 1) > > -#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ > +#define __BF_FIELD_CHECK_MASK(_mask, _pfx) \ > ({ \ > BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ > _pfx "mask is not constant"); \ > BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \ > + __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ > + (1ULL << __bf_shf(_mask))); \ > + }) > + > +#define __BF_FIELD_CHECK_VAL(_mask, _val, _pfx) > \ > + ({ \ > BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ > ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ > _pfx "value too large for the field"); \ > - BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ > + }) > + > +#define __BF_FIELD_CHECK_REG(_mask, _reg, _pfx) > \ > + ({ \ > + BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ULL, \ > _pfx "type of reg too small for mask"); \ > - __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ > - (1ULL << __bf_shf(_mask))); \ > }) > > /** > @@ -64,7 +72,7 @@ > */ > #define FIELD_MAX(_mask) \ > ({ \ > - __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: "); \ > + __BF_FIELD_CHECK_MASK(_mask, "FIELD_MAX: "); \ > (typeof(_mask))((_mask) >> __bf_shf(_mask)); \ > }) > > @@ -77,7 +85,7 @@ > */ > #define FIELD_FIT(_mask, _val) \ > ({ \ > - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ > + __BF_FIELD_CHECK_MASK(_mask, "FIELD_FIT: "); \ > !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ > }) > @@ -91,7 +99,8 @@ > */ > #define FIELD_PREP(_mask, _val) > \ > ({ \ > - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ > + __BF_FIELD_CHECK_MASK(_mask, "FIELD_PREP: "); \ > + __BF_FIELD_CHECK_VAL(_mask, _val, "FIELD_PREP: "); \ > ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ > }) > > @@ -105,7 +114,8 @@ > */ > #define FIELD_GET(_mask, _reg) \ > ({ \ > - __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ > + __BF_FIELD_CHECK_MASK(_mask, "FIELD_GET: "); \ > + __BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \ > (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ > }) > > > >> >> That's all--just questions, I have no problem with the patch... >> >> -Alex >> >> >> >> >>> FIELD_FIT() should return true or false at runtime for whether a value >>> can fit for not. Don't break the build over a value that's too large for >>> the mask. We'd prefer to keep the inlining and compiler optimizations >>> though we know this case will always return false. >>> >>> Cc: stable@vger.kernel.org >>> Link: https://lore.kernel.org/kernel-hardening/CAK7LNASvb0UDJ0U5wkYYRzTAdnEs64HjXpEUL7d=V0CXiAXcNw@mail.gmail.com/ >>> Reported-by: Masahiro Yamada <masahiroy@kernel.org> >>> Debugged-by: Sami Tolvanen <samitolvanen@google.com> >>> Signed-off-by: Jakub Kicinski <kuba@kernel.org> >>> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> >>> --- >>> include/linux/bitfield.h | 2 +- >>> 1 file changed, 1 insertion(+), 1 deletion(-) >>> >>> diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h >>> index 48ea093ff04c..4e035aca6f7e 100644 >>> --- a/include/linux/bitfield.h >>> +++ b/include/linux/bitfield.h >>> @@ -77,7 +77,7 @@ >>> */ >>> #define FIELD_FIT(_mask, _val) \ >>> ({ \ >>> - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \ >>> + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \ >>> !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ >>> }) >>> >>> >> > > > -- > Thanks, > ~Nick Desaulniers > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT 2020-07-08 17:34 ` Alex Elder @ 2020-07-08 17:56 ` Nick Desaulniers 2020-07-08 20:34 ` Jakub Kicinski 0 siblings, 1 reply; 7+ messages in thread From: Nick Desaulniers @ 2020-07-08 17:56 UTC (permalink / raw) To: Alex Elder, Jakub Kicinski, David S . Miller Cc: # 3.4.x, Masahiro Yamada, Sami Tolvanen, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, LKML, Network Development, bpf On Wed, Jul 8, 2020 at 10:34 AM Alex Elder <elder@linaro.org> wrote: > > I understand why something needs to be done to handle that case. > There's fancy macro gymnastics in "bitfield.h" to add convenient > build-time checks for usage problems; I just thought there might > be something we could do to preserve the checking--even in this > case. But figuring that out takes more time than I was willing > to spend on it yesterday... I also find the use of 0U in FIELD_GET sticks out from the use of 0ULL or (0ull) in these macros (hard to notice, but I changed it in my diff to 0ULL). Are there implicit promotion+conversion bugs here? I don't know, but I'd rather not think about it by just using types of the same width and signedness. > >> A second comment about this is that it might be nice to break > >> __BF_FIELD_CHECK() into the parts that verify the mask (which > >> could be used by FIELD_FIT() here) and the parts that verify > >> other things. > > > > Like so? Jakub, WDYT? Or do you prefer v1+Alex's suggestion about > > using `(typeof(_mask))0` in place of 0ULL? > > Yes, very much like that! But you could do that as a follow-on > instead, so as not to delay or confuse things. No rush; let's get it right. So I can think of splitting this into maybe 3 patches, based on feedback: 1. there's a bug in compile time validating _val in FIELD_FIT, since we want to be able to call it at runtime with "bad" values. 2. the FIELD_* macros use constants (0ull, 0ULL, 0U) that don't match typeof(_mask). 3. It might be nice to break up __BF_FIELD_CHECK. I don't think anyone's raised an objection to 1. Assuming Jakub is ok with 3, fixing 3 will actually also address 2. So then we don't need 3 patches; only 2. But if we don't do 3 first, then I have to resend a v2 of 1 anyways to address 2 (which was Alex's original feedback). My above diff was all three in one go, but I don't think it would be unreasonable to break it up into 3 then 1. If we prefer not to do 3, then I can send a v2 of 1 that addresses the inconsistent use of types, as one or two patches. Jakub, what is your preference? (Also, noting that I'm sending to David, assuming he'll pick up the patches once we have everyone's buy in? Or is there someone else more appropriate to accept changes to this header? I guess Jakub and David are the listed maintainers for drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c) -- Thanks, ~Nick Desaulniers ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT 2020-07-08 17:56 ` Nick Desaulniers @ 2020-07-08 20:34 ` Jakub Kicinski 0 siblings, 0 replies; 7+ messages in thread From: Jakub Kicinski @ 2020-07-08 20:34 UTC (permalink / raw) To: Nick Desaulniers, David S . Miller Cc: Alex Elder, # 3.4.x, Masahiro Yamada, Sami Tolvanen, Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song, Andrii Nakryiko, John Fastabend, KP Singh, LKML, Network Development, bpf On Wed, 8 Jul 2020 10:56:43 -0700 Nick Desaulniers wrote: > On Wed, Jul 8, 2020 at 10:34 AM Alex Elder <elder@linaro.org> wrote: > > > > I understand why something needs to be done to handle that case. > > There's fancy macro gymnastics in "bitfield.h" to add convenient > > build-time checks for usage problems; I just thought there might > > be something we could do to preserve the checking--even in this > > case. But figuring that out takes more time than I was willing > > to spend on it yesterday... > > I also find the use of 0U in FIELD_GET sticks out from the use of 0ULL > or (0ull) in these macros (hard to notice, but I changed it in my diff > to 0ULL). Are there implicit promotion+conversion bugs here? I don't > know, but I'd rather not think about it by just using types of the > same width and signedness. TBH I just copied the type from other arguments. It doesn't matter in practice now in this case. I have no preference. > > >> A second comment about this is that it might be nice to break > > >> __BF_FIELD_CHECK() into the parts that verify the mask (which > > >> could be used by FIELD_FIT() here) and the parts that verify > > >> other things. > > > > > > Like so? Jakub, WDYT? Or do you prefer v1+Alex's suggestion about > > > using `(typeof(_mask))0` in place of 0ULL? > > > > Yes, very much like that! But you could do that as a follow-on > > instead, so as not to delay or confuse things. > > No rush; let's get it right. > > So I can think of splitting this into maybe 3 patches, based on feedback: > 1. there's a bug in compile time validating _val in FIELD_FIT, since > we want to be able to call it at runtime with "bad" values. > 2. the FIELD_* macros use constants (0ull, 0ULL, 0U) that don't match > typeof(_mask). > 3. It might be nice to break up __BF_FIELD_CHECK. > > I don't think anyone's raised an objection to 1. > > Assuming Jakub is ok with 3, fixing 3 will actually also address 2. > So then we don't need 3 patches; only 2. But if we don't do 3 first, > then I have to resend a v2 of 1 anyways to address 2 (which was Alex's > original feedback). > > My above diff was all three in one go, but I don't think it would be > unreasonable to break it up into 3 then 1. > > If we prefer not to do 3, then I can send a v2 of 1 that addresses the > inconsistent use of types, as one or two patches. > > Jakub, what is your preference? I don't see much point in breaking up the checking macro. But even less in arguing either way :) > (Also, noting that I'm sending to David, assuming he'll pick up the > patches once we have everyone's buy in? Or is there someone else more > appropriate to accept changes to this header? I guess Jakub and David > are the listed maintainers for > drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c) Seems reasonable, put [PATCH net] in the subject to make that explicit. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2020-07-08 20:34 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-07-07 21:16 [PATCH] bitfield.h: don't compile-time validate _val in FIELD_FIT Nick Desaulniers 2020-07-07 21:49 ` Sami Tolvanen 2020-07-07 22:43 ` Alex Elder 2020-07-08 17:10 ` Nick Desaulniers 2020-07-08 17:34 ` Alex Elder 2020-07-08 17:56 ` Nick Desaulniers 2020-07-08 20:34 ` Jakub Kicinski
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).