Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
libssh (0.11.3-1deepin13) unstable; urgency=medium

* fix(cve): CVE-2026-59846

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 13:20:56 +0800

libssh (0.11.3-1deepin12) unstable; urgency=medium

* fix(cve): CVE-2026-59849

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 13:11:23 +0800

libssh (0.11.3-1deepin11) unstable; urgency=medium

* fix(cve): CVE-2026-59850

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 13:03:37 +0800

libssh (0.11.3-1deepin10) unstable; urgency=medium

* fix(cve): CVE-2026-59845

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 12:54:40 +0800

libssh (0.11.3-1deepin9) unstable; urgency=medium

* fix(cve): CVE-2026-15370

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 12:49:16 +0800

libssh (0.11.3-1deepin8) unstable; urgency=medium

* fix(cve): CVE-2026-59848

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 12:38:46 +0800

libssh (0.11.3-1deepin7) unstable; urgency=medium

* fix(cve): CVE-2026-59847

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 12:25:10 +0800

libssh (0.11.3-1deepin6) unstable; urgency=medium

* fix(cve): CVE-2026-59844

-- deepin-ci-robot <packages@deepin.org> Mon, 27 Jul 2026 12:10:33 +0800

libssh (0.11.3-1deepin5) unstable; urgency=medium

* fix(cve): CVE-2026-0965
Expand Down
329 changes: 329 additions & 0 deletions debian/patches/CVE-2026-15370.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
Description: CVE-2026-15370 - 安全修复
Author: YubarajDas <dasyubaraj2020@gmail.com>
Origin: https://gitlab.com/libssh/libssh-mirror/-/commit/b2065f71c905d347b5e8dd7f8e24856807d71e99
Bug: https://nvd.nist.gov/vuln/detail/CVE-2026-15370
Last-Update: 2026-04-22 22:40:19 +0530
---
diff --git a/config.h.cmake b/config.h.cmake
index 8dce527..b97fb52 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -135,6 +135,12 @@
/* Define to 1 if you have the `strndup' function. */
#cmakedefine HAVE_STRNDUP 1

+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#cmakedefine HAVE_STRLCAT 1
+
/* Define to 1 if you have the `cfmakeraw' function. */
#cmakedefine HAVE_CFMAKERAW 1

diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index 6206997..0f19c34 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -59,6 +59,14 @@ extern "C" {
char *strndup(const char *s, size_t n);
#endif /* ! HAVE_STRNDUP */

+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t size);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t size);
+#endif
+
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
diff --git a/src/gcrypt_missing.c b/src/gcrypt_missing.c
index 5f84e6b..dc06377 100644
--- a/src/gcrypt_missing.c
+++ b/src/gcrypt_missing.c
@@ -61,7 +61,8 @@ char *ssh_gcry_bn2dec(bignum bn) {
}

