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:
Ingo Weinhold
2013-12-01 18:34:07 +01:00
parent 9f1425e2f4
commit e551626f40
7 changed files with 222 additions and 30 deletions
+2 -2
View File
@@ -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);
+3 -3
View File
@@ -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;
+3 -3
View File
@@ -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;
+4 -9
View File
@@ -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;
+2 -1
View File
@@ -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
View File
@@ -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;
} }
+1 -1
View File
@@ -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,