2022-03-29 19:30:09 +00:00
|
|
|
#include <zstd.h>
|
|
|
|
#include <sys/mman.h>
|
2022-07-21 15:43:00 +00:00
|
|
|
#if defined(OS_DARWIN) || defined(OS_FREEBSD)
|
|
|
|
# include <sys/mount.h>
|
2022-06-13 10:14:21 +00:00
|
|
|
#else
|
2022-07-21 15:43:00 +00:00
|
|
|
# include <sys/statfs.h>
|
2022-06-13 10:14:21 +00:00
|
|
|
#endif
|
2022-03-29 19:30:09 +00:00
|
|
|
#include <fcntl.h>
|
2022-04-14 11:43:40 +00:00
|
|
|
#include <sys/wait.h>
|
2022-03-29 19:30:09 +00:00
|
|
|
#include <unistd.h>
|
2022-06-28 11:29:07 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
2022-06-15 11:36:45 +00:00
|
|
|
#include <iostream>
|
2022-08-01 14:58:08 +00:00
|
|
|
#include <filesystem>
|
2022-08-24 21:05:00 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
2022-07-21 04:20:23 +00:00
|
|
|
|
2022-07-21 14:14:53 +00:00
|
|
|
#if (defined(OS_DARWIN) || defined(OS_FREEBSD)) && defined(__GNUC__)
|
2022-07-21 06:08:07 +00:00
|
|
|
# include <machine/endian.h>
|
2022-07-25 01:13:00 +00:00
|
|
|
#else
|
2022-07-21 06:08:07 +00:00
|
|
|
# include <endian.h>
|
|
|
|
#endif
|
2022-07-15 14:48:34 +00:00
|
|
|
|
2022-07-21 06:08:07 +00:00
|
|
|
#if defined OS_DARWIN
|
2022-08-08 21:56:16 +00:00
|
|
|
# include <mach-o/dyld.h>
|
2022-07-21 06:08:07 +00:00
|
|
|
# include <libkern/OSByteOrder.h>
|
|
|
|
// define 64 bit macros
|
|
|
|
# define le64toh(x) OSSwapLittleToHostInt64(x)
|
2022-07-21 04:20:23 +00:00
|
|
|
#endif
|
2022-03-29 19:30:09 +00:00
|
|
|
|
2022-08-08 21:56:16 +00:00
|
|
|
#if defined(OS_FREEBSD)
|
|
|
|
# include <sys/sysctl.h>
|
|
|
|
#endif
|
|
|
|
|
2022-05-29 18:37:02 +00:00
|
|
|
#include "types.h"
|
2022-04-07 12:21:14 +00:00
|
|
|
|
2022-03-29 19:30:09 +00:00
|
|
|
/// decompress part
|
|
|
|
int doDecompress(char * input, char * output, off_t & in_offset, off_t & out_offset,
|
|
|
|
off_t input_size, off_t output_size, ZSTD_DCtx* dctx)
|
|
|
|
{
|
|
|
|
size_t decompressed_size = ZSTD_decompressDCtx(dctx, output + out_offset, output_size, input + in_offset, input_size);
|
|
|
|
if (ZSTD_isError(decompressed_size))
|
|
|
|
{
|
2022-06-15 11:36:45 +00:00
|
|
|
std::cerr << "Error (ZSTD):" << decompressed_size << " " << ZSTD_getErrorName(decompressed_size) << std::endl;
|
2022-03-29 19:30:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// decompress data from in_fd into out_fd
|
2022-04-14 11:43:40 +00:00
|
|
|
int decompress(char * input, char * output, off_t start, off_t end, size_t max_number_of_forks=10)
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
|
|
|
off_t in_pointer = start, out_pointer = 0;
|
|
|
|
off_t size = 0;
|
|
|
|
off_t max_block_size = 1ull<<27;
|
2022-04-14 11:43:40 +00:00
|
|
|
off_t decompressed_size = 0;
|
|
|
|
size_t number_of_forks = 0;
|
2022-04-07 12:21:14 +00:00
|
|
|
|
|
|
|
/// Create context
|
|
|
|
ZSTD_DCtx * dctx = ZSTD_createDCtx();
|
|
|
|
if (dctx == nullptr)
|
|
|
|
{
|
2022-06-15 11:36:45 +00:00
|
|
|
std::cerr << "Error (ZSTD): failed to create decompression context" << std::endl;
|
2022-04-07 12:21:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2022-04-14 11:43:40 +00:00
|
|
|
pid_t pid;
|
|
|
|
bool error_happened = false;
|
2022-04-07 12:21:14 +00:00
|
|
|
|
2022-06-07 11:04:39 +00:00
|
|
|
/// Decompress data
|
2022-06-07 11:04:57 +00:00
|
|
|
while (in_pointer < end && !error_happened)
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
|
|
|
size = ZSTD_findFrameCompressedSize(input + in_pointer, max_block_size);
|
2022-04-14 11:43:40 +00:00
|
|
|
if (ZSTD_isError(size))
|
|
|
|
{
|
2022-06-15 11:36:45 +00:00
|
|
|
std::cerr << "Error (ZSTD): " << size << " " << ZSTD_getErrorName(size) << std::endl;
|
2022-05-30 18:48:48 +00:00
|
|
|
error_happened = true;
|
2022-04-14 11:43:40 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-04-07 12:21:14 +00:00
|
|
|
|
2022-04-14 11:43:40 +00:00
|
|
|
decompressed_size = ZSTD_getFrameContentSize(input + in_pointer, max_block_size);
|
|
|
|
if (ZSTD_isError(decompressed_size))
|
|
|
|
{
|
2022-06-15 11:36:45 +00:00
|
|
|
std::cerr << "Error (ZSTD): " << decompressed_size << " " << ZSTD_getErrorName(decompressed_size) << std::endl;
|
2022-05-30 18:48:48 +00:00
|
|
|
error_happened = true;
|
2022-04-14 11:43:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (-1 == pid)
|
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("fork");
|
2022-05-30 18:48:48 +00:00
|
|
|
/// If fork failed just decompress data in main process.
|
2022-07-09 20:05:12 +00:00
|
|
|
if (0 != doDecompress(input, output, in_pointer, out_pointer, size, decompressed_size, dctx))
|
|
|
|
{
|
|
|
|
error_happened = true;
|
2022-04-14 11:43:40 +00:00
|
|
|
break;
|
2022-07-09 20:05:12 +00:00
|
|
|
}
|
|
|
|
in_pointer += size;
|
|
|
|
out_pointer += decompressed_size;
|
2022-04-14 11:43:40 +00:00
|
|
|
}
|
|
|
|
else if (pid == 0)
|
|
|
|
{
|
2022-05-30 18:48:48 +00:00
|
|
|
/// Decompress data in child process.
|
2022-07-09 20:05:12 +00:00
|
|
|
if (0 != doDecompress(input, output, in_pointer, out_pointer, size, decompressed_size, dctx))
|
2022-08-20 15:09:20 +00:00
|
|
|
_exit(1);
|
|
|
|
_exit(0);
|
2022-04-14 11:43:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++number_of_forks;
|
|
|
|
while (number_of_forks >= max_number_of_forks)
|
|
|
|
{
|
|
|
|
/// Wait any fork
|
|
|
|
int status;
|
|
|
|
waitpid(0, &status, 0);
|
|
|
|
|
|
|
|
/// If error happened, stop processing
|
|
|
|
if (WEXITSTATUS(status) != 0)
|
|
|
|
{
|
|
|
|
error_happened = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
--number_of_forks;
|
|
|
|
}
|
|
|
|
in_pointer += size;
|
|
|
|
out_pointer += decompressed_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// wait for all working decompressions
|
|
|
|
while (number_of_forks > 0)
|
|
|
|
{
|
|
|
|
/// Wait any fork
|
|
|
|
int status;
|
|
|
|
waitpid(0, &status, 0);
|
|
|
|
|
2022-07-09 20:05:12 +00:00
|
|
|
if (WIFEXITED(status))
|
|
|
|
{
|
|
|
|
if (WEXITSTATUS(status) != 0)
|
|
|
|
error_happened = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error_happened = true;
|
|
|
|
if (WIFSIGNALED(status))
|
|
|
|
{
|
|
|
|
if (WCOREDUMP(status))
|
|
|
|
std::cerr << "Error: child process core dumped with signal " << WTERMSIG(status) << std::endl;
|
|
|
|
else
|
|
|
|
std::cerr << "Error: child process was terminated with signal " << WTERMSIG(status) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 11:43:40 +00:00
|
|
|
if (WEXITSTATUS(status) != 0)
|
|
|
|
error_happened = true;
|
|
|
|
|
|
|
|
--number_of_forks;
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
|
|
|
|
2022-07-25 19:22:48 +00:00
|
|
|
ZSTD_freeDCtx(dctx);
|
|
|
|
|
2022-04-14 11:43:40 +00:00
|
|
|
/// If error happen end of processed part will not reach end
|
|
|
|
if (in_pointer < end || error_happened)
|
|
|
|
return 1;
|
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-02 14:49:49 +00:00
|
|
|
bool isSudo()
|
2023-03-02 00:42:02 +00:00
|
|
|
{
|
2023-03-08 13:26:07 +00:00
|
|
|
return geteuid() == 0;
|
2023-03-02 00:42:02 +00:00
|
|
|
}
|
2022-04-07 12:21:14 +00:00
|
|
|
|
|
|
|
/// Read data about files and decomrpess them.
|
2022-08-21 21:39:24 +00:00
|
|
|
int decompressFiles(int input_fd, char * path, char * name, bool & have_compressed_analoge, bool & has_exec, char * decompressed_suffix, uint64_t * decompressed_umask)
|
2022-03-29 19:30:09 +00:00
|
|
|
{
|
|
|
|
/// Read data about output file.
|
|
|
|
/// Compressed data will replace data in file
|
|
|
|
struct stat info_in;
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != fstat(input_fd, &info_in))
|
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("fstat");
|
2022-04-07 12:21:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2022-03-29 19:30:09 +00:00
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
/// mmap input file
|
2022-04-07 12:31:41 +00:00
|
|
|
char * input = static_cast<char*>(mmap(nullptr, info_in.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0));
|
2022-04-07 12:21:14 +00:00
|
|
|
if (input == MAP_FAILED)
|
2022-03-29 19:30:09 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("mmap");
|
2022-03-29 19:30:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
/// Read metadata from end of file
|
|
|
|
MetaData metadata = *reinterpret_cast<MetaData*>(input + info_in.st_size - sizeof(MetaData));
|
2022-03-29 19:30:09 +00:00
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
/// Prepare to read information about files and decompress them
|
2022-07-09 20:05:12 +00:00
|
|
|
off_t files_pointer = le64toh(metadata.start_of_files_data);
|
2022-04-07 12:21:14 +00:00
|
|
|
size_t decompressed_full_size = 0;
|
|
|
|
|
|
|
|
/// Read files metadata and check if decompression is possible
|
2022-07-09 20:05:12 +00:00
|
|
|
off_t check_pointer = le64toh(metadata.start_of_files_data);
|
|
|
|
for (size_t i = 0; i < le64toh(metadata.number_of_files); ++i)
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
|
|
|
FileData data = *reinterpret_cast<FileData*>(input + check_pointer);
|
2022-07-09 20:05:12 +00:00
|
|
|
decompressed_full_size += le64toh(data.uncompressed_size);
|
|
|
|
check_pointer += sizeof(FileData) + le64toh(data.name_length);
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check free space
|
|
|
|
struct statfs fs_info;
|
|
|
|
if (0 != fstatfs(input_fd, &fs_info))
|
2022-03-29 19:30:09 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("fstatfs");
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != munmap(input, info_in.st_size))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-03-29 19:30:09 +00:00
|
|
|
return 1;
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
|
|
|
if (fs_info.f_blocks * info_in.st_blksize < decompressed_full_size)
|
|
|
|
{
|
2022-06-15 11:36:45 +00:00
|
|
|
std::cerr << "Not enough space for decompression. Have " << fs_info.f_blocks * info_in.st_blksize << ", need " << decompressed_full_size << std::endl;
|
2022-04-07 12:21:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2022-03-29 19:30:09 +00:00
|
|
|
|
2023-03-02 14:49:49 +00:00
|
|
|
bool is_sudo = isSudo();
|
2023-03-02 00:42:02 +00:00
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
FileData file_info;
|
|
|
|
/// Decompress files with appropriate file names
|
2022-07-09 20:05:12 +00:00
|
|
|
for (size_t i = 0; i < le64toh(metadata.number_of_files); ++i)
|
2022-03-29 19:30:09 +00:00
|
|
|
{
|
2022-04-07 12:21:14 +00:00
|
|
|
/// Read information about file
|
|
|
|
file_info = *reinterpret_cast<FileData*>(input + files_pointer);
|
|
|
|
files_pointer += sizeof(FileData);
|
2022-03-29 19:30:09 +00:00
|
|
|
|
2022-08-22 12:14:29 +00:00
|
|
|
/// for output filename matching compressed allow additional 13 + 7 symbols for ".decompressed.XXXXXX" suffix
|
2022-08-20 21:02:36 +00:00
|
|
|
size_t file_name_len = file_info.exec ? strlen(name) + 13 + 7 + 1 : le64toh(file_info.name_length);
|
2022-05-30 00:39:42 +00:00
|
|
|
|
|
|
|
size_t file_path_len = path ? strlen(path) + 1 + file_name_len : file_name_len;
|
|
|
|
|
|
|
|
char file_name[file_path_len];
|
|
|
|
memset(file_name, '\0', file_path_len);
|
|
|
|
if (path)
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
2023-09-26 11:01:35 +00:00
|
|
|
strcat(file_name, path); // NOLINT(clang-analyzer-security.insecureAPI.strcpy)
|
|
|
|
strcat(file_name, "/"); // NOLINT(clang-analyzer-security.insecureAPI.strcpy)
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
2022-08-21 21:39:24 +00:00
|
|
|
|
|
|
|
bool same_name = false;
|
2022-08-19 20:43:10 +00:00
|
|
|
if (file_info.exec)
|
2022-08-21 21:39:24 +00:00
|
|
|
{
|
|
|
|
has_exec = true;
|
2023-09-26 11:01:35 +00:00
|
|
|
strcat(file_name, name); // NOLINT(clang-analyzer-security.insecureAPI.strcpy)
|
2022-08-21 21:39:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (strcmp(name, input + files_pointer) == 0)
|
|
|
|
same_name = true;
|
2023-09-26 11:01:35 +00:00
|
|
|
strcat(file_name, input + files_pointer); // NOLINT(clang-analyzer-security.insecureAPI.strcpy)
|
2022-08-21 21:39:24 +00:00
|
|
|
}
|
|
|
|
|
2022-07-09 20:05:12 +00:00
|
|
|
files_pointer += le64toh(file_info.name_length);
|
2022-08-21 21:39:24 +00:00
|
|
|
if (file_info.exec || same_name)
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
2023-09-26 11:01:35 +00:00
|
|
|
strcat(file_name, ".decompressed.XXXXXX"); // NOLINT(clang-analyzer-security.insecureAPI.strcpy)
|
2022-08-01 14:58:08 +00:00
|
|
|
int fd = mkstemp(file_name);
|
2022-08-01 15:06:54 +00:00
|
|
|
if (fd == -1)
|
2022-08-01 14:58:08 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("mkstemp");
|
2022-08-01 14:58:08 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2023-02-07 08:50:02 +00:00
|
|
|
if (0 != close(fd))
|
|
|
|
perror("close");
|
2022-08-01 14:58:08 +00:00
|
|
|
strncpy(decompressed_suffix, file_name + strlen(file_name) - 6, 6);
|
2022-08-03 07:34:51 +00:00
|
|
|
*decompressed_umask = le64toh(file_info.umask);
|
2022-05-30 00:39:42 +00:00
|
|
|
have_compressed_analoge = true;
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
2022-05-30 00:39:42 +00:00
|
|
|
|
2022-07-09 20:05:12 +00:00
|
|
|
int output_fd = open(file_name, O_RDWR | O_CREAT, le64toh(file_info.umask));
|
2022-05-30 00:39:42 +00:00
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
if (output_fd == -1)
|
2022-03-29 19:30:09 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("open");
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != munmap(input, info_in.st_size))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-05-30 00:39:42 +00:00
|
|
|
return 1;
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Prepare output file
|
2022-07-09 20:05:12 +00:00
|
|
|
if (0 != ftruncate(output_fd, le64toh(file_info.uncompressed_size)))
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("ftruncate");
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != munmap(input, info_in.st_size))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-04-07 12:21:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char * output = static_cast<char*>(
|
2022-04-14 11:43:40 +00:00
|
|
|
mmap(nullptr,
|
2022-07-09 20:05:12 +00:00
|
|
|
le64toh(file_info.uncompressed_size),
|
2022-04-14 11:43:40 +00:00
|
|
|
PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
|
|
output_fd,
|
2022-04-07 12:21:14 +00:00
|
|
|
0)
|
|
|
|
);
|
|
|
|
if (output == MAP_FAILED)
|
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("mmap");
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != munmap(input, info_in.st_size))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-03-29 19:30:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
/// Decompress data into file
|
2022-07-09 20:05:12 +00:00
|
|
|
if (0 != decompress(input, output, le64toh(file_info.start), le64toh(file_info.end)))
|
2022-04-07 12:21:14 +00:00
|
|
|
{
|
|
|
|
if (0 != munmap(input, info_in.st_size))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-07-09 20:05:12 +00:00
|
|
|
if (0 != munmap(output, le64toh(file_info.uncompressed_size)))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-04-07 12:21:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 != fsync(output_fd))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("fsync");
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != close(output_fd))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("close");
|
2023-03-02 00:42:02 +00:00
|
|
|
|
2023-03-02 14:49:49 +00:00
|
|
|
if (is_sudo)
|
|
|
|
chown(file_name, info_in.st_uid, info_in.st_gid);
|
2022-04-07 12:21:14 +00:00
|
|
|
}
|
2022-04-14 11:43:40 +00:00
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != munmap(input, info_in.st_size))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("munmap");
|
2022-03-29 19:30:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2022-03-24 19:45:54 +00:00
|
|
|
|
2022-08-08 21:56:16 +00:00
|
|
|
#if defined(OS_DARWIN)
|
|
|
|
|
|
|
|
int read_exe_path(char *exe, size_t buf_sz)
|
|
|
|
{
|
2022-10-16 17:25:33 +00:00
|
|
|
uint32_t size = static_cast<uint32_t>(buf_sz);
|
2022-08-08 21:56:16 +00:00
|
|
|
char apple[size];
|
|
|
|
if (_NSGetExecutablePath(apple, &size) != 0)
|
|
|
|
return 1;
|
|
|
|
if (realpath(apple, exe) == nullptr)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(OS_FREEBSD)
|
|
|
|
|
|
|
|
int read_exe_path(char *exe, size_t buf_sz)
|
|
|
|
{
|
|
|
|
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
|
|
size_t length = buf_sz;
|
|
|
|
int error = sysctl(name, 4, exe, &length, nullptr, 0);
|
|
|
|
if (error < 0 || length <= 1)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2023-07-17 10:09:11 +00:00
|
|
|
int read_exe_path(char *exe, size_t buf_sz)
|
2022-08-08 21:56:16 +00:00
|
|
|
{
|
2023-07-17 10:09:11 +00:00
|
|
|
ssize_t n = readlink("/proc/self/exe", exe, buf_sz - 1);
|
|
|
|
if (n > 0)
|
|
|
|
exe[n] = '\0';
|
|
|
|
return n > 0 && n < static_cast<ssize_t>(buf_sz);
|
2022-08-08 21:56:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2022-04-14 11:43:40 +00:00
|
|
|
|
2022-09-05 15:41:52 +00:00
|
|
|
#if !defined(OS_DARWIN) && !defined(OS_FREEBSD)
|
|
|
|
|
2023-01-16 18:32:41 +00:00
|
|
|
uint64_t getInode(const char * self)
|
2022-08-24 21:05:00 +00:00
|
|
|
{
|
|
|
|
std::ifstream maps("/proc/self/maps");
|
|
|
|
if (maps.fail())
|
|
|
|
{
|
|
|
|
perror("open maps");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-30 01:11:04 +00:00
|
|
|
/// Record example for /proc/self/maps:
|
|
|
|
/// address perms offset device inode pathname
|
|
|
|
/// 561a247de000-561a247e0000 r--p 00000000 103:01 1564 /usr/bin/cat
|
|
|
|
/// see "man 5 proc"
|
2022-08-24 21:47:37 +00:00
|
|
|
for (std::string line; std::getline(maps, line);)
|
2022-08-24 21:05:00 +00:00
|
|
|
{
|
2022-08-24 21:28:52 +00:00
|
|
|
std::stringstream ss(line); // STYLE_CHECK_ALLOW_STD_STRING_STREAM
|
2022-08-24 21:05:00 +00:00
|
|
|
std::string addr, mode, offset, id, path;
|
2023-01-16 18:32:41 +00:00
|
|
|
uint64_t inode = 0;
|
2022-08-24 21:05:00 +00:00
|
|
|
if (ss >> addr >> mode >> offset >> id >> inode >> path && path == self)
|
|
|
|
return inode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-05 15:41:52 +00:00
|
|
|
#endif
|
|
|
|
|
2022-08-01 00:07:33 +00:00
|
|
|
int main(int/* argc*/, char* argv[])
|
2022-03-24 19:45:54 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
char self[4096] = {0};
|
|
|
|
if (read_exe_path(self, 4096) == -1)
|
|
|
|
{
|
|
|
|
perror("read_exe_path");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char file_path[strlen(self) + 1];
|
2023-09-26 11:01:35 +00:00
|
|
|
strcpy(file_path, self); // NOLINT(clang-analyzer-security.insecureAPI.strcpy)
|
2022-05-30 00:39:42 +00:00
|
|
|
|
|
|
|
char * path = nullptr;
|
|
|
|
char * name = strrchr(file_path, '/');
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
path = file_path;
|
|
|
|
*name = 0;
|
|
|
|
++name;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
name = file_path;
|
|
|
|
|
2023-03-07 02:24:04 +00:00
|
|
|
struct stat input_info;
|
|
|
|
if (0 != stat(self, &input_info))
|
|
|
|
{
|
|
|
|
perror("stat");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-09-05 15:41:52 +00:00
|
|
|
#if !defined(OS_DARWIN) && !defined(OS_FREEBSD)
|
2022-08-30 01:11:04 +00:00
|
|
|
/// get inode of this executable
|
2023-01-16 18:32:41 +00:00
|
|
|
uint64_t inode = getInode(self);
|
2023-07-17 10:01:47 +00:00
|
|
|
if (inode == 0)
|
2022-08-24 21:05:00 +00:00
|
|
|
{
|
2023-07-17 10:02:54 +00:00
|
|
|
std::cerr << "Unable to obtain inode for exe '" << self << "'." << std::endl;
|
2023-07-17 10:01:47 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2022-08-24 21:05:00 +00:00
|
|
|
|
2023-07-17 10:01:47 +00:00
|
|
|
std::stringstream lock_path; // STYLE_CHECK_ALLOW_STD_STRING_STREAM
|
|
|
|
lock_path << "/tmp/" << name << ".decompression." << inode << ".lock";
|
|
|
|
int lock = open(lock_path.str().c_str(), O_CREAT | O_RDWR, 0666);
|
|
|
|
if (lock < 0)
|
|
|
|
{
|
|
|
|
perror("lock open");
|
|
|
|
return 1;
|
|
|
|
}
|
2023-01-16 18:32:41 +00:00
|
|
|
|
2023-07-17 10:01:47 +00:00
|
|
|
/// lock file should be closed on exec call
|
|
|
|
fcntl(lock, F_SETFD, FD_CLOEXEC);
|
|
|
|
|
|
|
|
if (lockf(lock, F_LOCK, 0))
|
|
|
|
{
|
|
|
|
perror("lockf");
|
|
|
|
return 1;
|
|
|
|
}
|
2022-08-24 21:05:00 +00:00
|
|
|
|
2023-07-17 10:01:47 +00:00
|
|
|
/// inconsistency in WSL1 Ubuntu - inode reported in /proc/self/maps is a 64bit to
|
|
|
|
/// 32bit conversion of input_info.st_ino
|
|
|
|
if (input_info.st_ino & 0xFFFFFFFF00000000 && !(inode & 0xFFFFFFFF00000000))
|
|
|
|
input_info.st_ino &= 0x00000000FFFFFFFF;
|
2022-08-24 21:05:00 +00:00
|
|
|
|
2023-07-17 10:01:47 +00:00
|
|
|
/// if decompression was performed by another process since this copy was started
|
|
|
|
/// then file referred by path "self" is already pointing to different inode
|
|
|
|
if (input_info.st_ino != inode)
|
|
|
|
{
|
|
|
|
struct stat lock_info;
|
|
|
|
if (0 != fstat(lock, &lock_info))
|
Skip protection from double decompression if inode from maps cannot be obtained
Under some circumstances, like using qemu-$ARCH-static, /proc/self/maps
will not contain information about /proc/self/exe.
Well, strictly speaking it does contains, however qemu will not pass it
to the user program:
<details>
<summary>strace</summary>
$ sudo strace -s10000 -f arch-chroot . /qemu-riscv64-static /clickhouse
...
execve("/qemu-riscv64-static", ["/qemu-riscv64-static", "/clickhouse"], 0x7fffffffe458 /* 20 vars */) = 0
readlinkat(AT_FDCWD, "/proc/self/exe", "/qemu-riscv64-static", 4096) = 20
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 4
[pid 3126] read(4, "00010000-00111000 r--p 00000000 fe:01 30312571 /clickhouse\n00111000-00119000 r--p 00100000 fe:01 30312571 /clickhouse\n00119000-0011a000 rw-p 00108000 fe:01 30312571 /clickhouse\n0011a000-0013d000 rw-p 00000000 00:00 0 \n4000000000-4000001000 ---p 00000000 00:00 0 \n4000001000-4000801000 rw-p 00000000 00:00 0 \n4000801000-400081a000 r--p 00000000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081a000-400081b000 ---p 00000000 00:00 0 \n400081b000-400081c000 r--p 00019000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081c000-400081e000 rw-p 0001a000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081e000-400081f000 r--p 00000000 00:00 0 \n400081f000-4000922000 r--p 00000000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000922000-4000926000 r--p 00102000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000926000-4000928000 rw-p 00106000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000928000-400092d000 rw-p 00000000 00:00 0 \n400092d000-40009af000 r--p 00000000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009af000-40009b0000 r--p 00081000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009b0000-40009b1000 rw-p 00082000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009b1000-40009c5000 r--p 00000000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c5000-40009c6000 r--p 00013000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c6000-40009c7000 rw-p 00014000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c7000-40009cb000 rw-p 00000000 00:00 0 \n40009cb000-40009cd000 r--p 00000000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009cd000-40009ce000 r--p 00001000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009ce000-40009cf000 rw-p 00002000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009cf000-40009d1000 rw-p 00000000 00:00 0 \n7fffe8000000-7fffeffff000 rwxp 00000000 00:00 0 \n7fffeffff000-7ffff0000000 ---p 00000000 00:00 0 \n7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0 \n7ffff0021000-7ffff4000000 ---p 00000000 00:00 0 \n7ffff6b4b000-7ffff6b5b000 rw-p 00000000 00:00 0 \n7ffff71ff000-7ffff7200000 ---p 00000000 00:00 0 \n7ffff7200000-7ffff7a00000 rw-p 00000000 00:00 0\n7ffff7a00000-7ffff7a3c000 r--p 00000000 fe:01 30316953 /qemu-riscv64-static\n7ffff7a3c000-7ffff7c74000 r-xp 0003c000 fe:01 30316953 /qemu-riscv64-static\n7ffff7c74000-7ffff7d77000 r--p 00274000 fe:01 30316953 /qemu-riscv64-static\n7ffff7d77000-7ffff7dce000 r--p 00377000 fe:01 30316953 /qemu-riscv64-static\n7ffff7dce000-7ffff7df7000 rw-p 003ce000 fe:01 30316953 /qemu-riscv64-static\n7ffff7df7000-7ffff7e0c000 rw-p 00000000 00:00 0 [heap]\n7ffff7e0c000-7ffff7e70000 rw-p 00000000 00:00 0 [heap]\n7ffff7f42000-7ffff7ff9000 rw-p 00000000 00:00 0 \n7ffff7ff9000-7ffff7ffd000 r--p 00000000 00:00 0 [vvar]\n7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0 [vdso]\n7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]\nffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n", 4096) = 3608
[pid 3126] read(4, "", 1024) = 0
[pid 3126] close(4) = 0
[pid 3126] write(3, "10000-111000 r-xp 00000000 fe:01 30312571", 41) = 41
[pid 3126] write(3, " /clickhouse\n", 44) = 44
[pid 3126] write(3, "111000-119000 r--p 00100000 fe:01 30312571", 42) = 42
[pid 3126] write(3, " /clickhouse\n", 43) = 43
[pid 3126] write(3, "119000-11a000 rw-p 00108000 fe:01 30312571", 42) = 42
[pid 3126] write(3, " /clickhouse\n", 43) = 43
[pid 3126] write(3, "11a000-13d000 rw-p 00000000 00:00 0", 35) = 35
[pid 3126] write(3, " \n", 39) = 39
[pid 3126] write(3, "4000000000-4000001000 ---p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "4000001000-4000801000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " [stack]\n", 38) = 38
[pid 3126] write(3, "4000801000-400081a000 r-xp 00000000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57 <unfinished ...>
[pid 3127] <... clock_nanosleep resumed>0x7ffff79ff060) = 0
[pid 3126] <... write resumed>) = 57
[pid 3127] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=10000000}, <unfinished ...>
[pid 3126] write(3, "400081a000-400081b000 ---p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400081b000-400081c000 r--p 00019000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57) = 57
[pid 3126] write(3, "400081c000-400081e000 rw-p 0001a000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57) = 57
[pid 3126] write(3, "400081e000-400081f000 r-xp 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400081f000-4000922000 r-xp 00000000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000922000-4000926000 r--p 00102000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000926000-4000928000 rw-p 00106000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000928000-400092d000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400092d000-40009af000 r-xp 00000000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009af000-40009b0000 r--p 00081000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009b0000-40009b1000 rw-p 00082000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009b1000-40009c5000 r-xp 00000000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c5000-40009c6000 r--p 00013000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c6000-40009c7000 rw-p 00014000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c7000-40009cb000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "40009cb000-40009cd000 r-xp 00000000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009cd000-40009ce000 r--p 00001000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009ce000-40009cf000 rw-p 00002000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009cf000-40009d1000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
</details>
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2023-07-15 17:44:29 +00:00
|
|
|
{
|
2023-07-17 10:01:47 +00:00
|
|
|
perror("fstat lock");
|
|
|
|
return 1;
|
|
|
|
}
|
Skip protection from double decompression if inode from maps cannot be obtained
Under some circumstances, like using qemu-$ARCH-static, /proc/self/maps
will not contain information about /proc/self/exe.
Well, strictly speaking it does contains, however qemu will not pass it
to the user program:
<details>
<summary>strace</summary>
$ sudo strace -s10000 -f arch-chroot . /qemu-riscv64-static /clickhouse
...
execve("/qemu-riscv64-static", ["/qemu-riscv64-static", "/clickhouse"], 0x7fffffffe458 /* 20 vars */) = 0
readlinkat(AT_FDCWD, "/proc/self/exe", "/qemu-riscv64-static", 4096) = 20
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 4
[pid 3126] read(4, "00010000-00111000 r--p 00000000 fe:01 30312571 /clickhouse\n00111000-00119000 r--p 00100000 fe:01 30312571 /clickhouse\n00119000-0011a000 rw-p 00108000 fe:01 30312571 /clickhouse\n0011a000-0013d000 rw-p 00000000 00:00 0 \n4000000000-4000001000 ---p 00000000 00:00 0 \n4000001000-4000801000 rw-p 00000000 00:00 0 \n4000801000-400081a000 r--p 00000000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081a000-400081b000 ---p 00000000 00:00 0 \n400081b000-400081c000 r--p 00019000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081c000-400081e000 rw-p 0001a000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081e000-400081f000 r--p 00000000 00:00 0 \n400081f000-4000922000 r--p 00000000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000922000-4000926000 r--p 00102000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000926000-4000928000 rw-p 00106000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000928000-400092d000 rw-p 00000000 00:00 0 \n400092d000-40009af000 r--p 00000000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009af000-40009b0000 r--p 00081000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009b0000-40009b1000 rw-p 00082000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009b1000-40009c5000 r--p 00000000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c5000-40009c6000 r--p 00013000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c6000-40009c7000 rw-p 00014000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c7000-40009cb000 rw-p 00000000 00:00 0 \n40009cb000-40009cd000 r--p 00000000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009cd000-40009ce000 r--p 00001000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009ce000-40009cf000 rw-p 00002000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009cf000-40009d1000 rw-p 00000000 00:00 0 \n7fffe8000000-7fffeffff000 rwxp 00000000 00:00 0 \n7fffeffff000-7ffff0000000 ---p 00000000 00:00 0 \n7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0 \n7ffff0021000-7ffff4000000 ---p 00000000 00:00 0 \n7ffff6b4b000-7ffff6b5b000 rw-p 00000000 00:00 0 \n7ffff71ff000-7ffff7200000 ---p 00000000 00:00 0 \n7ffff7200000-7ffff7a00000 rw-p 00000000 00:00 0\n7ffff7a00000-7ffff7a3c000 r--p 00000000 fe:01 30316953 /qemu-riscv64-static\n7ffff7a3c000-7ffff7c74000 r-xp 0003c000 fe:01 30316953 /qemu-riscv64-static\n7ffff7c74000-7ffff7d77000 r--p 00274000 fe:01 30316953 /qemu-riscv64-static\n7ffff7d77000-7ffff7dce000 r--p 00377000 fe:01 30316953 /qemu-riscv64-static\n7ffff7dce000-7ffff7df7000 rw-p 003ce000 fe:01 30316953 /qemu-riscv64-static\n7ffff7df7000-7ffff7e0c000 rw-p 00000000 00:00 0 [heap]\n7ffff7e0c000-7ffff7e70000 rw-p 00000000 00:00 0 [heap]\n7ffff7f42000-7ffff7ff9000 rw-p 00000000 00:00 0 \n7ffff7ff9000-7ffff7ffd000 r--p 00000000 00:00 0 [vvar]\n7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0 [vdso]\n7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]\nffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n", 4096) = 3608
[pid 3126] read(4, "", 1024) = 0
[pid 3126] close(4) = 0
[pid 3126] write(3, "10000-111000 r-xp 00000000 fe:01 30312571", 41) = 41
[pid 3126] write(3, " /clickhouse\n", 44) = 44
[pid 3126] write(3, "111000-119000 r--p 00100000 fe:01 30312571", 42) = 42
[pid 3126] write(3, " /clickhouse\n", 43) = 43
[pid 3126] write(3, "119000-11a000 rw-p 00108000 fe:01 30312571", 42) = 42
[pid 3126] write(3, " /clickhouse\n", 43) = 43
[pid 3126] write(3, "11a000-13d000 rw-p 00000000 00:00 0", 35) = 35
[pid 3126] write(3, " \n", 39) = 39
[pid 3126] write(3, "4000000000-4000001000 ---p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "4000001000-4000801000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " [stack]\n", 38) = 38
[pid 3126] write(3, "4000801000-400081a000 r-xp 00000000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57 <unfinished ...>
[pid 3127] <... clock_nanosleep resumed>0x7ffff79ff060) = 0
[pid 3126] <... write resumed>) = 57
[pid 3127] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=10000000}, <unfinished ...>
[pid 3126] write(3, "400081a000-400081b000 ---p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400081b000-400081c000 r--p 00019000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57) = 57
[pid 3126] write(3, "400081c000-400081e000 rw-p 0001a000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57) = 57
[pid 3126] write(3, "400081e000-400081f000 r-xp 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400081f000-4000922000 r-xp 00000000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000922000-4000926000 r--p 00102000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000926000-4000928000 rw-p 00106000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000928000-400092d000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400092d000-40009af000 r-xp 00000000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009af000-40009b0000 r--p 00081000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009b0000-40009b1000 rw-p 00082000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009b1000-40009c5000 r-xp 00000000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c5000-40009c6000 r--p 00013000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c6000-40009c7000 rw-p 00014000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c7000-40009cb000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "40009cb000-40009cd000 r-xp 00000000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009cd000-40009ce000 r--p 00001000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009ce000-40009cf000 rw-p 00002000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009cf000-40009d1000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
</details>
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2023-07-15 17:44:29 +00:00
|
|
|
|
2023-07-17 10:01:47 +00:00
|
|
|
/// size 1 of lock file indicates that another decompressor has found active executable
|
|
|
|
if (lock_info.st_size == 1)
|
|
|
|
execv(self, argv);
|
Skip protection from double decompression if inode from maps cannot be obtained
Under some circumstances, like using qemu-$ARCH-static, /proc/self/maps
will not contain information about /proc/self/exe.
Well, strictly speaking it does contains, however qemu will not pass it
to the user program:
<details>
<summary>strace</summary>
$ sudo strace -s10000 -f arch-chroot . /qemu-riscv64-static /clickhouse
...
execve("/qemu-riscv64-static", ["/qemu-riscv64-static", "/clickhouse"], 0x7fffffffe458 /* 20 vars */) = 0
readlinkat(AT_FDCWD, "/proc/self/exe", "/qemu-riscv64-static", 4096) = 20
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 4
[pid 3126] read(4, "00010000-00111000 r--p 00000000 fe:01 30312571 /clickhouse\n00111000-00119000 r--p 00100000 fe:01 30312571 /clickhouse\n00119000-0011a000 rw-p 00108000 fe:01 30312571 /clickhouse\n0011a000-0013d000 rw-p 00000000 00:00 0 \n4000000000-4000001000 ---p 00000000 00:00 0 \n4000001000-4000801000 rw-p 00000000 00:00 0 \n4000801000-400081a000 r--p 00000000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081a000-400081b000 ---p 00000000 00:00 0 \n400081b000-400081c000 r--p 00019000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081c000-400081e000 rw-p 0001a000 fe:01 30316932 /lib/riscv64-linux-gnu/ld-2.32.so\n400081e000-400081f000 r--p 00000000 00:00 0 \n400081f000-4000922000 r--p 00000000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000922000-4000926000 r--p 00102000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000926000-4000928000 rw-p 00106000 fe:01 30316935 /lib/riscv64-linux-gnu/libc-2.32.so\n4000928000-400092d000 rw-p 00000000 00:00 0 \n400092d000-40009af000 r--p 00000000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009af000-40009b0000 r--p 00081000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009b0000-40009b1000 rw-p 00082000 fe:01 30316943 /lib/riscv64-linux-gnu/libm-2.32.so\n40009b1000-40009c5000 r--p 00000000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c5000-40009c6000 r--p 00013000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c6000-40009c7000 rw-p 00014000 fe:01 30316946 /lib/riscv64-linux-gnu/libpthread-2.32.so\n40009c7000-40009cb000 rw-p 00000000 00:00 0 \n40009cb000-40009cd000 r--p 00000000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009cd000-40009ce000 r--p 00001000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009ce000-40009cf000 rw-p 00002000 fe:01 30316939 /lib/riscv64-linux-gnu/libdl-2.32.so\n40009cf000-40009d1000 rw-p 00000000 00:00 0 \n7fffe8000000-7fffeffff000 rwxp 00000000 00:00 0 \n7fffeffff000-7ffff0000000 ---p 00000000 00:00 0 \n7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0 \n7ffff0021000-7ffff4000000 ---p 00000000 00:00 0 \n7ffff6b4b000-7ffff6b5b000 rw-p 00000000 00:00 0 \n7ffff71ff000-7ffff7200000 ---p 00000000 00:00 0 \n7ffff7200000-7ffff7a00000 rw-p 00000000 00:00 0\n7ffff7a00000-7ffff7a3c000 r--p 00000000 fe:01 30316953 /qemu-riscv64-static\n7ffff7a3c000-7ffff7c74000 r-xp 0003c000 fe:01 30316953 /qemu-riscv64-static\n7ffff7c74000-7ffff7d77000 r--p 00274000 fe:01 30316953 /qemu-riscv64-static\n7ffff7d77000-7ffff7dce000 r--p 00377000 fe:01 30316953 /qemu-riscv64-static\n7ffff7dce000-7ffff7df7000 rw-p 003ce000 fe:01 30316953 /qemu-riscv64-static\n7ffff7df7000-7ffff7e0c000 rw-p 00000000 00:00 0 [heap]\n7ffff7e0c000-7ffff7e70000 rw-p 00000000 00:00 0 [heap]\n7ffff7f42000-7ffff7ff9000 rw-p 00000000 00:00 0 \n7ffff7ff9000-7ffff7ffd000 r--p 00000000 00:00 0 [vvar]\n7ffff7ffd000-7ffff7fff000 r-xp 00000000 00:00 0 [vdso]\n7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]\nffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n", 4096) = 3608
[pid 3126] read(4, "", 1024) = 0
[pid 3126] close(4) = 0
[pid 3126] write(3, "10000-111000 r-xp 00000000 fe:01 30312571", 41) = 41
[pid 3126] write(3, " /clickhouse\n", 44) = 44
[pid 3126] write(3, "111000-119000 r--p 00100000 fe:01 30312571", 42) = 42
[pid 3126] write(3, " /clickhouse\n", 43) = 43
[pid 3126] write(3, "119000-11a000 rw-p 00108000 fe:01 30312571", 42) = 42
[pid 3126] write(3, " /clickhouse\n", 43) = 43
[pid 3126] write(3, "11a000-13d000 rw-p 00000000 00:00 0", 35) = 35
[pid 3126] write(3, " \n", 39) = 39
[pid 3126] write(3, "4000000000-4000001000 ---p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "4000001000-4000801000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " [stack]\n", 38) = 38
[pid 3126] write(3, "4000801000-400081a000 r-xp 00000000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57 <unfinished ...>
[pid 3127] <... clock_nanosleep resumed>0x7ffff79ff060) = 0
[pid 3126] <... write resumed>) = 57
[pid 3127] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=10000000}, <unfinished ...>
[pid 3126] write(3, "400081a000-400081b000 ---p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400081b000-400081c000 r--p 00019000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57) = 57
[pid 3126] write(3, "400081c000-400081e000 rw-p 0001a000 fe:01 30316932", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/ld-2.32.so\n", 57) = 57
[pid 3126] write(3, "400081e000-400081f000 r-xp 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400081f000-4000922000 r-xp 00000000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000922000-4000926000 r--p 00102000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000926000-4000928000 rw-p 00106000 fe:01 30316935", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libc-2.32.so\n", 59) = 59
[pid 3126] write(3, "4000928000-400092d000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "400092d000-40009af000 r-xp 00000000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009af000-40009b0000 r--p 00081000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009b0000-40009b1000 rw-p 00082000 fe:01 30316943", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libm-2.32.so\n", 59) = 59
[pid 3126] write(3, "40009b1000-40009c5000 r-xp 00000000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c5000-40009c6000 r--p 00013000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c6000-40009c7000 rw-p 00014000 fe:01 30316946", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libpthread-2.32.so\n", 65) = 65
[pid 3126] write(3, "40009c7000-40009cb000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
[pid 3126] write(3, "40009cb000-40009cd000 r-xp 00000000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009cd000-40009ce000 r--p 00001000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009ce000-40009cf000 rw-p 00002000 fe:01 30316939", 50) = 50
[pid 3126] write(3, " /lib/riscv64-linux-gnu/libdl-2.32.so\n", 60) = 60
[pid 3126] write(3, "40009cf000-40009d1000 rw-p 00000000 00:00 0", 43) = 43
[pid 3126] write(3, " \n", 31) = 31
</details>
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2023-07-15 17:44:29 +00:00
|
|
|
|
2023-09-20 22:11:23 +00:00
|
|
|
printf("No target executable - decompression only was performed.\n"); // NOLINT(modernize-use-std-print)
|
2023-07-17 10:01:47 +00:00
|
|
|
return 0;
|
2022-08-24 21:05:00 +00:00
|
|
|
}
|
2022-09-05 15:41:52 +00:00
|
|
|
#endif
|
2022-08-24 21:05:00 +00:00
|
|
|
|
2022-08-08 21:56:16 +00:00
|
|
|
int input_fd = open(self, O_RDONLY);
|
2022-03-29 19:30:09 +00:00
|
|
|
if (input_fd == -1)
|
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("open");
|
2022-05-30 00:39:42 +00:00
|
|
|
return 1;
|
2022-03-29 19:30:09 +00:00
|
|
|
}
|
|
|
|
|
2022-04-14 11:43:40 +00:00
|
|
|
bool have_compressed_analoge = false;
|
2022-08-21 21:39:24 +00:00
|
|
|
bool has_exec = false;
|
2022-08-03 07:34:51 +00:00
|
|
|
char decompressed_suffix[7] = {0};
|
|
|
|
uint64_t decompressed_umask = 0;
|
2022-04-14 11:43:40 +00:00
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
/// Decompress all files
|
2022-08-21 21:39:24 +00:00
|
|
|
if (0 != decompressFiles(input_fd, path, name, have_compressed_analoge, has_exec, decompressed_suffix, &decompressed_umask))
|
2022-03-29 19:30:09 +00:00
|
|
|
{
|
2023-09-20 22:11:23 +00:00
|
|
|
printf("Error happened during decompression.\n"); // NOLINT(modernize-use-std-print)
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != close(input_fd))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("close");
|
2022-03-29 19:30:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-04-07 12:21:14 +00:00
|
|
|
if (0 != close(input_fd))
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("close");
|
2022-04-07 12:21:14 +00:00
|
|
|
|
2022-08-08 21:56:16 +00:00
|
|
|
if (unlink(self))
|
2022-04-14 11:43:40 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("unlink");
|
2022-04-14 11:43:40 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2022-08-01 18:32:32 +00:00
|
|
|
|
|
|
|
if (!have_compressed_analoge)
|
2023-09-20 22:11:23 +00:00
|
|
|
printf("No target executable - decompression only was performed.\n"); // NOLINT(modernize-use-std-print)
|
2022-04-14 11:43:40 +00:00
|
|
|
else
|
|
|
|
{
|
2022-08-01 14:58:08 +00:00
|
|
|
const char * const decompressed_name_fmt = "%s.decompressed.%s";
|
2022-08-08 21:56:16 +00:00
|
|
|
int decompressed_name_len = snprintf(nullptr, 0, decompressed_name_fmt, self, decompressed_suffix);
|
2022-08-01 14:58:08 +00:00
|
|
|
char decompressed_name[decompressed_name_len + 1];
|
2022-08-08 21:56:16 +00:00
|
|
|
(void)snprintf(decompressed_name, decompressed_name_len + 1, decompressed_name_fmt, self, decompressed_suffix);
|
2022-08-01 14:58:08 +00:00
|
|
|
|
|
|
|
std::error_code ec;
|
2022-08-08 21:56:16 +00:00
|
|
|
std::filesystem::copy_file(static_cast<char *>(decompressed_name), static_cast<char *>(self), ec);
|
2022-08-01 14:58:08 +00:00
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
std::cerr << ec.message() << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
2022-08-01 15:06:54 +00:00
|
|
|
|
2022-10-16 14:23:27 +00:00
|
|
|
if (chmod(self, static_cast<uint32_t>(decompressed_umask)))
|
2022-08-01 14:58:08 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("chmod");
|
2022-08-01 14:58:08 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-08-01 17:39:26 +00:00
|
|
|
if (unlink(decompressed_name))
|
2022-08-01 14:58:08 +00:00
|
|
|
{
|
2022-08-08 21:56:16 +00:00
|
|
|
perror("unlink");
|
2022-08-01 14:58:08 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2022-08-01 00:07:33 +00:00
|
|
|
|
2023-03-02 14:49:49 +00:00
|
|
|
if (isSudo())
|
|
|
|
chown(static_cast<char *>(self), input_info.st_uid, input_info.st_gid);
|
2023-03-02 00:42:02 +00:00
|
|
|
|
2022-08-21 22:06:11 +00:00
|
|
|
if (has_exec)
|
2022-08-21 21:39:24 +00:00
|
|
|
{
|
2023-07-17 10:01:47 +00:00
|
|
|
#if !defined(OS_DARWIN) && !defined(OS_FREEBSD)
|
2022-08-30 01:11:04 +00:00
|
|
|
/// write one byte to the lock in case other copies of compressed are running to indicate that
|
|
|
|
/// execution should be performed
|
2023-07-17 10:01:47 +00:00
|
|
|
write(lock, "1", 1);
|
|
|
|
#endif
|
2022-08-21 21:39:24 +00:00
|
|
|
execv(self, argv);
|
2022-04-14 11:43:40 +00:00
|
|
|
|
2022-08-21 21:39:24 +00:00
|
|
|
/// This part of code will be reached only if error happened
|
|
|
|
perror("execv");
|
|
|
|
return 1;
|
|
|
|
}
|
2023-07-17 10:01:47 +00:00
|
|
|
#if !defined(OS_DARWIN) && !defined(OS_FREEBSD)
|
2022-08-30 01:11:04 +00:00
|
|
|
/// since inodes can be reused - it's a precaution if lock file already exists and have size of 1
|
2023-07-17 10:01:47 +00:00
|
|
|
ftruncate(lock, 0);
|
|
|
|
#endif
|
2022-08-25 10:52:56 +00:00
|
|
|
|
2023-09-20 22:11:23 +00:00
|
|
|
printf("No target executable - decompression only was performed.\n"); // NOLINT(modernize-use-std-print)
|
2022-04-14 11:43:40 +00:00
|
|
|
}
|
2022-03-24 19:45:54 +00:00
|
|
|
}
|