This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit b2abfc982a5343dba1434deb6fbffdf7c0269b87
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 26 09:02:21 2026 +0100

    libs/libc/unistd: Fail crypt_r() when a step of the MD5 hash fails.
    
    crypt_r() computes MD5 through /dev/crypto and ignored the result of
    each step.  Without /dev/crypto (no CRYPTO_CRYPTODEV), or when an ioctl()
    failed, it returned "$1$<salt>$" and a hash of whatever was in its buffer
    (zeros, or another value on each call), not an error.  A failed open()
    of a step also left the session or the file open.
    
    Keep the first error of a step in the context: the later steps do
    nothing, and md5_finish() closes the session and the file on every path
    and returns the error.  crypt_r() then returns NULL with errno set.  A
    salt that is not "$1$" and a key that is too long also set EINVAL.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 libs/libc/unistd/lib_crypt_r.c | 108 ++++++++++++++++++++++++++++-------------
 1 file changed, 75 insertions(+), 33 deletions(-)

diff --git a/libs/libc/unistd/lib_crypt_r.c b/libs/libc/unistd/lib_crypt_r.c
index 3fac5a5d3fa..dc3d71db5ec 100644
--- a/libs/libc/unistd/lib_crypt_r.c
+++ b/libs/libc/unistd/lib_crypt_r.c
@@ -25,6 +25,7 @@
 #include <crypto/cryptodev.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdbool.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
@@ -43,6 +44,8 @@
 typedef struct cryptodev_context_s
 {
   int fd;
+  int error;                  /* The first error (negative errno), or 0 */
+  bool session_open;          /* CIOCGSESSION done (ids start at 0) */
   struct session_op session;
   struct crypt_op crypt;
 }cryptodev_context_t;
@@ -71,48 +74,60 @@ static FAR char *md5_to64(FAR char *s, unsigned long v, int 
n)
   return s;
 }
 
-static int md5_init(FAR cryptodev_context_t *ctx)
+/* A failed step keeps its error in ctx->error: the later steps do nothing,
+ * and md5_finish() returns the error after it closes the session.
+ */
+
+static void md5_init(FAR cryptodev_context_t *ctx)
 {
-  int ret;
   int fd;
 
   memset(ctx, 0, sizeof(cryptodev_context_t));
+  ctx->fd = -1;
   fd = open("/dev/crypto", O_RDWR, 0);
   if (fd < 0)
     {
-      return -get_errno();
+      ctx->error = -get_errno();
+      return;
     }
 
-  ret = ioctl(fd, CRIOGET, &ctx->fd);
-  close(fd);
-  if (ret < 0)
+  if (ioctl(fd, CRIOGET, &ctx->fd) < 0)
     {
-      return -get_errno();
+      ctx->error = -get_errno();
+      ctx->fd = -1;
+      close(fd);
+      return;
     }
 
+  close(fd);
   ctx->session.mac = CRYPTO_MD5;
-  ret = ioctl(ctx->fd, CIOCGSESSION, &ctx->session);
-  if (ret < 0)
+  if (ioctl(ctx->fd, CIOCGSESSION, &ctx->session) < 0)
     {
-      return -get_errno();
+      ctx->error = -get_errno();
+      return;
     }
 
+  ctx->session_open = true;
   ctx->crypt.ses = ctx->session.ses;
-  return ret;
 }
 
