Message ID | 20210818060533.3569517-1-keescook@chromium.org |
---|---|
Headers | show |
Series | Introduce strict memcpy() bounds checking | expand |
On Tue, 17 Aug 2021 23:05:20 -0700 Kees Cook <keescook@chromium.org> wrote: > In preparation for FORTIFY_SOURCE performing compile-time and run-time > field bounds checking for memset(), avoid intentionally writing across > neighboring fields. > > Use memset_startat() to avoid confusing memset() about writing beyond > the target struct member. > > Cc: Steven Rostedt <rostedt@goodmis.org> > Cc: Ingo Molnar <mingo@redhat.com> > Signed-off-by: Kees Cook <keescook@chromium.org> > --- > kernel/trace/trace.c | 4 +--- > 1 file changed, 1 insertion(+), 3 deletions(-) > > diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c > index 13587e771567..9ff8c31975cd 100644 > --- a/kernel/trace/trace.c > +++ b/kernel/trace/trace.c > @@ -6691,9 +6691,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, > cnt = PAGE_SIZE - 1; > > /* reset all but tr, trace, and overruns */ > - memset(&iter->seq, 0, > - sizeof(struct trace_iterator) - > - offsetof(struct trace_iterator, seq)); > + memset_startat(iter, 0, seq); I can't find memset_startat() in mainline nor linux-next. I don't see it in this thread either, but since this has 63 patches, I could have easily missed it. This change really should belong to a patch set that just introduces memset_startat() (and perhaps memset_after()) and then updates all the places that should use it. That way I can give it a proper review. In other words, you should break this patch set up into smaller, more digestible portions for the reviewers. Thanks, -- Steve > cpumask_clear(iter->started); > trace_seq_init(&iter->seq); > iter->pos = -1;
On Wed, Aug 18, 2021 at 09:33:49AM -0400, Steven Rostedt wrote: > On Tue, 17 Aug 2021 23:05:20 -0700 > Kees Cook <keescook@chromium.org> wrote: > > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > field bounds checking for memset(), avoid intentionally writing across > > neighboring fields. > > > > Use memset_startat() to avoid confusing memset() about writing beyond > > the target struct member. > > > > Cc: Steven Rostedt <rostedt@goodmis.org> > > Cc: Ingo Molnar <mingo@redhat.com> > > Signed-off-by: Kees Cook <keescook@chromium.org> > > --- > > kernel/trace/trace.c | 4 +--- > > 1 file changed, 1 insertion(+), 3 deletions(-) > > > > diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c > > index 13587e771567..9ff8c31975cd 100644 > > --- a/kernel/trace/trace.c > > +++ b/kernel/trace/trace.c > > @@ -6691,9 +6691,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, > > cnt = PAGE_SIZE - 1; > > > > /* reset all but tr, trace, and overruns */ > > - memset(&iter->seq, 0, > > - sizeof(struct trace_iterator) - > > - offsetof(struct trace_iterator, seq)); > > + memset_startat(iter, 0, seq); > > I can't find memset_startat() in mainline nor linux-next. I don't see it > in this thread either, but since this has 63 patches, I could have > easily missed it. Sorry, it isn't called out in the Subject, but it's part of this patch: https://lore.kernel.org/lkml/20210818060533.3569517-38-keescook@chromium.org/ > This change really should belong to a patch set that just introduces > memset_startat() (and perhaps memset_after()) and then updates all the > places that should use it. That way I can give it a proper review. In > other words, you should break this patch set up into smaller, more > digestible portions for the reviewers. I will split memset_after() and memset_startat() introduction patches. I already split up each use into individual cases, so that those changes could be checked one step at a time for differences in pahole struct layout and object code. Thanks for taking a look! -Kees
On Tue, Aug 17, 2021 at 11:06 PM Kees Cook <keescook@chromium.org> wrote: > > Use the newly introduced struct_group_typed() macro to clean up the > declaration of struct cxl_regs. > > Cc: Alison Schofield <alison.schofield@intel.com> > Cc: Vishal Verma <vishal.l.verma@intel.com> > Cc: Ira Weiny <ira.weiny@intel.com> > Cc: Ben Widawsky <ben.widawsky@intel.com> > Cc: linux-cxl@vger.kernel.org > Suggested-by: Dan Williams <dan.j.williams@intel.com> Looks good and tests ok here: Reviewed-by: Dan Williams <dan.j.williams@intel.com>
On Wed, Aug 18, 2021 at 10:53:58PM +0000, Sean Christopherson wrote: > On Wed, Aug 18, 2021, Kees Cook wrote: > > On Wed, Aug 18, 2021 at 03:11:28PM +0000, Sean Christopherson wrote: > > > From dbdca1f4cd01fee418c252e54c360d518b2b1ad6 Mon Sep 17 00:00:00 2001 > > > From: Sean Christopherson <seanjc@google.com> > > > Date: Wed, 18 Aug 2021 08:03:08 -0700 > > > Subject: [PATCH] KVM: x86: Replace memset() "optimization" with normal > > > per-field writes > > > > > > Explicitly zero select fields in the emulator's decode cache instead of > > > zeroing the fields via a gross memset() that spans six fields. gcc and > > > clang are both clever enough to batch the first five fields into a single > > > quadword MOV, i.e. memset() and individually zeroing generate identical > > > code. > > > > > > Removing the wart also prepares KVM for FORTIFY_SOURCE performing > > > compile-time and run-time field bounds checking for memset(). > > > > > > No functional change intended. > > > > > > Reported-by: Kees Cook <keescook@chromium.org> > > > Signed-off-by: Sean Christopherson <seanjc@google.com> > > > > Reviewed-by: Kees Cook <keescook@chromium.org> > > > > Do you want me to take this patch into my tree, or do you want to carry > > it for KVM directly? > > That's a Paolo question :-) > > What's the expected timeframe for landing stricter bounds checking? If it's > 5.16 or later, the easiest thing would be to squeak this into 5.15. I'm hoping to land all the "compile time" stuff for 5.15, but realistically, some portions may not get there. I'll just carry this patch for now and if we need to swap trees we can do that. :) Thanks! -Kees
On Tue, Aug 17, 2021 at 11:05:26PM -0700, Kees Cook wrote: > In preparation for FORTIFY_SOURCE performing compile-time and run-time > field bounds checking for memset(), avoid intentionally writing across > neighboring fields. > > Add struct_group() to mark region of struct mlx5_ib_mr that should be > initialized to zero. > > Cc: Leon Romanovsky <leon@kernel.org> > Cc: Doug Ledford <dledford@redhat.com> > Cc: Jason Gunthorpe <jgg@ziepe.ca> > Cc: linux-rdma@vger.kernel.org > Signed-off-by: Kees Cook <keescook@chromium.org> > --- > drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h > index bf20a388eabe..f63bf204a7a1 100644 > --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h > +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h > @@ -644,6 +644,7 @@ struct mlx5_ib_mr { > struct ib_umem *umem; > > /* This is zero'd when the MR is allocated */ > + struct_group(cleared, > union { > /* Used only while the MR is in the cache */ > struct { > @@ -691,12 +692,13 @@ struct mlx5_ib_mr { > bool is_odp_implicit; > }; > }; > + ); > }; > > /* Zero the fields in the mr that are variant depending on usage */ > static inline void mlx5_clear_mr(struct mlx5_ib_mr *mr) > { > - memset(mr->out, 0, sizeof(*mr) - offsetof(struct mlx5_ib_mr, out)); > + memset(&mr->cleared, 0, sizeof(mr->cleared)); > } Why not use the memset_after(mr->umem) here? Jason
On Thu, Aug 19, 2021 at 09:27:16AM -0300, Jason Gunthorpe wrote: > On Tue, Aug 17, 2021 at 11:05:26PM -0700, Kees Cook wrote: > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > field bounds checking for memset(), avoid intentionally writing across > > neighboring fields. > > > > Add struct_group() to mark region of struct mlx5_ib_mr that should be > > initialized to zero. > > > > Cc: Leon Romanovsky <leon@kernel.org> > > Cc: Doug Ledford <dledford@redhat.com> > > Cc: Jason Gunthorpe <jgg@ziepe.ca> > > Cc: linux-rdma@vger.kernel.org > > Signed-off-by: Kees Cook <keescook@chromium.org> > > --- > > drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++- > > 1 file changed, 3 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h > > index bf20a388eabe..f63bf204a7a1 100644 > > --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h > > +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h > > @@ -644,6 +644,7 @@ struct mlx5_ib_mr { > > struct ib_umem *umem; > > > > /* This is zero'd when the MR is allocated */ > > + struct_group(cleared, > > union { > > /* Used only while the MR is in the cache */ > > struct { > > @@ -691,12 +692,13 @@ struct mlx5_ib_mr { > > bool is_odp_implicit; > > }; > > }; > > + ); > > }; > > > > /* Zero the fields in the mr that are variant depending on usage */ > > static inline void mlx5_clear_mr(struct mlx5_ib_mr *mr) > > { > > - memset(mr->out, 0, sizeof(*mr) - offsetof(struct mlx5_ib_mr, out)); > > + memset(&mr->cleared, 0, sizeof(mr->cleared)); > > } > > Why not use the memset_after(mr->umem) here? I can certainly do that instead. In this series I've tended to opt for groupings so the position of future struct member additions are explicitly chosen. (i.e. reducing the chance that a zeroing of the new member be a surprise.) -Kees -- Kees Cook
On Thu, Aug 19, 2021 at 09:19:08AM -0700, Kees Cook wrote: > On Thu, Aug 19, 2021 at 09:27:16AM -0300, Jason Gunthorpe wrote: > > On Tue, Aug 17, 2021 at 11:05:26PM -0700, Kees Cook wrote: > > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > > field bounds checking for memset(), avoid intentionally writing across > > > neighboring fields. > > > > > > Add struct_group() to mark region of struct mlx5_ib_mr that should be > > > initialized to zero. > > > > > > Cc: Leon Romanovsky <leon@kernel.org> > > > Cc: Doug Ledford <dledford@redhat.com> > > > Cc: Jason Gunthorpe <jgg@ziepe.ca> > > > Cc: linux-rdma@vger.kernel.org > > > Signed-off-by: Kees Cook <keescook@chromium.org> > > > drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++- > > > 1 file changed, 3 insertions(+), 1 deletion(-) > > > > > > diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h > > > index bf20a388eabe..f63bf204a7a1 100644 > > > +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h > > > @@ -644,6 +644,7 @@ struct mlx5_ib_mr { > > > struct ib_umem *umem; > > > > > > /* This is zero'd when the MR is allocated */ > > > + struct_group(cleared, > > > union { > > > /* Used only while the MR is in the cache */ > > > struct { > > > @@ -691,12 +692,13 @@ struct mlx5_ib_mr { > > > bool is_odp_implicit; > > > }; > > > }; > > > + ); > > > }; > > > > > > /* Zero the fields in the mr that are variant depending on usage */ > > > static inline void mlx5_clear_mr(struct mlx5_ib_mr *mr) > > > { > > > - memset(mr->out, 0, sizeof(*mr) - offsetof(struct mlx5_ib_mr, out)); > > > + memset(&mr->cleared, 0, sizeof(mr->cleared)); > > > } > > > > Why not use the memset_after(mr->umem) here? > > I can certainly do that instead. In this series I've tended to opt > for groupings so the position of future struct member additions are > explicitly chosen. (i.e. reducing the chance that a zeroing of the new > member be a surprise.) I saw the earlier RDMA patches where using other memset techniques though? Were there flex arrays or something that made groups infeasible? Jason
On Thu, Aug 19, 2021 at 01:47:57PM -0300, Jason Gunthorpe wrote: > On Thu, Aug 19, 2021 at 09:19:08AM -0700, Kees Cook wrote: > > On Thu, Aug 19, 2021 at 09:27:16AM -0300, Jason Gunthorpe wrote: > > > On Tue, Aug 17, 2021 at 11:05:26PM -0700, Kees Cook wrote: > > > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > > > field bounds checking for memset(), avoid intentionally writing across > > > > neighboring fields. > > > > > > > > Add struct_group() to mark region of struct mlx5_ib_mr that should be > > > > initialized to zero. > > > > > > > > Cc: Leon Romanovsky <leon@kernel.org> > > > > Cc: Doug Ledford <dledford@redhat.com> > > > > Cc: Jason Gunthorpe <jgg@ziepe.ca> > > > > Cc: linux-rdma@vger.kernel.org > > > > Signed-off-by: Kees Cook <keescook@chromium.org> > > > > drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++- > > > > 1 file changed, 3 insertions(+), 1 deletion(-) > > > > > > > > diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h > > > > index bf20a388eabe..f63bf204a7a1 100644 > > > > +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h > > > > @@ -644,6 +644,7 @@ struct mlx5_ib_mr { > > > > struct ib_umem *umem; > > > > > > > > /* This is zero'd when the MR is allocated */ > > > > + struct_group(cleared, > > > > union { > > > > /* Used only while the MR is in the cache */ > > > > struct { > > > > @@ -691,12 +692,13 @@ struct mlx5_ib_mr { > > > > bool is_odp_implicit; > > > > }; > > > > }; > > > > + ); > > > > }; > > > > > > > > /* Zero the fields in the mr that are variant depending on usage */ > > > > static inline void mlx5_clear_mr(struct mlx5_ib_mr *mr) > > > > { > > > > - memset(mr->out, 0, sizeof(*mr) - offsetof(struct mlx5_ib_mr, out)); > > > > + memset(&mr->cleared, 0, sizeof(mr->cleared)); > > > > } > > > > > > Why not use the memset_after(mr->umem) here? > > > > I can certainly do that instead. In this series I've tended to opt > > for groupings so the position of future struct member additions are > > explicitly chosen. (i.e. reducing the chance that a zeroing of the new > > member be a surprise.) > > I saw the earlier RDMA patches where using other memset techniques > though? Were there flex arrays or something that made groups infeasible? Which do you mean? When doing the conversions I tended to opt for struct_group() since it provides more robust "intentionality". Strictly speaking, the new memset helpers are doing field-spanning writes, but the "clear to the end" pattern was so common it made sense to add the helpers, as they're a bit less disruptive. It's totally up to you! :)
Kees Cook <keescook@chromium.org> writes: > In preparation for FORTIFY_SOURCE performing compile-time and run-time > field bounds checking for memset(), avoid intentionally writing across > neighboring fields. > > Add a struct_group() for the spe registers so that memset() can correctly reason > about the size: > > In function 'fortify_memset_chk', > inlined from 'restore_user_regs.part.0' at arch/powerpc/kernel/signal_32.c:539:3: >>> include/linux/fortify-string.h:195:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] > 195 | __write_overflow_field(); > | ^~~~~~~~~~~~~~~~~~~~~~~~ > > Cc: Michael Ellerman <mpe@ellerman.id.au> > Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> > Cc: Paul Mackerras <paulus@samba.org> > Cc: Christophe Leroy <christophe.leroy@csgroup.eu> > Cc: Sudeep Holla <sudeep.holla@arm.com> > Cc: linuxppc-dev@lists.ozlabs.org > Reported-by: kernel test robot <lkp@intel.com> > Signed-off-by: Kees Cook <keescook@chromium.org> > --- > arch/powerpc/include/asm/processor.h | 6 ++++-- > arch/powerpc/kernel/signal_32.c | 6 +++--- > 2 files changed, 7 insertions(+), 5 deletions(-) > > diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h > index f348e564f7dd..05dc567cb9a8 100644 > --- a/arch/powerpc/include/asm/processor.h > +++ b/arch/powerpc/include/asm/processor.h > @@ -191,8 +191,10 @@ struct thread_struct { > int used_vsr; /* set if process has used VSX */ > #endif /* CONFIG_VSX */ > #ifdef CONFIG_SPE > - unsigned long evr[32]; /* upper 32-bits of SPE regs */ > - u64 acc; /* Accumulator */ > + struct_group(spe, > + unsigned long evr[32]; /* upper 32-bits of SPE regs */ > + u64 acc; /* Accumulator */ > + ); > unsigned long spefscr; /* SPE & eFP status */ > unsigned long spefscr_last; /* SPEFSCR value on last prctl > call or trap return */ > diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c > index 0608581967f0..77b86caf5c51 100644 > --- a/arch/powerpc/kernel/signal_32.c > +++ b/arch/powerpc/kernel/signal_32.c > @@ -532,11 +532,11 @@ static long restore_user_regs(struct pt_regs *regs, > regs_set_return_msr(regs, regs->msr & ~MSR_SPE); > if (msr & MSR_SPE) { > /* restore spe registers from the stack */ > - unsafe_copy_from_user(current->thread.evr, &sr->mc_vregs, > - ELF_NEVRREG * sizeof(u32), failed); > + unsafe_copy_from_user(¤t->thread.spe, &sr->mc_vregs, > + sizeof(current->thread.spe), failed); This makes me nervous, because the ABI is that we copy ELF_NEVRREG * sizeof(u32) bytes, not whatever sizeof(current->thread.spe) happens to be. ie. if we use sizeof an inadvertent change to the fields in thread_struct could change how many bytes we copy out to userspace, which would be an ABI break. And that's not that hard to do, because it's not at all obvious that the size and layout of fields in thread_struct affects the user ABI. At the same time we don't want to copy the right number of bytes but the wrong content, so from that point of view using sizeof is good :) The way we handle it in ptrace is to have BUILD_BUG_ON()s to verify that things match up, so maybe we should do that here too. ie. add: BUILD_BUG_ON(sizeof(current->thread.spe) == ELF_NEVRREG * sizeof(u32)); Not sure if you are happy doing that as part of this patch. I can always do it later if not. cheers
Le 20/08/2021 à 09:49, Michael Ellerman a écrit : > Kees Cook <keescook@chromium.org> writes: >> In preparation for FORTIFY_SOURCE performing compile-time and run-time >> field bounds checking for memset(), avoid intentionally writing across >> neighboring fields. >> >> Add a struct_group() for the spe registers so that memset() can correctly reason >> about the size: >> >> In function 'fortify_memset_chk', >> inlined from 'restore_user_regs.part.0' at arch/powerpc/kernel/signal_32.c:539:3: >>>> include/linux/fortify-string.h:195:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] >> 195 | __write_overflow_field(); >> | ^~~~~~~~~~~~~~~~~~~~~~~~ >> >> Cc: Michael Ellerman <mpe@ellerman.id.au> >> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> >> Cc: Paul Mackerras <paulus@samba.org> >> Cc: Christophe Leroy <christophe.leroy@csgroup.eu> >> Cc: Sudeep Holla <sudeep.holla@arm.com> >> Cc: linuxppc-dev@lists.ozlabs.org >> Reported-by: kernel test robot <lkp@intel.com> >> Signed-off-by: Kees Cook <keescook@chromium.org> >> --- >> arch/powerpc/include/asm/processor.h | 6 ++++-- >> arch/powerpc/kernel/signal_32.c | 6 +++--- >> 2 files changed, 7 insertions(+), 5 deletions(-) >> >> diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h >> index f348e564f7dd..05dc567cb9a8 100644 >> --- a/arch/powerpc/include/asm/processor.h >> +++ b/arch/powerpc/include/asm/processor.h >> @@ -191,8 +191,10 @@ struct thread_struct { >> int used_vsr; /* set if process has used VSX */ >> #endif /* CONFIG_VSX */ >> #ifdef CONFIG_SPE >> - unsigned long evr[32]; /* upper 32-bits of SPE regs */ >> - u64 acc; /* Accumulator */ >> + struct_group(spe, >> + unsigned long evr[32]; /* upper 32-bits of SPE regs */ >> + u64 acc; /* Accumulator */ >> + ); >> unsigned long spefscr; /* SPE & eFP status */ >> unsigned long spefscr_last; /* SPEFSCR value on last prctl >> call or trap return */ >> diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c >> index 0608581967f0..77b86caf5c51 100644 >> --- a/arch/powerpc/kernel/signal_32.c >> +++ b/arch/powerpc/kernel/signal_32.c >> @@ -532,11 +532,11 @@ static long restore_user_regs(struct pt_regs *regs, >> regs_set_return_msr(regs, regs->msr & ~MSR_SPE); >> if (msr & MSR_SPE) { >> /* restore spe registers from the stack */ >> - unsafe_copy_from_user(current->thread.evr, &sr->mc_vregs, >> - ELF_NEVRREG * sizeof(u32), failed); >> + unsafe_copy_from_user(¤t->thread.spe, &sr->mc_vregs, >> + sizeof(current->thread.spe), failed); > > This makes me nervous, because the ABI is that we copy ELF_NEVRREG * > sizeof(u32) bytes, not whatever sizeof(current->thread.spe) happens to > be. > > ie. if we use sizeof an inadvertent change to the fields in > thread_struct could change how many bytes we copy out to userspace, > which would be an ABI break. > > And that's not that hard to do, because it's not at all obvious that the > size and layout of fields in thread_struct affects the user ABI. > > At the same time we don't want to copy the right number of bytes but > the wrong content, so from that point of view using sizeof is good :) > > The way we handle it in ptrace is to have BUILD_BUG_ON()s to verify that > things match up, so maybe we should do that here too. > > ie. add: > > BUILD_BUG_ON(sizeof(current->thread.spe) == ELF_NEVRREG * sizeof(u32)); You mean != I guess ? > > > Not sure if you are happy doing that as part of this patch. I can always > do it later if not. > > cheers >
Christophe Leroy <christophe.leroy@csgroup.eu> writes: > Le 20/08/2021 à 09:49, Michael Ellerman a écrit : >> Kees Cook <keescook@chromium.org> writes: >>> In preparation for FORTIFY_SOURCE performing compile-time and run-time >>> field bounds checking for memset(), avoid intentionally writing across >>> neighboring fields. >>> >>> Add a struct_group() for the spe registers so that memset() can correctly reason >>> about the size: >>> >>> In function 'fortify_memset_chk', >>> inlined from 'restore_user_regs.part.0' at arch/powerpc/kernel/signal_32.c:539:3: >>>>> include/linux/fortify-string.h:195:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] >>> 195 | __write_overflow_field(); >>> | ^~~~~~~~~~~~~~~~~~~~~~~~ >>> >>> Cc: Michael Ellerman <mpe@ellerman.id.au> >>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> >>> Cc: Paul Mackerras <paulus@samba.org> >>> Cc: Christophe Leroy <christophe.leroy@csgroup.eu> >>> Cc: Sudeep Holla <sudeep.holla@arm.com> >>> Cc: linuxppc-dev@lists.ozlabs.org >>> Reported-by: kernel test robot <lkp@intel.com> >>> Signed-off-by: Kees Cook <keescook@chromium.org> >>> --- >>> arch/powerpc/include/asm/processor.h | 6 ++++-- >>> arch/powerpc/kernel/signal_32.c | 6 +++--- >>> 2 files changed, 7 insertions(+), 5 deletions(-) >>> >>> diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h >>> index f348e564f7dd..05dc567cb9a8 100644 >>> --- a/arch/powerpc/include/asm/processor.h >>> +++ b/arch/powerpc/include/asm/processor.h >>> @@ -191,8 +191,10 @@ struct thread_struct { >>> int used_vsr; /* set if process has used VSX */ >>> #endif /* CONFIG_VSX */ >>> #ifdef CONFIG_SPE >>> - unsigned long evr[32]; /* upper 32-bits of SPE regs */ >>> - u64 acc; /* Accumulator */ >>> + struct_group(spe, >>> + unsigned long evr[32]; /* upper 32-bits of SPE regs */ >>> + u64 acc; /* Accumulator */ >>> + ); >>> unsigned long spefscr; /* SPE & eFP status */ >>> unsigned long spefscr_last; /* SPEFSCR value on last prctl >>> call or trap return */ >>> diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c >>> index 0608581967f0..77b86caf5c51 100644 >>> --- a/arch/powerpc/kernel/signal_32.c >>> +++ b/arch/powerpc/kernel/signal_32.c >>> @@ -532,11 +532,11 @@ static long restore_user_regs(struct pt_regs *regs, >>> regs_set_return_msr(regs, regs->msr & ~MSR_SPE); >>> if (msr & MSR_SPE) { >>> /* restore spe registers from the stack */ >>> - unsafe_copy_from_user(current->thread.evr, &sr->mc_vregs, >>> - ELF_NEVRREG * sizeof(u32), failed); >>> + unsafe_copy_from_user(¤t->thread.spe, &sr->mc_vregs, >>> + sizeof(current->thread.spe), failed); >> >> This makes me nervous, because the ABI is that we copy ELF_NEVRREG * >> sizeof(u32) bytes, not whatever sizeof(current->thread.spe) happens to >> be. >> >> ie. if we use sizeof an inadvertent change to the fields in >> thread_struct could change how many bytes we copy out to userspace, >> which would be an ABI break. >> >> And that's not that hard to do, because it's not at all obvious that the >> size and layout of fields in thread_struct affects the user ABI. >> >> At the same time we don't want to copy the right number of bytes but >> the wrong content, so from that point of view using sizeof is good :) >> >> The way we handle it in ptrace is to have BUILD_BUG_ON()s to verify that >> things match up, so maybe we should do that here too. >> >> ie. add: >> >> BUILD_BUG_ON(sizeof(current->thread.spe) == ELF_NEVRREG * sizeof(u32)); > > You mean != I guess ? Gah. Yes I do :) cheers
On Thu, Aug 19, 2021 at 11:14:37AM -0700, Kees Cook wrote: > Which do you mean? When doing the conversions I tended to opt for > struct_group() since it provides more robust "intentionality". Strictly > speaking, the new memset helpers are doing field-spanning writes, but the > "clear to the end" pattern was so common it made sense to add the helpers, > as they're a bit less disruptive. It's totally up to you! :) Well, of the patches you cc'd to me only this one used the struct group.. Jason
On Tue, 17 Aug 2021, Kees Cook wrote: > In preparation for FORTIFY_SOURCE performing compile-time and run-time > field bounds checking for memcpy(), memmove(), and memset(), avoid > intentionally writing across neighboring fields. > > Use struct_group() in struct cp2112_string_report around members report, > length, type, and string, so they can be referenced together. This will > allow memcpy() and sizeof() to more easily reason about sizes, improve > readability, and avoid future warnings about writing beyond the end of > report. > > "pahole" shows no size nor member offset changes to struct > cp2112_string_report. "objdump -d" shows no meaningful object > code changes (i.e. only source line number induced differences.) > > Cc: Jiri Kosina <jikos@kernel.org> > Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com> > Cc: linux-input@vger.kernel.org > Signed-off-by: Kees Cook <keescook@chromium.org> Applied, thanks.
On Fri, Aug 20, 2021 at 03:01:43PM +0200, Jiri Kosina wrote: > On Tue, 17 Aug 2021, Kees Cook wrote: > > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > field bounds checking for memcpy(), memmove(), and memset(), avoid > > intentionally writing across neighboring fields. > > > > Use struct_group() in struct cp2112_string_report around members report, > > length, type, and string, so they can be referenced together. This will > > allow memcpy() and sizeof() to more easily reason about sizes, improve > > readability, and avoid future warnings about writing beyond the end of > > report. > > > > "pahole" shows no size nor member offset changes to struct > > cp2112_string_report. "objdump -d" shows no meaningful object > > code changes (i.e. only source line number induced differences.) > > > > Cc: Jiri Kosina <jikos@kernel.org> > > Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com> > > Cc: linux-input@vger.kernel.org > > Signed-off-by: Kees Cook <keescook@chromium.org> > > Applied, thanks. I'm not sure if my other HTML email got through, but please don't apply these to separate trees -- struct_group() is introduced as part of this series.
On Fri, Aug 20, 2021 at 05:49:35PM +1000, Michael Ellerman wrote: > Kees Cook <keescook@chromium.org> writes: > > In preparation for FORTIFY_SOURCE performing compile-time and run-time > > field bounds checking for memset(), avoid intentionally writing across > > neighboring fields. > > > > Add a struct_group() for the spe registers so that memset() can correctly reason > > about the size: > > > > In function 'fortify_memset_chk', > > inlined from 'restore_user_regs.part.0' at arch/powerpc/kernel/signal_32.c:539:3: > >>> include/linux/fortify-string.h:195:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] > > 195 | __write_overflow_field(); > > | ^~~~~~~~~~~~~~~~~~~~~~~~ > > > > Cc: Michael Ellerman <mpe@ellerman.id.au> > > Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> > > Cc: Paul Mackerras <paulus@samba.org> > > Cc: Christophe Leroy <christophe.leroy@csgroup.eu> > > Cc: Sudeep Holla <sudeep.holla@arm.com> > > Cc: linuxppc-dev@lists.ozlabs.org > > Reported-by: kernel test robot <lkp@intel.com> > > Signed-off-by: Kees Cook <keescook@chromium.org> > > --- > > arch/powerpc/include/asm/processor.h | 6 ++++-- > > arch/powerpc/kernel/signal_32.c | 6 +++--- > > 2 files changed, 7 insertions(+), 5 deletions(-) > > > > diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h > > index f348e564f7dd..05dc567cb9a8 100644 > > --- a/arch/powerpc/include/asm/processor.h > > +++ b/arch/powerpc/include/asm/processor.h > > @@ -191,8 +191,10 @@ struct thread_struct { > > int used_vsr; /* set if process has used VSX */ > > #endif /* CONFIG_VSX */ > > #ifdef CONFIG_SPE > > - unsigned long evr[32]; /* upper 32-bits of SPE regs */ > > - u64 acc; /* Accumulator */ > > + struct_group(spe, > > + unsigned long evr[32]; /* upper 32-bits of SPE regs */ > > + u64 acc; /* Accumulator */ > > + ); > > unsigned long spefscr; /* SPE & eFP status */ > > unsigned long spefscr_last; /* SPEFSCR value on last prctl > > call or trap return */ > > diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c > > index 0608581967f0..77b86caf5c51 100644 > > --- a/arch/powerpc/kernel/signal_32.c > > +++ b/arch/powerpc/kernel/signal_32.c > > @@ -532,11 +532,11 @@ static long restore_user_regs(struct pt_regs *regs, > > regs_set_return_msr(regs, regs->msr & ~MSR_SPE); > > if (msr & MSR_SPE) { > > /* restore spe registers from the stack */ > > - unsafe_copy_from_user(current->thread.evr, &sr->mc_vregs, > > - ELF_NEVRREG * sizeof(u32), failed); > > + unsafe_copy_from_user(¤t->thread.spe, &sr->mc_vregs, > > + sizeof(current->thread.spe), failed); > > This makes me nervous, because the ABI is that we copy ELF_NEVRREG * > sizeof(u32) bytes, not whatever sizeof(current->thread.spe) happens to > be. > > ie. if we use sizeof an inadvertent change to the fields in > thread_struct could change how many bytes we copy out to userspace, > which would be an ABI break. > > And that's not that hard to do, because it's not at all obvious that the > size and layout of fields in thread_struct affects the user ABI. > > At the same time we don't want to copy the right number of bytes but > the wrong content, so from that point of view using sizeof is good :) > > The way we handle it in ptrace is to have BUILD_BUG_ON()s to verify that > things match up, so maybe we should do that here too. > > ie. add: > > BUILD_BUG_ON(sizeof(current->thread.spe) == ELF_NEVRREG * sizeof(u32)); > > Not sure if you are happy doing that as part of this patch. I can always > do it later if not. Sounds good to me; I did that in a few other cases in the series where the relationships between things seemed tenuous. :) I'll add this (as !=) in v3. Thanks!
On Fri, Aug 20, 2021 at 09:34:00AM -0300, Jason Gunthorpe wrote: > On Thu, Aug 19, 2021 at 11:14:37AM -0700, Kees Cook wrote: > > > Which do you mean? When doing the conversions I tended to opt for > > struct_group() since it provides more robust "intentionality". Strictly > > speaking, the new memset helpers are doing field-spanning writes, but the > > "clear to the end" pattern was so common it made sense to add the helpers, > > as they're a bit less disruptive. It's totally up to you! :) > > Well, of the patches you cc'd to me only this one used the struct > group.. Understood. I've adjusted this for v3. Thanks!
Kees Cook <keescook@chromium.org> writes: > On Fri, Aug 20, 2021 at 05:49:35PM +1000, Michael Ellerman wrote: >> Kees Cook <keescook@chromium.org> writes: >> > In preparation for FORTIFY_SOURCE performing compile-time and run-time >> > field bounds checking for memset(), avoid intentionally writing across >> > neighboring fields. >> > >> > Add a struct_group() for the spe registers so that memset() can correctly reason >> > about the size: >> > >> > In function 'fortify_memset_chk', >> > inlined from 'restore_user_regs.part.0' at arch/powerpc/kernel/signal_32.c:539:3: >> >>> include/linux/fortify-string.h:195:4: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] >> > 195 | __write_overflow_field(); >> > | ^~~~~~~~~~~~~~~~~~~~~~~~ >> > >> > Cc: Michael Ellerman <mpe@ellerman.id.au> >> > Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> >> > Cc: Paul Mackerras <paulus@samba.org> >> > Cc: Christophe Leroy <christophe.leroy@csgroup.eu> >> > Cc: Sudeep Holla <sudeep.holla@arm.com> >> > Cc: linuxppc-dev@lists.ozlabs.org >> > Reported-by: kernel test robot <lkp@intel.com> >> > Signed-off-by: Kees Cook <keescook@chromium.org> >> > --- >> > arch/powerpc/include/asm/processor.h | 6 ++++-- >> > arch/powerpc/kernel/signal_32.c | 6 +++--- >> > 2 files changed, 7 insertions(+), 5 deletions(-) >> > >> > diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h >> > index f348e564f7dd..05dc567cb9a8 100644 >> > --- a/arch/powerpc/include/asm/processor.h >> > +++ b/arch/powerpc/include/asm/processor.h >> > @@ -191,8 +191,10 @@ struct thread_struct { >> > int used_vsr; /* set if process has used VSX */ >> > #endif /* CONFIG_VSX */ >> > #ifdef CONFIG_SPE >> > - unsigned long evr[32]; /* upper 32-bits of SPE regs */ >> > - u64 acc; /* Accumulator */ >> > + struct_group(spe, >> > + unsigned long evr[32]; /* upper 32-bits of SPE regs */ >> > + u64 acc; /* Accumulator */ >> > + ); >> > unsigned long spefscr; /* SPE & eFP status */ >> > unsigned long spefscr_last; /* SPEFSCR value on last prctl >> > call or trap return */ >> > diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c >> > index 0608581967f0..77b86caf5c51 100644 >> > --- a/arch/powerpc/kernel/signal_32.c >> > +++ b/arch/powerpc/kernel/signal_32.c >> > @@ -532,11 +532,11 @@ static long restore_user_regs(struct pt_regs *regs, >> > regs_set_return_msr(regs, regs->msr & ~MSR_SPE); >> > if (msr & MSR_SPE) { >> > /* restore spe registers from the stack */ >> > - unsafe_copy_from_user(current->thread.evr, &sr->mc_vregs, >> > - ELF_NEVRREG * sizeof(u32), failed); >> > + unsafe_copy_from_user(¤t->thread.spe, &sr->mc_vregs, >> > + sizeof(current->thread.spe), failed); >> >> This makes me nervous, because the ABI is that we copy ELF_NEVRREG * >> sizeof(u32) bytes, not whatever sizeof(current->thread.spe) happens to >> be. >> >> ie. if we use sizeof an inadvertent change to the fields in >> thread_struct could change how many bytes we copy out to userspace, >> which would be an ABI break. >> >> And that's not that hard to do, because it's not at all obvious that the >> size and layout of fields in thread_struct affects the user ABI. >> >> At the same time we don't want to copy the right number of bytes but >> the wrong content, so from that point of view using sizeof is good :) >> >> The way we handle it in ptrace is to have BUILD_BUG_ON()s to verify that >> things match up, so maybe we should do that here too. >> >> ie. add: >> >> BUILD_BUG_ON(sizeof(current->thread.spe) == ELF_NEVRREG * sizeof(u32)); >> >> Not sure if you are happy doing that as part of this patch. I can always >> do it later if not. > > Sounds good to me; I did that in a few other cases in the series where > the relationships between things seemed tenuous. :) I'll add this (as > !=) in v3. Thanks. cheers