Skip to content

Commit 55e8757

Browse files
author
Paolo Abeni
committed
Merge branch 'net-mctp-improved-bind-handling'
Matt Johnston says: ==================== net: mctp: Improved bind handling This series improves a couple of aspects of MCTP bind() handling. MCTP wasn't checking whether the same MCTP type was bound by multiple sockets. That would result in messages being received by an arbitrary socket, which isn't useful behaviour. Instead it makes more sense to have the duplicate binds fail, the same as other network protocols. An exception is made for more-specific binds to particular MCTP addresses. It is also useful to be able to limit a bind to only receive incoming request messages (MCTP TO bit set) from a specific peer+type, so that individual processes can communicate with separate MCTP peers. One example is a PLDM firmware update requester, which will initiate communication with a device, and then the device will connect back to the requester process. These limited binds are implemented by a connect() call on the socket prior to bind. connect() isn't used in the general case for MCTP, since a plain send() wouldn't provide the required MCTP tag argument for addressing. Signed-off-by: Matt Johnston <[email protected]> ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents a8594c9 + e6d8e7d commit 55e8757

File tree

8 files changed

+634
-32
lines changed

8 files changed

+634
-32
lines changed

include/net/mctp.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ struct mctp_sock {
6969

7070
/* bind() params */
7171
unsigned int bind_net;
72-
mctp_eid_t bind_addr;
72+
mctp_eid_t bind_local_addr;
73+
mctp_eid_t bind_peer_addr;
74+
unsigned int bind_peer_net;
75+
bool bind_peer_set;
7376
__u8 bind_type;
7477

7578
/* sendmsg()/recvmsg() uses struct sockaddr_mctp_ext */

include/net/netns/mctp.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,25 @@
66
#ifndef __NETNS_MCTP_H__
77
#define __NETNS_MCTP_H__
88

9+
#include <linux/hash.h>
10+
#include <linux/hashtable.h>
911
#include <linux/mutex.h>
1012
#include <linux/types.h>
1113

14+
#define MCTP_BINDS_BITS 7
15+
1216
struct netns_mctp {
1317
/* Only updated under RTNL, entries freed via RCU */
1418
struct list_head routes;
1519

16-
/* Bound sockets: list of sockets bound by type.
17-
* This list is updated from non-atomic contexts (under bind_lock),
18-
* and read (under rcu) in packet rx
20+
/* Bound sockets: hash table of sockets, keyed by
21+
* (type, src_eid, dest_eid).
22+
* Specific src_eid/dest_eid entries also have an entry for
23+
* MCTP_ADDR_ANY. This list is updated from non-atomic contexts
24+
* (under bind_lock), and read (under rcu) in packet rx.
1925
*/
2026
struct mutex bind_lock;
21-
struct hlist_head binds;
27+
DECLARE_HASHTABLE(binds, MCTP_BINDS_BITS);
2228

2329
/* tag allocations. This list is read and updated from atomic contexts,
2430
* but elements are free()ed after a RCU grace-period
@@ -34,4 +40,10 @@ struct netns_mctp {
3440
struct list_head neighbours;
3541
};
3642

43+
static inline u32 mctp_bind_hash(u8 type, u8 local_addr, u8 peer_addr)
44+
{
45+
return hash_32(type | (u32)local_addr << 8 | (u32)peer_addr << 16,
46+
MCTP_BINDS_BITS);
47+
}
48+
3749
#endif /* __NETNS_MCTP_H__ */

net/mctp/af_mctp.c

Lines changed: 139 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
5353
{
5454
struct sock *sk = sock->sk;
5555
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
56+
struct net *net = sock_net(&msk->sk);
5657
struct sockaddr_mctp *smctp;
5758
int rc;
5859

@@ -73,14 +74,48 @@ static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
7374

7475
lock_sock(sk);
7576

76-
/* TODO: allow rebind */
7777
if (sk_hashed(sk)) {
7878
rc = -EADDRINUSE;
7979
goto out_release;
8080
}
81-
msk->bind_net = smctp->smctp_network;
82-
msk->bind_addr = smctp->smctp_addr.s_addr;
83-
msk->bind_type = smctp->smctp_type & 0x7f; /* ignore the IC bit */
81+
82+
msk->bind_local_addr = smctp->smctp_addr.s_addr;
83+
84+
/* MCTP_NET_ANY with a specific EID is resolved to the default net
85+
* at bind() time.
86+
* For bind_addr=MCTP_ADDR_ANY it is handled specially at route
87+
* lookup time.
88+
*/
89+
if (smctp->smctp_network == MCTP_NET_ANY &&
90+
msk->bind_local_addr != MCTP_ADDR_ANY) {
91+
msk->bind_net = mctp_default_net(net);
92+
} else {
93+
msk->bind_net = smctp->smctp_network;
94+
}
95+
96+
/* ignore the IC bit */
97+
smctp->smctp_type &= 0x7f;
98+
99+
if (msk->bind_peer_set) {
100+
if (msk->bind_type != smctp->smctp_type) {
101+
/* Prior connect() had a different type */
102+
rc = -EINVAL;
103+
goto out_release;
104+
}
105+
106+
if (msk->bind_net == MCTP_NET_ANY) {
107+
/* Restrict to the network passed to connect() */
108+
msk->bind_net = msk->bind_peer_net;
109+
}
110+
111+
if (msk->bind_net != msk->bind_peer_net) {
112+
/* connect() had a different net to bind() */
113+
rc = -EINVAL;
114+
goto out_release;
115+
}
116+
} else {
117+
msk->bind_type = smctp->smctp_type;
118+
}
84119

85120
rc = sk->sk_prot->hash(sk);
86121

@@ -90,6 +125,67 @@ static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
90125
return rc;
91126
}
92127

128+
/* Used to set a specific peer prior to bind. Not used for outbound
129+
* connections (Tag Owner set) since MCTP is a datagram protocol.
130+
*/
131+
static int mctp_connect(struct socket *sock, struct sockaddr *addr,
132+
int addrlen, int flags)
133+
{
134+
struct sock *sk = sock->sk;
135+
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
136+
struct net *net = sock_net(&msk->sk);
137+
struct sockaddr_mctp *smctp;
138+
int rc;
139+
140+
if (addrlen != sizeof(*smctp))
141+
return -EINVAL;
142+
143+
if (addr->sa_family != AF_MCTP)
144+
return -EAFNOSUPPORT;
145+
146+
/* It's a valid sockaddr for MCTP, cast and do protocol checks */
147+
smctp = (struct sockaddr_mctp *)addr;
148+
149+
if (!mctp_sockaddr_is_ok(smctp))
150+
return -EINVAL;
151+
152+
/* Can't bind by tag */
153+
if (smctp->smctp_tag)
154+
return -EINVAL;
155+
156+
/* IC bit must be unset */
157+
if (smctp->smctp_type & 0x80)
158+
return -EINVAL;
159+
160+
lock_sock(sk);
161+
162+
if (sk_hashed(sk)) {
163+
/* bind() already */
164+
rc = -EADDRINUSE;
165+
goto out_release;
166+
}
167+
168+
if (msk->bind_peer_set) {
169+
/* connect() already */
170+
rc = -EADDRINUSE;
171+
goto out_release;
172+
}
173+
174+
msk->bind_peer_set = true;
175+
msk->bind_peer_addr = smctp->smctp_addr.s_addr;
176+
msk->bind_type = smctp->smctp_type;
177+
if (smctp->smctp_network == MCTP_NET_ANY)
178+
msk->bind_peer_net = mctp_default_net(net);
179+
else
180+
msk->bind_peer_net = smctp->smctp_network;
181+
182+
rc = 0;
183+
184+
out_release:
185+
release_sock(sk);
186+
return rc;
187+
}
188+
93189
static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
94190
{
95191
DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
@@ -533,7 +629,7 @@ static const struct proto_ops mctp_dgram_ops = {
533629
.family = PF_MCTP,
534630
.release = mctp_release,
535631
.bind = mctp_bind,
536-
.connect = sock_no_connect,
632+
.connect = mctp_connect,
537633
.socketpair = sock_no_socketpair,
538634
.accept = sock_no_accept,
539635
.getname = sock_no_getname,
@@ -600,6 +696,7 @@ static int mctp_sk_init(struct sock *sk)
600696

601697
INIT_HLIST_HEAD(&msk->keys);
602698
timer_setup(&msk->key_expiry, mctp_sk_expire_keys, 0);
699+
msk->bind_peer_set = false;
603700
return 0;
604701
}
605702

@@ -611,15 +708,48 @@ static void mctp_sk_close(struct sock *sk, long timeout)
611708
static int mctp_sk_hash(struct sock *sk)
612709
{
613710
struct net *net = sock_net(sk);
711+
struct sock *existing;
712+
struct mctp_sock *msk;
713+
mctp_eid_t remote;
714+
u32 hash;
715+
int rc;
716+
717+
msk = container_of(sk, struct mctp_sock, sk);
718+
719+
if (msk->bind_peer_set)
720+
remote = msk->bind_peer_addr;
721+
else
722+
remote = MCTP_ADDR_ANY;
723+
hash = mctp_bind_hash(msk->bind_type, msk->bind_local_addr, remote);
724+
725+
mutex_lock(&net->mctp.bind_lock);
726+
727+
/* Prevent duplicate binds. */
728+
sk_for_each(existing, &net->mctp.binds[hash]) {
729+
struct mctp_sock *mex =
730+
container_of(existing, struct mctp_sock, sk);
731+
732+
bool same_peer = (mex->bind_peer_set && msk->bind_peer_set &&
733+
mex->bind_peer_addr == msk->bind_peer_addr) ||
734+
(!mex->bind_peer_set && !msk->bind_peer_set);
735+
736+
if (mex->bind_type == msk->bind_type &&
737+
mex->bind_local_addr == msk->bind_local_addr && same_peer &&
738+
mex->bind_net == msk->bind_net) {
739+
rc = -EADDRINUSE;
740+
goto out;
741+
}
742+
}
614743

615744
/* Bind lookup runs under RCU, remain live during that. */
616745
sock_set_flag(sk, SOCK_RCU_FREE);
617746

618-
mutex_lock(&net->mctp.bind_lock);
619-
sk_add_node_rcu(sk, &net->mctp.binds);
620-
mutex_unlock(&net->mctp.bind_lock);
747+
sk_add_node_rcu(sk, &net->mctp.binds[hash]);
748+
rc = 0;
621749

622-
return 0;
750+
out:
751+
mutex_unlock(&net->mctp.bind_lock);
752+
return rc;
623753
}
624754

625755
static void mctp_sk_unhash(struct sock *sk)

net/mctp/route.c

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,36 @@ static int mctp_dst_discard(struct mctp_dst *dst, struct sk_buff *skb)
4040
return 0;
4141
}
4242

43-
static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb)
43+
static struct mctp_sock *mctp_lookup_bind_details(struct net *net,
44+
struct sk_buff *skb,
45+
u8 type, u8 dest,
46+
u8 src, bool allow_net_any)
4447
{
4548
struct mctp_skb_cb *cb = mctp_cb(skb);
46-
struct mctp_hdr *mh;
4749
struct sock *sk;
48-
u8 type;
49-
50-
WARN_ON(!rcu_read_lock_held());
51-
52-
/* TODO: look up in skb->cb? */
53-
mh = mctp_hdr(skb);
50+
u8 hash;
5451

55-
if (!skb_headlen(skb))
56-
return NULL;
52+
WARN_ON_ONCE(!rcu_read_lock_held());
5753

58-
type = (*(u8 *)skb->data) & 0x7f;
54+
hash = mctp_bind_hash(type, dest, src);
5955

60-
sk_for_each_rcu(sk, &net->mctp.binds) {
56+
sk_for_each_rcu(sk, &net->mctp.binds[hash]) {
6157
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
6258

59+
if (!allow_net_any && msk->bind_net == MCTP_NET_ANY)
60+
continue;
61+
6362
if (msk->bind_net != MCTP_NET_ANY && msk->bind_net != cb->net)
6463
continue;
6564

6665
if (msk->bind_type != type)
6766
continue;
6867

69-
if (!mctp_address_matches(msk->bind_addr, mh->dest))
68+
if (msk->bind_peer_set &&
69+
!mctp_address_matches(msk->bind_peer_addr, src))
70+
continue;
71+
72+
if (!mctp_address_matches(msk->bind_local_addr, dest))
7073
continue;
7174

7275
return msk;
@@ -75,6 +78,54 @@ static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb)
7578
return NULL;
7679
}
7780

81+
static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb)
82+
{
83+
struct mctp_sock *msk;
84+
struct mctp_hdr *mh;
85+
u8 type;
86+
87+
/* TODO: look up in skb->cb? */
88+
mh = mctp_hdr(skb);
89+
90+
if (!skb_headlen(skb))
91+
return NULL;
92+
93+
type = (*(u8 *)skb->data) & 0x7f;
94+
95+
/* Look for binds in order of widening scope. A given destination or
96+
* source address also implies matching on a particular network.
97+
*
98+
* - Matching destination and source
99+
* - Matching destination
100+
* - Matching source
101+
* - Matching network, any address
102+
* - Any network or address
103+
*/
104+
105+
msk = mctp_lookup_bind_details(net, skb, type, mh->dest, mh->src,
106+
false);
107+
if (msk)
108+
return msk;
109+
msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY, mh->src,
110+
false);
111+
if (msk)
112+
return msk;
113+
msk = mctp_lookup_bind_details(net, skb, type, mh->dest, MCTP_ADDR_ANY,
114+
false);
115+
if (msk)
116+
return msk;
117+
msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY,
118+
MCTP_ADDR_ANY, false);
119+
if (msk)
120+
return msk;
121+
msk = mctp_lookup_bind_details(net, skb, type, MCTP_ADDR_ANY,
122+
MCTP_ADDR_ANY, true);
123+
if (msk)
124+
return msk;
125+
126+
return NULL;
127+
}
128+
78129
/* A note on the key allocations.
79130
*
80131
* struct net->mctp.keys contains our set of currently-allocated keys for
@@ -1671,7 +1722,7 @@ static int __net_init mctp_routes_net_init(struct net *net)
16711722
struct netns_mctp *ns = &net->mctp;
16721723

16731724
INIT_LIST_HEAD(&ns->routes);
1674-
INIT_HLIST_HEAD(&ns->binds);
1725+
hash_init(ns->binds);
16751726
mutex_init(&ns->bind_lock);
16761727
INIT_HLIST_HEAD(&ns->keys);
16771728
spin_lock_init(&ns->keys_lock);

0 commit comments

Comments
 (0)