Skip to content

Commit f9c41a6

Browse files
braunudavem330
authored andcommitted
af_iucv: fix recvmsg by replacing skb_pull() function
When receiving data messages, the "BUG_ON(skb->len < skb->data_len)" in the skb_pull() function triggers a kernel panic. Replace the skb_pull logic by a per skb offset as advised by Eric Dumazet. Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: Frank Blaschka <blaschka@linux.vnet.ibm.com> Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 88c5b5c commit f9c41a6

File tree

2 files changed

+24
-18
lines changed

2 files changed

+24
-18
lines changed

include/net/iucv/af_iucv.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ struct iucv_sock {
130130
enum iucv_tx_notify n);
131131
};
132132

133+
struct iucv_skb_cb {
134+
u32 class; /* target class of message */
135+
u32 tag; /* tag associated with message */
136+
u32 offset; /* offset for skb receival */
137+
};
138+
139+
#define IUCV_SKB_CB(__skb) ((struct iucv_skb_cb *)&((__skb)->cb[0]))
140+
133141
/* iucv socket options (SOL_IUCV) */
134142
#define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */
135143
#define SO_MSGLIMIT 0x1000 /* get/set IUCV MSGLIMIT */

net/iucv/af_iucv.c

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,6 @@ static const u8 iprm_shutdown[8] =
4949

5050
#define TRGCLS_SIZE (sizeof(((struct iucv_message *)0)->class))
5151

52-
/* macros to set/get socket control buffer at correct offset */
53-
#define CB_TAG(skb) ((skb)->cb) /* iucv message tag */
54-
#define CB_TAG_LEN (sizeof(((struct iucv_message *) 0)->tag))
55-
#define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */
56-
#define CB_TRGCLS_LEN (TRGCLS_SIZE)
57-
5852
#define __iucv_sock_wait(sk, condition, timeo, ret) \
5953
do { \
6054
DEFINE_WAIT(__wait); \
@@ -1141,7 +1135,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
11411135

11421136
/* increment and save iucv message tag for msg_completion cbk */
11431137
txmsg.tag = iucv->send_tag++;
1144-
memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
1138+
IUCV_SKB_CB(skb)->tag = txmsg.tag;
11451139

11461140
if (iucv->transport == AF_IUCV_TRANS_HIPER) {
11471141
atomic_inc(&iucv->msg_sent);
@@ -1224,7 +1218,7 @@ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len)
12241218
return -ENOMEM;
12251219

12261220
/* copy target class to control buffer of new skb */
1227-
memcpy(CB_TRGCLS(nskb), CB_TRGCLS(skb), CB_TRGCLS_LEN);
1221+
IUCV_SKB_CB(nskb)->class = IUCV_SKB_CB(skb)->class;
12281222

12291223
/* copy data fragment */
12301224
memcpy(nskb->data, skb->data + copied, size);
@@ -1256,7 +1250,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
12561250

12571251
/* store msg target class in the second 4 bytes of skb ctrl buffer */
12581252
/* Note: the first 4 bytes are reserved for msg tag */
1259-
memcpy(CB_TRGCLS(skb), &msg->class, CB_TRGCLS_LEN);
1253+
IUCV_SKB_CB(skb)->class = msg->class;
12601254

12611255
/* check for special IPRM messages (e.g. iucv_sock_shutdown) */
12621256
if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
@@ -1292,6 +1286,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
12921286
}
12931287
}
12941288

1289+
IUCV_SKB_CB(skb)->offset = 0;
12951290
if (sock_queue_rcv_skb(sk, skb))
12961291
skb_queue_head(&iucv_sk(sk)->backlog_skb_q, skb);
12971292
}
@@ -1327,6 +1322,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
13271322
unsigned int copied, rlen;
13281323
struct sk_buff *skb, *rskb, *cskb;
13291324
int err = 0;
1325+
u32 offset;
13301326

13311327
msg->msg_namelen = 0;
13321328

@@ -1348,13 +1344,14 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
13481344
return err;
13491345
}
13501346

1351-
rlen = skb->len; /* real length of skb */
1347+
offset = IUCV_SKB_CB(skb)->offset;
1348+
rlen = skb->len - offset; /* real length of skb */
13521349
copied = min_t(unsigned int, rlen, len);
13531350
if (!rlen)
13541351
sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;
13551352

13561353
cskb = skb;
1357-
if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
1354+
if (skb_copy_datagram_iovec(cskb, offset, msg->msg_iov, copied)) {
13581355
if (!(flags & MSG_PEEK))
13591356
skb_queue_head(&sk->sk_receive_queue, skb);
13601357
return -EFAULT;
@@ -1372,7 +1369,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
13721369
* get the trgcls from the control buffer of the skb due to
13731370
* fragmentation of original iucv message. */
13741371
err = put_cmsg(msg, SOL_IUCV, SCM_IUCV_TRGCLS,
1375-
CB_TRGCLS_LEN, CB_TRGCLS(skb));
1372+
sizeof(IUCV_SKB_CB(skb)->class),
1373+
(void *)&IUCV_SKB_CB(skb)->class);
13761374
if (err) {
13771375
if (!(flags & MSG_PEEK))
13781376
skb_queue_head(&sk->sk_receive_queue, skb);
@@ -1384,9 +1382,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
13841382

13851383
/* SOCK_STREAM: re-queue skb if it contains unreceived data */
13861384
if (sk->sk_type == SOCK_STREAM) {
1387-
skb_pull(skb, copied);
1388-
if (skb->len) {
1389-
skb_queue_head(&sk->sk_receive_queue, skb);
1385+
if (copied < rlen) {
1386+
IUCV_SKB_CB(skb)->offset = offset + copied;
13901387
goto done;
13911388
}
13921389
}
@@ -1405,6 +1402,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
14051402
spin_lock_bh(&iucv->message_q.lock);
14061403
rskb = skb_dequeue(&iucv->backlog_skb_q);
14071404
while (rskb) {
1405+
IUCV_SKB_CB(rskb)->offset = 0;
14081406
if (sock_queue_rcv_skb(sk, rskb)) {
14091407
skb_queue_head(&iucv->backlog_skb_q,
14101408
rskb);
@@ -1832,7 +1830,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
18321830
spin_lock_irqsave(&list->lock, flags);
18331831

18341832
while (list_skb != (struct sk_buff *)list) {
1835-
if (!memcmp(&msg->tag, CB_TAG(list_skb), CB_TAG_LEN)) {
1833+
if (msg->tag != IUCV_SKB_CB(list_skb)->tag) {
18361834
this = list_skb;
18371835
break;
18381836
}
@@ -2093,6 +2091,7 @@ static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb)
20932091
skb_pull(skb, sizeof(struct af_iucv_trans_hdr));
20942092
skb_reset_transport_header(skb);
20952093
skb_reset_network_header(skb);
2094+
IUCV_SKB_CB(skb)->offset = 0;
20962095
spin_lock(&iucv->message_q.lock);
20972096
if (skb_queue_empty(&iucv->backlog_skb_q)) {
20982097
if (sock_queue_rcv_skb(sk, skb)) {
@@ -2197,8 +2196,7 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
21972196
/* fall through and receive zero length data */
21982197
case 0:
21992198
/* plain data frame */
2200-
memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
2201-
CB_TRGCLS_LEN);
2199+
IUCV_SKB_CB(skb)->class = trans_hdr->iucv_hdr.class;
22022200
err = afiucv_hs_callback_rx(sk, skb);
22032201
break;
22042202
default:

0 commit comments

Comments
 (0)