]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nfsd: Use MD5 library instead of crypto_shash
authorEric Biggers <ebiggers@kernel.org>
Thu, 16 Oct 2025 18:15:34 +0000 (11:15 -0700)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 17 Nov 2025 13:46:12 +0000 (08:46 -0500)
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>
fs/nfsd/Kconfig
fs/nfsd/nfs4recover.c

index df09c5cefb7c1f5124b7963f52bb67254d5c08b6..0b5c1a0bf1cf75afc7bbbe1429e8028b7aeaaff9 100644 (file)
@@ -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
index b1005abcb9035b2cf743200808a251b00af7e3f4..aa15b30f9dbffa3ed255a12673cda398d309428b 100644 (file)
@@ -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;
 }