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

powerpc/powernv: Fix fortify source warnings in opal-prd.c

As reported by Mahesh & Aneesh, opal_prd_msg_notifier() triggers a
FORTIFY_SOURCE warning:

memcpy: detected field-spanning write (size 32) of single field "&item->msg" at arch/powerpc/platforms/powernv/opal-prd.c:355 (size 4)
WARNING: CPU: 9 PID: 660 at arch/powerpc/platforms/powernv/opal-prd.c:355 opal_prd_msg_notifier+0x174/0x188 [opal_prd]
NIP opal_prd_msg_notifier+0x174/0x188 [opal_prd]
LR opal_prd_msg_notifier+0x170/0x188 [opal_prd]
Call Trace:
opal_prd_msg_notifier+0x170/0x188 [opal_prd] (unreliable)
notifier_call_chain+0xc0/0x1b0
atomic_notifier_call_chain+0x2c/0x40
opal_message_notify+0xf4/0x2c0

This happens because the copy is targeting item->msg, which is only 4
bytes in size, even though the enclosing item was allocated with extra
space following the msg.

To fix the warning define struct opal_prd_msg with a union of the header
and a flex array, and have the memcpy target the flex array.

Reported-by: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
Reported-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
Tested-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
Reviewed-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230821142820.497107-1-mpe@ellerman.id.au

+12 -5
+12 -5
arch/powerpc/platforms/powernv/opal-prd.c
··· 24 24 #include <linux/uaccess.h> 25 25 26 26 27 + struct opal_prd_msg { 28 + union { 29 + struct opal_prd_msg_header header; 30 + DECLARE_FLEX_ARRAY(u8, data); 31 + }; 32 + }; 33 + 27 34 /* 28 35 * The msg member must be at the end of the struct, as it's followed by the 29 36 * message data. 30 37 */ 31 38 struct opal_prd_msg_queue_item { 32 - struct list_head list; 33 - struct opal_prd_msg_header msg; 39 + struct list_head list; 40 + struct opal_prd_msg msg; 34 41 }; 35 42 36 43 static struct device_node *prd_node; ··· 163 156 int rc; 164 157 165 158 /* we need at least a header's worth of data */ 166 - if (count < sizeof(item->msg)) 159 + if (count < sizeof(item->msg.header)) 167 160 return -EINVAL; 168 161 169 162 if (*ppos) ··· 193 186 return -EINTR; 194 187 } 195 188 196 - size = be16_to_cpu(item->msg.size); 189 + size = be16_to_cpu(item->msg.header.size); 197 190 if (size > count) { 198 191 err = -EINVAL; 199 192 goto err_requeue; ··· 359 352 if (!item) 360 353 return -ENOMEM; 361 354 362 - memcpy(&item->msg, msg->params, msg_size); 355 + memcpy(&item->msg.data, msg->params, msg_size); 363 356 364 357 spin_lock_irqsave(&opal_prd_msg_queue_lock, flags); 365 358 list_add_tail(&item->list, &opal_prd_msg_queue);