From a5c6356e67c3707c416776fe0445c5ace8e1e097 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Mon, 27 Feb 2023 18:55:31 +0530 Subject: [PATCH 1/4] deps: test postject_find_resource() crash fix on linux Testing https://github.com/nodejs/postject/pull/77. Signed-off-by: Darshan Sen --- deps/postject/postject-api.h | 111 +++++++++++------- .../test-single-executable-application.js | 20 +--- 2 files changed, 71 insertions(+), 60 deletions(-) diff --git a/deps/postject/postject-api.h b/deps/postject/postject-api.h index 4ec1f64faaf245..bbf08a13d270f0 100644 --- a/deps/postject/postject-api.h +++ b/deps/postject/postject-api.h @@ -12,7 +12,6 @@ #elif defined(__linux__) #include #include -#include #include #elif defined(_WIN32) #include @@ -44,6 +43,68 @@ static inline bool postject_has_resource() { return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1'; } +#if defined(__linux__) +struct postject__dl_iterate_phdr_data { + void* data; + size_t size; + const char* elf_section_name; + size_t elf_section_name_size; +}; + +static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, + size_t size, + void* opaque) { + /* + The first object visited by the callback is the main program. + For the main program, the dlpi_name field will be an empty string. + */ + if (info->dlpi_name == NULL || strcmp(info->dlpi_name, "") != 0) { + // skip to the next shared object + return 0; + } + + struct postject__dl_iterate_phdr_data* data = + (struct postject__dl_iterate_phdr_data*)opaque; + + // iterate program headers + for (unsigned i = 0; i < info->dlpi_phnum; i++) { + // skip everything but notes + if (info->dlpi_phdr[i].p_type != PT_NOTE) + continue; + + // note segment starts at base address + segment virtual address + uintptr_t pos = (info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); + uintptr_t end = (pos + info->dlpi_phdr[i].p_memsz); + + // iterate through segment until we reach the end + while (pos < end) { + if (pos + sizeof(ElfW(Nhdr)) > end) { + break; // invalid + } + + ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos; + if (note->n_namesz != 0 && note->n_descsz != 0 && + strncmp((char*)(pos + sizeof(ElfW(Nhdr))), data->elf_section_name, + data->elf_section_name_size) == 0) { + data->size = note->n_descsz; + // advance past note header and aligned name + // to get to description data + data->data = (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + + roundup(note->n_namesz, 4)); + // found the note, so terminate the search by returning 1 + return 1; + } + + pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + + roundup(note->n_descsz, 4)); + } + } + + // skip to the next shared object + return 0; +} +#endif + static const void* postject_find_resource( const char* name, size_t* size, @@ -114,46 +175,14 @@ static const void* postject_find_resource( name = options->elf_section_name; } - uintptr_t p = getauxval(AT_PHDR); - size_t n = getauxval(AT_PHNUM); - uintptr_t base_addr = p - sizeof(ElfW(Ehdr)); - - // iterate program header - for (; n > 0; n--, p += sizeof(ElfW(Phdr))) { - ElfW(Phdr)* phdr = (ElfW(Phdr)*)p; - - // skip everything but notes - if (phdr->p_type != PT_NOTE) { - continue; - } - - // note segment starts at base address + segment virtual address - uintptr_t pos = (base_addr + phdr->p_vaddr); - uintptr_t end = (pos + phdr->p_memsz); - - // iterate through segment until we reach the end - while (pos < end) { - if (pos + sizeof(ElfW(Nhdr)) > end) { - break; // invalid - } - - ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos; - if (note->n_namesz != 0 && note->n_descsz != 0 && - strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name, - sizeof(name)) == 0) { - *size = note->n_descsz; - // advance past note header and aligned name - // to get to description data - return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + - roundup(note->n_namesz, 4)); - } - - pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + - roundup(note->n_descsz, 4)); - } - } - return NULL; - + struct postject__dl_iterate_phdr_data data; + data.data = NULL; + data.size = 0; + data.elf_section_name = name; + data.elf_section_name_size = sizeof(name); + dl_iterate_phdr(postject__dl_iterate_phdr_callback, &data); + *size = data.size; + return data.data; #elif defined(_WIN32) void* ptr = NULL; char* resource_name = NULL; diff --git a/test/parallel/test-single-executable-application.js b/test/parallel/test-single-executable-application.js index f41b9d7778d7d3..30d1ecae716ed0 100644 --- a/test/parallel/test-single-executable-application.js +++ b/test/parallel/test-single-executable-application.js @@ -5,7 +5,7 @@ const common = require('../common'); const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); -const { copyFileSync, readFileSync, writeFileSync } = require('fs'); +const { copyFileSync, writeFileSync } = require('fs'); const { execFileSync } = require('child_process'); const { join } = require('path'); const { strictEqual } = require('assert'); @@ -16,9 +16,6 @@ if (!process.config.variables.single_executable_application) if (!['darwin', 'win32', 'linux'].includes(process.platform)) common.skip(`Unsupported platform ${process.platform}.`); -if (process.platform === 'linux' && process.config.variables.asan) - common.skip('Running the resultant binary fails with `Segmentation fault (core dumped)`.'); - if (process.platform === 'linux' && process.config.variables.is_debug === 1) common.skip('Running the resultant binary fails with `Couldn\'t read target executable"`.'); @@ -38,21 +35,6 @@ if (!process.config.variables.node_use_openssl || process.config.variables.node_ if (process.config.variables.want_separate_host_toolset !== 0) common.skip('Running the resultant binary fails with `Segmentation fault (core dumped)`.'); -if (process.platform === 'linux') { - try { - const osReleaseText = readFileSync('/etc/os-release', { encoding: 'utf-8' }); - if (!/^NAME="Ubuntu"/m.test(osReleaseText)) { - throw new Error('Not Ubuntu.'); - } - } catch { - common.skip('Only supported Linux distribution is Ubuntu.'); - } - - if (process.arch !== 'x64') { - common.skip(`Unsupported architecture for Linux - ${process.arch}.`); - } -} - const inputFile = fixtures.path('sea.js'); const requirableFile = join(tmpdir.path, 'requirable.js'); const outputFile = join(tmpdir.path, process.platform === 'win32' ? 'sea.exe' : 'sea'); From 31fd0e00e0c6dafbf888e1148781db7cc85a2313 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Tue, 28 Feb 2023 19:39:57 +0530 Subject: [PATCH 2/4] deps: import if block removal change from postject Refs: https://github.com/nodejs/postject/pull/77/commits/19ab4539753a0cc940ad317dbba8957c752e2ce8 Signed-off-by: Darshan Sen --- deps/postject/postject-api.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/deps/postject/postject-api.h b/deps/postject/postject-api.h index bbf08a13d270f0..e0e6ca21e7d3cf 100644 --- a/deps/postject/postject-api.h +++ b/deps/postject/postject-api.h @@ -54,15 +54,6 @@ struct postject__dl_iterate_phdr_data { static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, size_t size, void* opaque) { - /* - The first object visited by the callback is the main program. - For the main program, the dlpi_name field will be an empty string. - */ - if (info->dlpi_name == NULL || strcmp(info->dlpi_name, "") != 0) { - // skip to the next shared object - return 0; - } - struct postject__dl_iterate_phdr_data* data = (struct postject__dl_iterate_phdr_data*)opaque; From ef1da08d3398760f043ecb82b5b3f6f1dae6c000 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Thu, 2 Mar 2023 11:42:17 +0530 Subject: [PATCH 3/4] deps: import "only iterate the main executable program headers" change from postject Refs: https://github.com/nodejs/postject/pull/77/commits/35a279ff390d85f21f51d0fd205e414676d4775d Signed-off-by: Darshan Sen --- deps/postject/postject-api.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deps/postject/postject-api.h b/deps/postject/postject-api.h index e0e6ca21e7d3cf..43b8875f085585 100644 --- a/deps/postject/postject-api.h +++ b/deps/postject/postject-api.h @@ -91,8 +91,9 @@ static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, } } - // skip to the next shared object - return 0; + // wasn't able to find the note in the main executable program headers, so + // terminate the search + return 1; } #endif From e468871fd014d07930d8e94103f34505d38a70e0 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Thu, 2 Mar 2023 21:31:43 +0530 Subject: [PATCH 4/4] deps: import "chore: shorten change" from postject Refs: https://github.com/nodejs/postject/pull/77/commits/2b7cbdd9fdcab7acec48bc5d88da85b8f7db145c Signed-off-by: Darshan Sen --- deps/postject/postject-api.h | 101 ++++++++++++++++------------------- 1 file changed, 46 insertions(+), 55 deletions(-) diff --git a/deps/postject/postject-api.h b/deps/postject/postject-api.h index 43b8875f085585..875ddc36537eae 100644 --- a/deps/postject/postject-api.h +++ b/deps/postject/postject-api.h @@ -44,55 +44,11 @@ static inline bool postject_has_resource() { } #if defined(__linux__) -struct postject__dl_iterate_phdr_data { - void* data; - size_t size; - const char* elf_section_name; - size_t elf_section_name_size; -}; - static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, size_t size, - void* opaque) { - struct postject__dl_iterate_phdr_data* data = - (struct postject__dl_iterate_phdr_data*)opaque; - - // iterate program headers - for (unsigned i = 0; i < info->dlpi_phnum; i++) { - // skip everything but notes - if (info->dlpi_phdr[i].p_type != PT_NOTE) - continue; - - // note segment starts at base address + segment virtual address - uintptr_t pos = (info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); - uintptr_t end = (pos + info->dlpi_phdr[i].p_memsz); - - // iterate through segment until we reach the end - while (pos < end) { - if (pos + sizeof(ElfW(Nhdr)) > end) { - break; // invalid - } - - ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos; - if (note->n_namesz != 0 && note->n_descsz != 0 && - strncmp((char*)(pos + sizeof(ElfW(Nhdr))), data->elf_section_name, - data->elf_section_name_size) == 0) { - data->size = note->n_descsz; - // advance past note header and aligned name - // to get to description data - data->data = (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + - roundup(note->n_namesz, 4)); - // found the note, so terminate the search by returning 1 - return 1; - } - - pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + - roundup(note->n_descsz, 4)); - } - } - - // wasn't able to find the note in the main executable program headers, so - // terminate the search + void* data) { + // Snag the dl_phdr_info struct for the main program, then stop iterating + *((struct dl_phdr_info*)data) = *info; return 1; } #endif @@ -167,14 +123,49 @@ static const void* postject_find_resource( name = options->elf_section_name; } - struct postject__dl_iterate_phdr_data data; - data.data = NULL; - data.size = 0; - data.elf_section_name = name; - data.elf_section_name_size = sizeof(name); - dl_iterate_phdr(postject__dl_iterate_phdr_callback, &data); - *size = data.size; - return data.data; + struct dl_phdr_info main_program_info; + dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info); + + uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr; + size_t n = main_program_info.dlpi_phnum; + uintptr_t base_addr = main_program_info.dlpi_addr; + + // iterate program header + for (; n > 0; n--, p += sizeof(ElfW(Phdr))) { + ElfW(Phdr)* phdr = (ElfW(Phdr)*)p; + + // skip everything but notes + if (phdr->p_type != PT_NOTE) { + continue; + } + + // note segment starts at base address + segment virtual address + uintptr_t pos = (base_addr + phdr->p_vaddr); + uintptr_t end = (pos + phdr->p_memsz); + + // iterate through segment until we reach the end + while (pos < end) { + if (pos + sizeof(ElfW(Nhdr)) > end) { + break; // invalid + } + + ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos; + if (note->n_namesz != 0 && note->n_descsz != 0 && + strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name, + sizeof(name)) == 0) { + *size = note->n_descsz; + // advance past note header and aligned name + // to get to description data + return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + + roundup(note->n_namesz, 4)); + } + + pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + + roundup(note->n_descsz, 4)); + } + } + return NULL; + #elif defined(_WIN32) void* ptr = NULL; char* resource_name = NULL;