Prevent RzBuffer's Oxff_priv from overriding io.0xff (#6371)

* Prevent RzBuffer's `Oxff_priv` from overriding `io.0xff`
* Use io from RZ_BUFFER_IO and RZ_BUFFER_IO_FD buffers
* Add `RzIO *` param to rz_buf_new_mmap()
* pe: Discard incomplete import directory
This commit is contained in:
Khairul Azhar Kasmiran 2026-05-27 06:18:45 +08:00 committed by GitHub
parent c6820479c6
commit 1abe2dce99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 122 additions and 32 deletions

View file

@ -11,7 +11,9 @@ int PE_(read_image_import_directory)(RzBuffer *b, ut64 addr, PE_(image_import_di
return -1;
}
ut8 buf[sizeof(PE_(image_import_directory))];
rz_buf_read(b, buf, sizeof(buf));
if (rz_buf_read(b, buf, sizeof(buf)) != sizeof(buf)) {
return -1;
}
PE_READ_STRUCT_FIELD(import_dir, PE_(image_import_directory), Characteristics, 32);
PE_READ_STRUCT_FIELD(import_dir, PE_(image_import_directory), TimeDateStamp, 32);
PE_READ_STRUCT_FIELD(import_dir, PE_(image_import_directory), ForwarderChain, 32);
@ -395,8 +397,7 @@ int PE_(bin_pe_init_imports)(RzBinPEObj *bin) {
curr_import_dir = import_dir + indx;
if (PE_(read_image_import_directory)(bin->b, import_dir_offset + indx * dir_size, curr_import_dir) <= 0) {
RZ_LOG_INFO("read (import directory)\n");
RZ_FREE(import_dir);
break; // return false;
goto fail;
}
if (((2 + indx) * dir_size) > import_dir_size) {
break; // goto fail;

View file

@ -103,7 +103,7 @@ static inline st64 rz_seek_offset(ut64 cur, ut64 length, st64 addr, int whence)
/* constructors */
RZ_API RZ_OWN RzBuffer *rz_buf_new_empty(ut64 len);
RZ_API RZ_OWN RzBuffer *rz_buf_new_file(const char *file, int perm, int mode);
RZ_API RZ_OWN RzBuffer *rz_buf_new_mmap(const char *file, int flags, int mode);
RZ_API RZ_OWN RzBuffer *rz_buf_new_mmap(const char *file, int flags, int mode, RZ_NULLABLE void /* RzIO */ *io);
RZ_API RZ_OWN RzBuffer *rz_buf_new_slice(RzBuffer *b, ut64 offset, ut64 size);
RZ_API RZ_OWN RzBuffer *rz_buf_new_slurp(const char *file);
RZ_API RZ_OWN RzBuffer *rz_buf_new_sparse(ut8 Oxff);

View file

@ -78,7 +78,7 @@ RzIOMMapFileObj *rz_io_def_mmap_create_new_file(RzIO *io, const char *filename,
mmo->perm = rz_sys_open_perms(perm);
mmo->mode = mode;
if (!mmo->nocache) {
mmo->buf = rz_buf_new_mmap(mmo->filename, mmo->perm, mmo->mode);
mmo->buf = rz_buf_new_mmap(mmo->filename, mmo->perm, mmo->mode, io);
}
if (!mmo->buf) {
mmo->buf = rz_buf_new_file(mmo->filename, mmo->perm, mmo->mode);

View file

@ -468,6 +468,7 @@ static int rzfind_open_file(RzfindOptions *ro, const char *file, const ut8 *data
}
RzIO *io = rz_io_new();
io->ff = true;
if (!io) {
free(efile);
return 1;

View file

@ -403,6 +403,7 @@ RZ_API RZ_OWN RzBuffer *rz_buf_new_file(const char *file, int perm, int mode) {
* \param file The filename used to create the new buffer.
* \param perm Same meaning than the symbolic constants defined in sys/stat.h.
* \param mode Same meaning than the symbolic constants use with open (fcntl.h).
* \param io Optional RzIO for configuration variables.
* \return Return the new allocated buffer.
*
* \see rz_file_mmap()
@ -410,13 +411,14 @@ RZ_API RZ_OWN RzBuffer *rz_buf_new_file(const char *file, int perm, int mode) {
* The function creates a new buffer synchronized with the file content, using
* mmap to access the file.
*/
RZ_API RZ_OWN RzBuffer *rz_buf_new_mmap(const char *filename, int perm, int mode) {
RZ_API RZ_OWN RzBuffer *rz_buf_new_mmap(const char *filename, int perm, int mode, RZ_NULLABLE void /* RzIO */ *io) {
rz_return_val_if_fail(filename, NULL);
struct buf_mmap_user u = { 0 };
u.filename = filename;
u.perm = perm;
u.mode = mode;
u.io = io;
return new_buffer(RZ_BUFFER_MMAP, &u);
}
@ -1223,6 +1225,22 @@ RZ_API st64 rz_buf_insert_bytes(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL co
return result;
}
static RzIO *get_io_from_buffer(RZ_NONNULL RzBuffer *b) {
rz_return_val_if_fail(b, NULL);
switch (b->type) {
case RZ_BUFFER_IO:
case RZ_BUFFER_IO_FD: {
RzIOBind *iob = b->type == RZ_BUFFER_IO ? ((BufIOPriv *)b->priv)->iob : ((struct buf_io_fd_priv *)b->priv)->iob;
rz_return_val_if_fail(iob, NULL);
return iob->io;
}
case RZ_BUFFER_MMAP:
return ((struct buf_mmap_priv *)b->priv)->io;
default:
return NULL;
}
}
/**
* \brief Reads \p len bytes from buffer \p b into \p buf.
* \p buf should have enough space to contain the bytes.
@ -1246,7 +1264,16 @@ RZ_API st64 rz_buf_read(RZ_NONNULL RzBuffer *b, RZ_NONNULL ut8 RZ_OUT *buf, ut64
}
if (len > result) {
memset(buf + result, b->Oxff_priv, len - result);
ut8 Oxff = b->Oxff_priv;
RzIO *io = get_io_from_buffer(b);
if (io) {
if (!io->ff) {
RZ_LOG_ERROR("Incomplete buffer read: expected 0x%" PFMT64x " bytes, got %" PFMT64d " bytes.\n", len, result);
return -1;
}
Oxff = io->Oxff;
}
memset(buf + result, Oxff, len - result);
}
return result;

View file

@ -2,11 +2,13 @@
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util.h>
#include <rz_io.h>
struct buf_mmap_user {
const char *filename;
int perm;
int mode;
RzIO *io;
};
// "subclass"" of buf_bytes_priv
@ -14,6 +16,7 @@ struct buf_mmap_priv {
// NOTE: this needs to be first, so that bytes operations will work without changes
struct buf_bytes_priv bytes_priv;
RzMmap *mmap;
RzIO *io;
};
static inline struct buf_mmap_priv *get_priv_mmap(RzBuffer *b) {
@ -37,6 +40,7 @@ static bool buf_mmap_init(RzBuffer *b, const void *user) {
priv->bytes_priv.buf = priv->mmap->buf;
priv->bytes_priv.length = priv->mmap->len;
priv->bytes_priv.offset = 0;
priv->io = u->io;
b->priv = priv;
b->fd = priv->mmap->fd;
return true;

View file

@ -740,22 +740,22 @@ EXPECT=<<EOF
0x0000fffa ????????????se,,,,,,
0x0001000a .. ..
0x0001001a en....OO,,OO;; ..
0x0001002a ..
0x0001002a .. ##########
0x0000fffa ------------se,,,,,,
0x0001000a .. ..
0x0001001a en....OO,,OO;; ..
0x0001002a ..
0x0001002a .. ##########
0x0000fffa ............se         
0x0001000a                 
0x0001001a       en         
0x0001002a         
0x0001002a         
0x0000fffa ????????????se         
0x0001000a                 
0x0001001a       en         
0x0001002a         
0x0001002a         
EOF
RUN

View file

@ -178,9 +178,9 @@ EXPECT=<<EOF
0x0000fffa .... .... .... 7f45 4c46 0100 0000 0000       .ELF...... ; segment.ehdr ; [01] -rw- segment size 45 named ehdr
0x0001000a 0000 0000 0100 0200 0300 2000 0100 2000 .......... ... .
0x0001001a 0100 0400 0000 b32a 31c0 40cd 8000 3400 .......*1.@...4. ; entry0
0x0001002a 2000 0100 0000 0000 0000 0000 0000 0000  ...............
0x0001003a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001004a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001002a 2000 01ff ffff ffff ffff ffff ffff ffff  ...............
0x0001003a ffff ffff ffff ffff ffff ffff ffff ffff ................
0x0001004a ffff ffff ffff ffff ffff ffff ffff ffff ................
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF comment
0x0000ffca .... .... .... .... .... .... .... ....
@ -189,9 +189,9 @@ EXPECT=<<EOF
0x0000fffa .... .... .... 7f45 4c46 0100 0000 0000 .ELF...... ; segment.ehdr ; [01] -rw- segment size 45 named ehdr
0x0001000a 0000 0000 0100 0200 0300 2000 0100 2000 .......... ... .
0x0001001a 0100 0400 0000 b32a 31c0 40cd 8000 3400 .......*1.@...4. ; entry0
0x0001002a 2000 0100 0000 0000 0000 0000 0000 0000 ...............
0x0001003a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001004a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001002a 2000 01ff ffff ffff ffff ffff ffff ffff ...............
0x0001003a ffff ffff ffff ffff ffff ffff ffff ffff ................
0x0001004a ffff ffff ffff ffff ffff ffff ffff ffff ................
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x0000ffca ???? ???? ???? ???? ???? ???? ???? ????
@ -200,9 +200,9 @@ EXPECT=<<EOF
0x0000fffa ???? ???? ???? 7f45 4c46 0100 0000 0000 .ELF......
0x0001000a 0000 0000 0100 0200 0300 2000 0100 2000 .......... ... .
0x0001001a 0100 0400 0000 b32a 31c0 40cd 8000 3400 .......*1.@...4.
0x0001002a 2000 0100 0000 0000 0000 0000 0000 0000 ...............
0x0001003a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001004a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001002a 2000 01ff ffff ffff ffff ffff ffff ffff ...............
0x0001003a ffff ffff ffff ffff ffff ffff ffff ffff ................
0x0001004a ffff ffff ffff ffff ffff ffff ffff ffff ................
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x0000ffca
@ -211,9 +211,9 @@ EXPECT=<<EOF
0x0000fffa 7f45 4c46 0100 0000 0000 .ELF......
0x0001000a 0000 0000 0100 0200 0300 2000 0100 2000 .......... ... .
0x0001001a 0100 0400 0000 b32a 31c0 40cd 8000 3400 .......*1.@...4.
0x0001002a 2000 0100 0000 0000 0000 0000 0000 0000 ...............
0x0001003a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001004a 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0001002a 2000 01ff ffff ffff ffff ffff ffff ffff ...............
0x0001003a ffff ffff ffff ffff ffff ffff ffff ffff ................
0x0001004a ffff ffff ffff ffff ffff ffff ffff ffff ................
EOF
RUN

View file

@ -15,15 +15,34 @@ e analysis.in=io.maps
aF
e log.level=3
pd 10
afb
echo -- 4.5 --
e io.ff=false
pd 4
e io.ff=true
echo -- 5 --
af-
e io.0xff=0
e analysis.nonull=16
aF
pd 10
afb
echo -- 6 --
afb-*
af-
e analysis.nonull=0
e analysis.from=0
e analysis.to=0x30000
e analysis.limits=true
aF
pd 10
afb
echo -- 7 --
afb+ entry0 entry0 `aos 4`
afb-*
afb
echo -- 8 --
afb+ entry0 entry0 `aos 4`
afb
echo -- 9 --
pdf
EOF
EXPECT=<<EOF
@ -63,19 +82,55 @@ WARNING: Failed to read chunk of size 0x101 at 0x10020 from io.
| 0x00010025 cd80 int 0x80
| 0x00010027 003400 add byte [eax+eax*1], dh
| 0x0001002a 2000 and byte [eax], al
\ 0x0001002c 01ff add edi, edi
0x0001002e ff invalid
0x0001002f ff invalid
0x00010030 ff invalid
0x00010020 0x0001002e 00:0000 14
-- 4.5 --
ERROR: Incomplete buffer read: expected 0x101 bytes, got 13 bytes.
WARNING: Failed to read chunk of size 0x101 at 0x10020 from io.
/ entry0();
| 0x00010020 b32a mov bl, 0x2a ; '*'
| 0x00010022 31c0 xor eax, eax
| 0x00010024 40 inc eax
| 0x00010025 cd80 int 0x80
-- 5 --
WARNING: Failed to read chunk of size 0x101 at 0x10020 from io.
/ entry0();
| 0x00010020 b32a mov bl, 0x2a ; '*'
| 0x00010022 31c0 xor eax, eax
| 0x00010024 40 inc eax
| 0x00010025 cd80 int 0x80
| 0x00010027 003400 add byte [eax+eax*1], dh
| 0x0001002a 2000 and byte [eax], al
\ 0x0001002c 0100 add dword [eax], eax
0x0001002e 0000 add byte [eax], al
0x00010030 0000 add byte [eax], al
0x00010032 0000 add byte [eax], al
0x00010020 0x0001002e 00:0000 14
-- 6 --
WARNING: Failed to read chunk of size 0x101 at 0x10020 from io.
/ entry0();
| 0x00010020 b32a mov bl, 0x2a ; '*'
| 0x00010022 31c0 xor eax, eax
| 0x00010024 40 inc eax
| 0x00010025 cd80 int 0x80
| 0x00010027 003400 add byte [eax+eax*1], dh
| 0x0001002a 2000 and byte [eax], al
| 0x0001002c 0100 add dword [eax], eax
| 0x0001002e 0000 add byte [eax], al
| 0x00010030 0000 add byte [eax], al
| 0x00010032 0000 add byte [eax], al
-- 5 --
0x00010020 0x0001fc1e 00:0000 64510 j 0x0001fc1e
0x0001fc1e 0x00020020 00:0000 1026
-- 6 --
0x0001fc1e 0x0002f81c 00:0000 64510 j 0x0002f81c
0x0002f81c 0x00030000 00:0000 2020
-- 7 --
0x00010020 0x00010027 00:0000 7
-- 8 --
0x00010020 0x00010027 00:0000 7
-- 9 --
/ entry0();
| 0x00010020 b32a mov bl, 0x2a ; '*' ; 42
| 0x00010020 b32a mov bl, 0x2a ; '*'
| 0x00010022 31c0 xor eax, eax
| 0x00010024 40 inc eax
\ 0x00010025 cd80 int 0x80

View file

@ -31,6 +31,7 @@ e io.va=0
i~^size[1]
wx 010203
i~^size[1]
e io.0xff=0
w hello world
i~^size[1]
ps

View file

@ -159,7 +159,7 @@ bool test_rz_buf_mmap(void) {
rz_xwrite(fd, content, length);
close(fd);
b = rz_buf_new_mmap(filename, O_RDWR, 0);
b = rz_buf_new_mmap(filename, O_RDWR, 0, NULL);
mu_assert_notnull(b, "rz_buf_new_mmap failed");
if (test_buf(b) != MU_PASSED) {
@ -175,7 +175,7 @@ bool test_rz_buf_mmap(void) {
free(filename);
filename = rz_file_temp(NULL);
b = rz_buf_new_mmap(filename, O_RDWR | O_CREAT, 0644);
b = rz_buf_new_mmap(filename, O_RDWR | O_CREAT, 0644, NULL);
mu_assert_notnull(b, "buffer mmaped should be created");
st64 r = rz_buf_write(b, (const ut8 *)content, length);
@ -202,6 +202,7 @@ bool test_rz_buf_io_fd(void) {
const int length = 23;
RzIO *io = rz_io_new();
io->ff = true;
char *tmpfile = rz_file_temp(NULL);
char *filename = rz_str_newf("file://%s", tmpfile);
free(tmpfile);