if (!gcry_mpi_cmp_ui(bn, 0)) {
- strcpy(ret, "0");
+ ret[0] = '0';
+ ret[1] = '\0';
} else {
ten = bignum_new();
if (ten == NULL) {
diff --git a/src/getpass.c b/src/getpass.c
index c19c4bc..384f06e 100644
--- a/src/getpass.c
+++ b/src/getpass.c
@@ -74,7 +74,7 @@ static int ssh_gets(const char *prompt, char *buf, size_t len, int verify)
fprintf(stdout, "\n");

if (*tmp) {
- strncpy(buf, tmp, len);
+ strlcpy(buf, tmp, len);
}

if (verify) {
diff --git a/src/knownhosts.c b/src/knownhosts.c
index 3ab468d..5f37c8e 100644
--- a/src/knownhosts.c
+++ b/src/knownhosts.c
@@ -594,14 +594,10 @@ char *ssh_known_hosts_get_algorithms_names(ssh_session session)
}

if (needcomma) {
- strncat(methods_buffer,
- ",",
- sizeof(methods_buffer) - strlen(methods_buffer) - 1);
+ strlcat(methods_buffer, ",", sizeof(methods_buffer));
}

- strncat(methods_buffer,
- algo,
- sizeof(methods_buffer) - strlen(methods_buffer) - 1);
+ strlcat(methods_buffer, algo, sizeof(methods_buffer));
needcomma = true;

ssh_knownhosts_entry_free(entry);
diff --git a/src/match.c b/src/match.c
index 771ee63..eb765ef 100644
--- a/src/match.c
+++ b/src/match.c
@@ -384,7 +384,7 @@ match_cidr_address_list(const char *address,
}

if (address != NULL) {
- strncpy(addr, address, NI_MAXHOST - 1);
+ strlcpy(addr, address, sizeof(addr));

/* Remove interface in case of IPv6 address: addr%interface */
a = strchr(addr, '%');
@@ -482,7 +482,7 @@ match_cidr_address_list(const char *address,
}
#undef VALID_CIDR_CHARS

- strncpy(addr_buffer, cp, sizeof(addr_buffer) - 1);
+ strlcpy(addr_buffer, cp, sizeof(addr_buffer));
sp = strchr(addr_buffer, '/');
if (sp != NULL) {
*sp = '\0';
diff --git a/src/misc.c b/src/misc.c
index 3968e6b..218fbbf 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -952,8 +952,7 @@ char *ssh_dirname (const char *path)
return NULL;
}

- strncpy(new, path, len);
- new[len] = '\0';
+ strlcpy(new, path, len + 1);

return new;
}
@@ -1010,8 +1009,7 @@ char *ssh_basename (const char *path)
return NULL;
}

- strncpy(new, s, len);
- new[len] = '\0';
+ strlcpy(new, s, len + 1);

return new;
}
@@ -1316,7 +1314,7 @@ char *ssh_path_expand_escape(ssh_session session, const char *s)
return NULL;
}
l = strlen(buf);
- strncpy(buf + l, x, MAX_BUF_SIZE - l - 1);
+ strlcpy(buf + l, x, MAX_BUF_SIZE - l);
buf[i] = '\0';
SAFE_FREE(x);
}
@@ -2318,4 +2316,47 @@ FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
return f;
}

+/*
+ * BSD-compatible fallback implementations for systems without native
+ * strlcpy/strlcat. These are original implementations following the OpenBSD API
+ * specification. The strlcpy() and strlcat() API was designed by Todd C.
+ * Miller. See: https://man.openbsd.org/strlcpy.3
+ */
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+ size_t len = strlen(src);
+
+ if (size != 0) {
+ size_t copy_len = (len >= size) ? size - 1 : len;
+
+ memcpy(dst, src, copy_len);
+ dst[copy_len] = '\0';
+ }
+
+ return len;
+}
+#endif /* HAVE_STRLCPY */
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+ size_t dst_len;
+ const char *p = memchr(dst, '\0', size);
+ size_t src_len = strlen(src);
+
+ dst_len = (p != NULL) ? (size_t)(p - dst) : size;
+
+ if (dst_len < size) {
+ size_t copy_len =
+ (src_len >= size - dst_len) ? size - dst_len - 1 : src_len;
+ memcpy(dst + dst_len, src, copy_len);
+ dst[dst_len + copy_len] = '\0';
+ }
+
+ return dst_len + src_len;
+}
+#endif /* HAVE_STRLCAT */
+
/** @} */
diff --git a/src/options.c b/src/options.c
index 785296d..f084b5a 100644
--- a/src/options.c
+++ b/src/options.c
@@ -2663,7 +2663,7 @@ static char *ssh_bind_options_expand_escape(ssh_bind sshbind, const char *s)
return NULL;
}
l = strlen(buf);
- strncpy(buf + l, x, MAX_BUF_SIZE - l - 1);
+ strlcpy(buf + l, x, MAX_BUF_SIZE - l);
buf[i] = '\0';
SAFE_FREE(x);
}
diff --git a/src/server.c b/src/server.c
index c6ad11f..9430c57 100644
--- a/src/server.c
+++ b/src/server.c
@@ -619,24 +619,19 @@ int ssh_auth_reply_default(ssh_session session,int partial) {
session->auth.supported_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD;
}
if (session->auth.supported_methods & SSH_AUTH_METHOD_PUBLICKEY) {
- strncat(methods_c, "publickey,",
- sizeof(methods_c) - strlen(methods_c) - 1);
+ strlcat(methods_c, "publickey,", sizeof(methods_c));
}
if (session->auth.supported_methods & SSH_AUTH_METHOD_GSSAPI_MIC){
- strncat(methods_c,"gssapi-with-mic,",
- sizeof(methods_c) - strlen(methods_c) - 1);
+ strlcat(methods_c, "gssapi-with-mic,", sizeof(methods_c));
}
if (session->auth.supported_methods & SSH_AUTH_METHOD_INTERACTIVE) {
- strncat(methods_c, "keyboard-interactive,",
- sizeof(methods_c) - strlen(methods_c) - 1);
+ strlcat(methods_c, "keyboard-interactive,", sizeof(methods_c));
}
if (session->auth.supported_methods & SSH_AUTH_METHOD_PASSWORD) {
- strncat(methods_c, "password,",
- sizeof(methods_c) - strlen(methods_c) - 1);
+ strlcat(methods_c, "password,", sizeof(methods_c));
}
if (session->auth.supported_methods & SSH_AUTH_METHOD_HOSTBASED) {
- strncat(methods_c, "hostbased,",
- sizeof(methods_c) - strlen(methods_c) - 1);
+ strlcat(methods_c, "hostbased,", sizeof(methods_c));
}

