You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Fix buffer over-read and memory leaks when using long filepaths in a zip archive and improved robustness of long filepaths and reading files.
This commit is contained in:
@@ -30,6 +30,48 @@
|
||||
|
||||
#include "zip_io.h"
|
||||
|
||||
#include "core/templates/local_vector.h"
|
||||
|
||||
int godot_unzip_get_current_file_info(unzFile p_zip_file, unz_file_info64 &r_file_info, String &r_filepath) {
|
||||
const uLong short_file_path_buffer_size = 16384ul;
|
||||
char short_file_path_buffer[short_file_path_buffer_size];
|
||||
|
||||
int err = unzGetCurrentFileInfo64(p_zip_file, &r_file_info, short_file_path_buffer, short_file_path_buffer_size, nullptr, 0, nullptr, 0);
|
||||
if (unlikely((err != UNZ_OK) || (r_file_info.size_filename > short_file_path_buffer_size))) {
|
||||
LocalVector<char> long_file_path_buffer;
|
||||
long_file_path_buffer.resize(r_file_info.size_filename);
|
||||
|
||||
err = unzGetCurrentFileInfo64(p_zip_file, &r_file_info, long_file_path_buffer.ptr(), long_file_path_buffer.size(), nullptr, 0, nullptr, 0);
|
||||
if (err != UNZ_OK) {
|
||||
return err;
|
||||
}
|
||||
r_filepath = String::utf8(long_file_path_buffer.ptr(), r_file_info.size_filename);
|
||||
} else {
|
||||
r_filepath = String::utf8(short_file_path_buffer, r_file_info.size_filename);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int godot_unzip_locate_file(unzFile p_zip_file, String p_filepath, bool p_case_sensitive) {
|
||||
int err = unzGoToFirstFile(p_zip_file);
|
||||
while (err == UNZ_OK) {
|
||||
unz_file_info64 current_file_info;
|
||||
String current_filepath;
|
||||
err = godot_unzip_get_current_file_info(p_zip_file, current_file_info, current_filepath);
|
||||
if (err == UNZ_OK) {
|
||||
bool filepaths_are_equal = p_case_sensitive ? (p_filepath == current_filepath) : (p_filepath.nocasecmp_to(current_filepath) == 0);
|
||||
if (filepaths_are_equal) {
|
||||
return UNZ_OK;
|
||||
}
|
||||
err = unzGoToNextFile(p_zip_file);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
|
||||
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
|
||||
ERR_FAIL_COND_V(fa == nullptr, nullptr);
|
||||
@@ -38,17 +80,17 @@ void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
|
||||
fname.parse_utf8(p_fname);
|
||||
|
||||
int file_access_mode = 0;
|
||||
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
|
||||
file_access_mode |= FileAccess::WRITE;
|
||||
}
|
||||
if (mode & ZLIB_FILEFUNC_MODE_READ) {
|
||||
file_access_mode |= FileAccess::READ;
|
||||
}
|
||||
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
|
||||
file_access_mode |= FileAccess::WRITE;
|
||||
}
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
|
||||
file_access_mode |= FileAccess::WRITE_READ;
|
||||
}
|
||||
(*fa) = FileAccess::open(fname, file_access_mode);
|
||||
|
||||
(*fa) = FileAccess::open(fname, file_access_mode);
|
||||
if (fa->is_null()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user