diff --git a/common/platform/config.c b/common/platform/config.c index e90dd24..dc64c83 100644 --- a/common/platform/config.c +++ b/common/platform/config.c @@ -348,6 +348,7 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"vfs", L"enable", 1, filename); + cfg->allowAmfsDownloads = GetPrivateProfileIntW(L"vfs", L"allowAmfsDownloads", 0, filename); GetPrivateProfileStringW( L"vfs", diff --git a/common/platform/vfs.c b/common/platform/vfs.c index ae5953e..1cfc5bd 100644 --- a/common/platform/vfs.c +++ b/common/platform/vfs.c @@ -41,6 +41,10 @@ static HRESULT vfs_custom_path_hook( const wchar_t *src, wchar_t *dest, size_t *count); +static HRESULT vfs_path_hook_tmp_icf( + const wchar_t *src, + wchar_t *dest, + size_t *count); static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); @@ -77,6 +81,9 @@ static const size_t vfs_option_len = _countof(vfs_option) - 1; static const wchar_t vfs_apm3[] = L"C:\\Mount\\Apm"; static const size_t vfs_apm3_len = _countof(vfs_apm3) - 1; +static const wchar_t vfs_tmp_icf[] = L"E:\\tmpIcf.icf"; +static const size_t vfs_tmp_icf_len = _countof(vfs_tmp_icf) - 1; + static const struct reg_hook_val vfs_reg_vals[] = { { .name = L"AMFS", @@ -168,6 +175,12 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id) vfs_fixup_path(vfs_config.option, _countof(vfs_config.option), true); } + hr = path_hook_push(vfs_path_hook_tmp_icf); + + if (FAILED(hr)) { + return hr; + } + hr = vfs_mkdir_rec(vfs_config.amfs); if (FAILED(hr)) { @@ -601,6 +614,29 @@ static HRESULT vfs_path_hook_apm( return S_OK; } +// Block writing of E:\tmpIcf.icf to intentionally break the download process if the user has not enabled it +static HRESULT vfs_path_hook_tmp_icf( + const wchar_t *src, + wchar_t *dest, + size_t *count) +{ + assert(src != NULL); + assert(count != NULL); + + /* Case-insensitive check to see if src starts with vfs_tmp_icf */ + + if (path_compare_w(src, vfs_tmp_icf, vfs_tmp_icf_len) != 0) { + return S_FALSE; + } + + if (vfs_config.allowAmfsDownloads) { + return S_FALSE; + } + + dprintf("Vfs: AMFS downloads are blocked\n"); + return E_FAIL; +} + static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes) { return reg_hook_read_wstr(bytes, nbytes, L"E:\\"); diff --git a/common/platform/vfs.h b/common/platform/vfs.h index 9ff8111..87a2d3e 100644 --- a/common/platform/vfs.h +++ b/common/platform/vfs.h @@ -15,6 +15,7 @@ struct vfs_config { wchar_t redirections_from[MAX_REDIRECTIONS][MAX_PATH]; int redirections_from_len[MAX_REDIRECTIONS]; wchar_t redirections_to[MAX_REDIRECTIONS][MAX_PATH]; + bool allowAmfsDownloads; }; HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id); diff --git a/doc/config/common.md b/doc/config/common.md index d6a7651..2fc3176 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -685,6 +685,12 @@ redirection0from=\\.\COM5 redirection0to=\\.\COM10 ``` +### `allowAmfsDownloads` + +Default: `0` + +Allows network services to download arbitrary files to the AMFS directory specified above. This has security implications, do not enable this, unless you trust your server operator. + ## `[epay]` Configure Thinca Payment (E-Money) emulation and hooks.