Skip to content
This repository was archived by the owner on Jan 26, 2026. It is now read-only.

Commit d117de1

Browse files
ansasakicryptomilk
authored andcommitted
scp: Do not allow newlines in pushed files names
When pushing files or directories, encode the newlines contained in the names as the string "\\n". This way the user cannot inject protocol messages through the file name. Fixes T189 Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org> Reviewed-by: Jakub Jelen <jjelen@redhat.com> (cherry picked from commit bab7ba0)
1 parent ae68f13 commit d117de1

1 file changed

Lines changed: 74 additions & 9 deletions

File tree

src/scp.c

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
323323
int rc;
324324
char *dir = NULL;
325325
char *perms = NULL;
326+
char *vis_encoded = NULL;
327+
size_t vis_encoded_len;
326328

327329
if (scp == NULL) {
328330
return SSH_ERROR;
@@ -340,16 +342,40 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
340342
return SSH_ERROR;
341343
}
342344

345+
vis_encoded_len = (2 * strlen(dir)) + 1;
346+
vis_encoded = (char *)calloc(1, vis_encoded_len);
347+
if (vis_encoded == NULL) {
348+
ssh_set_error(scp->session, SSH_FATAL,
349+
"Failed to allocate buffer to vis encode directory name");
350+
goto error;
351+
}
352+
353+
rc = ssh_newline_vis(dir, vis_encoded, vis_encoded_len);
354+
if (rc <= 0) {
355+
ssh_set_error(scp->session, SSH_FATAL,
356+
"Failed to vis encode directory name");
357+
goto error;
358+
}
359+
343360
perms = ssh_scp_string_mode(mode);
344361
if (perms == NULL) {
345-
SAFE_FREE(dir);
346-
ssh_set_error_oom(scp->session);
347-
return SSH_ERROR;
362+
ssh_set_error(scp->session, SSH_FATAL,
363+
"Failed to get directory permission string");
364+
goto error;
348365
}
349366

350-
snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
367+
SSH_LOG(SSH_LOG_PROTOCOL,
368+
"SCP pushing directory %s with permissions '%s'",
369+
vis_encoded, perms);
370+
371+
/* Use vis encoded directory name */
372+
snprintf(buffer, sizeof(buffer),
373+
"D%s 0 %s\n",
374+
perms, vis_encoded);
375+
351376
SAFE_FREE(dir);
352377
SAFE_FREE(perms);
378+
SAFE_FREE(vis_encoded);
353379

354380
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
355381
if (rc == SSH_ERROR) {
@@ -363,6 +389,13 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
363389
}
364390

365391
return SSH_OK;
392+
393+
error:
394+
SAFE_FREE(dir);
395+
SAFE_FREE(perms);
396+
SAFE_FREE(vis_encoded);
397+
398+
return SSH_ERROR;
366399
}
367400

368401
/**
@@ -427,6 +460,8 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
427460
int rc;
428461
char *file = NULL;
429462
char *perms = NULL;
463+
char *vis_encoded = NULL;
464+
size_t vis_encoded_len;
430465

431466
if (scp == NULL) {
432467
return SSH_ERROR;
@@ -443,18 +478,41 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
443478
ssh_set_error_oom(scp->session);
444479
return SSH_ERROR;
445480
}
481+
482+
vis_encoded_len = (2 * strlen(file)) + 1;
483+
vis_encoded = (char *)calloc(1, vis_encoded_len);
484+
if (vis_encoded == NULL) {
485+
ssh_set_error(scp->session, SSH_FATAL,
486+
"Failed to allocate buffer to vis encode file name");
487+
goto error;
488+
}
489+
490+
rc = ssh_newline_vis(file, vis_encoded, vis_encoded_len);
491+
if (rc <= 0) {
492+
ssh_set_error(scp->session, SSH_FATAL,
493+
"Failed to vis encode file name");
494+
goto error;
495+
}
496+
446497
perms = ssh_scp_string_mode(mode);
447498
if (perms == NULL) {
448-
SAFE_FREE(file);
449-
ssh_set_error_oom(scp->session);
450-
return SSH_ERROR;
499+
ssh_set_error(scp->session, SSH_FATAL,
500+
"Failed to get file permission string");
501+
goto error;
451502
}
503+
452504
SSH_LOG(SSH_LOG_PROTOCOL,
453505
"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",
454-
file, size, perms);
455-
snprintf(buffer, sizeof(buffer), "C%s %" PRIu64 " %s\n", perms, size, file);
506+
vis_encoded, size, perms);
507+
508+
/* Use vis encoded file name */
509+
snprintf(buffer, sizeof(buffer),
510+
"C%s %" PRIu64 " %s\n",
511+
perms, size, vis_encoded);
512+
456513
SAFE_FREE(file);
457514
SAFE_FREE(perms);
515+
SAFE_FREE(vis_encoded);
458516

459517
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
460518
if (rc == SSH_ERROR) {
@@ -472,6 +530,13 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
472530
scp->state = SSH_SCP_WRITE_WRITING;
473531

474532
return SSH_OK;
533+
534+
error:
535+
SAFE_FREE(file);
536+
SAFE_FREE(perms);
537+
SAFE_FREE(vis_encoded);
538+
539+
return SSH_ERROR;
475540
}
476541

477542
/**

0 commit comments

Comments
 (0)