This is an archive of the discontinued LLVM Phabricator instance.

[LLDB][NFC] Reliability fixes for ObjectFileMachO.cpp
ClosedPublic

Authored by fixathon on Aug 10 2022, 2:59 AM.

Details

Summary

Static code inspection guided fixes for the following issues:

  • dead code
  • buffer not null-terminated
  • null-dereference
  • out-of-bounds access

Diff Detail

Event Timeline

fixathon created this revision.Aug 10 2022, 2:59 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 10 2022, 2:59 AM
fixathon requested review of this revision.Aug 10 2022, 2:59 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 10 2022, 2:59 AM

Added inline comments to clarify the fixes. Specifically need feedback on the null-termination of strings since it seems possible this may not be needed based on existing comments.

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
552–553

fpu_reg_buf is the destination buffer, and fpu_reg_buf_size is the number of bytes to write.

Originally, the buffer had the address of fpu.floats.s[0] that is the start of a 128 bytes long array, and fpu_reg_buf_size is 256 bytes. However, there's no buffer overrun because the target buffer is a union member, and the union has sufficient size:

struct FPU {

  union {
    uint32_t s[32];                            /// 4*32 =  128 bytes
    uint64_t d[32];                            /// 8*32  = 256 bytes
    QReg q[16]; // the 128-bit NEON registers  /// 16*16 = 256 bytes
  } floats;
  uint32_t fpscr;
};

Instead we have a misleading use of the smaller of the available buffers inside of the union to obtain the buffer address. According to the C++ specification, all non-static union members of the union, as well as the union itself will have the same address in memory. I have modified the code to be less misleading, and to keep the static code inspection happy, while the outcome will be exactly the same as before.

4126

potential null dereference

6351

strncpy may not have null-termination. Please comment if you believe this should not be corrected. I'd like to at least add the comments with sufficient explanation if that is the case.

6740–6743

Please clarify why this is the case. Thanks

6744–6745

strncpy may not have null-termination. Please comment if you believe this should not be corrected. I'd like to at least add the comments with sufficient explanation if that is the case.

6906

offset is re-assigned here, so there's no point in the previous 2 lines. However it is likely those follow the decoding format specification, so left it in as comments for clarity.

jasonmolenda accepted this revision.Aug 10 2022, 1:25 PM

Looks good to me with a few suggestions inlined.

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
536

'constraining'

539

The count field for a Darwin register context is the number of 4-byte entries in the object - it's a trick the kernel API often use so they can add fields later and the kernel knows what version of the object the userland process is requesting when it asks for "flavor, size" in a get_thread_state call. This Aarch32 register context is struct GPR {uint32_t r[16]; uint32_t cpsr}; or count 17, but sizeof(gpr.r) is going to be 64. We only want to loop for 16 entries.

6351

Yes, the segment name in a Mach-O LC_SEGMENT/LC_SEGMENT_64 is char[16] and is not guaranteed to be nul terminated if all 16 characters are used. This code shouldn't be changed - adding a comment to that effect would be fine though.

6744–6745

Same thing here - LC_NOTE name field is char[16] and is not guaranteed to be nul terminated.

This revision is now accepted and ready to land.Aug 10 2022, 1:25 PM
jasonmolenda added inline comments.Aug 10 2022, 1:52 PM
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
539

FWIW the Aarch64 version of this function hardcodes the number of elements (where each general purpose register is 8-bytes, so count==2, and then there's one cpsr 4-byte register),

// x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1
// 32-bit register)
if (count >= (33 * 2) + 1) {
  for (uint32_t i = 0; i < 29; ++i)
    gpr.x[i] = data.GetU64(&offset);
  gpr.fp = data.GetU64(&offset);
  gpr.lr = data.GetU64(&offset);
  gpr.sp = data.GetU64(&offset);
  gpr.pc = data.GetU64(&offset);
  gpr.cpsr = data.GetU32(&offset);
fixathon added inline comments.Aug 10 2022, 2:04 PM
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
539

Good catch. I'll: count <= sizeof(gpr.r)/sizeof(gpr.r[0])

fixathon updated this revision to Diff 451629.Aug 10 2022, 2:23 PM

Addressing reviewer comments

JDevlieghere added inline comments.Aug 10 2022, 3:01 PM
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
6344

Nit: capital

jasonmolenda accepted this revision.Aug 10 2022, 3:06 PM

LGTM. fwiw it's nul-terminated ("NUL" being the '\0' character), not null-terminated ((void*)0). i don't really care, but nb.

fixathon updated this revision to Diff 451652.Aug 10 2022, 3:14 PM
fixathon marked 4 inline comments as done.

Fix some nits in comments

This revision was landed with ongoing or failed builds.Aug 10 2022, 3:17 PM
This revision was automatically updated to reflect the committed changes.
fixathon marked 2 inline comments as done.
clayborg added inline comments.Aug 10 2022, 8:51 PM
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
536–542

Just a quick FYI: if the "offset" value ends up being out of bounds for the data, it will stop parsing anything and set the offset value to UINT64_MAX, so this is safe already.

539
4117
4126

Revert, see above code suggestion.

6351

Need to revert this. If the segment name is actually 16 characters long, you will change the segment name which we can't do and there is no NULL termination in this case.

6744–6745

Revert this. If the name is actually 16 characters long it isn't supposed to be null terminated.

6906

Maybe change to something like:

// entries_size is not used, nor is the unused entry.
// uint32_t entries_size = m_data.GetU32(&offset);
// uint32_t unused = m_data.GetU32(&offset);
fixathon marked 2 inline comments as done.Aug 11 2022, 11:12 AM
fixathon added inline comments.
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
539

"count > 0 && count <= sizeof(gpr.r)/sizeof(uint32_t) && i < count - 1; ++i)" was causing a compiler warning, which is the reason I moved count out of the for loop condition

fixathon marked 3 inline comments as done.Aug 11 2022, 6:59 PM

Replied to comments, and adding the suggested modifications in https://reviews.llvm.org/D131743 because this diff has already been pushed.