2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-08-21 23:05:39 -07:00
/*
* Point - to - Point Tunneling Protocol for Linux
*
* Authors : Dmitry Kozlov < xeb @ mail . ru >
*/
# include <linux/string.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/net.h>
# include <linux/skbuff.h>
# include <linux/vmalloc.h>
# include <linux/init.h>
# include <linux/ppp_channel.h>
# include <linux/ppp_defs.h>
# include <linux/if_pppox.h>
2012-03-04 12:56:04 +00:00
# include <linux/ppp-ioctl.h>
2010-08-21 23:05:39 -07:00
# include <linux/notifier.h>
# include <linux/file.h>
# include <linux/in.h>
# include <linux/ip.h>
# include <linux/rcupdate.h>
2023-07-03 19:14:46 +02:00
# include <linux/security.h>
2010-08-21 23:05:39 -07:00
# include <linux/spinlock.h>
# include <net/sock.h>
# include <net/protocol.h>
# include <net/ip.h>
# include <net/icmp.h>
# include <net/route.h>
# include <net/gre.h>
2016-08-09 12:38:24 +08:00
# include <net/pptp.h>
2010-08-21 23:05:39 -07:00
# include <linux/uaccess.h>
# define PPTP_DRIVER_VERSION "0.8.5"
# define MAX_CALLID 65535
static DECLARE_BITMAP ( callid_bitmap , MAX_CALLID + 1 ) ;
2013-08-08 10:27:14 -07:00
static struct pppox_sock __rcu * * callid_sock ;
2010-08-21 23:05:39 -07:00
static DEFINE_SPINLOCK ( chan_lock ) ;
static struct proto pptp_sk_proto __read_mostly ;
2010-09-21 06:43:54 +00:00
static const struct ppp_channel_ops pptp_chan_ops ;
2010-08-21 23:05:39 -07:00
static const struct proto_ops pptp_ops ;
static struct pppox_sock * lookup_chan ( u16 call_id , __be32 s_addr )
{
struct pppox_sock * sock ;
struct pptp_opt * opt ;
rcu_read_lock ( ) ;
sock = rcu_dereference ( callid_sock [ call_id ] ) ;
if ( sock ) {
opt = & sock - > proto . pptp ;
if ( opt - > dst_addr . sin_addr . s_addr ! = s_addr )
sock = NULL ;
else
sock_hold ( sk_pppox ( sock ) ) ;
}
rcu_read_unlock ( ) ;
return sock ;
}
static int lookup_chan_dst ( u16 call_id , __be32 d_addr )
{
struct pppox_sock * sock ;
struct pptp_opt * opt ;
int i ;
rcu_read_lock ( ) ;
2012-04-02 22:47:16 +00:00
i = 1 ;
for_each_set_bit_from ( i , callid_bitmap , MAX_CALLID ) {
2010-08-21 23:05:39 -07:00
sock = rcu_dereference ( callid_sock [ i ] ) ;
if ( ! sock )
continue ;
opt = & sock - > proto . pptp ;
if ( opt - > dst_addr . call_id = = call_id & &
opt - > dst_addr . sin_addr . s_addr = = d_addr )
break ;
}
rcu_read_unlock ( ) ;
return i < MAX_CALLID ;
}
2016-01-22 01:39:43 +01:00
static int add_chan ( struct pppox_sock * sock ,
struct pptp_addr * sa )
2010-08-21 23:05:39 -07:00
{
static int call_id ;
spin_lock ( & chan_lock ) ;
2016-01-22 01:39:43 +01:00
if ( ! sa - > call_id ) {
2010-08-21 23:05:39 -07:00
call_id = find_next_zero_bit ( callid_bitmap , MAX_CALLID , call_id + 1 ) ;
if ( call_id = = MAX_CALLID ) {
call_id = find_next_zero_bit ( callid_bitmap , MAX_CALLID , 1 ) ;
if ( call_id = = MAX_CALLID )
goto out_err ;
}
2016-01-22 01:39:43 +01:00
sa - > call_id = call_id ;
} else if ( test_bit ( sa - > call_id , callid_bitmap ) ) {
2010-08-21 23:05:39 -07:00
goto out_err ;
2016-01-22 01:39:43 +01:00
}
2010-08-21 23:05:39 -07:00
2016-01-22 01:39:43 +01:00
sock - > proto . pptp . src_addr = * sa ;
set_bit ( sa - > call_id , callid_bitmap ) ;
rcu_assign_pointer ( callid_sock [ sa - > call_id ] , sock ) ;
2010-08-21 23:05:39 -07:00
spin_unlock ( & chan_lock ) ;
return 0 ;
out_err :
spin_unlock ( & chan_lock ) ;
return - 1 ;
}
static void del_chan ( struct pppox_sock * sock )
{
spin_lock ( & chan_lock ) ;
clear_bit ( sock - > proto . pptp . src_addr . call_id , callid_bitmap ) ;
2011-11-23 07:09:32 +00:00
RCU_INIT_POINTER ( callid_sock [ sock - > proto . pptp . src_addr . call_id ] , NULL ) ;
2010-08-21 23:05:39 -07:00
spin_unlock ( & chan_lock ) ;
}
2023-07-03 19:14:46 +02:00
static struct rtable * pptp_route_output ( struct pppox_sock * po ,
struct flowi4 * fl4 )
{
struct sock * sk = & po - > sk ;
struct net * net ;
net = sock_net ( sk ) ;
flowi4_init_output ( fl4 , sk - > sk_bound_dev_if , sk - > sk_mark , 0 ,
RT_SCOPE_UNIVERSE , IPPROTO_GRE , 0 ,
po - > proto . pptp . dst_addr . sin_addr . s_addr ,
po - > proto . pptp . src_addr . sin_addr . s_addr ,
0 , 0 , sock_net_uid ( net , sk ) ) ;
security_sk_classify_flow ( sk , flowi4_to_flowi_common ( fl4 ) ) ;
return ip_route_output_flow ( net , fl4 , sk ) ;
}
2010-08-21 23:05:39 -07:00
static int pptp_xmit ( struct ppp_channel * chan , struct sk_buff * skb )
{
struct sock * sk = ( struct sock * ) chan - > private ;
struct pppox_sock * po = pppox_sk ( sk ) ;
2015-10-07 16:48:43 -05:00
struct net * net = sock_net ( sk ) ;
2010-08-21 23:05:39 -07:00
struct pptp_opt * opt = & po - > proto . pptp ;
struct pptp_gre_header * hdr ;
unsigned int header_len = sizeof ( * hdr ) ;
2011-05-03 20:25:42 -07:00
struct flowi4 fl4 ;
2010-08-21 23:05:39 -07:00
int islcp ;
int len ;
unsigned char * data ;
__u32 seq_recv ;
struct rtable * rt ;
struct net_device * tdev ;
struct iphdr * iph ;
int max_headroom ;
if ( sk_pppox ( po ) - > sk_state & PPPOX_DEAD )
goto tx_error ;
2023-07-03 19:14:46 +02:00
rt = pptp_route_output ( po , & fl4 ) ;
2011-03-12 00:00:52 -05:00
if ( IS_ERR ( rt ) )
goto tx_error ;
2010-08-21 23:05:39 -07:00
tdev = rt - > dst . dev ;
max_headroom = LL_RESERVED_SPACE ( tdev ) + sizeof ( * iph ) + sizeof ( * hdr ) + 2 ;
if ( skb_headroom ( skb ) < max_headroom | | skb_cloned ( skb ) | | skb_shared ( skb ) ) {
struct sk_buff * new_skb = skb_realloc_headroom ( skb , max_headroom ) ;
if ( ! new_skb ) {
ip_rt_put ( rt ) ;
goto tx_error ;
}
if ( skb - > sk )
skb_set_owner_w ( new_skb , skb - > sk ) ;
2012-05-18 20:23:00 +00:00
consume_skb ( skb ) ;
2010-08-21 23:05:39 -07:00
skb = new_skb ;
}
data = skb - > data ;
islcp = ( ( data [ 0 ] < < 8 ) + data [ 1 ] ) = = PPP_LCP & & 1 < = data [ 2 ] & & data [ 2 ] < = 7 ;
/* compress protocol field */
if ( ( opt - > ppp_flags & SC_COMP_PROT ) & & data [ 0 ] = = 0 & & ! islcp )
skb_pull ( skb , 1 ) ;
/* Put in the address/control bytes if necessary */
if ( ( opt - > ppp_flags & SC_COMP_AC ) = = 0 | | islcp ) {
data = skb_push ( skb , 2 ) ;
data [ 0 ] = PPP_ALLSTATIONS ;
data [ 1 ] = PPP_UI ;
}
len = skb - > len ;
seq_recv = opt - > seq_recv ;
if ( opt - > ack_sent = = seq_recv )
header_len - = sizeof ( hdr - > ack ) ;
/* Push down and install GRE header */
skb_push ( skb , header_len ) ;
hdr = ( struct pptp_gre_header * ) ( skb - > data ) ;
2016-08-13 00:30:48 +08:00
hdr - > gre_hd . flags = GRE_KEY | GRE_VERSION_1 | GRE_SEQ ;
hdr - > gre_hd . protocol = GRE_PROTO_PPP ;
hdr - > call_id = htons ( opt - > dst_addr . call_id ) ;
2010-08-21 23:05:39 -07:00
2016-08-13 00:30:48 +08:00
hdr - > seq = htonl ( + + opt - > seq_sent ) ;
2010-08-21 23:05:39 -07:00
if ( opt - > ack_sent ! = seq_recv ) {
/* send ack with this message */
2016-08-13 00:30:48 +08:00
hdr - > gre_hd . flags | = GRE_ACK ;
2010-08-21 23:05:39 -07:00
hdr - > ack = htonl ( seq_recv ) ;
opt - > ack_sent = seq_recv ;
}
hdr - > payload_len = htons ( len ) ;
/* Push down and install the IP header. */
skb_reset_transport_header ( skb ) ;
skb_push ( skb , sizeof ( * iph ) ) ;
skb_reset_network_header ( skb ) ;
memset ( & ( IPCB ( skb ) - > opt ) , 0 , sizeof ( IPCB ( skb ) - > opt ) ) ;
IPCB ( skb ) - > flags & = ~ ( IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED ) ;
iph = ip_hdr ( skb ) ;
iph - > version = 4 ;
iph - > ihl = sizeof ( struct iphdr ) > > 2 ;
if ( ip_dont_fragment ( sk , & rt - > dst ) )
iph - > frag_off = htons ( IP_DF ) ;
else
iph - > frag_off = 0 ;
iph - > protocol = IPPROTO_GRE ;
iph - > tos = 0 ;
2011-05-03 20:41:42 -07:00
iph - > daddr = fl4 . daddr ;
iph - > saddr = fl4 . saddr ;
2010-12-12 21:55:08 -08:00
iph - > ttl = ip4_dst_hoplimit ( & rt - > dst ) ;
2010-08-21 23:05:39 -07:00
iph - > tot_len = htons ( skb - > len ) ;
skb_dst_drop ( skb ) ;
skb_dst_set ( skb , & rt - > dst ) ;
2019-09-29 20:54:03 +02:00
nf_reset_ct ( skb ) ;
2010-08-21 23:05:39 -07:00
skb - > ip_summed = CHECKSUM_NONE ;
2015-10-07 16:48:43 -05:00
ip_select_ident ( net , skb , NULL ) ;
2010-08-21 23:05:39 -07:00
ip_send_check ( iph ) ;
2015-10-07 16:48:46 -05:00
ip_local_out ( net , skb - > sk , skb ) ;
2011-10-17 17:01:47 +00:00
return 1 ;
2010-08-21 23:05:39 -07:00
tx_error :
2011-10-17 17:01:47 +00:00
kfree_skb ( skb ) ;
2010-08-21 23:05:39 -07:00
return 1 ;
}
static int pptp_rcv_core ( struct sock * sk , struct sk_buff * skb )
{
struct pppox_sock * po = pppox_sk ( sk ) ;
struct pptp_opt * opt = & po - > proto . pptp ;
int headersize , payload_len , seq ;
__u8 * payload ;
struct pptp_gre_header * header ;
if ( ! ( sk - > sk_state & PPPOX_CONNECTED ) ) {
if ( sock_queue_rcv_skb ( sk , skb ) )
goto drop ;
return NET_RX_SUCCESS ;
}
header = ( struct pptp_gre_header * ) ( skb - > data ) ;
2011-10-17 17:59:53 +00:00
headersize = sizeof ( * header ) ;
2010-08-21 23:05:39 -07:00
/* test if acknowledgement present */
2016-08-13 00:30:48 +08:00
if ( GRE_IS_ACK ( header - > gre_hd . flags ) ) {
2011-10-17 17:59:53 +00:00
__u32 ack ;
if ( ! pskb_may_pull ( skb , headersize ) )
goto drop ;
header = ( struct pptp_gre_header * ) ( skb - > data ) ;
/* ack in different place if S = 0 */
2021-01-07 15:39:56 +01:00
ack = GRE_IS_SEQ ( header - > gre_hd . flags ) ? ntohl ( header - > ack ) :
ntohl ( header - > seq ) ;
2010-08-21 23:05:39 -07:00
if ( ack > opt - > ack_recv )
opt - > ack_recv = ack ;
/* also handle sequence number wrap-around */
if ( WRAPPED ( ack , opt - > ack_recv ) )
opt - > ack_recv = ack ;
2011-10-17 17:59:53 +00:00
} else {
headersize - = sizeof ( header - > ack ) ;
2010-08-21 23:05:39 -07:00
}
/* test if payload present */
2016-08-13 00:30:48 +08:00
if ( ! GRE_IS_SEQ ( header - > gre_hd . flags ) )
2010-08-21 23:05:39 -07:00
goto drop ;
payload_len = ntohs ( header - > payload_len ) ;
seq = ntohl ( header - > seq ) ;
/* check for incomplete packet (length smaller than expected) */
2011-10-17 17:59:53 +00:00
if ( ! pskb_may_pull ( skb , headersize + payload_len ) )
2010-08-21 23:05:39 -07:00
goto drop ;
payload = skb - > data + headersize ;
/* check for expected sequence number */
if ( seq < opt - > seq_recv + 1 | | WRAPPED ( opt - > seq_recv , seq ) ) {
if ( ( payload [ 0 ] = = PPP_ALLSTATIONS ) & & ( payload [ 1 ] = = PPP_UI ) & &
( PPP_PROTOCOL ( payload ) = = PPP_LCP ) & &
( ( payload [ 4 ] = = PPP_LCP_ECHOREQ ) | | ( payload [ 4 ] = = PPP_LCP_ECHOREP ) ) )
goto allow_packet ;
} else {
opt - > seq_recv = seq ;
allow_packet :
skb_pull ( skb , headersize ) ;
if ( payload [ 0 ] = = PPP_ALLSTATIONS & & payload [ 1 ] = = PPP_UI ) {
/* chop off address/control */
if ( skb - > len < 3 )
goto drop ;
skb_pull ( skb , 2 ) ;
}
skb - > ip_summed = CHECKSUM_NONE ;
skb_set_network_header ( skb , skb - > head - skb - > data ) ;
ppp_input ( & po - > chan , skb ) ;
return NET_RX_SUCCESS ;
}
drop :
kfree_skb ( skb ) ;
return NET_RX_DROP ;
}
static int pptp_rcv ( struct sk_buff * skb )
{
struct pppox_sock * po ;
struct pptp_gre_header * header ;
struct iphdr * iph ;
if ( skb - > pkt_type ! = PACKET_HOST )
goto drop ;
if ( ! pskb_may_pull ( skb , 12 ) )
goto drop ;
iph = ip_hdr ( skb ) ;
header = ( struct pptp_gre_header * ) skb - > data ;
2016-08-13 00:30:48 +08:00
if ( header - > gre_hd . protocol ! = GRE_PROTO_PPP | | /* PPTP-GRE protocol for PPTP */
GRE_IS_CSUM ( header - > gre_hd . flags ) | | /* flag CSUM should be clear */
GRE_IS_ROUTING ( header - > gre_hd . flags ) | | /* flag ROUTING should be clear */
! GRE_IS_KEY ( header - > gre_hd . flags ) | | /* flag KEY should be set */
( header - > gre_hd . flags & GRE_FLAGS ) ) /* flag Recursion Ctrl should be clear */
2010-08-21 23:05:39 -07:00
/* if invalid, discard this packet */
goto drop ;
2021-01-07 15:39:56 +01:00
po = lookup_chan ( ntohs ( header - > call_id ) , iph - > saddr ) ;
2010-08-21 23:05:39 -07:00
if ( po ) {
skb_dst_drop ( skb ) ;
2019-09-29 20:54:03 +02:00
nf_reset_ct ( skb ) ;
2010-08-21 23:05:39 -07:00
return sk_receive_skb ( sk_pppox ( po ) , skb , 0 ) ;
}
drop :
kfree_skb ( skb ) ;
return NET_RX_DROP ;
}
static int pptp_bind ( struct socket * sock , struct sockaddr * uservaddr ,
int sockaddr_len )
{
struct sock * sk = sock - > sk ;
struct sockaddr_pppox * sp = ( struct sockaddr_pppox * ) uservaddr ;
struct pppox_sock * po = pppox_sk ( sk ) ;
int error = 0 ;
2015-12-14 13:48:36 -08:00
if ( sockaddr_len < sizeof ( struct sockaddr_pppox ) )
return - EINVAL ;
2010-08-21 23:05:39 -07:00
lock_sock ( sk ) ;
2016-01-22 01:39:43 +01:00
if ( sk - > sk_state & PPPOX_DEAD ) {
error = - EALREADY ;
goto out ;
}
if ( sk - > sk_state & PPPOX_BOUND ) {
2010-08-21 23:05:39 -07:00
error = - EBUSY ;
2016-01-22 01:39:43 +01:00
goto out ;
}
if ( add_chan ( po , & sp - > sa_addr . pptp ) )
error = - EBUSY ;
else
sk - > sk_state | = PPPOX_BOUND ;
2010-08-21 23:05:39 -07:00
2016-01-22 01:39:43 +01:00
out :
2010-08-21 23:05:39 -07:00
release_sock ( sk ) ;
return error ;
}
static int pptp_connect ( struct socket * sock , struct sockaddr * uservaddr ,
int sockaddr_len , int flags )
{
struct sock * sk = sock - > sk ;
struct sockaddr_pppox * sp = ( struct sockaddr_pppox * ) uservaddr ;
struct pppox_sock * po = pppox_sk ( sk ) ;
struct pptp_opt * opt = & po - > proto . pptp ;
struct rtable * rt ;
2011-05-03 20:25:42 -07:00
struct flowi4 fl4 ;
2010-08-21 23:05:39 -07:00
int error = 0 ;
2015-12-14 13:48:36 -08:00
if ( sockaddr_len < sizeof ( struct sockaddr_pppox ) )
return - EINVAL ;
2010-08-21 23:05:39 -07:00
if ( sp - > sa_protocol ! = PX_PROTO_PPTP )
return - EINVAL ;
if ( lookup_chan_dst ( sp - > sa_addr . pptp . call_id , sp - > sa_addr . pptp . sin_addr . s_addr ) )
return - EALREADY ;
lock_sock ( sk ) ;
/* Check for already bound sockets */
if ( sk - > sk_state & PPPOX_CONNECTED ) {
error = - EBUSY ;
goto end ;
}
/* Check for already disconnected sockets, on attempts to disconnect */
if ( sk - > sk_state & PPPOX_DEAD ) {
error = - EALREADY ;
goto end ;
}
if ( ! opt - > src_addr . sin_addr . s_addr | | ! sp - > sa_addr . pptp . sin_addr . s_addr ) {
error = - EINVAL ;
goto end ;
}
po - > chan . private = sk ;
po - > chan . ops = & pptp_chan_ops ;
2023-07-03 19:14:46 +02:00
rt = pptp_route_output ( po , & fl4 ) ;
2011-03-12 00:00:52 -05:00
if ( IS_ERR ( rt ) ) {
error = - EHOSTUNREACH ;
goto end ;
2010-08-21 23:05:39 -07:00
}
2011-03-12 00:00:52 -05:00
sk_setup_caps ( sk , & rt - > dst ) ;
2010-08-21 23:05:39 -07:00
po - > chan . mtu = dst_mtu ( & rt - > dst ) ;
if ( ! po - > chan . mtu )
2012-03-04 12:56:04 +00:00
po - > chan . mtu = PPP_MRU ;
2010-08-21 23:05:39 -07:00
po - > chan . mtu - = PPTP_HEADER_OVERHEAD ;
po - > chan . hdrlen = 2 + sizeof ( struct pptp_gre_header ) ;
error = ppp_register_channel ( & po - > chan ) ;
if ( error ) {
pr_err ( " PPTP: failed to register PPP channel (%d) \n " , error ) ;
goto end ;
}
opt - > dst_addr = sp - > sa_addr . pptp ;
2016-01-22 01:39:43 +01:00
sk - > sk_state | = PPPOX_CONNECTED ;
2010-08-21 23:05:39 -07:00
end :
release_sock ( sk ) ;
return error ;
}
static int pptp_getname ( struct socket * sock , struct sockaddr * uaddr ,
2018-02-12 20:00:20 +01:00
int peer )
2010-08-21 23:05:39 -07:00
{
int len = sizeof ( struct sockaddr_pppox ) ;
struct sockaddr_pppox sp ;
2014-11-19 18:05:26 +01:00
memset ( & sp . sa_addr , 0 , sizeof ( sp . sa_addr ) ) ;
sp . sa_family = AF_PPPOX ;
2010-08-21 23:05:39 -07:00
sp . sa_protocol = PX_PROTO_PPTP ;
sp . sa_addr . pptp = pppox_sk ( sock - > sk ) - > proto . pptp . src_addr ;
memcpy ( uaddr , & sp , len ) ;
2018-02-12 20:00:20 +01:00
return len ;
2010-08-21 23:05:39 -07:00
}
static int pptp_release ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
struct pppox_sock * po ;
int error = 0 ;
if ( ! sk )
return 0 ;
lock_sock ( sk ) ;
if ( sock_flag ( sk , SOCK_DEAD ) ) {
release_sock ( sk ) ;
return - EBADF ;
}
po = pppox_sk ( sk ) ;
del_chan ( po ) ;
2017-07-31 18:07:38 +08:00
synchronize_rcu ( ) ;
2010-08-21 23:05:39 -07:00
pppox_unbind_sock ( sk ) ;
sk - > sk_state = PPPOX_DEAD ;
sock_orphan ( sk ) ;
sock - > sk = NULL ;
release_sock ( sk ) ;
sock_put ( sk ) ;
return error ;
}
static void pptp_sock_destruct ( struct sock * sk )
{
if ( ! ( sk - > sk_state & PPPOX_DEAD ) ) {
del_chan ( pppox_sk ( sk ) ) ;
pppox_unbind_sock ( sk ) ;
}
skb_queue_purge ( & sk - > sk_receive_queue ) ;
pptp: dst_release sk_dst_cache in pptp_sock_destruct
sk_setup_caps() is called to set sk->sk_dst_cache in pptp_connect,
so we have to dst_release(sk->sk_dst_cache) in pptp_sock_destruct,
otherwise, the dst refcnt will leak.
It can be reproduced by this syz log:
r1 = socket$pptp(0x18, 0x1, 0x2)
bind$pptp(r1, &(0x7f0000000100)={0x18, 0x2, {0x0, @local}}, 0x1e)
connect$pptp(r1, &(0x7f0000000000)={0x18, 0x2, {0x3, @remote}}, 0x1e)
Consecutive dmesg warnings will occur:
unregister_netdevice: waiting for lo to become free. Usage count = 1
v1->v2:
- use rcu_dereference_protected() instead of rcu_dereference_check(),
as suggested by Eric.
Fixes: 00959ade36ac ("PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)")
Reported-by: Xiumei Mu <xmu@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-03-13 17:00:48 +08:00
dst_release ( rcu_dereference_protected ( sk - > sk_dst_cache , 1 ) ) ;
2010-08-21 23:05:39 -07:00
}
2015-05-08 21:09:13 -05:00
static int pptp_create ( struct net * net , struct socket * sock , int kern )
2010-08-21 23:05:39 -07:00
{
int error = - ENOMEM ;
struct sock * sk ;
struct pppox_sock * po ;
struct pptp_opt * opt ;
2015-05-08 21:09:13 -05:00
sk = sk_alloc ( net , PF_PPPOX , GFP_KERNEL , & pptp_sk_proto , kern ) ;
2010-08-21 23:05:39 -07:00
if ( ! sk )
goto out ;
sock_init_data ( sock , sk ) ;
sock - > state = SS_UNCONNECTED ;
sock - > ops = & pptp_ops ;
sk - > sk_backlog_rcv = pptp_rcv_core ;
sk - > sk_state = PPPOX_NONE ;
sk - > sk_type = SOCK_STREAM ;
sk - > sk_family = PF_PPPOX ;
sk - > sk_protocol = PX_PROTO_PPTP ;
sk - > sk_destruct = pptp_sock_destruct ;
po = pppox_sk ( sk ) ;
opt = & po - > proto . pptp ;
2012-01-12 10:39:16 +00:00
opt - > seq_sent = 0 ; opt - > seq_recv = 0xffffffff ;
opt - > ack_recv = 0 ; opt - > ack_sent = 0xffffffff ;
2010-08-21 23:05:39 -07:00
error = 0 ;
out :
return error ;
}
static int pptp_ppp_ioctl ( struct ppp_channel * chan , unsigned int cmd ,
unsigned long arg )
{
struct sock * sk = ( struct sock * ) chan - > private ;
struct pppox_sock * po = pppox_sk ( sk ) ;
struct pptp_opt * opt = & po - > proto . pptp ;
void __user * argp = ( void __user * ) arg ;
int __user * p = argp ;
int err , val ;
err = - EFAULT ;
switch ( cmd ) {
case PPPIOCGFLAGS :
val = opt - > ppp_flags ;
if ( put_user ( val , p ) )
break ;
err = 0 ;
break ;
case PPPIOCSFLAGS :
if ( get_user ( val , p ) )
break ;
opt - > ppp_flags = val & ~ SC_RCV_BITS ;
err = 0 ;
break ;
default :
err = - ENOTTY ;
}
return err ;
}
2010-09-21 06:43:54 +00:00
static const struct ppp_channel_ops pptp_chan_ops = {
2010-08-21 23:05:39 -07:00
. start_xmit = pptp_xmit ,
. ioctl = pptp_ppp_ioctl ,
} ;
static struct proto pptp_sk_proto __read_mostly = {
. name = " PPTP " ,
. owner = THIS_MODULE ,
. obj_size = sizeof ( struct pppox_sock ) ,
} ;
static const struct proto_ops pptp_ops = {
. family = AF_PPPOX ,
. owner = THIS_MODULE ,
. release = pptp_release ,
. bind = pptp_bind ,
. connect = pptp_connect ,
. socketpair = sock_no_socketpair ,
. accept = sock_no_accept ,
. getname = pptp_getname ,
. listen = sock_no_listen ,
. shutdown = sock_no_shutdown ,
. sendmsg = sock_no_sendmsg ,
. recvmsg = sock_no_recvmsg ,
. mmap = sock_no_mmap ,
. ioctl = pppox_ioctl ,
2019-07-30 21:25:20 +02:00
# ifdef CONFIG_COMPAT
. compat_ioctl = pppox_compat_ioctl ,
# endif
2010-08-21 23:05:39 -07:00
} ;
2010-09-21 06:43:54 +00:00
static const struct pppox_proto pppox_pptp_proto = {
2010-08-21 23:05:39 -07:00
. create = pptp_create ,
. owner = THIS_MODULE ,
} ;
2010-09-21 06:43:54 +00:00
static const struct gre_protocol gre_pptp_protocol = {
2010-08-21 23:05:39 -07:00
. handler = pptp_rcv ,
} ;
static int __init pptp_init_module ( void )
{
int err = 0 ;
pr_info ( " PPTP driver version " PPTP_DRIVER_VERSION " \n " ) ;
treewide: Use array_size() in vzalloc()
The vzalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vzalloc(a * b)
with:
vzalloc(array_size(a, b))
as well as handling cases of:
vzalloc(a * b * c)
with:
vzalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vzalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vzalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vzalloc(C1 * C2 * C3, ...)
|
vzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vzalloc(C1 * C2, ...)
|
vzalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:27:37 -07:00
callid_sock = vzalloc ( array_size ( sizeof ( void * ) , ( MAX_CALLID + 1 ) ) ) ;
2012-01-29 12:56:23 +00:00
if ( ! callid_sock )
2010-08-21 23:05:39 -07:00
return - ENOMEM ;
err = gre_add_protocol ( & gre_pptp_protocol , GREPROTO_PPTP ) ;
if ( err ) {
pr_err ( " PPTP: can't add gre protocol \n " ) ;
goto out_mem_free ;
}
err = proto_register ( & pptp_sk_proto , 0 ) ;
if ( err ) {
pr_err ( " PPTP: can't register sk_proto \n " ) ;
goto out_gre_del_protocol ;
}
err = register_pppox_proto ( PX_PROTO_PPTP , & pppox_pptp_proto ) ;
if ( err ) {
pr_err ( " PPTP: can't register pppox_proto \n " ) ;
goto out_unregister_sk_proto ;
}
return 0 ;
out_unregister_sk_proto :
proto_unregister ( & pptp_sk_proto ) ;
out_gre_del_protocol :
gre_del_protocol ( & gre_pptp_protocol , GREPROTO_PPTP ) ;
out_mem_free :
vfree ( callid_sock ) ;
return err ;
}
static void __exit pptp_exit_module ( void )
{
unregister_pppox_proto ( PX_PROTO_PPTP ) ;
proto_unregister ( & pptp_sk_proto ) ;
gre_del_protocol ( & gre_pptp_protocol , GREPROTO_PPTP ) ;
vfree ( callid_sock ) ;
}
module_init ( pptp_init_module ) ;
module_exit ( pptp_exit_module ) ;
MODULE_DESCRIPTION ( " Point-to-Point Tunneling Protocol " ) ;
MODULE_AUTHOR ( " D. Kozlov (xeb@mail.ru) " ) ;
MODULE_LICENSE ( " GPL " ) ;
2015-12-02 16:27:39 +01:00
MODULE_ALIAS_NET_PF_PROTO ( PF_PPPOX , PX_PROTO_PPTP ) ;