@ -34,6 +34,11 @@ struct hash_ctx {
struct ahash_request req ;
} ;
struct algif_hash_tfm {
struct crypto_ahash * hash ;
bool has_key ;
} ;
static int hash_sendmsg ( struct socket * sock , struct msghdr * msg ,
size_t ignored )
{
@ -235,22 +240,151 @@ static struct proto_ops algif_hash_ops = {
. accept = hash_accept ,
} ;
static int hash_check_key ( struct socket * sock )
{
int err ;
struct sock * psk ;
struct alg_sock * pask ;
struct algif_hash_tfm * tfm ;
struct sock * sk = sock - > sk ;
struct alg_sock * ask = alg_sk ( sk ) ;
if ( ask - > refcnt )
return 0 ;
psk = ask - > parent ;
pask = alg_sk ( ask - > parent ) ;
tfm = pask - > private ;
err = - ENOKEY ;
lock_sock ( psk ) ;
if ( ! tfm - > has_key )
goto unlock ;
if ( ! pask - > refcnt + + )
sock_hold ( psk ) ;
ask - > refcnt = 1 ;
sock_put ( psk ) ;
err = 0 ;
unlock :
release_sock ( psk ) ;
return err ;
}
static int hash_sendmsg_nokey ( struct socket * sock , struct msghdr * msg ,
size_t size )
{
int err ;
err = hash_check_key ( sock ) ;
if ( err )
return err ;
return hash_sendmsg ( sock , msg , size ) ;
}
static ssize_t hash_sendpage_nokey ( struct socket * sock , struct page * page ,
int offset , size_t size , int flags )
{
int err ;
err = hash_check_key ( sock ) ;
if ( err )
return err ;
return hash_sendpage ( sock , page , offset , size , flags ) ;
}
static int hash_recvmsg_nokey ( struct socket * sock , struct msghdr * msg ,
size_t ignored , int flags )
{
int err ;
err = hash_check_key ( sock ) ;
if ( err )
return err ;
return hash_recvmsg ( sock , msg , ignored , flags ) ;
}
static int hash_accept_nokey ( struct socket * sock , struct socket * newsock ,
int flags )
{
int err ;
err = hash_check_key ( sock ) ;
if ( err )
return err ;
return hash_accept ( sock , newsock , flags ) ;
}
static struct proto_ops algif_hash_ops_nokey = {
. family = PF_ALG ,
. connect = sock_no_connect ,
. socketpair = sock_no_socketpair ,
. getname = sock_no_getname ,
. ioctl = sock_no_ioctl ,
. listen = sock_no_listen ,
. shutdown = sock_no_shutdown ,
. getsockopt = sock_no_getsockopt ,
. mmap = sock_no_mmap ,
. bind = sock_no_bind ,
. setsockopt = sock_no_setsockopt ,
. poll = sock_no_poll ,
. release = af_alg_release ,
. sendmsg = hash_sendmsg_nokey ,
. sendpage = hash_sendpage_nokey ,
. recvmsg = hash_recvmsg_nokey ,
. accept = hash_accept_nokey ,
} ;
static void * hash_bind ( const char * name , u32 type , u32 mask )
{
return crypto_alloc_ahash ( name , type , mask ) ;
struct algif_hash_tfm * tfm ;
struct crypto_ahash * hash ;
tfm = kzalloc ( sizeof ( * tfm ) , GFP_KERNEL ) ;
if ( ! tfm )
return ERR_PTR ( - ENOMEM ) ;
hash = crypto_alloc_ahash ( name , type , mask ) ;
if ( IS_ERR ( hash ) ) {
kfree ( tfm ) ;
return ERR_CAST ( hash ) ;
}
tfm - > hash = hash ;
return tfm ;
}
static void hash_release ( void * private )
{
crypto_free_ahash ( private ) ;
struct algif_hash_tfm * tfm = private ;
crypto_free_ahash ( tfm - > hash ) ;
kfree ( tfm ) ;
}
static int hash_setkey ( void * private , const u8 * key , unsigned int keylen )
{
return crypto_ahash_setkey ( private , key , keylen ) ;
struct algif_hash_tfm * tfm = private ;
int err ;
err = crypto_ahash_setkey ( tfm - > hash , key , keylen ) ;
tfm - > has_key = ! err ;
return err ;
}
static void hash_sock_destruct ( struct sock * sk )
static void hash_sock_destruct_common ( struct sock * sk )
{
struct alg_sock * ask = alg_sk ( sk ) ;
struct hash_ctx * ctx = ask - > private ;
@ -258,15 +392,40 @@ static void hash_sock_destruct(struct sock *sk)
sock_kzfree_s ( sk , ctx - > result ,
crypto_ahash_digestsize ( crypto_ahash_reqtfm ( & ctx - > req ) ) ) ;
sock_kfree_s ( sk , ctx , ctx - > len ) ;
}
static void hash_sock_destruct ( struct sock * sk )
{
hash_sock_destruct_common ( sk ) ;
af_alg_release_parent ( sk ) ;
}
static int hash_accept_parent ( void * private , struct sock * sk )
static void hash_release_parent_nokey ( struct sock * sk )
{
struct alg_sock * ask = alg_sk ( sk ) ;
if ( ! ask - > refcnt ) {
sock_put ( ask - > parent ) ;
return ;
}
af_alg_release_parent ( sk ) ;
}
static void hash_sock_destruct_nokey ( struct sock * sk )
{
hash_sock_destruct_common ( sk ) ;
hash_release_parent_nokey ( sk ) ;
}
static int hash_accept_parent_common ( void * private , struct sock * sk )
{
struct hash_ctx * ctx ;
struct alg_sock * ask = alg_sk ( sk ) ;
unsigned len = sizeof ( * ctx ) + crypto_ahash_reqsize ( private ) ;
unsigned ds = crypto_ahash_digestsize ( private ) ;
struct algif_hash_tfm * tfm = private ;
struct crypto_ahash * hash = tfm - > hash ;
unsigned len = sizeof ( * ctx ) + crypto_ahash_reqsize ( hash ) ;
unsigned ds = crypto_ahash_digestsize ( hash ) ;
ctx = sock_kmalloc ( sk , len , GFP_KERNEL ) ;
if ( ! ctx )
@ -286,7 +445,7 @@ static int hash_accept_parent(void *private, struct sock *sk)
ask - > private = ctx ;
ahash_request_set_tfm ( & ctx - > req , private ) ;
ahash_request_set_tfm ( & ctx - > req , hash ) ;
ahash_request_set_callback ( & ctx - > req , CRYPTO_TFM_REQ_MAY_BACKLOG ,
af_alg_complete , & ctx - > completion ) ;
@ -295,12 +454,38 @@ static int hash_accept_parent(void *private, struct sock *sk)
return 0 ;
}
static int hash_accept_parent ( void * private , struct sock * sk )
{
struct algif_hash_tfm * tfm = private ;
if ( ! tfm - > has_key & & crypto_ahash_has_setkey ( tfm - > hash ) )
return - ENOKEY ;
return hash_accept_parent_common ( private , sk ) ;
}
static int hash_accept_parent_nokey ( void * private , struct sock * sk )
{
int err ;
err = hash_accept_parent_common ( private , sk ) ;
if ( err )
goto out ;
sk - > sk_destruct = hash_sock_destruct_nokey ;
out :
return err ;
}
static const struct af_alg_type algif_type_hash = {
. bind = hash_bind ,
. release = hash_release ,
. setkey = hash_setkey ,
. accept = hash_accept_parent ,
. accept_nokey = hash_accept_parent_nokey ,
. ops = & algif_hash_ops ,
. ops_nokey = & algif_hash_ops_nokey ,
. name = " hash " ,
. owner = THIS_MODULE
} ;