Commit message: sftpserver: Add missing NULL check for ssh_buffer_new()

Thanks to Ramin Farajpour Cami for spotting this.

Fixes T232

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
CVE: CVE-2020-16135
CWE: CWE-476
Vulnerability description: libssh 0.9.4 has a NULL pointer dereference in tftpserver.c if ssh_buffer_new returns NULL.

Project: libssh-mirror
File: sftpserver.c

uint32_t sftp_client_message_get_flags(sftp_client_message msg){
	return msg->flags;
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_handle(sftp_client_message msg, ssh_string handle){
  ssh_buffer out;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_ssh_string(out, handle) < 0 ||
      sftp_packet_write(msg->sftp, SSH_FXP_HANDLE, out) < 0) {
    SSH_BUFFER_FREE(out);
    return -1;
  }
  SSH_BUFFER_FREE(out);

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_data(sftp_client_message msg, const void *data, int len) {
  ssh_buffer out;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_u32(out, ntohl(len)) < 0 ||
      ssh_buffer_add_data(out, data, len) < 0 ||
      sftp_packet_write(msg->sftp, SSH_FXP_DATA, out) < 0) {
    SSH_BUFFER_FREE(out);
    return -1;
  }
  SSH_BUFFER_FREE(out);

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

void *sftp_handle(sftp_session sftp, ssh_string handle){
  uint32_t val;

  if (sftp->handles == NULL) {
    return NULL;
  }

  if (ssh_string_len(handle) != sizeof(uint32_t)) {
    return NULL;
  }

  memcpy(&val, ssh_string_data(handle), sizeof(uint32_t));

  if (val > SFTP_HANDLES) {
    return NULL;
  }

  return sftp->handles[val];
}

Project: libssh-mirror
File: sftpserver.c

int sftp_send_client_message(sftp_session sftp, sftp_client_message msg){
	return sftp_packet_write(sftp, msg->type, msg->complete_message);
}

Project: libssh-mirror
File: sftpserver.c

void sftp_handle_remove(sftp_session sftp, void *handle) {
  int i;

  for (i = 0; i < SFTP_HANDLES; i++) {
    if (sftp->handles[i] == handle) {
      sftp->handles[i] = NULL;
      break;
    }
  }
}

Project: libssh-mirror
File: sftpserver.c

ssh_string sftp_handle_alloc(sftp_session sftp, void *info) {
  ssh_string ret;
  uint32_t val;
  uint32_t i;

  if (sftp->handles == NULL) {
    sftp->handles = calloc(SFTP_HANDLES, sizeof(void *));
    if (sftp->handles == NULL) {
      return NULL;
    }
  }

  for (i = 0; i < SFTP_HANDLES; i++) {
    if (sftp->handles[i] == NULL) {
      break;
    }
  }

  if (i == SFTP_HANDLES) {
    return NULL; /* no handle available */
  }

  val = i;
  ret = ssh_string_new(4);
  if (ret == NULL) {
    return NULL;
  }

  memcpy(ssh_string_data(ret), &val, sizeof(uint32_t));
  sftp->handles[i] = info;

  return ret;
}

Project: libssh-mirror
File: sftpserver.c

uint8_t sftp_client_message_get_type(sftp_client_message msg){
	return msg->type;
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr) {
  ssh_buffer out;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      buffer_add_attributes(out, attr) < 0 ||
      sftp_packet_write(msg->sftp, SSH_FXP_ATTRS, out) < 0) {
    SSH_BUFFER_FREE(out);
    return -1;
  }
  SSH_BUFFER_FREE(out);

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

const char *sftp_client_message_get_filename(sftp_client_message msg){
	return msg->filename;
}

Project: libssh-mirror
File: sftpserver.c

void sftp_client_message_free(sftp_client_message msg) {
  if (msg == NULL) {
    return;
  }

  SAFE_FREE(msg->filename);
  SAFE_FREE(msg->submessage);
  SSH_STRING_FREE(msg->data);
  SSH_STRING_FREE(msg->handle);
  sftp_attributes_free(msg->attr);
  SSH_BUFFER_FREE(msg->complete_message);
  SAFE_FREE(msg->str_data);
  ZERO_STRUCTP(msg);
  SAFE_FREE(msg);
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_status(sftp_client_message msg, uint32_t status,
    const char *message) {
  ssh_buffer out;
  ssh_string s;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  s = ssh_string_from_char(message ? message : "");
  if (s == NULL) {
    SSH_BUFFER_FREE(out);
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_u32(out, htonl(status)) < 0 ||
      ssh_buffer_add_ssh_string(out, s) < 0 ||
      ssh_buffer_add_u32(out, 0) < 0 || /* language string */
      sftp_packet_write(msg->sftp, SSH_FXP_STATUS, out) < 0) {
    SSH_BUFFER_FREE(out);
    SSH_STRING_FREE(s);
    return -1;
  }

  SSH_BUFFER_FREE(out);
  SSH_STRING_FREE(s);

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_name(sftp_client_message msg, const char *name,
    sftp_attributes attr) {
  ssh_buffer out;
  ssh_string file;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  file = ssh_string_from_char(name);
  if (file == NULL) {
    SSH_BUFFER_FREE(out);
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_u32(out, htonl(1)) < 0 ||
      ssh_buffer_add_ssh_string(out, file) < 0 ||
      ssh_buffer_add_ssh_string(out, file) < 0 || /* The protocol is broken here between 3 & 4 */
      buffer_add_attributes(out, attr) < 0 ||
      sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
    SSH_BUFFER_FREE(out);
    SSH_STRING_FREE(file);
    return -1;
  }
  SSH_BUFFER_FREE(out);
  SSH_STRING_FREE(file);

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

void sftp_client_message_set_filename(sftp_client_message msg, const char *newname){
	free(msg->filename);
	msg->filename = strdup(newname);
}

Project: libssh-mirror
File: sftpserver.c

const char *sftp_client_message_get_data(sftp_client_message msg){
	if (msg->str_data == NULL)
		msg->str_data = ssh_string_to_char(msg->data);
	return msg->str_data;
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_names(sftp_client_message msg) {
  ssh_buffer out;

  out = ssh_buffer_new();
  if (out == NULL) {
    SSH_BUFFER_FREE(msg->attrbuf);
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_u32(out, htonl(msg->attr_num)) < 0 ||
      ssh_buffer_add_data(out, ssh_buffer_get(msg->attrbuf),
        ssh_buffer_get_len(msg->attrbuf)) < 0 ||
      sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
    SSH_BUFFER_FREE(out);
    SSH_BUFFER_FREE(msg->attrbuf);
    return -1;
  }

  SSH_BUFFER_FREE(out);
  SSH_BUFFER_FREE(msg->attrbuf);

  msg->attr_num = 0;
  msg->attrbuf = NULL;

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

int sftp_reply_names_add(sftp_client_message msg, const char *file,
    const char *longname, sftp_attributes attr) {
  ssh_string name;

  name = ssh_string_from_char(file);
  if (name == NULL) {
    return -1;
  }

  if (msg->attrbuf == NULL) {
    msg->attrbuf = ssh_buffer_new();
    if (msg->attrbuf == NULL) {
      SSH_STRING_FREE(name);
      return -1;
    }
  }

  if (ssh_buffer_add_ssh_string(msg->attrbuf, name) < 0) {
    SSH_STRING_FREE(name);
    return -1;
  }

  SSH_STRING_FREE(name);
  name = ssh_string_from_char(longname);
  if (name == NULL) {
    return -1;
  }
  if (ssh_buffer_add_ssh_string(msg->attrbuf,name) < 0 ||
      buffer_add_attributes(msg->attrbuf,attr) < 0) {
    SSH_STRING_FREE(name);
    return -1;
  }
  SSH_STRING_FREE(name);
  msg->attr_num++;

  return 0;
}

Project: libssh-mirror
File: sftpserver.c

const char *sftp_client_message_get_submessage(sftp_client_message msg){
        return msg->submessage;
}