Implement support for a SYS:ENV attribute on executable
__flatten_process_args() does now have the executable path as an additional (optional) parameter. If specified, the function will read the file's SYS:ENV attribute (if set) and use its value to modified the environment it is preparing for the new process. Currently supported attribute values are strings consisting of "<var>=<value>" substrings separated by "\0" (backslash zero), with '\' being used as an escape character. The environment will be altered to contain the specified "<var>=<value>" elements, replacing a preexisting <var> element (if any). A possible use case would be setting a SYS:ENV attribute with value "DISABLE_ASLR=1" on an executable that needs ASLR disabled.
This commit is contained in:
@@ -29,8 +29,8 @@ status_t __get_next_image_dependency(image_id id, uint32 *cookie,
|
|||||||
const char **_name);
|
const char **_name);
|
||||||
status_t __test_executable(const char *path, char *invoker);
|
status_t __test_executable(const char *path, char *invoker);
|
||||||
status_t __flatten_process_args(const char* const* args, int32 argCount,
|
status_t __flatten_process_args(const char* const* args, int32 argCount,
|
||||||
const char* const* env, int32 envCount, char*** _flatArgs,
|
const char* const* env, int32* envCount, const char* executablePath,
|
||||||
size_t* _flatSize);
|
char*** _flatArgs, size_t* _flatSize);
|
||||||
void _call_atexit_hooks_for_range(addr_t start, addr_t size);
|
void _call_atexit_hooks_for_range(addr_t start, addr_t size);
|
||||||
void __init_env(const struct user_space_program_args *args);
|
void __init_env(const struct user_space_program_args *args);
|
||||||
status_t __init_heap(void);
|
status_t __init_heap(void);
|
||||||
|
|||||||
@@ -90,15 +90,15 @@ load_program(const char* const* args, int32 argCount, bool traceLoading)
|
|||||||
mutableArgs[0] = programPath.c_str();
|
mutableArgs[0] = programPath.c_str();
|
||||||
|
|
||||||
// count environment variables
|
// count environment variables
|
||||||
int envCount = 0;
|
int32 envCount = 0;
|
||||||
while (environ[envCount] != NULL)
|
while (environ[envCount] != NULL)
|
||||||
envCount++;
|
envCount++;
|
||||||
|
|
||||||
// flatten the program args and environment
|
// flatten the program args and environment
|
||||||
char** flatArgs = NULL;
|
char** flatArgs = NULL;
|
||||||
size_t flatArgsSize;
|
size_t flatArgsSize;
|
||||||
error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
|
error = __flatten_process_args(mutableArgs, argCount, environ, &envCount,
|
||||||
&flatArgs, &flatArgsSize);
|
mutableArgs[0], &flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
// load the program
|
// load the program
|
||||||
thread_id thread;
|
thread_id thread;
|
||||||
|
|||||||
@@ -134,15 +134,15 @@ BTeamDebugger::_LoadProgram(const char* const* args, int32 argCount,
|
|||||||
mutableArgs[0] = programPath.Path();
|
mutableArgs[0] = programPath.Path();
|
||||||
|
|
||||||
// count environment variables
|
// count environment variables
|
||||||
int envCount = 0;
|
int32 envCount = 0;
|
||||||
while (environ[envCount] != NULL)
|
while (environ[envCount] != NULL)
|
||||||
envCount++;
|
envCount++;
|
||||||
|
|
||||||
// flatten the program args and environment
|
// flatten the program args and environment
|
||||||
char** flatArgs = NULL;
|
char** flatArgs = NULL;
|
||||||
size_t flatArgsSize;
|
size_t flatArgsSize;
|
||||||
error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
|
error = __flatten_process_args(mutableArgs, argCount, environ, &envCount,
|
||||||
&flatArgs, &flatArgsSize);
|
mutableArgs[0], &flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
// load the program
|
// load the program
|
||||||
thread_id thread;
|
thread_id thread;
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ respective holders. All rights reserved.
|
|||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
|
#include <libroot/libroot_private.h>
|
||||||
|
#include <system/syscalls.h>
|
||||||
|
|
||||||
#include "Attributes.h"
|
#include "Attributes.h"
|
||||||
#include "Bitmaps.h"
|
#include "Bitmaps.h"
|
||||||
@@ -3334,13 +3336,6 @@ _TrackerLaunchAppWithDocuments(const entry_ref* appRef, const BMessage* refs,
|
|||||||
|
|
||||||
extern "C" char** environ;
|
extern "C" char** environ;
|
||||||
|
|
||||||
extern "C" status_t _kern_load_image(const char* const* flatArgs,
|
|
||||||
size_t flatArgsSize, int32 argCount, int32 envCount, int32 priority,
|
|
||||||
uint32 flags, port_id errorPort, uint32 errorToken);
|
|
||||||
extern "C" status_t __flatten_process_args(const char* const* args,
|
|
||||||
int32 argCount, const char* const* env, int32 envCount, char***_flatArgs,
|
|
||||||
size_t* _flatSize);
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
LoaderErrorDetails(const entry_ref* app, BString &details)
|
LoaderErrorDetails(const entry_ref* app, BString &details)
|
||||||
@@ -3357,14 +3352,14 @@ LoaderErrorDetails(const entry_ref* app, BString &details)
|
|||||||
port_id errorPort = create_port(1, "Tracker loader error");
|
port_id errorPort = create_port(1, "Tracker loader error");
|
||||||
|
|
||||||
// count environment variables
|
// count environment variables
|
||||||
uint32 envCount = 0;
|
int32 envCount = 0;
|
||||||
while (environ[envCount] != NULL)
|
while (environ[envCount] != NULL)
|
||||||
envCount++;
|
envCount++;
|
||||||
|
|
||||||
char** flatArgs = NULL;
|
char** flatArgs = NULL;
|
||||||
size_t flatArgsSize;
|
size_t flatArgsSize;
|
||||||
result = __flatten_process_args((const char**)argv, 1,
|
result = __flatten_process_args((const char**)argv, 1,
|
||||||
environ, envCount, &flatArgs, &flatArgsSize);
|
environ, &envCount, argv[0], &flatArgs, &flatArgsSize);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ SubDir HAIKU_TOP src kits tracker ;
|
|||||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
AddSubDirSupportedPlatforms libbe_test ;
|
AddSubDirSupportedPlatforms libbe_test ;
|
||||||
|
|
||||||
UsePrivateHeaders interface mount shared storage support system tracker ;
|
UsePrivateHeaders interface mount shared storage support tracker ;
|
||||||
|
UsePrivateSystemHeaders ;
|
||||||
|
|
||||||
SubDirC++Flags
|
SubDirC++Flags
|
||||||
-D_BUILDING_tracker=1
|
-D_BUILDING_tracker=1
|
||||||
|
|||||||
+207
-11
@@ -9,7 +9,12 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <OS.h>
|
#include <algorithm>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <fs_attr.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include <libroot_private.h>
|
#include <libroot_private.h>
|
||||||
#include <runtime_loader.h>
|
#include <runtime_loader.h>
|
||||||
@@ -17,6 +22,183 @@
|
|||||||
#include <user_runtime.h>
|
#include <user_runtime.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct EnvironmentFilter {
|
||||||
|
EnvironmentFilter()
|
||||||
|
:
|
||||||
|
fBuffer(NULL),
|
||||||
|
fEntries(NULL),
|
||||||
|
fBufferSize(0),
|
||||||
|
fEntryCount(0),
|
||||||
|
fAdditionalEnvCount(0),
|
||||||
|
fNextEntryIndex(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~EnvironmentFilter()
|
||||||
|
{
|
||||||
|
free(fBuffer);
|
||||||
|
delete[] fEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init(const char* path, const char* const* env, size_t envCount)
|
||||||
|
{
|
||||||
|
int fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
FileDescriptorCloser fdCloser(fd);
|
||||||
|
|
||||||
|
static const char* const kEnvAttribute = "SYS:ENV";
|
||||||
|
attr_info info;
|
||||||
|
if (fs_stat_attr(fd, kEnvAttribute, &info) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_Init(fd, kEnvAttribute, info.size, env, envCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AdditionalSlotsNeeded() const
|
||||||
|
{
|
||||||
|
return fAdditionalEnvCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AdditionalSizeNeeded() const
|
||||||
|
{
|
||||||
|
return fBufferSize + fAdditionalEnvCount * sizeof(char*);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PrepareSlot(const char* env, int32 index, char* buffer)
|
||||||
|
{
|
||||||
|
if (fNextEntryIndex < fEntryCount
|
||||||
|
&& fEntries[fNextEntryIndex].index == index) {
|
||||||
|
env = fEntries[fNextEntryIndex].replacement;
|
||||||
|
fNextEntryIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _FillSlot(env, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrepareAdditionalSlots(char**& slot, char*& buffer)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < fAdditionalEnvCount; i++) {
|
||||||
|
size_t envSize = _FillSlot(fEntries[i].replacement, buffer);
|
||||||
|
*slot++ = buffer;
|
||||||
|
buffer += envSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _Init(int fd, const char* attribute, size_t size,
|
||||||
|
const char* const* env, size_t envCount)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// read the attribute
|
||||||
|
char* buffer = (char*)malloc(size + 1);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return;
|
||||||
|
MemoryDeleter bufferDeleter(buffer);
|
||||||
|
|
||||||
|
ssize_t bytesRead = fs_read_attr(fd, attribute, B_STRING_TYPE, 0,
|
||||||
|
buffer, size);
|
||||||
|
if (bytesRead < 0 || (size_t)bytesRead != size)
|
||||||
|
return;
|
||||||
|
buffer[size] = '\0';
|
||||||
|
|
||||||
|
// deescape the buffer and count the entries
|
||||||
|
size_t entryCount = 1;
|
||||||
|
char* out = buffer;
|
||||||
|
for (const char* c = buffer; *c != '\0'; c++) {
|
||||||
|
if (*c == '\\') {
|
||||||
|
c++;
|
||||||
|
if (*c == '\0')
|
||||||
|
break;
|
||||||
|
if (*c == '0') {
|
||||||
|
*out++ = '\0';
|
||||||
|
entryCount++;
|
||||||
|
} else
|
||||||
|
*out++ = *c;
|
||||||
|
} else
|
||||||
|
*out++ = *c;
|
||||||
|
}
|
||||||
|
*out++ = '\0';
|
||||||
|
size = out - buffer + 1;
|
||||||
|
|
||||||
|
// create an entry array
|
||||||
|
fEntries = new(std::nothrow) Entry[entryCount];
|
||||||
|
if (fEntries == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bufferDeleter.Detach();
|
||||||
|
fBuffer = buffer;
|
||||||
|
fBufferSize = size;
|
||||||
|
|
||||||
|
// init the entries
|
||||||
|
out = buffer;
|
||||||
|
for (size_t i = 0; i < entryCount; i++) {
|
||||||
|
const char* separator = strchr(out, '=');
|
||||||
|
if (separator != NULL && separator != out) {
|
||||||
|
fEntries[fEntryCount].replacement = out;
|
||||||
|
fEntries[fEntryCount].index = _FindEnvEntry(env, envCount, out,
|
||||||
|
separator - out);
|
||||||
|
if (fEntries[fEntryCount].index < 0)
|
||||||
|
fAdditionalEnvCount++;
|
||||||
|
fEntryCount++;
|
||||||
|
}
|
||||||
|
out += strlen(out) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fEntryCount > 1)
|
||||||
|
std::sort(fEntries, fEntries + fEntryCount);
|
||||||
|
|
||||||
|
// Advance fNextEntryIndex to the first entry pointing to an existing
|
||||||
|
// env variable.
|
||||||
|
while (fNextEntryIndex < fEntryCount
|
||||||
|
&& fEntries[fNextEntryIndex].index < 0) {
|
||||||
|
fNextEntryIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 _FindEnvEntry(const char* const* env, size_t envCount,
|
||||||
|
const char* variable, size_t variableLength)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < envCount; i++) {
|
||||||
|
if (strncmp(env[i], variable, variableLength) == 0
|
||||||
|
&& env[i][variableLength] == '=') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _FillSlot(const char* env, char* buffer)
|
||||||
|
{
|
||||||
|
size_t envSize = strlen(env) + 1;
|
||||||
|
memcpy(buffer, env, envSize);
|
||||||
|
return envSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Entry {
|
||||||
|
char* replacement;
|
||||||
|
int32 index;
|
||||||
|
|
||||||
|
bool operator<(const Entry& other) const
|
||||||
|
{
|
||||||
|
return index < other.index;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* fBuffer;
|
||||||
|
Entry* fEntries;
|
||||||
|
size_t fBufferSize;
|
||||||
|
size_t fEntryCount;
|
||||||
|
size_t fAdditionalEnvCount;
|
||||||
|
size_t fNextEntryIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
thread_id
|
thread_id
|
||||||
load_image(int32 argCount, const char **args, const char **environ)
|
load_image(int32 argCount, const char **args, const char **environ)
|
||||||
{
|
{
|
||||||
@@ -48,8 +230,8 @@ load_image(int32 argCount, const char **args, const char **environ)
|
|||||||
|
|
||||||
char** flatArgs = NULL;
|
char** flatArgs = NULL;
|
||||||
size_t flatArgsSize;
|
size_t flatArgsSize;
|
||||||
status_t status = __flatten_process_args(args, argCount, environ, envCount,
|
status_t status = __flatten_process_args(args, argCount, environ,
|
||||||
&flatArgs, &flatArgsSize);
|
&envCount, args[0], &flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
|
thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
|
||||||
@@ -230,15 +412,20 @@ __test_executable(const char *path, char *invoker)
|
|||||||
into it. The buffer starts with a char* array which contains pointers to
|
into it. The buffer starts with a char* array which contains pointers to
|
||||||
the strings of the arguments and environment, followed by the strings. Both
|
the strings of the arguments and environment, followed by the strings. Both
|
||||||
arguments and environment arrays are NULL-terminated.
|
arguments and environment arrays are NULL-terminated.
|
||||||
|
If executablePath is non-NULL, it should refer to the executable to be
|
||||||
|
executed. If the executable file specifies changes to environment variable
|
||||||
|
values, those will be performed.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
__flatten_process_args(const char* const* args, int32 argCount,
|
__flatten_process_args(const char* const* args, int32 argCount,
|
||||||
const char* const* env, int32 envCount, char*** _flatArgs,
|
const char* const* env, int32* _envCount, const char* executablePath,
|
||||||
size_t* _flatSize)
|
char*** _flatArgs, size_t* _flatSize)
|
||||||
{
|
{
|
||||||
if (args == NULL || env == NULL)
|
if (args == NULL || env == NULL || _envCount == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
int32 envCount = *_envCount;
|
||||||
|
|
||||||
// determine total needed size
|
// determine total needed size
|
||||||
int32 argSize = 0;
|
int32 argSize = 0;
|
||||||
for (int32 i = 0; i < argCount; i++) {
|
for (int32 i = 0; i < argCount; i++) {
|
||||||
@@ -254,7 +441,14 @@ __flatten_process_args(const char* const* args, int32 argCount,
|
|||||||
envSize += strlen(env[i]) + 1;
|
envSize += strlen(env[i]) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize;
|
EnvironmentFilter envFilter;
|
||||||
|
if (executablePath != NULL)
|
||||||
|
envFilter.Init(executablePath, env, envCount);
|
||||||
|
|
||||||
|
int32 totalSlotCount = argCount + envCount + 2
|
||||||
|
+ envFilter.AdditionalSlotsNeeded();
|
||||||
|
int32 size = totalSlotCount * sizeof(char*) + argSize + envSize
|
||||||
|
+ envFilter.AdditionalSizeNeeded();
|
||||||
if (size > MAX_PROCESS_ARGS_SIZE)
|
if (size > MAX_PROCESS_ARGS_SIZE)
|
||||||
return B_TOO_MANY_ARGS;
|
return B_TOO_MANY_ARGS;
|
||||||
|
|
||||||
@@ -264,7 +458,7 @@ __flatten_process_args(const char* const* args, int32 argCount,
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
char** slot = flatArgs;
|
char** slot = flatArgs;
|
||||||
char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
|
char* stringSpace = (char*)(flatArgs + totalSlotCount);
|
||||||
|
|
||||||
// copy arguments and environment
|
// copy arguments and environment
|
||||||
for (int32 i = 0; i < argCount; i++) {
|
for (int32 i = 0; i < argCount; i++) {
|
||||||
@@ -277,16 +471,18 @@ __flatten_process_args(const char* const* args, int32 argCount,
|
|||||||
*slot++ = NULL;
|
*slot++ = NULL;
|
||||||
|
|
||||||
for (int32 i = 0; i < envCount; i++) {
|
for (int32 i = 0; i < envCount; i++) {
|
||||||
int32 envSize = strlen(env[i]) + 1;
|
size_t envSize = envFilter.PrepareSlot(env[i], i, stringSpace);
|
||||||
memcpy(stringSpace, env[i], envSize);
|
|
||||||
*slot++ = stringSpace;
|
*slot++ = stringSpace;
|
||||||
stringSpace += envSize;
|
stringSpace += envSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envFilter.PrepareAdditionalSlots(slot, stringSpace);
|
||||||
|
|
||||||
*slot++ = NULL;
|
*slot++ = NULL;
|
||||||
|
|
||||||
|
*_envCount = envCount + envFilter.AdditionalSlotsNeeded();
|
||||||
*_flatArgs = flatArgs;
|
*_flatArgs = flatArgs;
|
||||||
*_flatSize = size;
|
*_flatSize = stringSpace - (char*)flatArgs;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ do_exec(const char *path, char * const args[], char * const environment[],
|
|||||||
char** flatArgs = NULL;
|
char** flatArgs = NULL;
|
||||||
size_t flatArgsSize;
|
size_t flatArgsSize;
|
||||||
status = __flatten_process_args(newArgs ? newArgs : args, argCount,
|
status = __flatten_process_args(newArgs ? newArgs : args, argCount,
|
||||||
environment, envCount, &flatArgs, &flatArgsSize);
|
environment, &envCount, path, &flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
__set_errno(_kern_exec(path, flatArgs, flatArgsSize, argCount, envCount,
|
__set_errno(_kern_exec(path, flatArgs, flatArgsSize, argCount, envCount,
|
||||||
|
|||||||
Reference in New Issue
Block a user