Commit f853c4e3 authored by Natanael Copa's avatar Natanael Copa
Browse files

main/libssh: security fix for CVE-2019-14889

fixes #11042
parent b98ba48c
......@@ -2,7 +2,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=libssh
pkgver=0.7.6
pkgrel=0
pkgrel=1
pkgdesc="Library for accessing ssh client services through C libraries"
url="http://www.libssh.org/"
arch="all"
......@@ -11,10 +11,14 @@ makedepends="zlib-dev libressl-dev cmake doxygen"
subpackages="$pkgname-dev"
options="!check"
source="https://www.libssh.org/files/0.7/libssh-$pkgver.tar.xz
fix-includes.patch"
fix-includes.patch
CVE-2019-14889.patch
"
builddir="$srcdir"/$pkgname-$pkgver
# secfixes:
# 0.7.6-r1:
# - CVE-2019-14889
# 0.7.6-r0:
# - CVE-2018-10933
......@@ -33,4 +37,5 @@ package() {
}
sha512sums="2a01402b5a9fab9ecc29200544ed45d3f2c40871ed1c8241ca793f8dc7fdb3ad2150f6a522c4321affa9b8778e280dc7ed10f76adfc4a73f0751ae735a42f56c libssh-0.7.6.tar.xz
055a8f6b97c65384a5a3ab8fe00c69d94cc30092fe926093dbbc122ce301fbe9d76127aa07b5e6107d7fa9dd2aad6b165fa0958b56520253b5d64428ff42a318 fix-includes.patch"
055a8f6b97c65384a5a3ab8fe00c69d94cc30092fe926093dbbc122ce301fbe9d76127aa07b5e6107d7fa9dd2aad6b165fa0958b56520253b5d64428ff42a318 fix-includes.patch
ed832fd00cb1ccae94e4b9e6771d92822dd1ef0e3fcc4649fab04dcde9f959909b7564fe1533e48eb4d016d3fef2dd711e1b9be5bda286545bd18bb81ae9cb6a CVE-2019-14889.patch"
From 4aea835974996b2deb011024c53f4ff4329a95b5 Mon Sep 17 00:00:00 2001
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Date: Thu, 31 Oct 2019 17:56:34 +0100
Subject: CVE-2019-14889: scp: Reformat scp.c
Fixes T181
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 42c727d0c186a1e2fa84a31ab40e16e58b404ab3)
---
src/scp.c | 1200 +++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 698 insertions(+), 502 deletions(-)
diff --git a/src/scp.c b/src/scp.c
index fd9aaaaa..5de0e6ff 100644
--- a/src/scp.c
+++ b/src/scp.c
@@ -57,30 +57,47 @@
*
* @returns A ssh_scp handle, NULL if the creation was impossible.
*/
-ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
- ssh_scp scp=malloc(sizeof(struct ssh_scp_struct));
- if(scp == NULL){
- ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
- return NULL;
- }
- ZERO_STRUCTP(scp);
- if((mode&~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE && (mode &~SSH_SCP_RECURSIVE) != SSH_SCP_READ){
- ssh_set_error(session,SSH_FATAL,"Invalid mode %d for ssh_scp_new()",mode);
- ssh_scp_free(scp);
- return NULL;
- }
- scp->location=strdup(location);
- if (scp->location == NULL) {
- ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
+ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location)
+{
+ ssh_scp scp = NULL;
+
+ if (session == NULL) {
+ goto error;
+ }
+
+ scp = (ssh_scp)calloc(1, sizeof(struct ssh_scp_struct));
+ if (scp == NULL) {
+ ssh_set_error(session, SSH_FATAL,
+ "Error allocating memory for ssh_scp");
+ goto error;
+ }
+
+ if ((mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE &&
+ (mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_READ)
+ {
+ ssh_set_error(session, SSH_FATAL,
+ "Invalid mode %d for ssh_scp_new()", mode);
+ goto error;
+ }
+
+ scp->location = strdup(location);
+ if (scp->location == NULL) {
+ ssh_set_error(session, SSH_FATAL,
+ "Error allocating memory for ssh_scp");
+ goto error;
+ }
+
+ scp->session = session;
+ scp->mode = mode & ~SSH_SCP_RECURSIVE;
+ scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
+ scp->channel = NULL;
+ scp->state = SSH_SCP_NEW;
+
+ return scp;
+
+error:
ssh_scp_free(scp);
return NULL;
- }
- scp->session=session;
- scp->mode=mode & ~SSH_SCP_RECURSIVE;
- scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
- scp->channel=NULL;
- scp->state=SSH_SCP_NEW;
- return scp;
}
/**
@@ -94,59 +111,78 @@ ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
*/
int ssh_scp_init(ssh_scp scp)
{
- int r;
- char execbuffer[1024];
- uint8_t code;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_NEW){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_init called under invalid state");
- return SSH_ERROR;
- }
- SSH_LOG(SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'",
- scp->mode==SSH_SCP_WRITE?"write":"read",
- scp->recursive?"recursive ":"",
- scp->location);
- scp->channel=ssh_channel_new(scp->session);
- if(scp->channel == NULL){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r= ssh_channel_open_session(scp->channel);
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(scp->mode == SSH_SCP_WRITE)
- snprintf(execbuffer,sizeof(execbuffer),"scp -t %s %s",
- scp->recursive ? "-r":"", scp->location);
- else
- snprintf(execbuffer,sizeof(execbuffer),"scp -f %s %s",
- scp->recursive ? "-r":"", scp->location);
- if(ssh_channel_request_exec(scp->channel,execbuffer) == SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(scp->mode == SSH_SCP_WRITE){
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- } else {
- ssh_channel_write(scp->channel,"",1);
- }
- if(scp->mode == SSH_SCP_WRITE)
- scp->state=SSH_SCP_WRITE_INITED;
- else
- scp->state=SSH_SCP_READ_INITED;
- return SSH_OK;
+ int rc;
+ char execbuffer[1024] = {0};
+ uint8_t code;
+
+ if (scp == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (scp->state != SSH_SCP_NEW) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "ssh_scp_init called under invalid state");
+ return SSH_ERROR;
+ }
+
+ SSH_LOG(SSH_LOG_PROTOCOL,
+ "Initializing scp session %s %son location '%s'",
+ scp->mode == SSH_SCP_WRITE?"write":"read",
+ scp->recursive?"recursive ":"",
+ scp->location);
+
+ scp->channel = ssh_channel_new(scp->session);
+ if (scp->channel == NULL) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ rc = ssh_channel_open_session(scp->channel);
+ if (rc == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ if (scp->mode == SSH_SCP_WRITE) {
+ snprintf(execbuffer, sizeof(execbuffer), "scp -t %s %s",
+ scp->recursive ? "-r":"", scp->location);
+ } else {
+ snprintf(execbuffer, sizeof(execbuffer), "scp -f %s %s",
+ scp->recursive ? "-r":"", scp->location);
+ }
+
+ if (ssh_channel_request_exec(scp->channel, execbuffer) == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ if (scp->mode == SSH_SCP_WRITE) {
+ rc = ssh_channel_read(scp->channel, &code, 1, 0);
+ if (rc <= 0) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "Error reading status code: %s",
+ ssh_get_error(scp->session));
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ if (code != 0) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "scp status code %ud not valid", code);
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+ } else {
+ ssh_channel_write(scp->channel, "", 1);
+ }
+
+ if (scp->mode == SSH_SCP_WRITE) {
+ scp->state = SSH_SCP_WRITE_INITED;
+ } else {
+ scp->state = SSH_SCP_READ_INITED;
+ }
+
+ return SSH_OK;
}
/**
@@ -160,33 +196,40 @@ int ssh_scp_init(ssh_scp scp)
*/
int ssh_scp_close(ssh_scp scp)
{
- char buffer[128];
- int err;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->channel != NULL){
- if(ssh_channel_send_eof(scp->channel) == SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- /* avoid situations where data are buffered and
- * not yet stored on disk. This can happen if the close is sent
- * before we got the EOF back
- */
- while(!ssh_channel_is_eof(scp->channel)){
- err=ssh_channel_read(scp->channel,buffer,sizeof(buffer),0);
- if(err==SSH_ERROR || err==0)
- break;
+ char buffer[128] = {0};
+ int rc;
+
+ if (scp == NULL) {
+ return SSH_ERROR;
}
- if(ssh_channel_close(scp->channel) == SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
+
+ if (scp->channel != NULL) {
+ if (ssh_channel_send_eof(scp->channel) == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+ /* avoid situations where data are buffered and
+ * not yet stored on disk. This can happen if the close is sent
+ * before we got the EOF back
+ */
+ while (!ssh_channel_is_eof(scp->channel)) {
+ rc = ssh_channel_read(scp->channel, buffer, sizeof(buffer), 0);
+ if (rc == SSH_ERROR || rc == 0) {
+ break;
+ }
+ }
+
+ if (ssh_channel_close(scp->channel) == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ ssh_channel_free(scp->channel);
+ scp->channel = NULL;
}
- ssh_channel_free(scp->channel);
- scp->channel=NULL;
- }
- scp->state=SSH_SCP_NEW;
- return SSH_OK;
+
+ scp->state = SSH_SCP_NEW;
+ return SSH_OK;
}
/**
@@ -198,16 +241,22 @@ int ssh_scp_close(ssh_scp scp)
*/
void ssh_scp_free(ssh_scp scp)
{
- if(scp==NULL)
- return;
- if(scp->state != SSH_SCP_NEW)
- ssh_scp_close(scp);
- if(scp->channel)
- ssh_channel_free(scp->channel);
- SAFE_FREE(scp->location);
- SAFE_FREE(scp->request_name);
- SAFE_FREE(scp->warning);
- SAFE_FREE(scp);
+ if (scp == NULL) {
+ return;
+ }
+
+ if (scp->state != SSH_SCP_NEW) {
+ ssh_scp_close(scp);
+ }
+
+ if (scp->channel) {
+ ssh_channel_free(scp->channel);
+ }
+
+ SAFE_FREE(scp->location);
+ SAFE_FREE(scp->request_name);
+ SAFE_FREE(scp->warning);
+ SAFE_FREE(scp);
}
/**
@@ -224,81 +273,106 @@ void ssh_scp_free(ssh_scp scp)
*
* @see ssh_scp_leave_directory()
*/
-int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
- char buffer[1024];
- int r;
- uint8_t code;
- char *dir;
- char *perms;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_directory called under invalid state");
- return SSH_ERROR;
- }
- dir=ssh_basename(dirname);
- perms=ssh_scp_string_mode(mode);
- snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
- SAFE_FREE(dir);
- SAFE_FREE(perms);
- r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- return SSH_OK;
+int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
+{
+ char buffer[1024] = {0};
+ int rc;
+ uint8_t code;
+ char *dir = NULL;
+ char *perms = NULL;
+
+ if (scp == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (scp->state != SSH_SCP_WRITE_INITED) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "ssh_scp_push_directory called under invalid state");
+ return SSH_ERROR;
+ }
+
+ dir = ssh_basename(dirname);
+ perms = ssh_scp_string_mode(mode);
+ snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
+ SAFE_FREE(dir);
+ SAFE_FREE(perms);
+
+ rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
+ if (rc == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ rc = ssh_channel_read(scp->channel, &code, 1, 0);
+ if (rc <= 0) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "Error reading status code: %s",
+ ssh_get_error(scp->session));
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ if (code != 0) {
+ ssh_set_error(scp->session, SSH_FATAL, "scp status code %ud not valid",
+ code);
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
}
/**
* @brief Leave a directory.
*
- * @returns SSH_OK if the directory has been left,SSH_ERROR if an
+ * @returns SSH_OK if the directory has been left, SSH_ERROR if an
* error occured.
*
* @see ssh_scp_push_directory()
*/
- int ssh_scp_leave_directory(ssh_scp scp){
- char buffer[]="E\n";
- int r;
- uint8_t code;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_leave_directory called under invalid state");
- return SSH_ERROR;
- }
- r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- return SSH_OK;
+int ssh_scp_leave_directory(ssh_scp scp)
+{
+ char buffer[] = "E\n";
+ int rc;
+ uint8_t code;
+
+ if (scp == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (scp->state != SSH_SCP_WRITE_INITED) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "ssh_scp_leave_directory called under invalid state");
+ return SSH_ERROR;
+ }
+
+ rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
+ if (rc == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ rc = ssh_channel_read(scp->channel, &code, 1, 0);
+ if (rc <= 0) {
+ ssh_set_error(scp->session, SSH_FATAL, "Error reading status code: %s",
+ ssh_get_error(scp->session));
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ if (code != 0) {
+ ssh_set_error(scp->session, SSH_FATAL, "scp status code %ud not valid",
+ code);
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
}
/**
- * @brief Initialize the sending of a file to a scp in sink mode, using a 64-bit size.
+ * @brief Initialize the sending of a file to a scp in sink mode, using a 64-bit
+ * size.
*
* @param[in] scp The scp handle.
*
@@ -314,44 +388,61 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
*
* @see ssh_scp_push_file()
*/
-int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size, int mode){
- char buffer[1024];
- int r;
- uint8_t code;
- char *file;
- char *perms;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_file called under invalid state");
- return SSH_ERROR;
- }
- file=ssh_basename(filename);
- perms=ssh_scp_string_mode(mode);
- SSH_LOG(SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",file,size,perms);
- snprintf(buffer, sizeof(buffer), "C%s %" PRIu64 " %s\n", perms, size, file);
- SAFE_FREE(file);
- SAFE_FREE(perms);
- r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- scp->filelen = size;
- scp->processed = 0;
- scp->state=SSH_SCP_WRITE_WRITING;
- return SSH_OK;
+int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
+ int mode)
+{
+ char buffer[1024] = {0};
+ int rc;
+ char *file = NULL;
+ char *perms = NULL;
+ uint8_t code;
+
+ if (scp == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (scp->state != SSH_SCP_WRITE_INITED) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "ssh_scp_push_file called under invalid state");
+ return SSH_ERROR;
+ }
+
+ file = ssh_basename(filename);
+ perms = ssh_scp_string_mode(mode);
+ SSH_LOG(SSH_LOG_PROTOCOL,
+ "SCP pushing file %s, size %" PRIu64 " with permissions '%s'",
+ file, size, perms);
+ snprintf(buffer, sizeof(buffer), "C%s %" PRIu64 " %s\n", perms, size, file);
+ SAFE_FREE(file);
+ SAFE_FREE(perms);
+
+ rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
+ if (rc == SSH_ERROR) {
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ rc = ssh_channel_read(scp->channel, &code, 1, 0);
+ if (rc <= 0) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "Error reading status code: %s",
+ ssh_get_error(scp->session));
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ if (code != 0) {
+ ssh_set_error(scp->session, SSH_FATAL,
+ "scp status code %ud not valid", code);
+ scp->state = SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+
+ scp->filelen = size;
+ scp->processed = 0;
+ scp->state = SSH_SCP_WRITE_WRITING;
+
+ return SSH_OK;
}
/**
@@ -369,8 +460,9 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size, int mo
* @returns SSH_OK if the file is ready to be sent, SSH_ERROR if an
* error occured.
*/
-int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){
- return ssh_scp_push_file64(scp, filename, (uint64_t) size, mode);
+int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode)
+{
+ return ssh_scp_push_file64(scp, filename, (uint64_t) size, mode);
}
/**
@@ -385,41 +477,60 @@ int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){
*
* @returns The return code, SSH_ERROR a error occured.
*/
-int ssh_scp_response(ssh_scp scp, char **response){
- unsigned char code;
- int r;
- char msg[128];
- if(scp==NULL)
- return SSH_ERROR;
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r == SSH_ERROR)
- return SSH_ERROR;
- if(code == 0)