2005-04-17 02:20:36 +04:00
/** -*- linux-c -*- ***********************************************************
* Linux PPP over X / Ethernet ( PPPoX / PPPoE ) Sockets
*
* PPPoX - - - Generic PPP encapsulation socket family
* PPPoE - - - PPP over Ethernet ( RFC 2516 )
*
*
* Version : 0.5 .2
*
* Author : Michal Ostrowski < mostrows @ speakeasy . net >
*
* 051000 : Initialization cleanup
*
* License :
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
# 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/init.h>
# include <linux/if_pppox.h>
# include <linux/ppp_defs.h>
# include <linux/if_ppp.h>
# include <linux/ppp_channel.h>
2007-04-30 11:21:02 +04:00
# include <linux/kmod.h>
2005-04-17 02:20:36 +04:00
# include <net/sock.h>
# include <asm/uaccess.h>
static struct pppox_proto * pppox_protos [ PX_MAX_PROTO + 1 ] ;
int register_pppox_proto ( int proto_num , struct pppox_proto * pp )
{
if ( proto_num < 0 | | proto_num > PX_MAX_PROTO )
return - EINVAL ;
if ( pppox_protos [ proto_num ] )
return - EALREADY ;
pppox_protos [ proto_num ] = pp ;
return 0 ;
}
void unregister_pppox_proto ( int proto_num )
{
if ( proto_num > = 0 & & proto_num < = PX_MAX_PROTO )
pppox_protos [ proto_num ] = NULL ;
}
void pppox_unbind_sock ( struct sock * sk )
{
/* Clear connection to ppp device, if attached. */
[PPPOE]: memory leak when socket is release()d before PPPIOCGCHAN has been called on it
below you find a patch that fixes a memory leak when a PPPoE socket is
release()d after it has been connect()ed, but before the PPPIOCGCHAN ioctl
ever has been called on it.
This is somewhat of a security problem, too, since PPPoE sockets can be
created by any user, so any user can easily allocate all the machine's
RAM to non-swappable address space and thus DoS the system.
Is there any specific reason for PPPoE sockets being available to any
unprivileged process, BTW? After all, you need a packet socket for the
discovery stage anyway, so it's unlikely that any unprivileged process
will ever need to create a PPPoE socket, no? Allocating all session IDs
for a known AC is a kind of DoS, too, after all - with Juniper ERXes,
this is really easy, actually, since they don't ever assign session ids
above 8000 ...
Signed-off-by: Florian Zumbiehl <florz@florz.de>
Acked-by: Michal Ostrowski <mostrows@earthlink.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-04-21 03:58:14 +04:00
if ( sk - > sk_state & ( PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE ) ) {
2005-04-17 02:20:36 +04:00
ppp_unregister_channel ( & pppox_sk ( sk ) - > chan ) ;
sk - > sk_state = PPPOX_DEAD ;
}
}
EXPORT_SYMBOL ( register_pppox_proto ) ;
EXPORT_SYMBOL ( unregister_pppox_proto ) ;
EXPORT_SYMBOL ( pppox_unbind_sock ) ;
2005-12-28 07:57:40 +03:00
int pppox_ioctl ( struct socket * sock , unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
struct sock * sk = sock - > sk ;
struct pppox_sock * po = pppox_sk ( sk ) ;
2007-07-31 04:48:23 +04:00
int rc ;
2005-04-17 02:20:36 +04:00
lock_sock ( sk ) ;
switch ( cmd ) {
case PPPIOCGCHAN : {
int index ;
rc = - ENOTCONN ;
if ( ! ( sk - > sk_state & PPPOX_CONNECTED ) )
break ;
rc = - EINVAL ;
index = ppp_channel_index ( & po - > chan ) ;
if ( put_user ( index , ( int __user * ) arg ) )
break ;
rc = 0 ;
sk - > sk_state | = PPPOX_BOUND ;
break ;
}
default :
2007-07-31 04:48:23 +04:00
rc = pppox_protos [ sk - > sk_protocol ] - > ioctl ?
pppox_protos [ sk - > sk_protocol ] - > ioctl ( sock , cmd , arg ) : - ENOTTY ;
}
2005-04-17 02:20:36 +04:00
release_sock ( sk ) ;
return rc ;
}
2005-12-28 07:57:40 +03:00
EXPORT_SYMBOL ( pppox_ioctl ) ;
2005-04-17 02:20:36 +04:00
2009-11-06 09:18:14 +03:00
static int pppox_create ( struct net * net , struct socket * sock , int protocol ,
int kern )
2005-04-17 02:20:36 +04:00
{
int rc = - EPROTOTYPE ;
if ( protocol < 0 | | protocol > PX_MAX_PROTO )
goto out ;
rc = - EPROTONOSUPPORT ;
2008-07-09 12:28:38 +04:00
if ( ! pppox_protos [ protocol ] )
request_module ( " pppox-proto-%d " , protocol ) ;
2005-04-17 02:20:36 +04:00
if ( ! pppox_protos [ protocol ] | |
! try_module_get ( pppox_protos [ protocol ] - > owner ) )
goto out ;
2007-10-09 10:24:22 +04:00
rc = pppox_protos [ protocol ] - > create ( net , sock ) ;
2005-12-28 07:57:40 +03:00
2005-04-17 02:20:36 +04:00
module_put ( pppox_protos [ protocol ] - > owner ) ;
out :
return rc ;
}
2009-10-05 09:58:39 +04:00
static const struct net_proto_family pppox_proto_family = {
2005-04-17 02:20:36 +04:00
. family = PF_PPPOX ,
. create = pppox_create ,
. owner = THIS_MODULE ,
} ;
static int __init pppox_init ( void )
{
return sock_register ( & pppox_proto_family ) ;
}
static void __exit pppox_exit ( void )
{
sock_unregister ( PF_PPPOX ) ;
}
module_init ( pppox_init ) ;
module_exit ( pppox_exit ) ;
MODULE_AUTHOR ( " Michal Ostrowski <mostrows@speakeasy.net> " ) ;
MODULE_DESCRIPTION ( " PPP over Ethernet driver (generic socket layer) " ) ;
MODULE_LICENSE ( " GPL " ) ;