Skip to content

Commit 41734eb

Browse files
authored
Update chroot symlink check (#765)
* start sftp chroot symlink fix * update symlink logic chroot check * fix order
1 parent 8fe096c commit 41734eb

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

contrib/win32/win32compat/fileio.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -435,14 +435,20 @@ file_in_chroot_jail(HANDLE handle) {
435435
return 1;
436436
}
437437

438+
return file_in_chroot_jail_helper(final_path);
439+
}
440+
441+
/* returns 1 if true, 0 otherwise */
442+
int
443+
file_in_chroot_jail_helper(wchar_t* final_path) {
444+
/* ensure final path is within chroot */
438445
to_wlower_case(final_path);
439446
if ((wcslen(final_path) < wcslen(chroot_pathw)) ||
440-
memcmp(final_path, chroot_pathw, 2 * wcslen(chroot_pathw)) != 0 ||
441-
final_path[wcslen(chroot_pathw)] != '\\') {
447+
memcmp(final_path, chroot_pathw, 2 * wcslen(chroot_pathw)) != 0 ||
448+
final_path[wcslen(chroot_pathw)] != '\\') {
442449
debug3("access denied due to attempt to escape chroot jail");
443450
return 0;
444451
}
445-
446452
return 1;
447453
}
448454

@@ -1268,6 +1274,7 @@ fileio_symlink(const char *target, const char *linkpath)
12681274
DWORD ret = -1;
12691275
char target_modified[PATH_MAX] = { 0 };
12701276
char *linkpath_resolved = NULL, *target_resolved = NULL;
1277+
wchar_t *linkpath_utf16 = NULL, *resolved_target_utf16 = NULL, *resolved_target_chroot = NULL;
12711278

12721279
if (target == NULL || linkpath == NULL) {
12731280
errno = EFAULT;
@@ -1301,13 +1308,21 @@ fileio_symlink(const char *target, const char *linkpath)
13011308
strcpy_s(target_modified, _countof(target_modified), target_resolved);
13021309
}
13031310

1304-
wchar_t *linkpath_utf16 = resolved_path_utf16(linkpath);
1305-
wchar_t *resolved_target_utf16 = utf8_to_utf16(target_modified);
1306-
if (resolved_target_utf16 == NULL || linkpath_utf16 == NULL) {
1311+
if ((linkpath_utf16 = resolved_path_utf16(linkpath)) == NULL ||
1312+
(resolved_target_utf16 = utf8_to_utf16(target_modified)) == NULL) {
13071313
errno = ENOMEM;
13081314
goto cleanup;
13091315
}
13101316

1317+
/* if chroot, get full path for target, similar to behavior in realpath() in misc.c
1318+
note: _wfullpath() is required to resolve paths containing unicode characters */
1319+
if (chroot_pathw != NULL &&
1320+
(resolved_target_chroot = _wfullpath(NULL, resolved_target_utf16, 0)) != NULL &&
1321+
file_in_chroot_jail_helper(resolved_target_chroot) != 1) {
1322+
errno = EPERM;
1323+
goto cleanup;
1324+
}
1325+
13111326
/* unlike other platforms, we need to know whether the symbolic link target is
13121327
* a file or a directory. the only way we can confidently do this is to
13131328
* get the attributes of the target. therefore, our symlink() has the
@@ -1338,15 +1353,18 @@ fileio_symlink(const char *target, const char *linkpath)
13381353
ret = 0;
13391354
cleanup:
13401355

1356+
if (linkpath_resolved)
1357+
free(linkpath_resolved);
1358+
13411359
if (linkpath_utf16)
13421360
free(linkpath_utf16);
13431361

1362+
if (resolved_target_chroot)
1363+
free(resolved_target_chroot);
1364+
13441365
if (resolved_target_utf16)
13451366
free(resolved_target_utf16);
13461367

1347-
if (linkpath_resolved)
1348-
free(linkpath_resolved);
1349-
13501368
if (target_resolved)
13511369
free(target_resolved);
13521370

contrib/win32/win32compat/misc_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ int load_user_profile(HANDLE user_token, char* user);
7070
int create_directory_withsddl(wchar_t *path, wchar_t *sddl, BOOL check_permissions);
7171
int is_absolute_path(const char *);
7272
int file_in_chroot_jail(HANDLE);
73+
int file_in_chroot_jail_helper(wchar_t*);
7374
PSID lookup_sid(const wchar_t* name_utf16, PSID psid, DWORD * psid_len);
7475
PSID get_sid(const char*);
7576
int am_system();

0 commit comments

Comments
 (0)