linux-can-fixes-for-5.4-20191113
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEmvEkXzgOfc881GuFWsYho5HknSAFAl3L0SETHG1rbEBwZW5n dXRyb25peC5kZQAKCRBaxiGjkeSdIBReCACawwJlue5MIbawq+JD8wQ+RE117kJc x6z2QFEynNchywthMRfaCSj+QP0n5C4JY6BHtn7LMT2JOrPVzQAwz2cZ4eUPinUA eSd0/0ZqoBH+IZW4c3sYNkrGSi47qIytGi3jgbfNbZj4mIYBCikLDhLhWVk9+rTp HZiqS2vWUaZ42bKvbHE2CHTV/oPdz/3wJIQmctkyoFvxKcJM1WyI6y7QSJ/VJWv1 bpX4dymK4qgnGHGyiOcoeRmaDFOg53gDTRfIQZoc++5/dlczov7eA48XedrzQUV7 qGR4j6BjZrxloQsS3Y4ynTRC+x5aE+jajEaf3QEKrO7VCRS6jdV1bX2E =13Km -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-5.4-20191113' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2019-11-13 this is a pull request of 9 patches for net/master, hopefully for the v5.4 release cycle. All nine patches are by Oleksij Rempel and fix locking and use-after-free bugs in the j1939 stack found by the syzkaller syzbot. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b3dff0eb4b
|
@ -65,5 +65,6 @@ extern void can_rx_unregister(struct net *net, struct net_device *dev,
|
|||
void *data);
|
||||
|
||||
extern int can_send(struct sk_buff *skb, int loop);
|
||||
void can_sock_destruct(struct sock *sk);
|
||||
|
||||
#endif /* !_CAN_CORE_H */
|
||||
|
|
|
@ -86,11 +86,12 @@ static atomic_t skbcounter = ATOMIC_INIT(0);
|
|||
|
||||
/* af_can socket functions */
|
||||
|
||||
static void can_sock_destruct(struct sock *sk)
|
||||
void can_sock_destruct(struct sock *sk)
|
||||
{
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
skb_queue_purge(&sk->sk_error_queue);
|
||||
}
|
||||
EXPORT_SYMBOL(can_sock_destruct);
|
||||
|
||||
static const struct can_proto *can_get_proto(int protocol)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data)
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
j1939_priv_get(priv);
|
||||
can_skb_set_owner(skb, iskb->sk);
|
||||
|
||||
/* get a pointer to the header of the skb
|
||||
|
@ -104,6 +105,7 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data)
|
|||
j1939_simple_recv(priv, skb);
|
||||
j1939_sk_recv(priv, skb);
|
||||
done:
|
||||
j1939_priv_put(priv);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
@ -150,6 +152,10 @@ static void __j1939_priv_release(struct kref *kref)
|
|||
|
||||
netdev_dbg(priv->ndev, "%s: 0x%p\n", __func__, priv);
|
||||
|
||||
WARN_ON_ONCE(!list_empty(&priv->active_session_list));
|
||||
WARN_ON_ONCE(!list_empty(&priv->ecus));
|
||||
WARN_ON_ONCE(!list_empty(&priv->j1939_socks));
|
||||
|
||||
dev_put(ndev);
|
||||
kfree(priv);
|
||||
}
|
||||
|
@ -207,6 +213,9 @@ static inline struct j1939_priv *j1939_ndev_to_priv(struct net_device *ndev)
|
|||
{
|
||||
struct can_ml_priv *can_ml_priv = ndev->ml_priv;
|
||||
|
||||
if (!can_ml_priv)
|
||||
return NULL;
|
||||
|
||||
return can_ml_priv->j1939_priv;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ static void j1939_jsk_add(struct j1939_priv *priv, struct j1939_sock *jsk)
|
|||
{
|
||||
jsk->state |= J1939_SOCK_BOUND;
|
||||
j1939_priv_get(priv);
|
||||
jsk->priv = priv;
|
||||
|
||||
spin_lock_bh(&priv->j1939_socks_lock);
|
||||
list_add_tail(&jsk->list, &priv->j1939_socks);
|
||||
|
@ -91,7 +90,6 @@ static void j1939_jsk_del(struct j1939_priv *priv, struct j1939_sock *jsk)
|
|||
list_del_init(&jsk->list);
|
||||
spin_unlock_bh(&priv->j1939_socks_lock);
|
||||
|
||||
jsk->priv = NULL;
|
||||
j1939_priv_put(priv);
|
||||
jsk->state &= ~J1939_SOCK_BOUND;
|
||||
}
|
||||
|
@ -349,6 +347,34 @@ void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb)
|
|||
spin_unlock_bh(&priv->j1939_socks_lock);
|
||||
}
|
||||
|
||||
static void j1939_sk_sock_destruct(struct sock *sk)
|
||||
{
|
||||
struct j1939_sock *jsk = j1939_sk(sk);
|
||||
|
||||
/* This function will be call by the generic networking code, when then
|
||||
* the socket is ultimately closed (sk->sk_destruct).
|
||||
*
|
||||
* The race between
|
||||
* - processing a received CAN frame
|
||||
* (can_receive -> j1939_can_recv)
|
||||
* and accessing j1939_priv
|
||||
* ... and ...
|
||||
* - closing a socket
|
||||
* (j1939_can_rx_unregister -> can_rx_unregister)
|
||||
* and calling the final j1939_priv_put()
|
||||
*
|
||||
* is avoided by calling the final j1939_priv_put() from this
|
||||
* RCU deferred cleanup call.
|
||||
*/
|
||||
if (jsk->priv) {
|
||||
j1939_priv_put(jsk->priv);
|
||||
jsk->priv = NULL;
|
||||
}
|
||||
|
||||
/* call generic CAN sock destruct */
|
||||
can_sock_destruct(sk);
|
||||
}
|
||||
|
||||
static int j1939_sk_init(struct sock *sk)
|
||||
{
|
||||
struct j1939_sock *jsk = j1939_sk(sk);
|
||||
|
@ -371,6 +397,7 @@ static int j1939_sk_init(struct sock *sk)
|
|||
atomic_set(&jsk->skb_pending, 0);
|
||||
spin_lock_init(&jsk->sk_session_queue_lock);
|
||||
INIT_LIST_HEAD(&jsk->sk_session_queue);
|
||||
sk->sk_destruct = j1939_sk_sock_destruct;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -443,6 +470,12 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
|||
}
|
||||
|
||||
jsk->ifindex = addr->can_ifindex;
|
||||
|
||||
/* the corresponding j1939_priv_put() is called via
|
||||
* sk->sk_destruct, which points to j1939_sk_sock_destruct()
|
||||
*/
|
||||
j1939_priv_get(priv);
|
||||
jsk->priv = priv;
|
||||
}
|
||||
|
||||
/* set default transmit pgn */
|
||||
|
@ -560,8 +593,8 @@ static int j1939_sk_release(struct socket *sock)
|
|||
if (!sk)
|
||||
return 0;
|
||||
|
||||
jsk = j1939_sk(sk);
|
||||
lock_sock(sk);
|
||||
jsk = j1939_sk(sk);
|
||||
|
||||
if (jsk->state & J1939_SOCK_BOUND) {
|
||||
struct j1939_priv *priv = jsk->priv;
|
||||
|
@ -1059,51 +1092,72 @@ static int j1939_sk_sendmsg(struct socket *sock, struct msghdr *msg,
|
|||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct j1939_sock *jsk = j1939_sk(sk);
|
||||
struct j1939_priv *priv = jsk->priv;
|
||||
struct j1939_priv *priv;
|
||||
int ifindex;
|
||||
int ret;
|
||||
|
||||
lock_sock(sock->sk);
|
||||
/* various socket state tests */
|
||||
if (!(jsk->state & J1939_SOCK_BOUND))
|
||||
return -EBADFD;
|
||||
if (!(jsk->state & J1939_SOCK_BOUND)) {
|
||||
ret = -EBADFD;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
|
||||
priv = jsk->priv;
|
||||
ifindex = jsk->ifindex;
|
||||
|
||||
if (!jsk->addr.src_name && jsk->addr.sa == J1939_NO_ADDR)
|
||||
if (!jsk->addr.src_name && jsk->addr.sa == J1939_NO_ADDR) {
|
||||
/* no source address assigned yet */
|
||||
return -EBADFD;
|
||||
ret = -EBADFD;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
|
||||
/* deal with provided destination address info */
|
||||
if (msg->msg_name) {
|
||||
struct sockaddr_can *addr = msg->msg_name;
|
||||
|
||||
if (msg->msg_namelen < J1939_MIN_NAMELEN)
|
||||
return -EINVAL;
|
||||
if (msg->msg_namelen < J1939_MIN_NAMELEN) {
|
||||
ret = -EINVAL;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
|
||||
if (addr->can_family != AF_CAN)
|
||||
return -EINVAL;
|
||||
if (addr->can_family != AF_CAN) {
|
||||
ret = -EINVAL;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
|
||||
if (addr->can_ifindex && addr->can_ifindex != ifindex)
|
||||
return -EBADFD;
|
||||
if (addr->can_ifindex && addr->can_ifindex != ifindex) {
|
||||
ret = -EBADFD;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
|
||||
if (j1939_pgn_is_valid(addr->can_addr.j1939.pgn) &&
|
||||
!j1939_pgn_is_clean_pdu(addr->can_addr.j1939.pgn))
|
||||
return -EINVAL;
|
||||
!j1939_pgn_is_clean_pdu(addr->can_addr.j1939.pgn)) {
|
||||
ret = -EINVAL;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
|
||||
if (!addr->can_addr.j1939.name &&
|
||||
addr->can_addr.j1939.addr == J1939_NO_ADDR &&
|
||||
!sock_flag(sk, SOCK_BROADCAST))
|
||||
!sock_flag(sk, SOCK_BROADCAST)) {
|
||||
/* broadcast, but SO_BROADCAST not set */
|
||||
return -EACCES;
|
||||
ret = -EACCES;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
} else {
|
||||
if (!jsk->addr.dst_name && jsk->addr.da == J1939_NO_ADDR &&
|
||||
!sock_flag(sk, SOCK_BROADCAST))
|
||||
!sock_flag(sk, SOCK_BROADCAST)) {
|
||||
/* broadcast, but SO_BROADCAST not set */
|
||||
return -EACCES;
|
||||
ret = -EACCES;
|
||||
goto sendmsg_done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = j1939_sk_send_loop(priv, sk, msg, size);
|
||||
|
||||
sendmsg_done:
|
||||
release_sock(sock->sk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -255,6 +255,7 @@ static void __j1939_session_drop(struct j1939_session *session)
|
|||
return;
|
||||
|
||||
j1939_sock_pending_del(session->sk);
|
||||
sock_put(session->sk);
|
||||
}
|
||||
|
||||
static void j1939_session_destroy(struct j1939_session *session)
|
||||
|
@ -266,6 +267,9 @@ static void j1939_session_destroy(struct j1939_session *session)
|
|||
|
||||
netdev_dbg(session->priv->ndev, "%s: 0x%p\n", __func__, session);
|
||||
|
||||
WARN_ON_ONCE(!list_empty(&session->sk_session_queue_entry));
|
||||
WARN_ON_ONCE(!list_empty(&session->active_session_list_entry));
|
||||
|
||||
skb_queue_purge(&session->skb_queue);
|
||||
__j1939_session_drop(session);
|
||||
j1939_priv_put(session->priv);
|
||||
|
@ -1042,12 +1046,13 @@ j1939_session_deactivate_activate_next(struct j1939_session *session)
|
|||
j1939_sk_queue_activate_next(session);
|
||||
}
|
||||
|
||||
static void j1939_session_cancel(struct j1939_session *session,
|
||||
static void __j1939_session_cancel(struct j1939_session *session,
|
||||
enum j1939_xtp_abort err)
|
||||
{
|
||||
struct j1939_priv *priv = session->priv;
|
||||
|
||||
WARN_ON_ONCE(!err);
|
||||
lockdep_assert_held(&session->priv->active_session_list_lock);
|
||||
|
||||
session->err = j1939_xtp_abort_to_errno(priv, err);
|
||||
/* do not send aborts on incoming broadcasts */
|
||||
|
@ -1062,6 +1067,20 @@ static void j1939_session_cancel(struct j1939_session *session,
|
|||
j1939_sk_send_loop_abort(session->sk, session->err);
|
||||
}
|
||||
|
||||
static void j1939_session_cancel(struct j1939_session *session,
|
||||
enum j1939_xtp_abort err)
|
||||
{
|
||||
j1939_session_list_lock(session->priv);
|
||||
|
||||
if (session->state >= J1939_SESSION_ACTIVE &&
|
||||
session->state < J1939_SESSION_WAITING_ABORT) {
|
||||
j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS);
|
||||
__j1939_session_cancel(session, err);
|
||||
}
|
||||
|
||||
j1939_session_list_unlock(session->priv);
|
||||
}
|
||||
|
||||
static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
|
||||
{
|
||||
struct j1939_session *session =
|
||||
|
@ -1108,8 +1127,6 @@ static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
|
|||
netdev_alert(priv->ndev, "%s: 0x%p: tx aborted with unknown reason: %i\n",
|
||||
__func__, session, ret);
|
||||
if (session->skcb.addr.type != J1939_SIMPLE) {
|
||||
j1939_tp_set_rxtimeout(session,
|
||||
J1939_XTP_ABORT_TIMEOUT_MS);
|
||||
j1939_session_cancel(session, J1939_XTP_ABORT_OTHER);
|
||||
} else {
|
||||
session->err = ret;
|
||||
|
@ -1169,7 +1186,7 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer)
|
|||
hrtimer_start(&session->rxtimer,
|
||||
ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS),
|
||||
HRTIMER_MODE_REL_SOFT);
|
||||
j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT);
|
||||
__j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT);
|
||||
}
|
||||
j1939_session_list_unlock(session->priv);
|
||||
}
|
||||
|
@ -1375,7 +1392,6 @@ j1939_xtp_rx_cts_one(struct j1939_session *session, struct sk_buff *skb)
|
|||
|
||||
out_session_cancel:
|
||||
j1939_session_timers_cancel(session);
|
||||
j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS);
|
||||
j1939_session_cancel(session, err);
|
||||
}
|
||||
|
||||
|
@ -1572,7 +1588,6 @@ static int j1939_xtp_rx_rts_session_active(struct j1939_session *session,
|
|||
|
||||
/* RTS on active session */
|
||||
j1939_session_timers_cancel(session);
|
||||
j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS);
|
||||
j1939_session_cancel(session, J1939_XTP_ABORT_BUSY);
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1598,6 @@ static int j1939_xtp_rx_rts_session_active(struct j1939_session *session,
|
|||
session->last_cmd);
|
||||
|
||||
j1939_session_timers_cancel(session);
|
||||
j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS);
|
||||
j1939_session_cancel(session, J1939_XTP_ABORT_BUSY);
|
||||
|
||||
return -EBUSY;
|
||||
|
@ -1785,7 +1799,6 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
|
|||
|
||||
out_session_cancel:
|
||||
j1939_session_timers_cancel(session);
|
||||
j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS);
|
||||
j1939_session_cancel(session, J1939_XTP_ABORT_FAULT);
|
||||
j1939_session_put(session);
|
||||
}
|
||||
|
@ -1866,6 +1879,7 @@ struct j1939_session *j1939_tp_send(struct j1939_priv *priv,
|
|||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* skb is recounted in j1939_session_new() */
|
||||
sock_hold(skb->sk);
|
||||
session->sk = skb->sk;
|
||||
session->transmission = true;
|
||||
session->pkt.total = (size + 6) / 7;
|
||||
|
@ -2028,7 +2042,11 @@ int j1939_cancel_active_session(struct j1939_priv *priv, struct sock *sk)
|
|||
&priv->active_session_list,
|
||||
active_session_list_entry) {
|
||||
if (!sk || sk == session->sk) {
|
||||
j1939_session_timers_cancel(session);
|
||||
if (hrtimer_try_to_cancel(&session->txtimer) == 1)
|
||||
j1939_session_put(session);
|
||||
if (hrtimer_try_to_cancel(&session->rxtimer) == 1)
|
||||
j1939_session_put(session);
|
||||
|
||||
session->err = ESHUTDOWN;
|
||||
j1939_session_deactivate_locked(session);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue