Skip to content

Commit cc5d590

Browse files
Olga KornievskaiaTrond Myklebust
authored andcommitted
sunrpc: fix client side handling of tls alerts
A security exploit was discovered in NFS over TLS in tls_alert_recv due to its assumption that there is valid data in the msghdr's iterator's kvec. Instead, this patch proposes the rework how control messages are setup and used by sock_recvmsg(). If no control message structure is setup, kTLS layer will read and process TLS data record types. As soon as it encounters a TLS control message, it would return an error. At that point, NFS can setup a kvec backed control buffer and read in the control message such as a TLS alert. Scott found that a msg iterator can advance the kvec pointer as a part of the copy process thus we need to revert the iterator before calling into the tls_alert_recv. Fixes: dea034b ("SUNRPC: Capture CMSG metadata on client-side receive") Suggested-by: Trond Myklebust <[email protected]> Suggested-by: Scott Mayhew <[email protected]> Signed-off-by: Olga Kornievskaia <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Trond Myklebust <[email protected]>
1 parent 533210f commit cc5d590

File tree

1 file changed

+30
-10
lines changed

1 file changed

+30
-10
lines changed

net/sunrpc/xprtsock.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ xs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp)
358358

359359
static int
360360
xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
361-
struct cmsghdr *cmsg, int ret)
361+
unsigned int *msg_flags, struct cmsghdr *cmsg, int ret)
362362
{
363363
u8 content_type = tls_get_record_type(sock->sk, cmsg);
364364
u8 level, description;
@@ -371,7 +371,7 @@ xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
371371
* record, even though there might be more frames
372372
* waiting to be decrypted.
373373
*/
374-
msg->msg_flags &= ~MSG_EOR;
374+
*msg_flags &= ~MSG_EOR;
375375
break;
376376
case TLS_RECORD_TYPE_ALERT:
377377
tls_alert_recv(sock->sk, msg, &level, &description);
@@ -386,19 +386,33 @@ xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
386386
}
387387

388388
static int
389-
xs_sock_recv_cmsg(struct socket *sock, struct msghdr *msg, int flags)
389+
xs_sock_recv_cmsg(struct socket *sock, unsigned int *msg_flags, int flags)
390390
{
391391
union {
392392
struct cmsghdr cmsg;
393393
u8 buf[CMSG_SPACE(sizeof(u8))];
394394
} u;
395+
u8 alert[2];
396+
struct kvec alert_kvec = {
397+
.iov_base = alert,
398+
.iov_len = sizeof(alert),
399+
};
400+
struct msghdr msg = {
401+
.msg_flags = *msg_flags,
402+
.msg_control = &u,
403+
.msg_controllen = sizeof(u),
404+
};
395405
int ret;
396406

397-
msg->msg_control = &u;
398-
msg->msg_controllen = sizeof(u);
399-
ret = sock_recvmsg(sock, msg, flags);
400-
if (msg->msg_controllen != sizeof(u))
401-
ret = xs_sock_process_cmsg(sock, msg, &u.cmsg, ret);
407+
iov_iter_kvec(&msg.msg_iter, ITER_DEST, &alert_kvec, 1,
408+
alert_kvec.iov_len);
409+
ret = sock_recvmsg(sock, &msg, flags);
410+
if (ret > 0 &&
411+
tls_get_record_type(sock->sk, &u.cmsg) == TLS_RECORD_TYPE_ALERT) {
412+
iov_iter_revert(&msg.msg_iter, ret);
413+
ret = xs_sock_process_cmsg(sock, &msg, msg_flags, &u.cmsg,
414+
-EAGAIN);
415+
}
402416
return ret;
403417
}
404418

@@ -408,7 +422,13 @@ xs_sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags, size_t seek)
408422
ssize_t ret;
409423
if (seek != 0)
410424
iov_iter_advance(&msg->msg_iter, seek);
411-
ret = xs_sock_recv_cmsg(sock, msg, flags);
425+
ret = sock_recvmsg(sock, msg, flags);
426+
/* Handle TLS inband control message lazily */
427+
if (msg->msg_flags & MSG_CTRUNC) {
428+
msg->msg_flags &= ~(MSG_CTRUNC | MSG_EOR);
429+
if (ret == 0 || ret == -EIO)
430+
ret = xs_sock_recv_cmsg(sock, &msg->msg_flags, flags);
431+
}
412432
return ret > 0 ? ret + seek : ret;
413433
}
414434

@@ -434,7 +454,7 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
434454
size_t count)
435455
{
436456
iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
437-
return xs_sock_recv_cmsg(sock, msg, flags);
457+
return xs_sock_recvmsg(sock, msg, flags, 0);
438458
}
439459

440460
#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE

0 commit comments

Comments
 (0)