nfsd: Use MD5 library instead of crypto_shash
Update NFSD's support for "legacy client tracking" (which uses MD5) to use the MD5 library instead of crypto_shash. This has several benefits: - Simpler code. Notably, much of the error-handling code is no longer needed, since the library functions can't fail. - Improved performance due to reduced overhead. A microbenchmark of nfs4_make_rec_clidname() shows a speedup from 1455 cycles to 425. - The MD5 code can now safely be built as a loadable module when nfsd is built as a loadable module. (Previously, nfsd forced the MD5 code to built-in, presumably to work around the unreliability of the name-based loading.) Thus select MD5 from the tristate option NFSD if NFSD_LEGACY_CLIENT_TRACKING, instead of from the bool option NFSD_V4. - Fixes a bug where legacy client tracking was not supported on kernels booted with "fips=1", due to crypto_shash not allowing MD5 to be used. This particular use of MD5 is not for a cryptographic purpose, though, so it is acceptable even when fips=1 (see https://lore.kernel.org/r/dae495a93cbcc482f4ca23c3a0d9360a1fd8c3a8.camel@redhat.com/). Signed-off-by: Eric Biggers <ebiggers@kernel.org> Acked-by: Ard Biesheuvel <ardb@kernel.org> Acked-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Scott Mayhew <smayhew@redhat.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>pull/1354/merge
parent
fceb8734e7
commit
78cd170d03
|
|
@ -5,6 +5,7 @@ config NFSD
|
|||
depends on FILE_LOCKING
|
||||
depends on FSNOTIFY
|
||||
select CRC32
|
||||
select CRYPTO_LIB_MD5 if NFSD_LEGACY_CLIENT_TRACKING
|
||||
select CRYPTO_LIB_SHA256 if NFSD_V4
|
||||
select LOCKD
|
||||
select SUNRPC
|
||||
|
|
@ -77,8 +78,7 @@ config NFSD_V4
|
|||
depends on NFSD && PROC_FS
|
||||
select FS_POSIX_ACL
|
||||
select RPCSEC_GSS_KRB5
|
||||
select CRYPTO
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO # required by RPCSEC_GSS_KRB5
|
||||
select GRACE_PERIOD
|
||||
select NFS_V4_2_SSC_HELPER if NFS_V4_2
|
||||
help
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/md5.h>
|
||||
#include <crypto/sha2.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -92,57 +92,18 @@ nfs4_reset_creds(const struct cred *original)
|
|||
put_cred(revert_creds(original));
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
nfs4_make_rec_clidname(char dname[HEXDIR_LEN], const struct xdr_netobj *clname)
|
||||
{
|
||||
u8 digest[MD5_DIGEST_SIZE];
|
||||
struct crypto_shash *tfm;
|
||||
int status;
|
||||
|
||||
dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
|
||||
clname->len, clname->data);
|
||||
tfm = crypto_alloc_shash("md5", 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
status = PTR_ERR(tfm);
|
||||
goto out_no_tfm;
|
||||
}
|
||||
|
||||
status = crypto_shash_tfm_digest(tfm, clname->data, clname->len,
|
||||
digest);
|
||||
if (status)
|
||||
goto out;
|
||||
md5(clname->data, clname->len, digest);
|
||||
|
||||
static_assert(HEXDIR_LEN == 2 * MD5_DIGEST_SIZE + 1);
|
||||
sprintf(dname, "%*phN", MD5_DIGEST_SIZE, digest);
|
||||
|
||||
status = 0;
|
||||
out:
|
||||
crypto_free_shash(tfm);
|
||||
out_no_tfm:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we had an error generating the recdir name for the legacy tracker
|
||||
* then warn the admin. If the error doesn't appear to be transient,
|
||||
* then disable recovery tracking.
|
||||
*/
|
||||
static void
|
||||
legacy_recdir_name_error(struct nfs4_client *clp, int error)
|
||||
{
|
||||
printk(KERN_ERR "NFSD: unable to generate recoverydir "
|
||||
"name (%d).\n", error);
|
||||
|
||||
/*
|
||||
* if the algorithm just doesn't exist, then disable the recovery
|
||||
* tracker altogether. The crypto libs will generally return this if
|
||||
* FIPS is enabled as well.
|
||||
*/
|
||||
if (error == -ENOENT) {
|
||||
printk(KERN_ERR "NFSD: disabling legacy clientid tracking. "
|
||||
"Reboot recovery will not function correctly!\n");
|
||||
nfsd4_client_tracking_exit(clp->net);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -171,9 +132,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
|
|||
if (!nn->rec_file)
|
||||
return;
|
||||
|
||||
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
if (status)
|
||||
return legacy_recdir_name_error(clp, status);
|
||||
nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
|
||||
status = nfs4_save_creds(&original_cred);
|
||||
if (status < 0)
|
||||
|
|
@ -354,9 +313,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
|
|||
if (!nn->rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
|
||||
return;
|
||||
|
||||
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
if (status)
|
||||
return legacy_recdir_name_error(clp, status);
|
||||
nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
|
||||
status = mnt_want_write_file(nn->rec_file);
|
||||
if (status)
|
||||
|
|
@ -636,7 +593,6 @@ nfs4_recoverydir(void)
|
|||
static int
|
||||
nfsd4_check_legacy_client(struct nfs4_client *clp)
|
||||
{
|
||||
int status;
|
||||
char dname[HEXDIR_LEN];
|
||||
struct nfs4_client_reclaim *crp;
|
||||
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
|
||||
|
|
@ -646,11 +602,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
|
|||
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
|
||||
return 0;
|
||||
|
||||
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
if (status) {
|
||||
legacy_recdir_name_error(clp, status);
|
||||
return status;
|
||||
}
|
||||
nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
|
||||
/* look for it in the reclaim hashtable otherwise */
|
||||
name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
|
||||
|
|
@ -1243,13 +1195,10 @@ nfsd4_cld_check(struct nfs4_client *clp)
|
|||
|
||||
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
|
||||
if (nn->cld_net->cn_has_legacy) {
|
||||
int status;
|
||||
char dname[HEXDIR_LEN];
|
||||
struct xdr_netobj name;
|
||||
|
||||
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
if (status)
|
||||
return -ENOENT;
|
||||
nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
|
||||
name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
|
||||
if (!name.data) {
|
||||
|
|
@ -1294,11 +1243,8 @@ nfsd4_cld_check_v2(struct nfs4_client *clp)
|
|||
if (cn->cn_has_legacy) {
|
||||
struct xdr_netobj name;
|
||||
char dname[HEXDIR_LEN];
|
||||
int status;
|
||||
|
||||
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
if (status)
|
||||
return -ENOENT;
|
||||
nfs4_make_rec_clidname(dname, &clp->cl_name);
|
||||
|
||||
name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
|
||||
if (!name.data) {
|
||||
|
|
@ -1671,11 +1617,7 @@ nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
copied = nfs4_make_rec_clidname(result + copied, name);
|
||||
if (copied) {
|
||||
kfree(result);
|
||||
return NULL;
|
||||
}
|
||||
nfs4_make_rec_clidname(result + copied, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue