]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.14.33/rdma-ucma-introduce-safer-rdma_addr_size-variants.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.14.33 / rdma-ucma-introduce-safer-rdma_addr_size-variants.patch
CommitLineData
6ee3c412
GKH
1From 84652aefb347297aa08e91e283adf7b18f77c2d5 Mon Sep 17 00:00:00 2001
2From: Roland Dreier <roland@purestorage.com>
3Date: Wed, 28 Mar 2018 11:27:22 -0700
4Subject: RDMA/ucma: Introduce safer rdma_addr_size() variants
5
6From: Roland Dreier <roland@purestorage.com>
7
8commit 84652aefb347297aa08e91e283adf7b18f77c2d5 upstream.
9
10There are several places in the ucma ABI where userspace can pass in a
11sockaddr but set the address family to AF_IB. When that happens,
12rdma_addr_size() will return a size bigger than sizeof struct sockaddr_in6,
13and the ucma kernel code might end up copying past the end of a buffer
14not sized for a struct sockaddr_ib.
15
16Fix this by introducing new variants
17
18 int rdma_addr_size_in6(struct sockaddr_in6 *addr);
19 int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
20
21that are type-safe for the types used in the ucma ABI and return 0 if the
22size computed is bigger than the size of the type passed in. We can use
23these new variants to check what size userspace has passed in before
24copying any addresses.
25
26Reported-by: <syzbot+6800425d54ed3ed8135d@syzkaller.appspotmail.com>
27Signed-off-by: Roland Dreier <roland@purestorage.com>
28Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
29Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
30
31---
32 drivers/infiniband/core/addr.c | 16 ++++++++++++++++
33 drivers/infiniband/core/ucma.c | 34 +++++++++++++++++-----------------
34 include/rdma/ib_addr.h | 2 ++
35 3 files changed, 35 insertions(+), 17 deletions(-)
36
37--- a/drivers/infiniband/core/addr.c
38+++ b/drivers/infiniband/core/addr.c
39@@ -207,6 +207,22 @@ int rdma_addr_size(struct sockaddr *addr
40 }
41 EXPORT_SYMBOL(rdma_addr_size);
42
43+int rdma_addr_size_in6(struct sockaddr_in6 *addr)
44+{
45+ int ret = rdma_addr_size((struct sockaddr *) addr);
46+
47+ return ret <= sizeof(*addr) ? ret : 0;
48+}
49+EXPORT_SYMBOL(rdma_addr_size_in6);
50+
51+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
52+{
53+ int ret = rdma_addr_size((struct sockaddr *) addr);
54+
55+ return ret <= sizeof(*addr) ? ret : 0;
56+}
57+EXPORT_SYMBOL(rdma_addr_size_kss);
58+
59 static struct rdma_addr_client self;
60
61 void rdma_addr_register_client(struct rdma_addr_client *client)
62--- a/drivers/infiniband/core/ucma.c
63+++ b/drivers/infiniband/core/ucma.c
64@@ -632,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_
65 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
66 return -EFAULT;
67
68+ if (!rdma_addr_size_in6(&cmd.addr))
69+ return -EINVAL;
70+
71 ctx = ucma_get_ctx(file, cmd.id);
72 if (IS_ERR(ctx))
73 return PTR_ERR(ctx);
74@@ -645,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_fil
75 int in_len, int out_len)
76 {
77 struct rdma_ucm_bind cmd;
78- struct sockaddr *addr;
79 struct ucma_context *ctx;
80 int ret;
81
82 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
83 return -EFAULT;
84
85- addr = (struct sockaddr *) &cmd.addr;
86- if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
87+ if (cmd.reserved || !cmd.addr_size ||
88+ cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
89 return -EINVAL;
90
91 ctx = ucma_get_ctx(file, cmd.id);
92 if (IS_ERR(ctx))
93 return PTR_ERR(ctx);
94
95- ret = rdma_bind_addr(ctx->cm_id, addr);
96+ ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
97 ucma_put_ctx(ctx);
98 return ret;
99 }
100@@ -670,23 +672,22 @@ static ssize_t ucma_resolve_ip(struct uc
101 int in_len, int out_len)
102 {
103 struct rdma_ucm_resolve_ip cmd;
104- struct sockaddr *src, *dst;
105 struct ucma_context *ctx;
106 int ret;
107
108 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
109 return -EFAULT;
110
111- src = (struct sockaddr *) &cmd.src_addr;
112- dst = (struct sockaddr *) &cmd.dst_addr;
113- if (!rdma_addr_size(src) || !rdma_addr_size(dst))
114+ if (!rdma_addr_size_in6(&cmd.src_addr) ||
115+ !rdma_addr_size_in6(&cmd.dst_addr))
116 return -EINVAL;
117
118 ctx = ucma_get_ctx(file, cmd.id);
119 if (IS_ERR(ctx))
120 return PTR_ERR(ctx);
121
122- ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
123+ ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
124+ (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
125 ucma_put_ctx(ctx);
126 return ret;
127 }
128@@ -696,24 +697,23 @@ static ssize_t ucma_resolve_addr(struct
129 int in_len, int out_len)
130 {
131 struct rdma_ucm_resolve_addr cmd;
132- struct sockaddr *src, *dst;
133 struct ucma_context *ctx;
134 int ret;
135
136 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
137 return -EFAULT;
138
139- src = (struct sockaddr *) &cmd.src_addr;
140- dst = (struct sockaddr *) &cmd.dst_addr;
141- if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
142- !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
143+ if (cmd.reserved ||
144+ (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
145+ !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
146 return -EINVAL;
147
148 ctx = ucma_get_ctx(file, cmd.id);
149 if (IS_ERR(ctx))
150 return PTR_ERR(ctx);
151
152- ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
153+ ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
154+ (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
155 ucma_put_ctx(ctx);
156 return ret;
157 }
158@@ -1432,7 +1432,7 @@ static ssize_t ucma_join_ip_multicast(st
159 join_cmd.response = cmd.response;
160 join_cmd.uid = cmd.uid;
161 join_cmd.id = cmd.id;
162- join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
163+ join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
164 if (!join_cmd.addr_size)
165 return -EINVAL;
166
167@@ -1451,7 +1451,7 @@ static ssize_t ucma_join_multicast(struc
168 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
169 return -EFAULT;
170
171- if (!rdma_addr_size((struct sockaddr *)&cmd.addr))
172+ if (!rdma_addr_size_kss(&cmd.addr))
173 return -EINVAL;
174
175 return ucma_process_join(file, &cmd, out_len);
176--- a/include/rdma/ib_addr.h
177+++ b/include/rdma/ib_addr.h
178@@ -129,6 +129,8 @@ int rdma_copy_addr(struct rdma_dev_addr
179 const unsigned char *dst_dev_addr);
180
181 int rdma_addr_size(struct sockaddr *addr);
182+int rdma_addr_size_in6(struct sockaddr_in6 *addr);
183+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
184
185 int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id);
186 int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,