File openssh-7.2p2-prevent_private_key_leakage.patch of Package openssh.29886
From 9de4e8533bf11b3d94becd16217d5322a31a7d74 Mon Sep 17 00:00:00 2001
From: Old openssh patches <pcerny@suse.com>
Date: Wed, 26 Oct 2022 09:56:19 +0200
Subject: [PATCH] openssh-7.2p2-prevent_private_key_leakage
# HG changeset patch
# Parent 04c1bb455bc260cd28dba823d5a325f84b586ad8
Pre-allocare buffer for private keys data to prevent leaking of sensitive data
via heap.
CVE-2016-10011
bsc#1016369
backported upstream commit 54d022026aae4f53fa74cc636e4a032d9689b64d
backported upstream commit a9c746088787549bb5b1ae3add7d06a1b6d93d5e
---
authfile.c | 14 ++++++++++-
sshbuf.c | 74 +++++++++++++++++++++++++++++++-----------------------
sshbuf.h | 8 ++++++
3 files changed, 63 insertions(+), 33 deletions(-)
diff --git a/authfile.c b/authfile.c
index d6704241..d2f04290 100644
--- a/authfile.c
+++ b/authfile.c
@@ -100,13 +100,25 @@ sshkey_load_file(int fd, struct sshbuf *blob)
u_char buf[1024];
size_t len;
struct stat st;
- int r;
+ int r, dontmax = 0;
if (fstat(fd, &st) < 0)
return SSH_ERR_SYSTEM_ERROR;
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
st.st_size > MAX_KEY_FILE_SIZE)
return SSH_ERR_INVALID_FORMAT;
+ /*
+ * Pre-allocate the buffer used for the key contents and clamp its
+ * maximum size. This ensures that key contents are never leaked via
+ * implicit realloc() in the sshbuf code.
+ */
+ if ((st.st_mode & S_IFREG) == 0 || st.st_size <= 0) {
+ st.st_size = 64*1024; /* 64k should be enough for anyone :) */
+ dontmax = 1;
+ }
+ if ((r = sshbuf_allocate(blob, st.st_size)) != 0 ||
+ (dontmax && (r = sshbuf_set_max_size(blob, st.st_size)) != 0))
+ return r;
for (;;) {
if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
if (errno == EPIPE)
diff --git a/sshbuf.c b/sshbuf.c
index 4d6e0ea0..562fd261 100644
--- a/sshbuf.c
+++ b/sshbuf.c
@@ -316,16 +316,13 @@ sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
}
int
-sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
+sshbuf_allocate(struct sshbuf *buf, size_t len)
{
size_t rlen, need;
u_char *dp;
int r;
- if (dpp != NULL)
- *dpp = NULL;
-
- SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
+ SSHBUF_DBG(("allocate buf = %p len = %zu", buf, len));
if ((r = sshbuf_check_reserve(buf, len)) != 0)
return r;
/*
@@ -333,36 +330,49 @@ sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
* then pack the buffer, zeroing buf->off.
*/
sshbuf_maybe_pack(buf, buf->size + len > buf->max_size);
- SSHBUF_TELL("reserve");
- if (len + buf->size > buf->alloc) {
- /*
- * Prefer to alloc in SSHBUF_SIZE_INC units, but
- * allocate less if doing so would overflow max_size.
- */
- need = len + buf->size - buf->alloc;
- rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC);
- SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
- if (rlen > buf->max_size)
- rlen = buf->alloc + need;
- SSHBUF_DBG(("adjusted rlen %zu", rlen));
- if ((dp = realloc(buf->d, rlen)) == NULL) {
- SSHBUF_DBG(("realloc fail"));
- if (dpp != NULL)
- *dpp = NULL;
- return SSH_ERR_ALLOC_FAIL;
- }
- buf->alloc = rlen;
- buf->cd = buf->d = dp;
- if ((r = sshbuf_check_reserve(buf, len)) < 0) {
- /* shouldn't fail */
- if (dpp != NULL)
- *dpp = NULL;
- return r;
- }
+ SSHBUF_TELL("allocate");
+ if (len + buf->size <= buf->alloc)
+ return 0; /* already have it. */
+
+ /*
+ * Prefer to alloc in SSHBUF_SIZE_INC units, but
+ * allocate less if doing so would overflow max_size.
+ */
+ need = len + buf->size - buf->alloc;
+ rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC);
+ SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
+ if (rlen > buf->max_size)
+ rlen = buf->alloc + need;
+ SSHBUF_DBG(("adjusted rlen %zu", rlen));
+ if ((dp = realloc(buf->d, rlen)) == NULL) {
+ SSHBUF_DBG(("realloc fail"));
+ return SSH_ERR_ALLOC_FAIL;
+ }
+ buf->alloc = rlen;
+ buf->cd = buf->d = dp;
+ if ((r = sshbuf_check_reserve(buf, len)) < 0) {
+ /* shouldn't fail */
+ return r;
}
+ SSHBUF_TELL("done");
+ return 0;
+}
+
+int
+sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
+{
+ u_char *dp;
+ int r;
+
+ if (dpp != NULL)
+ *dpp = NULL;
+
+ SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
+ if ((r = sshbuf_allocate(buf, len)) != 0)
+ return r;
+
dp = buf->d + buf->size;
buf->size += len;
- SSHBUF_TELL("done");
if (dpp != NULL)
*dpp = dp;
return 0;
diff --git a/sshbuf.h b/sshbuf.h
index 63495fbb..1cae68eb 100644
--- a/sshbuf.h
+++ b/sshbuf.h
@@ -138,6 +138,14 @@ u_char *sshbuf_mutable_ptr(const struct sshbuf *buf);
*/
int sshbuf_check_reserve(const struct sshbuf *buf, size_t len);
+/*
+ * Preallocates len additional bytes in buf.
+ * Useful for cases where the caller knows how many bytes will ultimately be
+ * required to avoid realloc in the buffer code.
+ * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
+ */
+int sshbuf_allocate(struct sshbuf *buf, size_t len);
+
/*
* Reserve len bytes in buf.
* Returns 0 on success and a pointer to the first reserved byte via the
--
2.38.0