if (methods_c[0] == '\0' || methods_c[strlen(methods_c)-1] != ',') {
diff --git a/src/sftpserver.c b/src/sftpserver.c
index 9a09dc3..46b191f 100644
--- a/src/sftpserver.c
+++ b/src/sftpserver.c
@@ -1200,16 +1200,20 @@ readdir_long_name(char *z_file_name, struct stat *z_st, char *z_long_name)
*ptr++ = ' ';
*ptr = '\0';

- snprintf(tmpbuf, sizeof(tmpbuf), "%3d %d %d %d", (int)z_st->st_nlink,
- (int)z_st->st_uid, (int)z_st->st_gid, (int)z_st->st_size);
- strcat(z_long_name, tmpbuf);
-
ctime_r(&z_st->st_mtime, time);
if ((ptr = strchr(time, '\n'))) {
*ptr = '\0';
}
- snprintf(tmpbuf, sizeof(tmpbuf), " %s %s", time + 4, z_file_name);
- strcat(z_long_name, tmpbuf);
+ snprintf(tmpbuf,
+ sizeof(tmpbuf),
+ "%3d %d %d %d %s %s",
+ (int)z_st->st_nlink,
+ (int)z_st->st_uid,
+ (int)z_st->st_gid,
+ (int)z_st->st_size,
+ time + 4,
+ z_file_name);
+ strlcat(z_long_name, tmpbuf, MAX_LONG_NAME_LEN);

return SSH_OK;
}
diff --git a/src/token.c b/src/token.c
index 6ce2b64..4c03256 100644
--- a/src/token.c
+++ b/src/token.c
@@ -338,9 +338,9 @@ char *ssh_remove_duplicates(const char *list)
for (i = 0; i < num_tokens; i++) {
if (should_copy[i]) {
if (need_comma) {
- strncat(ret, ",", (max_len - strlen(ret) - 1));
+ strlcat(ret, ",", max_len);
}
- strncat(ret, tok->tokens[i], (max_len - strlen(ret) - 1));
+ strlcat(ret, tok->tokens[i], max_len);
need_comma = true;
}
}
diff --git a/tests/client/torture_auth.c b/tests/client/torture_auth.c
index 614d80f..7eb8852 100644
--- a/tests/client/torture_auth.c
+++ b/tests/client/torture_auth.c
@@ -420,7 +420,7 @@ torture_auth_autopubkey_protected_auth_function (const char *prompt, char *buf,
ssh_string_free_char(expected_id);

data->n_calls += 1;
- strncpy(buf, "secret", len);
+ strlcpy(buf, "secret", len);
return 0;
}

diff --git a/tests/torture.c b/tests/torture.c
index 6bdd646..443d952 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -1593,8 +1593,7 @@ static int recursive_rm_dir_content(const char *path)
int rc = 0;
BOOL removed;

- strcpy(file_path, path);
- strcat(file_path, "\\*");
+ snprintf(file_path, sizeof(file_path), "%s\\*", path);

file_handle = FindFirstFile(file_path, &file_data);

@@ -1624,9 +1623,11 @@ static int recursive_rm_dir_content(const char *path)
}

/* Create full file path */
- strcpy(file_path, path);
- strcat(file_path, "\\");
- strcat(file_path, file_data.cFileName);
+ snprintf(file_path,
+ sizeof(file_path),
+ "%s\\%s",
+ path,
+ file_data.cFileName);

attributes = GetFileAttributes(file_path);
if (attributes & FILE_ATTRIBUTE_DIRECTORY) {
Loading
Loading