History

SUNRPC: Do not dereference non-socket transports in sysfs

Do not cast the struct xprt to a sock_xprt unless we know it is a UDP or TCP transport. Otherwise the call to lock the mutex will scribble over whatever structure is actually there. This has been seen to cause hard system lockups when the underlying transport was RDMA.

Trond Myklebust committed 4 years ago

Commit 421ab1b1 parent 1d15d124 files · +54 −31Browse files

Unified · Split

4 files
  1. include/linux/sunrpc/xprt.h +3 −0
  2. include/linux/sunrpc/xprtsock.h +0 −1
  3. net/sunrpc/sysfs.c +27 −28
  4. net/sunrpc/xprtsock.c +24 −2
include/linux/sunrpc/xprt.h+3−0
@@ -139,6 +139,9 @@ struct rpc_xprt_ops { · 138 unmodified lines
139 void (*rpcbind)(struct rpc_task *task);139 void (*rpcbind)(struct rpc_task *task);
140 void (*set_port)(struct rpc_xprt *xprt, unsigned short port);140 void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
141 void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task);141 void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task);
142 int (*get_srcaddr)(struct rpc_xprt *xprt, char *buf,
143 size_t buflen);
144 unsigned short (*get_srcport)(struct rpc_xprt *xprt);
142 int (*buf_alloc)(struct rpc_task *task);145 int (*buf_alloc)(struct rpc_task *task);
143 void (*buf_free)(struct rpc_task *task);146 void (*buf_free)(struct rpc_task *task);
144 void (*prepare_request)(struct rpc_rqst *req);147 void (*prepare_request)(struct rpc_rqst *req);
include/linux/sunrpc/xprtsock.h+0−1
@@ -10,7 +10,6 @@ · 9 unmodified lines
10 10
11int init_socket_xprt(void);11int init_socket_xprt(void);
12void cleanup_socket_xprt(void);12void cleanup_socket_xprt(void);
13unsigned short get_srcport(struct rpc_xprt *);
14 13
15#define RPC_MIN_RESVPORT (1U)14#define RPC_MIN_RESVPORT (1U)
16#define RPC_MAX_RESVPORT (65535U)15#define RPC_MAX_RESVPORT (65535U)
net/sunrpc/sysfs.c+27−28
@@ -97,7 +97,7 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj, · 96 unmodified lines
97 return 0;97 return 0;
98 ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);98 ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
99 xprt_put(xprt);99 xprt_put(xprt);
100 return ret + 1;100 return ret;
101}101}
102 102
103static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,103static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
@@ -105,33 +105,31 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj, · 1 unmodified line
105 char *buf)105 char *buf)
106{106{
107 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);107 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
108 struct sockaddr_storage saddr;108 size_t buflen = PAGE_SIZE;
109 struct sock_xprt *sock;109 ssize_t ret = -ENOTSOCK;
110 ssize_t ret = -1;
111 110
112 if (!xprt || !xprt_connected(xprt)) {111 if (!xprt || !xprt_connected(xprt)) {
113 xprt_put(xprt);112 ret = -ENOTCONN;
114 return -ENOTCONN;113 } else if (xprt->ops->get_srcaddr) {
114 ret = xprt->ops->get_srcaddr(xprt, buf, buflen);
115 if (ret > 0) {
116 if (ret < buflen - 1) {
117 buf[ret] = '\n';
118 ret++;
119 buf[ret] = '\0';
120 }
121 }
115 }122 }
116
117 sock = container_of(xprt, struct sock_xprt, xprt);
118 mutex_lock(&sock->recv_mutex);
119 if (sock->sock == NULL ||
120 kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
121 goto out;
122
123 ret = sprintf(buf, "%pISc\n", &saddr);
124out:
125 mutex_unlock(&sock->recv_mutex);
126 xprt_put(xprt);123 xprt_put(xprt);
127 return ret + 1;124 return ret;
128}125}
129 126
130static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,127static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
131 struct kobj_attribute *attr,128 struct kobj_attribute *attr, char *buf)
132 char *buf)
133{129{
134 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);130 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
131 unsigned short srcport = 0;
132 size_t buflen = PAGE_SIZE;
135 ssize_t ret;133 ssize_t ret;
136 134
137 if (!xprt || !xprt_connected(xprt)) {135 if (!xprt || !xprt_connected(xprt)) {
@@ -139,7 +137,11 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, · 1 unmodified line
139 return -ENOTCONN;137 return -ENOTCONN;
140 }138 }
141 139
142 ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"140 if (xprt->ops->get_srcport)
141 srcport = xprt->ops->get_srcport(xprt);
142
143 ret = snprintf(buf, buflen,
144 "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
143 "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"145 "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
144 "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"146 "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
145 "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"147 "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
@@ -147,14 +149,11 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, · 1 unmodified line
147 xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,149 xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
148 xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,150 xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
149 xprt->sending.qlen, xprt->pending.qlen,151 xprt->sending.qlen, xprt->pending.qlen,
150 xprt->backlog.qlen, xprt->main,152 xprt->backlog.qlen, xprt->main, srcport,
151 (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
152 get_srcport(xprt) : 0,
153 atomic_long_read(&xprt->queuelen),153 atomic_long_read(&xprt->queuelen),
154 (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?154 xprt->address_strings[RPC_DISPLAY_PORT]);
155 xprt->address_strings[RPC_DISPLAY_PORT] : "0");
156 xprt_put(xprt);155 xprt_put(xprt);
157 return ret + 1;156 return ret;
158}157}
159 158
160static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,159static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
@@ -201,7 +200,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, · 40 unmodified lines
201 }200 }
202 201
203 xprt_put(xprt);202 xprt_put(xprt);
204 return ret + 1;203 return ret;
205}204}
206 205
207static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,206static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
@@ -220,7 +219,7 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, · 12 unmodified lines
220 xprt_switch->xps_nunique_destaddr_xprts,219 xprt_switch->xps_nunique_destaddr_xprts,
221 atomic_long_read(&xprt_switch->xps_queuelen));220 atomic_long_read(&xprt_switch->xps_queuelen));
222 xprt_switch_put(xprt_switch);221 xprt_switch_put(xprt_switch);
223 return ret + 1;222 return ret;
224}223}
225 224
226static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,225static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
net/sunrpc/xprtsock.c+24−2
@@ -1638,7 +1638,7 @@ static int xs_get_srcport(struct sock_xprt *transport) · 1637 unmodified lines
1638 return port;1638 return port;
1639}1639}
1640 1640
1641unsigned short get_srcport(struct rpc_xprt *xprt)1641static unsigned short xs_sock_srcport(struct rpc_xprt *xprt)
1642{1642{
1643 struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);1643 struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
1644 unsigned short ret = 0;1644 unsigned short ret = 0;
@@ -1648,7 +1648,25 @@ unsigned short get_srcport(struct rpc_xprt *xprt) · 3 unmodified lines
1648 mutex_unlock(&sock->recv_mutex);1648 mutex_unlock(&sock->recv_mutex);
1649 return ret;1649 return ret;
1650}1650}
1651EXPORT_SYMBOL(get_srcport);1651
1652static int xs_sock_srcaddr(struct rpc_xprt *xprt, char *buf, size_t buflen)
1653{
1654 struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
1655 union {
1656 struct sockaddr sa;
1657 struct sockaddr_storage st;
1658 } saddr;
1659 int ret = -ENOTCONN;
1660
1661 mutex_lock(&sock->recv_mutex);
1662 if (sock->sock) {
1663 ret = kernel_getsockname(sock->sock, &saddr.sa);
1664 if (ret >= 0)
1665 ret = snprintf(buf, buflen, "%pISc", &saddr.sa);
1666 }
1667 mutex_unlock(&sock->recv_mutex);
1668 return ret;
1669}
1652 1670
1653static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)1671static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
1654{1672{
@@ -2622,6 +2640,8 @@ static const struct rpc_xprt_ops xs_udp_ops = { · 967 unmodified lines
2622 .rpcbind = rpcb_getport_async,2640 .rpcbind = rpcb_getport_async,
2623 .set_port = xs_set_port,2641 .set_port = xs_set_port,
2624 .connect = xs_connect,2642 .connect = xs_connect,
2643 .get_srcaddr = xs_sock_srcaddr,
2644 .get_srcport = xs_sock_srcport,
2625 .buf_alloc = rpc_malloc,2645 .buf_alloc = rpc_malloc,
2626 .buf_free = rpc_free,2646 .buf_free = rpc_free,
2627 .send_request = xs_udp_send_request,2647 .send_request = xs_udp_send_request,
@@ -2644,6 +2664,8 @@ static const struct rpc_xprt_ops xs_tcp_ops = { · 16 unmodified lines
2644 .rpcbind = rpcb_getport_async,2664 .rpcbind = rpcb_getport_async,
2645 .set_port = xs_set_port,2665 .set_port = xs_set_port,
2646 .connect = xs_connect,2666 .connect = xs_connect,
2667 .get_srcaddr = xs_sock_srcaddr,
2668 .get_srcport = xs_sock_srcport,
2647 .buf_alloc = rpc_malloc,2669 .buf_alloc = rpc_malloc,
2648 .buf_free = rpc_free,2670 .buf_free = rpc_free,
2649 .prepare_request = xs_stream_prepare_request,2671 .prepare_request = xs_stream_prepare_request,