Skip to content

Commit d55c6ab

Browse files
committed
Merge branch 'mptcp-fix-sockopt-crash-and-lockdep-splats'
Florian Westphal says: ==================== mptcp: fix sockopt crash and lockdep splats Christoph Paasch reported a few bugs and lockdep splats triggered by syzkaller. One patch fixes a crash in set/getsockopt. Two patches fix lockdep splats related to the order in which RTNL and socket lock are taken. Last patch fixes out-of-bounds access when TCP syncookies are used. Change since last iteration on mptcp-list: - add needed refcount in patch 2 - call tcp_get/setsockopt directly in patch 2 Other patches unchanged except minor amends to commit messages. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 44efc78 + ae2dd71 commit d55c6ab

File tree

6 files changed

+46
-25
lines changed

6 files changed

+46
-25
lines changed

include/linux/tcp.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,7 @@ struct tcp_request_sock {
148148
const struct tcp_request_sock_ops *af_specific;
149149
u64 snt_synack; /* first SYNACK sent time */
150150
bool tfo_listener;
151-
#if IS_ENABLED(CONFIG_MPTCP)
152151
bool is_mptcp;
153-
#endif
154152
u32 txhash;
155153
u32 rcv_isn;
156154
u32 snt_isn;

net/ipv4/syncookies.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
349349
req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
350350
treq->snt_synack = 0;
351351
treq->tfo_listener = false;
352+
353+
if (IS_ENABLED(CONFIG_MPTCP))
354+
treq->is_mptcp = 0;
355+
352356
if (IS_ENABLED(CONFIG_SMC))
353357
ireq->smc_ok = 0;
354358

net/ipv4/tcp_input.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6637,6 +6637,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
66376637

66386638
af_ops->init_req(req, sk, skb);
66396639

6640+
if (IS_ENABLED(CONFIG_MPTCP) && want_cookie)
6641+
tcp_rsk(req)->is_mptcp = 0;
6642+
66406643
if (security_inet_conn_request(sk, skb, req))
66416644
goto drop_and_free;
66426645

net/ipv6/syncookies.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
178178
treq = tcp_rsk(req);
179179
treq->tfo_listener = false;
180180

181+
if (IS_ENABLED(CONFIG_MPTCP))
182+
treq->is_mptcp = 0;
183+
181184
if (security_inet_conn_request(sk, skb, req))
182185
goto out_free;
183186

net/mptcp/protocol.c

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -644,19 +644,21 @@ static void __mptcp_close(struct sock *sk, long timeout)
644644
{
645645
struct mptcp_subflow_context *subflow, *tmp;
646646
struct mptcp_sock *msk = mptcp_sk(sk);
647+
LIST_HEAD(conn_list);
647648

648649
mptcp_token_destroy(msk->token);
649650
inet_sk_state_store(sk, TCP_CLOSE);
650651

651-
list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
652+
list_splice_init(&msk->conn_list, &conn_list);
653+
654+
release_sock(sk);
655+
656+
list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
652657
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
653658

654659
__mptcp_close_ssk(sk, ssk, subflow, timeout);
655660
}
656661

657-
if (msk->cached_ext)
658-
__skb_ext_put(msk->cached_ext);
659-
release_sock(sk);
660662
sk_common_release(sk);
661663
}
662664

@@ -776,18 +778,19 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
776778

777779
static void mptcp_destroy(struct sock *sk)
778780
{
781+
struct mptcp_sock *msk = mptcp_sk(sk);
782+
783+
if (msk->cached_ext)
784+
__skb_ext_put(msk->cached_ext);
779785
}
780786

781787
static int mptcp_setsockopt(struct sock *sk, int level, int optname,
782-
char __user *uoptval, unsigned int optlen)
788+
char __user *optval, unsigned int optlen)
783789
{
784790
struct mptcp_sock *msk = mptcp_sk(sk);
785-
char __kernel *optval;
786791
int ret = -EOPNOTSUPP;
787792
struct socket *ssock;
788-
789-
/* will be treated as __user in tcp_setsockopt */
790-
optval = (char __kernel __force *)uoptval;
793+
struct sock *ssk;
791794

792795
pr_debug("msk=%p", msk);
793796

@@ -796,27 +799,28 @@ static int mptcp_setsockopt(struct sock *sk, int level, int optname,
796799
*/
797800
lock_sock(sk);
798801
ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE);
799-
if (!IS_ERR(ssock)) {
800-
pr_debug("subflow=%p", ssock->sk);
801-
ret = kernel_setsockopt(ssock, level, optname, optval, optlen);
802+
if (IS_ERR(ssock)) {
803+
release_sock(sk);
804+
return ret;
802805
}
806+
807+
ssk = ssock->sk;
808+
sock_hold(ssk);
803809
release_sock(sk);
804810

811+
ret = tcp_setsockopt(ssk, level, optname, optval, optlen);
812+
sock_put(ssk);
813+
805814
return ret;
806815
}
807816

808817
static int mptcp_getsockopt(struct sock *sk, int level, int optname,
809-
char __user *uoptval, int __user *uoption)
818+
char __user *optval, int __user *option)
810819
{
811820
struct mptcp_sock *msk = mptcp_sk(sk);
812-
char __kernel *optval;
813821
int ret = -EOPNOTSUPP;
814-
int __kernel *option;
815822
struct socket *ssock;
816-
817-
/* will be treated as __user in tcp_getsockopt */
818-
optval = (char __kernel __force *)uoptval;
819-
option = (int __kernel __force *)uoption;
823+
struct sock *ssk;
820824

821825
pr_debug("msk=%p", msk);
822826

@@ -825,12 +829,18 @@ static int mptcp_getsockopt(struct sock *sk, int level, int optname,
825829
*/
826830
lock_sock(sk);
827831
ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE);
828-
if (!IS_ERR(ssock)) {
829-
pr_debug("subflow=%p", ssock->sk);
830-
ret = kernel_getsockopt(ssock, level, optname, optval, option);
832+
if (IS_ERR(ssock)) {
833+
release_sock(sk);
834+
return ret;
831835
}
836+
837+
ssk = ssock->sk;
838+
sock_hold(ssk);
832839
release_sock(sk);
833840

841+
ret = tcp_getsockopt(ssk, level, optname, optval, option);
842+
sock_put(ssk);
843+
834844
return ret;
835845
}
836846

net/mptcp/subflow.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
186186

187187
pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn);
188188

189+
if (tcp_rsk(req)->is_mptcp == 0)
190+
goto create_child;
191+
189192
/* if the sk is MP_CAPABLE, we try to fetch the client key */
190193
subflow_req = mptcp_subflow_rsk(req);
191194
if (subflow_req->mp_capable) {
@@ -769,7 +772,7 @@ static void subflow_ulp_clone(const struct request_sock *req,
769772
struct mptcp_subflow_context *old_ctx = mptcp_subflow_ctx(newsk);
770773
struct mptcp_subflow_context *new_ctx;
771774

772-
if (!subflow_req->mp_capable) {
775+
if (!tcp_rsk(req)->is_mptcp || !subflow_req->mp_capable) {
773776
subflow_ulp_fallback(newsk, old_ctx);
774777
return;
775778
}

0 commit comments

Comments
 (0)