2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-04-27 02:48:28 +04:00
/* RxRPC security handling
*
* Copyright ( C ) 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*/
# include <linux/module.h>
# include <linux/net.h>
# include <linux/skbuff.h>
# include <linux/udp.h>
# include <linux/crypto.h>
# include <net/sock.h>
# include <net/af_rxrpc.h>
2009-09-14 05:17:35 +04:00
# include <keys/rxrpc-type.h>
2007-04-27 02:48:28 +04:00
# include "ar-internal.h"
2016-04-07 19:23:51 +03:00
static const struct rxrpc_security * rxrpc_security_types [ ] = {
2016-04-07 19:23:58 +03:00
[ RXRPC_SECURITY_NONE ] = & rxrpc_no_security ,
2016-04-07 19:23:51 +03:00
# ifdef CONFIG_RXKAD
[ RXRPC_SECURITY_RXKAD ] = & rxkad ,
# endif
} ;
2007-04-27 02:48:28 +04:00
2016-04-07 19:23:51 +03:00
int __init rxrpc_init_security ( void )
2007-04-27 02:48:28 +04:00
{
2016-04-07 19:23:51 +03:00
int i , ret ;
2007-04-27 02:48:28 +04:00
2016-04-07 19:23:51 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( rxrpc_security_types ) ; i + + ) {
if ( rxrpc_security_types [ i ] ) {
ret = rxrpc_security_types [ i ] - > init ( ) ;
if ( ret < 0 )
goto failed ;
2007-04-27 02:48:28 +04:00
}
}
2016-04-07 19:23:51 +03:00
return 0 ;
failed :
for ( i - - ; i > = 0 ; i - - )
if ( rxrpc_security_types [ i ] )
rxrpc_security_types [ i ] - > exit ( ) ;
return ret ;
2007-04-27 02:48:28 +04:00
}
2016-04-07 19:23:51 +03:00
void rxrpc_exit_security ( void )
2007-04-27 02:48:28 +04:00
{
2016-04-07 19:23:51 +03:00
int i ;
2007-04-27 02:48:28 +04:00
2016-04-07 19:23:51 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( rxrpc_security_types ) ; i + + )
if ( rxrpc_security_types [ i ] )
rxrpc_security_types [ i ] - > exit ( ) ;
2007-04-27 02:48:28 +04:00
}
2016-04-07 19:23:51 +03:00
/*
* look up an rxrpc security module
2007-04-27 02:48:28 +04:00
*/
2020-09-16 10:37:29 +03:00
const struct rxrpc_security * rxrpc_security_lookup ( u8 security_index )
2007-04-27 02:48:28 +04:00
{
2016-04-07 19:23:51 +03:00
if ( security_index > = ARRAY_SIZE ( rxrpc_security_types ) )
return NULL ;
return rxrpc_security_types [ security_index ] ;
2007-04-27 02:48:28 +04:00
}
/*
* initialise the security on a client connection
*/
int rxrpc_init_client_conn_security ( struct rxrpc_connection * conn )
{
2016-04-07 19:23:51 +03:00
const struct rxrpc_security * sec ;
2009-09-14 05:17:35 +04:00
struct rxrpc_key_token * token ;
2016-04-04 16:00:36 +03:00
struct key * key = conn - > params . key ;
2007-04-27 02:48:28 +04:00
int ret ;
_enter ( " {%d},{%x} " , conn - > debug_id , key_serial ( key ) ) ;
if ( ! key )
return 0 ;
ret = key_validate ( key ) ;
if ( ret < 0 )
return ret ;
2020-09-16 10:19:12 +03:00
for ( token = key - > payload . data [ 0 ] ; token ; token = token - > next ) {
sec = rxrpc_security_lookup ( token - > security_index ) ;
if ( sec )
goto found ;
}
return - EKEYREJECTED ;
2009-09-14 05:17:35 +04:00
2020-09-16 10:19:12 +03:00
found :
2007-04-27 02:48:28 +04:00
conn - > security = sec ;
2020-09-16 10:19:12 +03:00
ret = conn - > security - > init_connection_security ( conn , token ) ;
2007-04-27 02:48:28 +04:00
if ( ret < 0 ) {
2016-04-07 19:23:58 +03:00
conn - > security = & rxrpc_no_security ;
2007-04-27 02:48:28 +04:00
return ret ;
}
_leave ( " = 0 " ) ;
return 0 ;
}
/*
2020-09-16 10:00:44 +03:00
* Set the ops a server connection .
2007-04-27 02:48:28 +04:00
*/
2020-09-16 10:00:44 +03:00
const struct rxrpc_security * rxrpc_get_incoming_security ( struct rxrpc_sock * rx ,
struct sk_buff * skb )
2007-04-27 02:48:28 +04:00
{
2016-04-07 19:23:51 +03:00
const struct rxrpc_security * sec ;
2019-12-20 19:17:16 +03:00
struct rxrpc_skb_priv * sp = rxrpc_skb ( skb ) ;
2007-04-27 02:48:28 +04:00
_enter ( " " ) ;
2019-12-20 19:17:16 +03:00
sec = rxrpc_security_lookup ( sp - > hdr . securityIndex ) ;
2007-04-27 02:48:28 +04:00
if ( ! sec ) {
2019-12-20 19:17:16 +03:00
trace_rxrpc_abort ( 0 , " SVS " ,
sp - > hdr . cid , sp - > hdr . callNumber , sp - > hdr . seq ,
RX_INVALID_OPERATION , EKEYREJECTED ) ;
skb - > mark = RXRPC_SKB_MARK_REJECT_ABORT ;
skb - > priority = RX_INVALID_OPERATION ;
2020-09-16 10:00:44 +03:00
return NULL ;
2007-04-27 02:48:28 +04:00
}
2020-09-16 10:00:44 +03:00
if ( sp - > hdr . securityIndex ! = RXRPC_SECURITY_NONE & &
! rx - > securities ) {
2019-12-20 19:17:16 +03:00
trace_rxrpc_abort ( 0 , " SVR " ,
sp - > hdr . cid , sp - > hdr . callNumber , sp - > hdr . seq ,
RX_INVALID_OPERATION , EKEYREJECTED ) ;
skb - > mark = RXRPC_SKB_MARK_REJECT_ABORT ;
2020-09-16 10:00:44 +03:00
skb - > priority = sec - > no_key_abort ;
return NULL ;
2007-04-27 02:48:28 +04:00
}
2020-09-16 10:00:44 +03:00
return sec ;
}
/*
* Find the security key for a server connection .
*/
struct key * rxrpc_look_up_server_security ( struct rxrpc_connection * conn ,
struct sk_buff * skb ,
u32 kvno , u32 enctype )
{
struct rxrpc_skb_priv * sp = rxrpc_skb ( skb ) ;
struct rxrpc_sock * rx ;
struct key * key = ERR_PTR ( - EKEYREJECTED ) ;
key_ref_t kref = NULL ;
char kdesc [ 5 + 1 + 3 + 1 + 12 + 1 + 12 + 1 ] ;
int ret ;
_enter ( " " ) ;
if ( enctype )
sprintf ( kdesc , " %u:%u:%u:%u " ,
sp - > hdr . serviceId , sp - > hdr . securityIndex , kvno , enctype ) ;
else if ( kvno )
sprintf ( kdesc , " %u:%u:%u " ,
sp - > hdr . serviceId , sp - > hdr . securityIndex , kvno ) ;
else
sprintf ( kdesc , " %u:%u " ,
sp - > hdr . serviceId , sp - > hdr . securityIndex ) ;
rcu_read_lock ( ) ;
rx = rcu_dereference ( conn - > params . local - > service ) ;
if ( ! rx )
goto out ;
2007-04-27 02:48:28 +04:00
/* look through the service's keyring */
kref = keyring_search ( make_key_ref ( rx - > securities , 1UL ) ,
2019-06-26 23:02:32 +03:00
& key_type_rxrpc_s , kdesc , true ) ;
2007-04-27 02:48:28 +04:00
if ( IS_ERR ( kref ) ) {
2020-09-16 10:00:44 +03:00
key = ERR_CAST ( kref ) ;
goto out ;
}
key = key_ref_to_ptr ( kref ) ;
ret = key_validate ( key ) ;
if ( ret < 0 ) {
key_put ( key ) ;
key = ERR_PTR ( ret ) ;
goto out ;
2007-04-27 02:48:28 +04:00
}
2019-12-20 19:17:16 +03:00
out :
2020-09-16 10:00:44 +03:00
rcu_read_unlock ( ) ;
return key ;
2007-04-27 02:48:28 +04:00
}