From 6aba6ae2316fe6299c855a3db52b221fff63c00c Mon Sep 17 00:00:00 2001 From: Rudy Mizrahi Celekli <47457359+rudycelekli@users.noreply.github.com> Date: Mon, 5 Oct 2026 12:14:37 -0400 Subject: [PATCH] fix(native): decode Mach protection bits in their proper positions (#586) Signed-off-by: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com> --- src/native/parsers/otool.ts | 4 ++-- .../native/nativeNumericPermissions.test.ts | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/boundary/providers/native/nativeNumericPermissions.test.ts diff --git a/src/native/parsers/otool.ts b/src/native/parsers/otool.ts index 9ed20f114..d4b7d94c7 100644 --- a/src/native/parsers/otool.ts +++ b/src/native/parsers/otool.ts @@ -253,9 +253,9 @@ const permissions = (raw: string | null) => { const numericValue = numeric(raw); if (numericValue !== null) return { - read: (numericValue & 4) !== 0, + read: (numericValue & 1) !== 0, write: (numericValue & 2) !== 0, - execute: (numericValue & 1) !== 0, + execute: (numericValue & 4) !== 0, raw, }; if (/^[r-][w-][x-]$/u.test(raw)) diff --git a/tests/boundary/providers/native/nativeNumericPermissions.test.ts b/tests/boundary/providers/native/nativeNumericPermissions.test.ts new file mode 100644 index 000000000..3ca85ec75 --- /dev/null +++ b/tests/boundary/providers/native/nativeNumericPermissions.test.ts @@ -0,0 +1,24 @@ +import { expect, it } from "vitest"; +import { parseOtoolLoadCommands } from "../../../../src/native/parsers/otool.js"; + +it.each([0, 1, 2, 3, 4, 5, 6, 7])( + "decodes Mach VM protection bits for mask %i", + (mask) => { + const parsed = parseOtoolLoadCommands(`Load command 0 + cmd LC_SEGMENT_64 + segname __DATA + maxprot 0x${mask.toString(16)} + initprot ${mask} +`); + for (const permissions of [ + parsed.segments[0]?.maximum_permissions, + parsed.segments[0]?.initial_permissions, + ]) { + expect(permissions).toMatchObject({ + read: (mask & 1) !== 0, + write: (mask & 2) !== 0, + execute: (mask & 4) !== 0, + }); + } + }, +);