2018-09-19 13:10:54 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Crypto user configuration API .
*
* Copyright ( C ) 2017 - 2018 Corentin Labbe < clabbe @ baylibre . com >
*
*/
# include <linux/crypto.h>
# include <linux/cryptouser.h>
# include <linux/sched.h>
# include <net/netlink.h>
2019-07-09 14:11:24 +03:00
# include <net/sock.h>
2018-09-19 13:10:54 +03:00
# include <crypto/internal/rng.h>
# include <crypto/internal/cryptouser.h>
# include "internal.h"
# define null_terminated(x) (strnlen(x, sizeof(x)) < sizeof(x))
struct crypto_dump_info {
struct sk_buff * in_skb ;
struct sk_buff * out_skb ;
u32 nlmsg_seq ;
u16 nlmsg_flags ;
} ;
static int crypto_report_cipher ( struct sk_buff * skb , struct crypto_alg * alg )
{
2018-11-29 17:42:19 +03:00
struct crypto_stat_cipher rcipher ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:01 +03:00
memset ( & rcipher , 0 , sizeof ( rcipher ) ) ;
2018-11-04 00:56:03 +03:00
strscpy ( rcipher . type , " cipher " , sizeof ( rcipher . type ) ) ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:03 +03:00
return nla_put ( skb , CRYPTOCFGA_STAT_CIPHER , sizeof ( rcipher ) , & rcipher ) ;
2018-09-19 13:10:54 +03:00
}
static int crypto_report_comp ( struct sk_buff * skb , struct crypto_alg * alg )
{
2018-11-29 17:42:19 +03:00
struct crypto_stat_compress rcomp ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:01 +03:00
memset ( & rcomp , 0 , sizeof ( rcomp ) ) ;
2018-11-04 00:56:03 +03:00
strscpy ( rcomp . type , " compression " , sizeof ( rcomp . type ) ) ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:03 +03:00
return nla_put ( skb , CRYPTOCFGA_STAT_COMPRESS , sizeof ( rcomp ) , & rcomp ) ;
2018-09-19 13:10:54 +03:00
}
static int crypto_report_rng ( struct sk_buff * skb , struct crypto_alg * alg )
{
2018-11-29 17:42:19 +03:00
struct crypto_stat_rng rrng ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:01 +03:00
memset ( & rrng , 0 , sizeof ( rrng ) ) ;
2018-11-04 00:56:03 +03:00
strscpy ( rrng . type , " rng " , sizeof ( rrng . type ) ) ;
2018-09-19 13:10:54 +03:00
2018-11-29 17:42:24 +03:00
rrng . stat_generate_cnt = atomic64_read ( & alg - > stats . rng . generate_cnt ) ;
rrng . stat_generate_tlen = atomic64_read ( & alg - > stats . rng . generate_tlen ) ;
rrng . stat_seed_cnt = atomic64_read ( & alg - > stats . rng . seed_cnt ) ;
2018-11-29 17:42:25 +03:00
rrng . stat_err_cnt = atomic64_read ( & alg - > stats . rng . err_cnt ) ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:03 +03:00
return nla_put ( skb , CRYPTOCFGA_STAT_RNG , sizeof ( rrng ) , & rrng ) ;
2018-09-19 13:10:54 +03:00
}
static int crypto_reportstat_one ( struct crypto_alg * alg ,
struct crypto_user_alg * ualg ,
struct sk_buff * skb )
{
2018-11-04 00:56:01 +03:00
memset ( ualg , 0 , sizeof ( * ualg ) ) ;
2018-11-04 00:56:03 +03:00
strscpy ( ualg - > cru_name , alg - > cra_name , sizeof ( ualg - > cru_name ) ) ;
strscpy ( ualg - > cru_driver_name , alg - > cra_driver_name ,
2018-09-19 13:10:54 +03:00
sizeof ( ualg - > cru_driver_name ) ) ;
2018-11-04 00:56:03 +03:00
strscpy ( ualg - > cru_module_name , module_name ( alg - > cra_module ) ,
2018-09-19 13:10:54 +03:00
sizeof ( ualg - > cru_module_name ) ) ;
ualg - > cru_type = 0 ;
ualg - > cru_mask = 0 ;
ualg - > cru_flags = alg - > cra_flags ;
ualg - > cru_refcnt = refcount_read ( & alg - > cra_refcnt ) ;
if ( nla_put_u32 ( skb , CRYPTOCFGA_PRIORITY_VAL , alg - > cra_priority ) )
goto nla_put_failure ;
if ( alg - > cra_flags & CRYPTO_ALG_LARVAL ) {
2018-11-29 17:42:19 +03:00
struct crypto_stat_larval rl ;
2018-09-19 13:10:54 +03:00
2018-11-04 00:56:01 +03:00
memset ( & rl , 0 , sizeof ( rl ) ) ;
2018-11-04 00:56:03 +03:00
strscpy ( rl . type , " larval " , sizeof ( rl . type ) ) ;
if ( nla_put ( skb , CRYPTOCFGA_STAT_LARVAL , sizeof ( rl ) , & rl ) )
2018-09-19 13:10:54 +03:00
goto nla_put_failure ;
goto out ;
}
2023-02-16 13:35:09 +03:00
if ( alg - > cra_type & & alg - > cra_type - > report_stat ) {
if ( alg - > cra_type - > report_stat ( skb , alg ) )
goto nla_put_failure ;
goto out ;
}
2018-09-19 13:10:54 +03:00
switch ( alg - > cra_flags & ( CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL ) ) {
case CRYPTO_ALG_TYPE_CIPHER :
if ( crypto_report_cipher ( skb , alg ) )
goto nla_put_failure ;
break ;
case CRYPTO_ALG_TYPE_COMPRESS :
if ( crypto_report_comp ( skb , alg ) )
goto nla_put_failure ;
break ;
case CRYPTO_ALG_TYPE_RNG :
if ( crypto_report_rng ( skb , alg ) )
goto nla_put_failure ;
break ;
default :
pr_err ( " ERROR: Unhandled alg %d in %s \n " ,
alg - > cra_flags & ( CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL ) ,
__func__ ) ;
}
out :
return 0 ;
nla_put_failure :
return - EMSGSIZE ;
}
static int crypto_reportstat_alg ( struct crypto_alg * alg ,
struct crypto_dump_info * info )
{
struct sk_buff * in_skb = info - > in_skb ;
struct sk_buff * skb = info - > out_skb ;
struct nlmsghdr * nlh ;
struct crypto_user_alg * ualg ;
int err = 0 ;
nlh = nlmsg_put ( skb , NETLINK_CB ( in_skb ) . portid , info - > nlmsg_seq ,
CRYPTO_MSG_GETSTAT , sizeof ( * ualg ) , info - > nlmsg_flags ) ;
if ( ! nlh ) {
err = - EMSGSIZE ;
goto out ;
}
ualg = nlmsg_data ( nlh ) ;
err = crypto_reportstat_one ( alg , ualg , skb ) ;
if ( err ) {
nlmsg_cancel ( skb , nlh ) ;
goto out ;
}
nlmsg_end ( skb , nlh ) ;
out :
return err ;
}
int crypto_reportstat ( struct sk_buff * in_skb , struct nlmsghdr * in_nlh ,
struct nlattr * * attrs )
{
2019-07-09 14:11:24 +03:00
struct net * net = sock_net ( in_skb - > sk ) ;
2018-09-19 13:10:54 +03:00
struct crypto_user_alg * p = nlmsg_data ( in_nlh ) ;
struct crypto_alg * alg ;
struct sk_buff * skb ;
struct crypto_dump_info info ;
int err ;
if ( ! null_terminated ( p - > cru_name ) | | ! null_terminated ( p - > cru_driver_name ) )
return - EINVAL ;
alg = crypto_alg_match ( p , 0 ) ;
if ( ! alg )
return - ENOENT ;
err = - ENOMEM ;
skb = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_ATOMIC ) ;
if ( ! skb )
goto drop_alg ;
info . in_skb = in_skb ;
info . out_skb = skb ;
info . nlmsg_seq = in_nlh - > nlmsg_seq ;
info . nlmsg_flags = 0 ;
err = crypto_reportstat_alg ( alg , & info ) ;
drop_alg :
crypto_mod_put ( alg ) ;
2019-10-04 22:34:54 +03:00
if ( err ) {
kfree_skb ( skb ) ;
2018-09-19 13:10:54 +03:00
return err ;
2019-10-04 22:34:54 +03:00
}
2018-09-19 13:10:54 +03:00
2019-07-09 14:11:24 +03:00
return nlmsg_unicast ( net - > crypto_nlsk , skb , NETLINK_CB ( in_skb ) . portid ) ;
2018-09-19 13:10:54 +03:00
}
MODULE_LICENSE ( " GPL " ) ;