]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
rand_egd: harden EGD I/O and bounds; defer fdopen until post connect
authorJoshua Rogers <MegaManSec@users.noreply.github.com>
Sun, 12 Oct 2025 13:52:21 +0000 (21:52 +0800)
committerNeil Horman <nhorman@openssl.org>
Thu, 12 Mar 2026 17:58:12 +0000 (13:58 -0400)
Tighten RAND_query_egd_bytes and fix edge cases:

* Reject nonpositive request sizes to avoid wrap when storing the
  length byte in tempbuf[1].
* Treat server length byte as untrusted; bound by the requested size
  and by sizeof(tempbuf) to avoid overrunning caller or stack buffers.
* Defer fdopen until after a successful connect. On HPE NonStop
  (OPENSSL_SYS_TANDEM) the connect retry path may swap the socket fd;
  creating the FILE* early could leave a stale stream pointing at a
  closed descriptor, causing EBADF or short I/O, and leaking the new
  socket. Creating the stream after connect avoids this.
* Initialize fd to -1 and close the raw fd when fdopen fails; ensure
  we close either FILE* or the raw fd on all error paths.
* Remove unused code.

Behavior is unchanged on platforms that do not swap fds during connect.
On TANDEM it prevents stale I/O and descriptor leaks. Overall this
improves robustness and bounds checking for EGD interactions.

Signed-off-by: Joshua Rogers <MegaManSec@users.noreply.github.com>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
MergeDate: Thu Mar 12 17:58:21 2026
(Merged from https://github.com/openssl/openssl/pull/28905)

crypto/rand/rand_egd.c

index ba8aa34dc2047c2ff456ad1cbba15897090d15e6..6513f4e557fe8bab41408f5527abf17cb78388eb 100644 (file)
@@ -108,10 +108,10 @@ int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
 {
     FILE *fp = NULL;
     struct sockaddr_un addr;
-    int mybuffer, ret = -1, i, numbytes, fd;
+    int mybuffer, ret = -1, i, numbytes, fd = -1;
     unsigned char tempbuf[255];
 
-    if (bytes > (int)sizeof(tempbuf))
+    if (bytes <= 0 || bytes > (int)sizeof(tempbuf))
         return -1;
 
     /* Make socket. */
@@ -126,9 +126,8 @@ int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
 #else
     fd = socket(AF_UNIX, SOCK_STREAM, 0);
 #endif
-    if (fd == -1 || (fp = fdopen(fd, "r+")) == NULL)
+    if (fd == -1)
         return -1;
-    setbuf(fp, NULL);
 
     /* Try to connect */
     for (;;) {
@@ -171,6 +170,14 @@ int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
         }
     }
 
+    /* Create stream only after a successful connect to avoid stale FILE* on fd swap. */
+    fp = fdopen(fd, "r+");
+    if (fp == NULL) {
+        close(fd);
+        return -1;
+    }
+    setbuf(fp, NULL);
+
     /* Make request, see how many bytes we can get back. */
     tempbuf[0] = 1;
     tempbuf[1] = bytes;
@@ -180,6 +187,9 @@ int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
         goto err;
     numbytes = tempbuf[0];
 
+    if (numbytes <= 0 || numbytes > bytes || numbytes > (int)sizeof(tempbuf))
+        goto err;
+
     /* Which buffer are we using? */
     mybuffer = buf == NULL;
     if (mybuffer)
@@ -196,6 +206,8 @@ int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
 err:
     if (fp != NULL)
         fclose(fp);
+    else if (fd != -1)
+        close(fd);
     return ret;
 }