forked from Minki/linux
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 <davem@davemloft.net>
This commit is contained in:
commit
d55c6ab4b3
@ -148,9 +148,7 @@ struct tcp_request_sock {
|
||||
const struct tcp_request_sock_ops *af_specific;
|
||||
u64 snt_synack; /* first SYNACK sent time */
|
||||
bool tfo_listener;
|
||||
#if IS_ENABLED(CONFIG_MPTCP)
|
||||
bool is_mptcp;
|
||||
#endif
|
||||
u32 txhash;
|
||||
u32 rcv_isn;
|
||||
u32 snt_isn;
|
||||
|
@ -349,6 +349,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
|
||||
req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
|
||||
treq->snt_synack = 0;
|
||||
treq->tfo_listener = false;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MPTCP))
|
||||
treq->is_mptcp = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SMC))
|
||||
ireq->smc_ok = 0;
|
||||
|
||||
|
@ -6637,6 +6637,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
|
||||
|
||||
af_ops->init_req(req, sk, skb);
|
||||
|
||||
if (IS_ENABLED(CONFIG_MPTCP) && want_cookie)
|
||||
tcp_rsk(req)->is_mptcp = 0;
|
||||
|
||||
if (security_inet_conn_request(sk, skb, req))
|
||||
goto drop_and_free;
|
||||
|
||||
|
@ -178,6 +178,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
|
||||
treq = tcp_rsk(req);
|
||||
treq->tfo_listener = false;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MPTCP))
|
||||
treq->is_mptcp = 0;
|
||||
|
||||
if (security_inet_conn_request(sk, skb, req))
|
||||
goto out_free;
|
||||
|
||||
|
@ -644,19 +644,21 @@ static void __mptcp_close(struct sock *sk, long timeout)
|
||||
{
|
||||
struct mptcp_subflow_context *subflow, *tmp;
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
LIST_HEAD(conn_list);
|
||||
|
||||
mptcp_token_destroy(msk->token);
|
||||
inet_sk_state_store(sk, TCP_CLOSE);
|
||||
|
||||
list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
|
||||
list_splice_init(&msk->conn_list, &conn_list);
|
||||
|
||||
release_sock(sk);
|
||||
|
||||
list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
|
||||
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
|
||||
|
||||
__mptcp_close_ssk(sk, ssk, subflow, timeout);
|
||||
}
|
||||
|
||||
if (msk->cached_ext)
|
||||
__skb_ext_put(msk->cached_ext);
|
||||
release_sock(sk);
|
||||
sk_common_release(sk);
|
||||
}
|
||||
|
||||
@ -776,18 +778,19 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
|
||||
|
||||
static void mptcp_destroy(struct sock *sk)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
|
||||
if (msk->cached_ext)
|
||||
__skb_ext_put(msk->cached_ext);
|
||||
}
|
||||
|
||||
static int mptcp_setsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *uoptval, unsigned int optlen)
|
||||
char __user *optval, unsigned int optlen)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
char __kernel *optval;
|
||||
int ret = -EOPNOTSUPP;
|
||||
struct socket *ssock;
|
||||
|
||||
/* will be treated as __user in tcp_setsockopt */
|
||||
optval = (char __kernel __force *)uoptval;
|
||||
struct sock *ssk;
|
||||
|
||||
pr_debug("msk=%p", msk);
|
||||
|
||||
@ -796,27 +799,28 @@ static int mptcp_setsockopt(struct sock *sk, int level, int optname,
|
||||
*/
|
||||
lock_sock(sk);
|
||||
ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE);
|
||||
if (!IS_ERR(ssock)) {
|
||||
pr_debug("subflow=%p", ssock->sk);
|
||||
ret = kernel_setsockopt(ssock, level, optname, optval, optlen);
|
||||
if (IS_ERR(ssock)) {
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssk = ssock->sk;
|
||||
sock_hold(ssk);
|
||||
release_sock(sk);
|
||||
|
||||
ret = tcp_setsockopt(ssk, level, optname, optval, optlen);
|
||||
sock_put(ssk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mptcp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *uoptval, int __user *uoption)
|
||||
char __user *optval, int __user *option)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
char __kernel *optval;
|
||||
int ret = -EOPNOTSUPP;
|
||||
int __kernel *option;
|
||||
struct socket *ssock;
|
||||
|
||||
/* will be treated as __user in tcp_getsockopt */
|
||||
optval = (char __kernel __force *)uoptval;
|
||||
option = (int __kernel __force *)uoption;
|
||||
struct sock *ssk;
|
||||
|
||||
pr_debug("msk=%p", msk);
|
||||
|
||||
@ -825,12 +829,18 @@ static int mptcp_getsockopt(struct sock *sk, int level, int optname,
|
||||
*/
|
||||
lock_sock(sk);
|
||||
ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE);
|
||||
if (!IS_ERR(ssock)) {
|
||||
pr_debug("subflow=%p", ssock->sk);
|
||||
ret = kernel_getsockopt(ssock, level, optname, optval, option);
|
||||
if (IS_ERR(ssock)) {
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssk = ssock->sk;
|
||||
sock_hold(ssk);
|
||||
release_sock(sk);
|
||||
|
||||
ret = tcp_getsockopt(ssk, level, optname, optval, option);
|
||||
sock_put(ssk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -186,6 +186,9 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
|
||||
|
||||
pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn);
|
||||
|
||||
if (tcp_rsk(req)->is_mptcp == 0)
|
||||
goto create_child;
|
||||
|
||||
/* if the sk is MP_CAPABLE, we try to fetch the client key */
|
||||
subflow_req = mptcp_subflow_rsk(req);
|
||||
if (subflow_req->mp_capable) {
|
||||
@ -769,7 +772,7 @@ static void subflow_ulp_clone(const struct request_sock *req,
|
||||
struct mptcp_subflow_context *old_ctx = mptcp_subflow_ctx(newsk);
|
||||
struct mptcp_subflow_context *new_ctx;
|
||||
|
||||
if (!subflow_req->mp_capable) {
|
||||
if (!tcp_rsk(req)->is_mptcp || !subflow_req->mp_capable) {
|
||||
subflow_ulp_fallback(newsk, old_ctx);
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user