2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2013-02-07 02:12:08 +04:00
/*
* Copyright ( C ) 2013 Intel Corporation
*
* Author :
* Dmitry Kasatkin < dmitry . kasatkin @ intel . com >
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/err.h>
2014-07-02 16:12:26 +04:00
# include <linux/ratelimit.h>
2013-02-07 02:12:08 +04:00
# include <linux/key-type.h>
# include <crypto/public_key.h>
2016-03-04 00:49:27 +03:00
# include <crypto/hash_info.h>
2013-02-07 02:12:08 +04:00
# include <keys/asymmetric-type.h>
2015-12-02 18:47:55 +03:00
# include <keys/system_keyring.h>
2013-02-07 02:12:08 +04:00
# include "integrity.h"
/*
* Request an asymmetric key .
*/
static struct key * request_asymmetric_key ( struct key * keyring , uint32_t keyid )
{
struct key * key ;
char name [ 12 ] ;
2014-10-06 20:31:58 +04:00
sprintf ( name , " id:%08x " , keyid ) ;
2013-02-07 02:12:08 +04:00
pr_debug ( " key search: \" %s \" \n " , name ) ;
2015-12-02 18:47:55 +03:00
key = get_ima_blacklist_keyring ( ) ;
if ( key ) {
key_ref_t kref ;
kref = keyring_search ( make_key_ref ( key , 1 ) ,
2019-06-26 23:02:32 +03:00
& key_type_asymmetric , name , true ) ;
2015-12-02 18:47:55 +03:00
if ( ! IS_ERR ( kref ) ) {
pr_err ( " Key '%s' is in ima_blacklist_keyring \n " , name ) ;
return ERR_PTR ( - EKEYREJECTED ) ;
}
}
2013-02-07 02:12:08 +04:00
if ( keyring ) {
/* search in specific keyring */
key_ref_t kref ;
2015-12-02 18:47:55 +03:00
2013-02-07 02:12:08 +04:00
kref = keyring_search ( make_key_ref ( keyring , 1 ) ,
2019-06-26 23:02:32 +03:00
& key_type_asymmetric , name , true ) ;
2013-02-07 02:12:08 +04:00
if ( IS_ERR ( kref ) )
key = ERR_CAST ( kref ) ;
else
key = key_ref_to_ptr ( kref ) ;
} else {
2019-07-11 04:43:43 +03:00
key = request_key ( & key_type_asymmetric , name , NULL ) ;
2013-02-07 02:12:08 +04:00
}
if ( IS_ERR ( key ) ) {
2014-07-02 16:12:26 +04:00
pr_err_ratelimited ( " Request for unknown key '%s' err %ld \n " ,
name , PTR_ERR ( key ) ) ;
2013-02-07 02:12:08 +04:00
switch ( PTR_ERR ( key ) ) {
/* Hide some search errors */
case - EACCES :
case - ENOTDIR :
case - EAGAIN :
return ERR_PTR ( - ENOKEY ) ;
default :
return key ;
}
}
pr_debug ( " %s() = 0 [%x] \n " , __func__ , key_serial ( key ) ) ;
return key ;
}
int asymmetric_verify ( struct key * keyring , const char * sig ,
int siglen , const char * data , int datalen )
{
struct public_key_signature pks ;
struct signature_v2_hdr * hdr = ( struct signature_v2_hdr * ) sig ;
struct key * key ;
int ret = - ENOMEM ;
if ( siglen < = sizeof ( * hdr ) )
return - EBADMSG ;
siglen - = sizeof ( * hdr ) ;
2017-06-08 04:49:10 +03:00
if ( siglen ! = be16_to_cpu ( hdr - > sig_size ) )
2013-02-07 02:12:08 +04:00
return - EBADMSG ;
2016-03-04 00:49:27 +03:00
if ( hdr - > hash_algo > = HASH_ALGO__LAST )
2013-02-07 02:12:08 +04:00
return - ENOPKG ;
2017-06-08 04:49:10 +03:00
key = request_asymmetric_key ( keyring , be32_to_cpu ( hdr - > keyid ) ) ;
2013-02-07 02:12:08 +04:00
if ( IS_ERR ( key ) )
return PTR_ERR ( key ) ;
memset ( & pks , 0 , sizeof ( pks ) ) ;
2016-03-04 00:49:27 +03:00
pks . hash_algo = hash_algo_name [ hdr - > hash_algo ] ;
2019-04-11 18:51:22 +03:00
if ( hdr - > hash_algo = = HASH_ALGO_STREEBOG_256 | |
hdr - > hash_algo = = HASH_ALGO_STREEBOG_512 ) {
/* EC-RDSA and Streebog should go together. */
pks . pkey_algo = " ecrdsa " ;
pks . encoding = " raw " ;
} else {
pks . pkey_algo = " rsa " ;
pks . encoding = " pkcs1 " ;
}
2013-02-07 02:12:08 +04:00
pks . digest = ( u8 * ) data ;
pks . digest_size = datalen ;
2016-02-02 21:08:58 +03:00
pks . s = hdr - > sig ;
pks . s_size = siglen ;
ret = verify_signature ( key , & pks ) ;
2013-02-07 02:12:08 +04:00
key_put ( key ) ;
pr_debug ( " %s() = %d \n " , __func__ , ret ) ;
return ret ;
}
integrity: prevent deadlock during digsig verification.
This patch aimed to prevent deadlock during digsig verification.The point
of issue - user space utility modprobe and/or it's dependencies (ld-*.so,
libz.so.*, libc-*.so and /lib/modules/ files) that could be used for
kernel modules load during digsig verification and could be signed by
digsig in the same time.
First at all, look at crypto_alloc_tfm() work algorithm:
crypto_alloc_tfm() will first attempt to locate an already loaded
algorithm. If that fails and the kernel supports dynamically loadable
modules, it will then attempt to load a module of the same name or alias.
If that fails it will send a query to any loaded crypto manager to
construct an algorithm on the fly.
We have situation, when public_key_verify_signature() in case of RSA
algorithm use alg_name to store internal information in order to construct
an algorithm on the fly, but crypto_larval_lookup() will try to use
alg_name in order to load kernel module with same name.
1) we can't do anything with crypto module work, since it designed to work
exactly in this way;
2) we can't globally filter module requests for modprobe, since it
designed to work with any requests.
In this patch, I propose add an exception for "crypto-pkcs1pad(rsa,*)"
module requests only in case of enabled integrity asymmetric keys support.
Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules for
sure, we are safe to fail such module request from crypto_larval_lookup().
In this way we prevent modprobe execution during digsig verification and
avoid possible deadlock if modprobe and/or it's dependencies also signed
with digsig.
Requested "crypto-pkcs1pad(rsa,*)" kernel module name formed by:
1) "pkcs1pad(rsa,%s)" in public_key_verify_signature();
2) "crypto-%s" / "crypto-%s-all" in crypto_larval_lookup().
"crypto-pkcs1pad(rsa," part of request is a constant and unique and could
be used as filter.
Signed-off-by: Mikhail Kurinnoi <viewizard@viewizard.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
include/linux/integrity.h | 13 +++++++++++++
security/integrity/digsig_asymmetric.c | 23 +++++++++++++++++++++++
security/security.c | 7 ++++++-
3 files changed, 42 insertions(+), 1 deletion(-)
2018-06-27 16:33:42 +03:00
/**
* integrity_kernel_module_request - prevent crypto - pkcs1pad ( rsa , * ) requests
* @ kmod_name : kernel module name
*
* We have situation , when public_key_verify_signature ( ) in case of RSA
* algorithm use alg_name to store internal information in order to
* construct an algorithm on the fly , but crypto_larval_lookup ( ) will try
* to use alg_name in order to load kernel module with same name .
* Since we don ' t have any real " crypto-pkcs1pad(rsa,*) " kernel modules ,
* we are safe to fail such module request from crypto_larval_lookup ( ) .
*
* In this way we prevent modprobe execution during digsig verification
* and avoid possible deadlock if modprobe and / or it ' s dependencies
* also signed with digsig .
*/
int integrity_kernel_module_request ( char * kmod_name )
{
if ( strncmp ( kmod_name , " crypto-pkcs1pad(rsa, " , 20 ) = = 0 )
return - EINVAL ;
return 0 ;
}