-static int md5_update(FAR cryptodev_context_t *ctx,
-                      FAR const void *input, size_t ilen)
+static void md5_update(FAR cryptodev_context_t *ctx,
+                       FAR const void *input, size_t ilen)
 {
-  int ret;
+  if (ctx->error < 0)
+    {
+      return;
+    }
 
   ctx->crypt.op = COP_ENCRYPT;
   ctx->crypt.flags |= COP_FLAG_UPDATE;
   ctx->crypt.src = (caddr_t)input;
   ctx->crypt.len = ilen;
 
-  ret = ioctl(ctx->fd, CIOCCRYPT, &ctx->crypt);
-  return ret < 0 ? -get_errno() : ret;
+  if (ioctl(ctx->fd, CIOCCRYPT, &ctx->crypt) < 0)
+    {
+      ctx->error = -get_errno();
+    }
 }
 
 static int md5_finish(FAR cryptodev_context_t *ctx,
@@ -120,18 +135,28 @@ static int md5_finish(FAR cryptodev_context_t *ctx,
 {
   int ret;
 
-  ctx->crypt.op = COP_ENCRYPT;
-  ctx->crypt.flags = 0;
-  ctx->crypt.mac = (caddr_t)output;
-  ret = ioctl(ctx->fd, CIOCCRYPT, &ctx->crypt);
-  if (ret < 0)
+  if (ctx->error == 0)
+    {
+      ctx->crypt.op = COP_ENCRYPT;
+      ctx->crypt.flags = 0;
+      ctx->crypt.mac = (caddr_t)output;
+      if (ioctl(ctx->fd, CIOCCRYPT, &ctx->crypt) < 0)
+        {
+          ctx->error = -get_errno();
+        }
+    }
+
+  if (ctx->fd >= 0)
     {
-      return -get_errno();
+      if (ctx->session_open)
+        {
+          ioctl(ctx->fd, CIOCFSESSION, &ctx->session.ses);
+        }
+
+      close(ctx->fd);
     }
 
-  ioctl(ctx->fd, CIOCFSESSION, &ctx->session.ses);
-  ctx->crypt.ses = 0;
-  close(ctx->fd);
+  ret = ctx->error;
   memset(ctx, 0, sizeof(cryptodev_context_t));
   return ret;
 }
@@ -150,6 +175,7 @@ static FAR char *md5_crypt(FAR const char *key, FAR const 
char *setting,
   unsigned int slen;
   FAR const char *salt;
   FAR char *p;
+  int ret;
   static const unsigned char perm[][3] =
   {
     {
@@ -174,7 +200,8 @@ static FAR char *md5_crypt(FAR const char *key, FAR const 
char *setting,
   klen = strnlen(key, KEY_MAX + 1);
   if (klen > KEY_MAX)
     {
-      return 0;
+      set_errno(EINVAL);
+      return NULL;
     }
 
   /* Setting: $1$salt$ (closing $ is optional) */
@@ -189,7 +216,11 @@ static FAR char *md5_crypt(FAR const char *key, FAR const 
char *setting,
   md5_update(&ctx, key, klen);
   md5_update(&ctx, salt, slen);
   md5_update(&ctx, key, klen);
-  md5_finish(&ctx, md);
+  ret = md5_finish(&ctx, md);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
   /* Md5(key $1$ salt repeated-md weird-key[0]-0) */
 
@@ -215,7 +246,11 @@ static FAR char *md5_crypt(FAR const char *key, FAR const 
char *setting,
         }
     }
 
-  md5_finish(&ctx, md);
+  ret = md5_finish(&ctx, md);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
   for (i = 0; i < 1000; i++)
     {
@@ -248,7 +283,11 @@ static FAR char *md5_crypt(FAR const char *key, FAR const 
char *setting,
           md5_update(&ctx, key, klen);
         }
 
-      md5_finish(&ctx, md);
+      ret = md5_finish(&ctx, md);
+      if (ret < 0)
+        {
+          goto errout;
+        }
     }
 
   /* Output is $1$salt$hash */
@@ -267,6 +306,10 @@ static FAR char *md5_crypt(FAR const char *key, FAR const 
char *setting,
   *p = 0;
 
   return output;
+
+errout:
+  set_errno(-ret);
+  return NULL;
 }
 
 /****************************************************************************
@@ -284,8 +327,7 @@ FAR char *crypt_r(FAR const char *key, FAR const char *salt,
     {
       return md5_crypt(key, salt, output);
     }
-  else
-    {
-      return NULL;
-    }
+
+  set_errno(EINVAL);
+  return NULL;
 }

Reply via email to