2010-04-02 14:18:33 +08:00
|
|
|
/*
|
|
|
|
* L2TP internal definitions.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2008,2009 Katalix Systems Ltd
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
2017-07-04 20:52:57 +08:00
|
|
|
#include <linux/refcount.h>
|
2010-04-02 14:18:33 +08:00
|
|
|
|
|
|
|
#ifndef _L2TP_CORE_H_
|
|
|
|
#define _L2TP_CORE_H_
|
|
|
|
|
|
|
|
/* Just some random numbers */
|
|
|
|
#define L2TP_TUNNEL_MAGIC 0x42114DDA
|
|
|
|
#define L2TP_SESSION_MAGIC 0x0C04EB7D
|
|
|
|
|
2010-04-02 14:18:49 +08:00
|
|
|
/* Per tunnel, session hash table size */
|
2010-04-02 14:18:33 +08:00
|
|
|
#define L2TP_HASH_BITS 4
|
|
|
|
#define L2TP_HASH_SIZE (1 << L2TP_HASH_BITS)
|
|
|
|
|
2010-04-02 14:18:49 +08:00
|
|
|
/* System-wide, session hash table size */
|
|
|
|
#define L2TP_HASH_BITS_2 8
|
|
|
|
#define L2TP_HASH_SIZE_2 (1 << L2TP_HASH_BITS_2)
|
|
|
|
|
2010-04-02 14:18:33 +08:00
|
|
|
struct sk_buff;
|
|
|
|
|
|
|
|
struct l2tp_stats {
|
2013-03-19 14:11:22 +08:00
|
|
|
atomic_long_t tx_packets;
|
|
|
|
atomic_long_t tx_bytes;
|
|
|
|
atomic_long_t tx_errors;
|
|
|
|
atomic_long_t rx_packets;
|
|
|
|
atomic_long_t rx_bytes;
|
|
|
|
atomic_long_t rx_seq_discards;
|
|
|
|
atomic_long_t rx_oos_packets;
|
|
|
|
atomic_long_t rx_errors;
|
|
|
|
atomic_long_t rx_cookie_discards;
|
2010-04-02 14:18:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct l2tp_tunnel;
|
|
|
|
|
|
|
|
/* Describes a session. Contains information to determine incoming
|
|
|
|
* packets and transmit outgoing ones.
|
|
|
|
*/
|
|
|
|
struct l2tp_session_cfg {
|
2010-04-02 14:18:49 +08:00
|
|
|
enum l2tp_pwtype pw_type;
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int data_seq:2; /* data sequencing level
|
2010-04-02 14:18:33 +08:00
|
|
|
* 0 => none, 1 => IP only,
|
|
|
|
* 2 => all
|
|
|
|
*/
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int recv_seq:1; /* expect receive packets with
|
2010-04-02 14:18:33 +08:00
|
|
|
* sequence numbers? */
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int send_seq:1; /* send packets with sequence
|
2010-04-02 14:18:33 +08:00
|
|
|
* numbers? */
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int lns_mode:1; /* behave as LNS? LAC enables
|
2010-04-02 14:18:33 +08:00
|
|
|
* sequence numbers under
|
|
|
|
* control of LNS. */
|
|
|
|
int debug; /* bitmask of debug message
|
|
|
|
* categories */
|
2010-04-02 14:19:10 +08:00
|
|
|
u16 vlan_id; /* VLAN pseudowire only */
|
2010-04-02 14:18:49 +08:00
|
|
|
u16 l2specific_type; /* Layer 2 specific type */
|
|
|
|
u8 cookie[8]; /* optional cookie */
|
|
|
|
int cookie_len; /* 0, 4 or 8 bytes */
|
|
|
|
u8 peer_cookie[8]; /* peer's cookie */
|
|
|
|
int peer_cookie_len; /* 0, 4 or 8 bytes */
|
2010-04-02 14:18:33 +08:00
|
|
|
int reorder_timeout; /* configured reorder timeout
|
|
|
|
* (in jiffies) */
|
|
|
|
int mtu;
|
|
|
|
int mru;
|
2010-04-02 14:19:10 +08:00
|
|
|
char *ifname;
|
2010-04-02 14:18:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct l2tp_session {
|
|
|
|
int magic; /* should be
|
|
|
|
* L2TP_SESSION_MAGIC */
|
l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
There are several ways to remove L2TP sessions:
* deleting a session explicitly using the netlink interface (with
L2TP_CMD_SESSION_DELETE),
* deleting the session's parent tunnel (either by closing the
tunnel's file descriptor or using the netlink interface),
* closing the PPPOL2TP file descriptor of a PPP pseudo-wire.
In some cases, when these methods are used concurrently on the same
session, the session can be removed twice, leading to use-after-free
bugs.
This patch adds a 'dead' flag, used by l2tp_session_delete() and
l2tp_tunnel_closeall() to prevent them from stepping on each other's
toes.
The session deletion path used when closing a PPPOL2TP file descriptor
doesn't need to be adapted. It already has to ensure that a session
remains valid for the lifetime of its PPPOL2TP file descriptor.
So it takes an extra reference on the session in the ->session_close()
callback (pppol2tp_session_close()), which is eventually dropped
in the ->sk_destruct() callback of the PPPOL2TP socket
(pppol2tp_session_destruct()).
Still, __l2tp_session_unhash() and l2tp_session_queue_purge() can be
called twice and even concurrently for a given session, but thanks to
proper locking and re-initialisation of list fields, this is not an
issue.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-22 21:39:24 +08:00
|
|
|
long dead;
|
2010-04-02 14:18:33 +08:00
|
|
|
|
|
|
|
struct l2tp_tunnel *tunnel; /* back pointer to tunnel
|
|
|
|
* context */
|
|
|
|
u32 session_id;
|
|
|
|
u32 peer_session_id;
|
2010-04-02 14:18:49 +08:00
|
|
|
u8 cookie[8];
|
|
|
|
int cookie_len;
|
|
|
|
u8 peer_cookie[8];
|
|
|
|
int peer_cookie_len;
|
|
|
|
u16 l2specific_type;
|
|
|
|
u16 hdr_len;
|
|
|
|
u32 nr; /* session NR state (receive) */
|
|
|
|
u32 ns; /* session NR state (send) */
|
2010-04-02 14:18:33 +08:00
|
|
|
struct sk_buff_head reorder_q; /* receive reorder queue */
|
2013-07-03 03:28:59 +08:00
|
|
|
u32 nr_max; /* max NR. Depends on tunnel */
|
|
|
|
u32 nr_window_size; /* NR window size */
|
2013-07-03 03:29:00 +08:00
|
|
|
u32 nr_oos; /* NR of last OOS packet */
|
|
|
|
int nr_oos_count; /* For OOS recovery */
|
|
|
|
int nr_oos_count_max;
|
2010-04-02 14:18:33 +08:00
|
|
|
struct hlist_node hlist; /* Hash list node */
|
2017-07-04 20:52:58 +08:00
|
|
|
refcount_t ref_count;
|
2010-04-02 14:18:33 +08:00
|
|
|
|
|
|
|
char name[32]; /* for logging */
|
2010-04-02 14:19:10 +08:00
|
|
|
char ifname[IFNAMSIZ];
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int data_seq:2; /* data sequencing level
|
2010-04-02 14:18:33 +08:00
|
|
|
* 0 => none, 1 => IP only,
|
|
|
|
* 2 => all
|
|
|
|
*/
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int recv_seq:1; /* expect receive packets with
|
2010-04-02 14:18:33 +08:00
|
|
|
* sequence numbers? */
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int send_seq:1; /* send packets with sequence
|
2010-04-02 14:18:33 +08:00
|
|
|
* numbers? */
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int lns_mode:1; /* behave as LNS? LAC enables
|
2010-04-02 14:18:33 +08:00
|
|
|
* sequence numbers under
|
|
|
|
* control of LNS. */
|
|
|
|
int debug; /* bitmask of debug message
|
|
|
|
* categories */
|
|
|
|
int reorder_timeout; /* configured reorder timeout
|
|
|
|
* (in jiffies) */
|
2012-05-10 07:43:08 +08:00
|
|
|
int reorder_skip; /* set if skip to next nr */
|
2010-04-02 14:18:33 +08:00
|
|
|
int mtu;
|
|
|
|
int mru;
|
2010-04-02 14:18:49 +08:00
|
|
|
enum l2tp_pwtype pwtype;
|
2010-04-02 14:18:33 +08:00
|
|
|
struct l2tp_stats stats;
|
2010-04-02 14:18:49 +08:00
|
|
|
struct hlist_node global_hlist; /* Global hash list node */
|
2010-04-02 14:18:33 +08:00
|
|
|
|
2010-04-02 14:18:49 +08:00
|
|
|
int (*build_header)(struct l2tp_session *session, void *buf);
|
2010-04-02 14:18:33 +08:00
|
|
|
void (*recv_skb)(struct l2tp_session *session, struct sk_buff *skb, int data_len);
|
|
|
|
void (*session_close)(struct l2tp_session *session);
|
2016-09-09 20:43:17 +08:00
|
|
|
#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
|
2010-04-02 14:19:33 +08:00
|
|
|
void (*show)(struct seq_file *m, void *priv);
|
|
|
|
#endif
|
2010-04-02 14:18:33 +08:00
|
|
|
uint8_t priv[0]; /* private data */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Describes the tunnel. It contains info to track all the associated
|
|
|
|
* sessions so incoming packets can be sorted out
|
|
|
|
*/
|
|
|
|
struct l2tp_tunnel_cfg {
|
|
|
|
int debug; /* bitmask of debug message
|
|
|
|
* categories */
|
2010-04-02 14:19:00 +08:00
|
|
|
enum l2tp_encap_type encap;
|
2010-04-02 14:19:40 +08:00
|
|
|
|
|
|
|
/* Used only for kernel-created sockets */
|
|
|
|
struct in_addr local_ip;
|
|
|
|
struct in_addr peer_ip;
|
2012-04-30 05:48:52 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
|
struct in6_addr *local_ip6;
|
|
|
|
struct in6_addr *peer_ip6;
|
|
|
|
#endif
|
2010-04-02 14:19:40 +08:00
|
|
|
u16 local_udp_port;
|
|
|
|
u16 peer_udp_port;
|
2014-05-23 23:47:40 +08:00
|
|
|
unsigned int use_udp_checksums:1,
|
|
|
|
udp6_zero_tx_checksums:1,
|
|
|
|
udp6_zero_rx_checksums:1;
|
2010-04-02 14:18:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct l2tp_tunnel {
|
|
|
|
int magic; /* Should be L2TP_TUNNEL_MAGIC */
|
2017-09-26 22:16:43 +08:00
|
|
|
|
|
|
|
unsigned long dead;
|
|
|
|
|
2012-08-24 09:07:38 +08:00
|
|
|
struct rcu_head rcu;
|
2010-04-02 14:18:33 +08:00
|
|
|
rwlock_t hlist_lock; /* protect session_hlist */
|
2017-09-01 23:58:48 +08:00
|
|
|
bool acpt_newsess; /* Indicates whether this
|
|
|
|
* tunnel accepts new sessions.
|
|
|
|
* Protected by hlist_lock.
|
|
|
|
*/
|
2010-04-02 14:18:33 +08:00
|
|
|
struct hlist_head session_hlist[L2TP_HASH_SIZE];
|
|
|
|
/* hashed list of sessions,
|
|
|
|
* hashed by id */
|
|
|
|
u32 tunnel_id;
|
|
|
|
u32 peer_tunnel_id;
|
|
|
|
int version; /* 2=>L2TPv2, 3=>L2TPv3 */
|
|
|
|
|
|
|
|
char name[20]; /* for logging */
|
|
|
|
int debug; /* bitmask of debug message
|
|
|
|
* categories */
|
2010-04-02 14:19:00 +08:00
|
|
|
enum l2tp_encap_type encap;
|
2010-04-02 14:18:33 +08:00
|
|
|
struct l2tp_stats stats;
|
|
|
|
|
|
|
|
struct list_head list; /* Keep a list of all tunnels */
|
|
|
|
struct net *l2tp_net; /* the net we belong to */
|
|
|
|
|
2017-07-04 20:52:57 +08:00
|
|
|
refcount_t ref_count;
|
2010-04-02 14:19:33 +08:00
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
void (*show)(struct seq_file *m, void *arg);
|
|
|
|
#endif
|
2010-04-02 14:18:33 +08:00
|
|
|
int (*recv_payload_hook)(struct sk_buff *skb);
|
|
|
|
void (*old_sk_destruct)(struct sock *);
|
|
|
|
struct sock *sock; /* Parent socket */
|
2013-01-22 13:13:48 +08:00
|
|
|
int fd; /* Parent fd, if tunnel socket
|
|
|
|
* was created by userspace */
|
2010-04-02 14:18:33 +08:00
|
|
|
|
2013-02-01 07:43:00 +08:00
|
|
|
struct work_struct del_work;
|
|
|
|
|
2010-04-02 14:18:33 +08:00
|
|
|
uint8_t priv[0]; /* private data */
|
|
|
|
};
|
|
|
|
|
2010-04-02 14:19:10 +08:00
|
|
|
struct l2tp_nl_cmd_ops {
|
2017-09-01 23:58:51 +08:00
|
|
|
int (*session_create)(struct net *net, struct l2tp_tunnel *tunnel,
|
|
|
|
u32 session_id, u32 peer_session_id,
|
|
|
|
struct l2tp_session_cfg *cfg);
|
2010-04-02 14:19:10 +08:00
|
|
|
int (*session_delete)(struct l2tp_session *session);
|
|
|
|
};
|
|
|
|
|
2010-04-02 14:18:33 +08:00
|
|
|
static inline void *l2tp_tunnel_priv(struct l2tp_tunnel *tunnel)
|
|
|
|
{
|
|
|
|
return &tunnel->priv[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void *l2tp_session_priv(struct l2tp_session *session)
|
|
|
|
{
|
|
|
|
return &session->priv[0];
|
|
|
|
}
|
|
|
|
|
2017-08-25 22:51:40 +08:00
|
|
|
struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
|
2018-04-13 02:50:33 +08:00
|
|
|
struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth);
|
|
|
|
|
l2tp: fix races with tunnel socket close
The tunnel socket tunnel->sock (struct sock) is accessed when
preparing a new ppp session on a tunnel at pppol2tp_session_init. If
the socket is closed by a thread while another is creating a new
session, the threads race. In pppol2tp_connect, the tunnel object may
be created if the pppol2tp socket is associated with the special
session_id 0 and the tunnel socket is looked up using the provided
fd. When handling this, pppol2tp_connect cannot sock_hold the tunnel
socket to prevent it being destroyed during pppol2tp_connect since
this may itself may race with the socket being destroyed. Doing
sockfd_lookup in pppol2tp_connect isn't sufficient to prevent
tunnel->sock going away either because a given tunnel socket fd may be
reused between calls to pppol2tp_connect. Instead, have
l2tp_tunnel_create sock_hold the tunnel socket before it does
sockfd_put. This ensures that the tunnel's socket is always extant
while the tunnel object exists. Hold a ref on the socket until the
tunnel is destroyed and ensure that all tunnel destroy paths go
through a common function (l2tp_tunnel_delete) since this will do the
final sock_put to release the tunnel socket.
Since the tunnel's socket is now guaranteed to exist if the tunnel
exists, we no longer need to use sockfd_lookup via l2tp_sock_to_tunnel
to derive the tunnel from the socket since this is always
sk_user_data.
Also, sessions no longer sock_hold the tunnel socket since sessions
already hold a tunnel ref and the tunnel sock will not be freed until
the tunnel is freed. Removing these sock_holds in
l2tp_session_register avoids a possible sock leak in the
pppol2tp_connect error path if l2tp_session_register succeeds but
attaching a ppp channel fails. The pppol2tp_connect error path could
have been fixed instead and have the sock ref dropped when the session
is freed, but doing a sock_put of the tunnel socket when the session
is freed would require a new session_free callback. It is simpler to
just remove the sock_hold of the tunnel socket in
l2tp_session_register, now that the tunnel socket lifetime is
guaranteed.
Finally, some init code in l2tp_tunnel_create is reordered to ensure
that the new tunnel object's refcount is set and the tunnel socket ref
is taken before the tunnel socket destructor callbacks are set.
kasan: CONFIG_KASAN_INLINE enabled
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] SMP KASAN
Modules linked in:
CPU: 0 PID: 4360 Comm: syzbot_19c09769 Not tainted 4.16.0-rc2+ #34
Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
RIP: 0010:pppol2tp_session_init+0x1d6/0x500
RSP: 0018:ffff88001377fb40 EFLAGS: 00010212
RAX: dffffc0000000000 RBX: ffff88001636a940 RCX: ffffffff84836c1d
RDX: 0000000000000045 RSI: 0000000055976744 RDI: 0000000000000228
RBP: ffff88001377fb60 R08: ffffffff84836bc8 R09: 0000000000000002
R10: ffff88001377fab8 R11: 0000000000000001 R12: 0000000000000000
R13: ffff88001636aac8 R14: ffff8800160f81c0 R15: 1ffff100026eff76
FS: 00007ffb3ea66700(0000) GS:ffff88001a400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020e77000 CR3: 0000000016261000 CR4: 00000000000006f0
Call Trace:
pppol2tp_connect+0xd18/0x13c0
? pppol2tp_session_create+0x170/0x170
? __might_fault+0x115/0x1d0
? lock_downgrade+0x860/0x860
? __might_fault+0xe5/0x1d0
? security_socket_connect+0x8e/0xc0
SYSC_connect+0x1b6/0x310
? SYSC_bind+0x280/0x280
? __do_page_fault+0x5d1/0xca0
? up_read+0x1f/0x40
? __do_page_fault+0x3c8/0xca0
SyS_connect+0x29/0x30
? SyS_accept+0x40/0x40
do_syscall_64+0x1e0/0x730
? trace_hardirqs_off_thunk+0x1a/0x1c
entry_SYSCALL_64_after_hwframe+0x42/0xb7
RIP: 0033:0x7ffb3e376259
RSP: 002b:00007ffeda4f6508 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
RAX: ffffffffffffffda RBX: 0000000020e77012 RCX: 00007ffb3e376259
RDX: 000000000000002e RSI: 0000000020e77000 RDI: 0000000000000004
RBP: 00007ffeda4f6540 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000400b60
R13: 00007ffeda4f6660 R14: 0000000000000000 R15: 0000000000000000
Code: 80 3d b0 ff 06 02 00 0f 84 07 02 00 00 e8 13 d6 db fc 49 8d bc 24 28 02 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 f
a 48 c1 ea 03 <80> 3c 02 00 0f 85 ed 02 00 00 4d 8b a4 24 28 02 00 00 e8 13 16
Fixes: 80d84ef3ff1dd ("l2tp: prevent l2tp_tunnel_delete racing with userspace close")
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-24 01:45:45 +08:00
|
|
|
void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
|
2017-08-25 22:51:40 +08:00
|
|
|
|
2017-04-12 16:05:29 +08:00
|
|
|
struct l2tp_session *l2tp_session_get(const struct net *net,
|
2017-03-31 19:02:25 +08:00
|
|
|
struct l2tp_tunnel *tunnel,
|
2017-11-01 00:36:42 +08:00
|
|
|
u32 session_id);
|
|
|
|
struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth);
|
2017-04-12 16:05:29 +08:00
|
|
|
struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
|
2017-11-01 00:36:42 +08:00
|
|
|
const char *ifname);
|
2013-10-19 04:48:25 +08:00
|
|
|
|
|
|
|
int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id,
|
|
|
|
u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg,
|
|
|
|
struct l2tp_tunnel **tunnelp);
|
l2tp: fix races in tunnel creation
l2tp_tunnel_create() inserts the new tunnel into the namespace's tunnel
list and sets the socket's ->sk_user_data field, before returning it to
the caller. Therefore, there are two ways the tunnel can be accessed
and freed, before the caller even had the opportunity to take a
reference. In practice, syzbot could crash the module by closing the
socket right after a new tunnel was returned to pppol2tp_create().
This patch moves tunnel registration out of l2tp_tunnel_create(), so
that the caller can safely hold a reference before publishing the
tunnel. This second step is done with the new l2tp_tunnel_register()
function, which is now responsible for associating the tunnel to its
socket and for inserting it into the namespace's list.
While moving the code to l2tp_tunnel_register(), a few modifications
have been done. First, the socket validation tests are done in a helper
function, for clarity. Also, modifying the socket is now done after
having inserted the tunnel to the namespace's tunnels list. This will
allow insertion to fail, without having to revert theses modifications
in the error path (a followup patch will check for duplicate tunnels
before insertion). Either the socket is a kernel socket which we
control, or it is a user-space socket for which we have a reference on
the file descriptor. In any case, the socket isn't going to be closed
from under us.
Reported-by: syzbot+fbeeb5c3b538e8545644@syzkaller.appspotmail.com
Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-04-11 03:01:12 +08:00
|
|
|
int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
|
|
|
|
struct l2tp_tunnel_cfg *cfg);
|
|
|
|
|
2013-10-19 04:48:25 +08:00
|
|
|
void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
|
2017-09-26 22:16:43 +08:00
|
|
|
void l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
|
2013-10-19 04:48:25 +08:00
|
|
|
struct l2tp_session *l2tp_session_create(int priv_size,
|
|
|
|
struct l2tp_tunnel *tunnel,
|
|
|
|
u32 session_id, u32 peer_session_id,
|
|
|
|
struct l2tp_session_cfg *cfg);
|
2017-10-27 22:51:50 +08:00
|
|
|
int l2tp_session_register(struct l2tp_session *session,
|
|
|
|
struct l2tp_tunnel *tunnel);
|
|
|
|
|
2013-10-19 04:48:25 +08:00
|
|
|
void __l2tp_session_unhash(struct l2tp_session *session);
|
|
|
|
int l2tp_session_delete(struct l2tp_session *session);
|
|
|
|
void l2tp_session_free(struct l2tp_session *session);
|
|
|
|
void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
|
|
|
|
unsigned char *ptr, unsigned char *optr, u16 hdrflags,
|
|
|
|
int length, int (*payload_hook)(struct sk_buff *skb));
|
|
|
|
int l2tp_session_queue_purge(struct l2tp_session *session);
|
|
|
|
int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
|
2014-03-06 18:14:30 +08:00
|
|
|
void l2tp_session_set_header_len(struct l2tp_session *session, int version);
|
2013-10-19 04:48:25 +08:00
|
|
|
|
|
|
|
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
|
|
|
|
int hdr_len);
|
|
|
|
|
|
|
|
int l2tp_nl_register_ops(enum l2tp_pwtype pw_type,
|
|
|
|
const struct l2tp_nl_cmd_ops *ops);
|
|
|
|
void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
|
2017-02-10 08:15:52 +08:00
|
|
|
int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
|
2010-04-02 14:19:10 +08:00
|
|
|
|
2017-08-25 22:51:40 +08:00
|
|
|
static inline void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel)
|
|
|
|
{
|
|
|
|
refcount_inc(&tunnel->ref_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel)
|
|
|
|
{
|
|
|
|
if (refcount_dec_and_test(&tunnel->ref_count))
|
l2tp: fix races with tunnel socket close
The tunnel socket tunnel->sock (struct sock) is accessed when
preparing a new ppp session on a tunnel at pppol2tp_session_init. If
the socket is closed by a thread while another is creating a new
session, the threads race. In pppol2tp_connect, the tunnel object may
be created if the pppol2tp socket is associated with the special
session_id 0 and the tunnel socket is looked up using the provided
fd. When handling this, pppol2tp_connect cannot sock_hold the tunnel
socket to prevent it being destroyed during pppol2tp_connect since
this may itself may race with the socket being destroyed. Doing
sockfd_lookup in pppol2tp_connect isn't sufficient to prevent
tunnel->sock going away either because a given tunnel socket fd may be
reused between calls to pppol2tp_connect. Instead, have
l2tp_tunnel_create sock_hold the tunnel socket before it does
sockfd_put. This ensures that the tunnel's socket is always extant
while the tunnel object exists. Hold a ref on the socket until the
tunnel is destroyed and ensure that all tunnel destroy paths go
through a common function (l2tp_tunnel_delete) since this will do the
final sock_put to release the tunnel socket.
Since the tunnel's socket is now guaranteed to exist if the tunnel
exists, we no longer need to use sockfd_lookup via l2tp_sock_to_tunnel
to derive the tunnel from the socket since this is always
sk_user_data.
Also, sessions no longer sock_hold the tunnel socket since sessions
already hold a tunnel ref and the tunnel sock will not be freed until
the tunnel is freed. Removing these sock_holds in
l2tp_session_register avoids a possible sock leak in the
pppol2tp_connect error path if l2tp_session_register succeeds but
attaching a ppp channel fails. The pppol2tp_connect error path could
have been fixed instead and have the sock ref dropped when the session
is freed, but doing a sock_put of the tunnel socket when the session
is freed would require a new session_free callback. It is simpler to
just remove the sock_hold of the tunnel socket in
l2tp_session_register, now that the tunnel socket lifetime is
guaranteed.
Finally, some init code in l2tp_tunnel_create is reordered to ensure
that the new tunnel object's refcount is set and the tunnel socket ref
is taken before the tunnel socket destructor callbacks are set.
kasan: CONFIG_KASAN_INLINE enabled
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] SMP KASAN
Modules linked in:
CPU: 0 PID: 4360 Comm: syzbot_19c09769 Not tainted 4.16.0-rc2+ #34
Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
RIP: 0010:pppol2tp_session_init+0x1d6/0x500
RSP: 0018:ffff88001377fb40 EFLAGS: 00010212
RAX: dffffc0000000000 RBX: ffff88001636a940 RCX: ffffffff84836c1d
RDX: 0000000000000045 RSI: 0000000055976744 RDI: 0000000000000228
RBP: ffff88001377fb60 R08: ffffffff84836bc8 R09: 0000000000000002
R10: ffff88001377fab8 R11: 0000000000000001 R12: 0000000000000000
R13: ffff88001636aac8 R14: ffff8800160f81c0 R15: 1ffff100026eff76
FS: 00007ffb3ea66700(0000) GS:ffff88001a400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020e77000 CR3: 0000000016261000 CR4: 00000000000006f0
Call Trace:
pppol2tp_connect+0xd18/0x13c0
? pppol2tp_session_create+0x170/0x170
? __might_fault+0x115/0x1d0
? lock_downgrade+0x860/0x860
? __might_fault+0xe5/0x1d0
? security_socket_connect+0x8e/0xc0
SYSC_connect+0x1b6/0x310
? SYSC_bind+0x280/0x280
? __do_page_fault+0x5d1/0xca0
? up_read+0x1f/0x40
? __do_page_fault+0x3c8/0xca0
SyS_connect+0x29/0x30
? SyS_accept+0x40/0x40
do_syscall_64+0x1e0/0x730
? trace_hardirqs_off_thunk+0x1a/0x1c
entry_SYSCALL_64_after_hwframe+0x42/0xb7
RIP: 0033:0x7ffb3e376259
RSP: 002b:00007ffeda4f6508 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
RAX: ffffffffffffffda RBX: 0000000020e77012 RCX: 00007ffb3e376259
RDX: 000000000000002e RSI: 0000000020e77000 RDI: 0000000000000004
RBP: 00007ffeda4f6540 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000400b60
R13: 00007ffeda4f6660 R14: 0000000000000000 R15: 0000000000000000
Code: 80 3d b0 ff 06 02 00 0f 84 07 02 00 00 e8 13 d6 db fc 49 8d bc 24 28 02 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 f
a 48 c1 ea 03 <80> 3c 02 00 0f 85 ed 02 00 00 4d 8b a4 24 28 02 00 00 e8 13 16
Fixes: 80d84ef3ff1dd ("l2tp: prevent l2tp_tunnel_delete racing with userspace close")
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-24 01:45:45 +08:00
|
|
|
l2tp_tunnel_free(tunnel);
|
2017-08-25 22:51:40 +08:00
|
|
|
}
|
|
|
|
|
2010-04-02 14:18:33 +08:00
|
|
|
/* Session reference counts. Incremented when code obtains a reference
|
|
|
|
* to a session.
|
|
|
|
*/
|
2017-11-01 00:36:44 +08:00
|
|
|
static inline void l2tp_session_inc_refcount(struct l2tp_session *session)
|
2010-04-02 14:18:33 +08:00
|
|
|
{
|
2017-07-04 20:52:58 +08:00
|
|
|
refcount_inc(&session->ref_count);
|
2010-04-02 14:18:33 +08:00
|
|
|
}
|
|
|
|
|
2017-11-01 00:36:44 +08:00
|
|
|
static inline void l2tp_session_dec_refcount(struct l2tp_session *session)
|
2010-04-02 14:18:33 +08:00
|
|
|
{
|
2017-07-04 20:52:58 +08:00
|
|
|
if (refcount_dec_and_test(&session->ref_count))
|
2010-04-02 14:18:33 +08:00
|
|
|
l2tp_session_free(session);
|
|
|
|
}
|
|
|
|
|
2018-01-17 06:01:55 +08:00
|
|
|
static inline int l2tp_get_l2specific_len(struct l2tp_session *session)
|
|
|
|
{
|
|
|
|
switch (session->l2specific_type) {
|
|
|
|
case L2TP_L2SPECTYPE_DEFAULT:
|
|
|
|
return 4;
|
|
|
|
case L2TP_L2SPECTYPE_NONE:
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-16 17:55:56 +08:00
|
|
|
#define l2tp_printk(ptr, type, func, fmt, ...) \
|
|
|
|
do { \
|
|
|
|
if (((ptr)->debug) & (type)) \
|
|
|
|
func(fmt, ##__VA_ARGS__); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define l2tp_warn(ptr, type, fmt, ...) \
|
|
|
|
l2tp_printk(ptr, type, pr_warn, fmt, ##__VA_ARGS__)
|
|
|
|
#define l2tp_info(ptr, type, fmt, ...) \
|
|
|
|
l2tp_printk(ptr, type, pr_info, fmt, ##__VA_ARGS__)
|
|
|
|
#define l2tp_dbg(ptr, type, fmt, ...) \
|
|
|
|
l2tp_printk(ptr, type, pr_debug, fmt, ##__VA_ARGS__)
|
|
|
|
|
2015-09-24 12:33:34 +08:00
|
|
|
#define MODULE_ALIAS_L2TP_PWTYPE(type) \
|
|
|
|
MODULE_ALIAS("net-l2tp-type-" __stringify(type))
|
|
|
|
|
2010-04-02 14:18:33 +08:00
|
|
|
#endif /* _L2TP_CORE_H_ */
|