net/rds: Whitelist rdma_cookie and rx_tstamp for usercopy
authorDag Moxnes <dag.moxnes@oracle.com>
Fri, 23 Aug 2019 14:03:18 +0000 (16:03 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 23 Aug 2019 21:55:52 +0000 (14:55 -0700)
Add the RDMA cookie and RX timestamp to the usercopy whitelist.

After the introduction of hardened usercopy whitelisting
(https://lwn.net/Articles/727322/), a warning is displayed when the
RDMA cookie or RX timestamp is copied to userspace:

kernel: WARNING: CPU: 3 PID: 5750 at
mm/usercopy.c:81 usercopy_warn+0x8e/0xa6
[...]
kernel: Call Trace:
kernel: __check_heap_object+0xb8/0x11b
kernel: __check_object_size+0xe3/0x1bc
kernel: put_cmsg+0x95/0x115
kernel: rds_recvmsg+0x43d/0x620 [rds]
kernel: sock_recvmsg+0x43/0x4a
kernel: ___sys_recvmsg+0xda/0x1e6
kernel: ? __handle_mm_fault+0xcae/0xf79
kernel: __sys_recvmsg+0x51/0x8a
kernel: SyS_recvmsg+0x12/0x1c
kernel: do_syscall_64+0x79/0x1ae

When the whitelisting feature was introduced, the memory for the RDMA
cookie and RX timestamp in RDS was not added to the whitelist, causing
the warning above.

Signed-off-by: Dag Moxnes <dag.moxnes@oracle.com>
Tested-by: Jenny <jenny.x.xu@oracle.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/rds/ib_recv.c
net/rds/rds.h
net/rds/recv.c

index 1a8a4a760b849fc1cfee4eae46864dc89b8c0015..a0f99bbf362ca0302d9028453ae26edbb7e6bdd1 100644 (file)
@@ -1048,9 +1048,14 @@ int rds_ib_recv_init(void)
        si_meminfo(&si);
        rds_ib_sysctl_max_recv_allocation = si.totalram / 3 * PAGE_SIZE / RDS_FRAG_SIZE;
 
-       rds_ib_incoming_slab = kmem_cache_create("rds_ib_incoming",
-                                       sizeof(struct rds_ib_incoming),
-                                       0, SLAB_HWCACHE_ALIGN, NULL);
+       rds_ib_incoming_slab =
+               kmem_cache_create_usercopy("rds_ib_incoming",
+                                          sizeof(struct rds_ib_incoming),
+                                          0, SLAB_HWCACHE_ALIGN,
+                                          offsetof(struct rds_ib_incoming,
+                                                   ii_inc.i_usercopy),
+                                          sizeof(struct rds_inc_usercopy),
+                                          NULL);
        if (!rds_ib_incoming_slab)
                goto out;
 
index ad605fd61655e814706cd1807376c53ead2e2c04..53e86911773a83fb8206a46c769600bcd71fe566 100644 (file)
@@ -271,6 +271,12 @@ struct rds_ext_header_rdma_dest {
 #define        RDS_MSG_RX_END          2
 #define        RDS_MSG_RX_CMSG         3
 
+/* The following values are whitelisted for usercopy */
+struct rds_inc_usercopy {
+       rds_rdma_cookie_t       rdma_cookie;
+       ktime_t                 rx_tstamp;
+};
+
 struct rds_incoming {
        refcount_t              i_refcount;
        struct list_head        i_item;
@@ -280,8 +286,7 @@ struct rds_incoming {
        unsigned long           i_rx_jiffies;
        struct in6_addr         i_saddr;
 
-       rds_rdma_cookie_t       i_rdma_cookie;
-       ktime_t                 i_rx_tstamp;
+       struct rds_inc_usercopy i_usercopy;
        u64                     i_rx_lat_trace[RDS_RX_MAX_TRACES];
 };
 
index 853de48760880603bf60142700cd668100ca289e..7e451c82595bfc0c6f4ac5e326d948f28c91ba91 100644 (file)
@@ -47,8 +47,8 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
        INIT_LIST_HEAD(&inc->i_item);
        inc->i_conn = conn;
        inc->i_saddr = *saddr;
-       inc->i_rdma_cookie = 0;
-       inc->i_rx_tstamp = ktime_set(0, 0);
+       inc->i_usercopy.rdma_cookie = 0;
+       inc->i_usercopy.rx_tstamp = ktime_set(0, 0);
 
        memset(inc->i_rx_lat_trace, 0, sizeof(inc->i_rx_lat_trace));
 }
@@ -62,8 +62,8 @@ void rds_inc_path_init(struct rds_incoming *inc, struct rds_conn_path *cp,
        inc->i_conn = cp->cp_conn;
        inc->i_conn_path = cp;
        inc->i_saddr = *saddr;
-       inc->i_rdma_cookie = 0;
-       inc->i_rx_tstamp = ktime_set(0, 0);
+       inc->i_usercopy.rdma_cookie = 0;
+       inc->i_usercopy.rx_tstamp = ktime_set(0, 0);
 }
 EXPORT_SYMBOL_GPL(rds_inc_path_init);
 
@@ -186,7 +186,7 @@ static void rds_recv_incoming_exthdrs(struct rds_incoming *inc, struct rds_sock
                case RDS_EXTHDR_RDMA_DEST:
                        /* We ignore the size for now. We could stash it
                         * somewhere and use it for error checking. */
-                       inc->i_rdma_cookie = rds_rdma_make_cookie(
+                       inc->i_usercopy.rdma_cookie = rds_rdma_make_cookie(
                                        be32_to_cpu(buffer.rdma_dest.h_rdma_rkey),
                                        be32_to_cpu(buffer.rdma_dest.h_rdma_offset));
 
@@ -380,7 +380,7 @@ void rds_recv_incoming(struct rds_connection *conn, struct in6_addr *saddr,
                                      be32_to_cpu(inc->i_hdr.h_len),
                                      inc->i_hdr.h_dport);
                if (sock_flag(sk, SOCK_RCVTSTAMP))
-                       inc->i_rx_tstamp = ktime_get_real();
+                       inc->i_usercopy.rx_tstamp = ktime_get_real();
                rds_inc_addref(inc);
                inc->i_rx_lat_trace[RDS_MSG_RX_END] = local_clock();
                list_add_tail(&inc->i_item, &rs->rs_recv_queue);
@@ -540,16 +540,18 @@ static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg,
 {
        int ret = 0;
 
-       if (inc->i_rdma_cookie) {
+       if (inc->i_usercopy.rdma_cookie) {
                ret = put_cmsg(msg, SOL_RDS, RDS_CMSG_RDMA_DEST,
-                               sizeof(inc->i_rdma_cookie), &inc->i_rdma_cookie);
+                               sizeof(inc->i_usercopy.rdma_cookie),
+                               &inc->i_usercopy.rdma_cookie);
                if (ret)
                        goto out;
        }
 
-       if ((inc->i_rx_tstamp != 0) &&
+       if ((inc->i_usercopy.rx_tstamp != 0) &&
            sock_flag(rds_rs_to_sk(rs), SOCK_RCVTSTAMP)) {
-               struct __kernel_old_timeval tv = ns_to_kernel_old_timeval(inc->i_rx_tstamp);
+               struct __kernel_old_timeval tv =
+                       ns_to_kernel_old_timeval(inc->i_usercopy.rx_tstamp);
 
                if (!sock_flag(rds_rs_to_sk(rs), SOCK_TSTAMP_NEW)) {
                        ret = put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,