The spufs_arch_write_note() function puts notes in the header and uses them to fin where the next note starts. The spufs_coredump_read[] array provides the sizes of the notes: dump_skip_to(cprm, roundup(cprm->pos - ret + sz, 4)); In this call @ret is the amount of data the dump callback wrote. @sz is the declared size. So the position moves backwards if the callback wrote more data than the declared size. For three note sizes that is the case: (1) signal1 sets sizeof(u32) and dumps u64 via sizeof(ctx->csa.spu_chnldata_RW[3]) (2) signal2 sets sizeof(u32) and dumps u64 via sizeof(ctx->csa.spu_chnldata_RW[4]) (3) ibox_info sets sizeof(u32) and dumps a u64 via puint_mb_R The note is 4 byte aligned. The dump_emit() call wrote the dump_align(4) just before the note. So if @ret is 8 and @sz is 4 the position ends up 4 bytes before the current position which means cprm->to_skip is now negative. For __dump_skip() with size_t that means the pipe or socket gets 2^52 PAGE_SIZE zeroes. This also means a file seeks backwards and overwrites the four bytes that it just wrote. Before commit 5456ffdee666 ("powerpc/spufs: simplify spufs core dumping") this was benign because this truncated (on purpose, I presume): u32 data; data = ctx->csa.spu_chnldata_RW[3]; ... copy_to_user(buf, &data, 4) and after said commit things became fscked. So let's truncate this again. Not truncation means the wrong bits will be picked on big endian. Afaict, spufs is effectively dead so the fix probably doesn't matter in the grand scheme of things. Fixes: 5456ffdee666 ("powerpc/spufs: simplify spufs core dumping") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) --- arch/powerpc/platforms/cell/spufs/file.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index de7494748fec..6f86d87e3749 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -956,10 +956,12 @@ spufs_signal1_release(struct inode *inode, struct file *file) static ssize_t spufs_signal1_dump(struct spu_context *ctx, struct coredump_params *cprm) { + u32 data; + if (!ctx->csa.spu_chnlcnt_RW[3]) return 0; - return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[3], - sizeof(ctx->csa.spu_chnldata_RW[3])); + data = ctx->csa.spu_chnldata_RW[3]; + return spufs_dump_emit(cprm, &data, sizeof(data)); } static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, @@ -1089,10 +1091,12 @@ spufs_signal2_release(struct inode *inode, struct file *file) static ssize_t spufs_signal2_dump(struct spu_context *ctx, struct coredump_params *cprm) { + u32 data; + if (!ctx->csa.spu_chnlcnt_RW[4]) return 0; - return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[4], - sizeof(ctx->csa.spu_chnldata_RW[4])); + data = ctx->csa.spu_chnldata_RW[4]; + return spufs_dump_emit(cprm, &data, sizeof(data)); } static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, @@ -1965,10 +1969,12 @@ static const struct file_operations spufs_mbox_info_fops = { static ssize_t spufs_ibox_info_dump(struct spu_context *ctx, struct coredump_params *cprm) { + u32 data; + if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) return 0; - return spufs_dump_emit(cprm, &ctx->csa.priv2.puint_mb_R, - sizeof(ctx->csa.priv2.puint_mb_R)); + data = ctx->csa.priv2.puint_mb_R; + return spufs_dump_emit(cprm, &data, sizeof(data)); } static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, -- 2.53.0