Skip to content

Commit 421ab1b

Browse files
author
Trond Myklebust
committed
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. Fixes: b49ea67 ("SUNRPC: lock against ->sock changing during sysfs read") Cc: [email protected] Signed-off-by: Trond Myklebust <[email protected]>
1 parent 1d15d12 commit 421ab1b

File tree

4 files changed

+54
-31
lines changed

4 files changed

+54
-31
lines changed

include/linux/sunrpc/xprt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ struct rpc_xprt_ops {
139139
void (*rpcbind)(struct rpc_task *task);
140140
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
141141
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);
142145
int (*buf_alloc)(struct rpc_task *task);
143146
void (*buf_free)(struct rpc_task *task);
144147
void (*prepare_request)(struct rpc_rqst *req);

include/linux/sunrpc/xprtsock.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
int init_socket_xprt(void);
1212
void cleanup_socket_xprt(void);
13-
unsigned short get_srcport(struct rpc_xprt *);
1413

1514
#define RPC_MIN_RESVPORT (1U)
1615
#define RPC_MAX_RESVPORT (65535U)

net/sunrpc/sysfs.c

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -97,64 +97,63 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
9797
return 0;
9898
ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
9999
xprt_put(xprt);
100-
return ret + 1;
100+
return ret;
101101
}
102102

103103
static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
104104
struct kobj_attribute *attr,
105105
char *buf)
106106
{
107107
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
108-
struct sockaddr_storage saddr;
109-
struct sock_xprt *sock;
110-
ssize_t ret = -1;
108+
size_t buflen = PAGE_SIZE;
109+
ssize_t ret = -ENOTSOCK;
111110

112111
if (!xprt || !xprt_connected(xprt)) {
113-
xprt_put(xprt);
114-
return -ENOTCONN;
112+
ret = -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+
}
115122
}
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);
124-
out:
125-
mutex_unlock(&sock->recv_mutex);
126123
xprt_put(xprt);
127-
return ret + 1;
124+
return ret;
128125
}
129126

130127
static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
131-
struct kobj_attribute *attr,
132-
char *buf)
128+
struct kobj_attribute *attr, char *buf)
133129
{
134130
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
131+
unsigned short srcport = 0;
132+
size_t buflen = PAGE_SIZE;
135133
ssize_t ret;
136134

137135
if (!xprt || !xprt_connected(xprt)) {
138136
xprt_put(xprt);
139137
return -ENOTCONN;
140138
}
141139

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"
143145
"max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
144146
"binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
145147
"backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
146148
"tasks_queuelen=%ld\ndst_port=%s\n",
147149
xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
148150
xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
149151
xprt->sending.qlen, xprt->pending.qlen,
150-
xprt->backlog.qlen, xprt->main,
151-
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
152-
get_srcport(xprt) : 0,
152+
xprt->backlog.qlen, xprt->main, srcport,
153153
atomic_long_read(&xprt->queuelen),
154-
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
155-
xprt->address_strings[RPC_DISPLAY_PORT] : "0");
154+
xprt->address_strings[RPC_DISPLAY_PORT]);
156155
xprt_put(xprt);
157-
return ret + 1;
156+
return ret;
158157
}
159158

160159
static 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,
201200
}
202201

203202
xprt_put(xprt);
204-
return ret + 1;
203+
return ret;
205204
}
206205

207206
static 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,
220219
xprt_switch->xps_nunique_destaddr_xprts,
221220
atomic_long_read(&xprt_switch->xps_queuelen));
222221
xprt_switch_put(xprt_switch);
223-
return ret + 1;
222+
return ret;
224223
}
225224

226225
static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,

net/sunrpc/xprtsock.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,7 +1638,7 @@ static int xs_get_srcport(struct sock_xprt *transport)
16381638
return port;
16391639
}
16401640

1641-
unsigned short get_srcport(struct rpc_xprt *xprt)
1641+
static unsigned short xs_sock_srcport(struct rpc_xprt *xprt)
16421642
{
16431643
struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
16441644
unsigned short ret = 0;
@@ -1648,7 +1648,25 @@ unsigned short get_srcport(struct rpc_xprt *xprt)
16481648
mutex_unlock(&sock->recv_mutex);
16491649
return ret;
16501650
}
1651-
EXPORT_SYMBOL(get_srcport);
1651+
1652+
static 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+
}
16521670

16531671
static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
16541672
{
@@ -2622,6 +2640,8 @@ static const struct rpc_xprt_ops xs_udp_ops = {
26222640
.rpcbind = rpcb_getport_async,
26232641
.set_port = xs_set_port,
26242642
.connect = xs_connect,
2643+
.get_srcaddr = xs_sock_srcaddr,
2644+
.get_srcport = xs_sock_srcport,
26252645
.buf_alloc = rpc_malloc,
26262646
.buf_free = rpc_free,
26272647
.send_request = xs_udp_send_request,
@@ -2644,6 +2664,8 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
26442664
.rpcbind = rpcb_getport_async,
26452665
.set_port = xs_set_port,
26462666
.connect = xs_connect,
2667+
.get_srcaddr = xs_sock_srcaddr,
2668+
.get_srcport = xs_sock_srcport,
26472669
.buf_alloc = rpc_malloc,
26482670
.buf_free = rpc_free,
26492671
.prepare_request = xs_stream_prepare_request,

0 commit comments

Comments
 (0)