[haiku-commits] haiku: hrev46468 - src/system/libroot/os src/kits/tracker src headers/private/libroot

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 1 Dec 2013 19:05:30 +0100 (CET)

hrev46468 adds 1 changeset to branch 'master'
old head: 9f1425e2f49a08243340c465c1eab9cb72cf5ba2
new head: e551626f40c89e7ff5dcac8ce368690fcf382375
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=e551626+%5E9f1425e

----------------------------------------------------------------------------

e551626: 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.

                                    [ Ingo Weinhold <ingo_weinhold@xxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev46468
Commit:      e551626f40c89e7ff5dcac8ce368690fcf382375
URL:         http://cgit.haiku-os.org/haiku/commit/?id=e551626
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sun Dec  1 17:33:42 2013 UTC

----------------------------------------------------------------------------

7 files changed, 222 insertions(+), 30 deletions(-)
headers/private/libroot/libroot_private.h |   4 +-
src/bin/debug/debug_utils.cpp             |   6 +-
src/kits/debug/TeamDebugger.cpp           |   6 +-
src/kits/tracker/FSUtils.cpp              |  13 +-
src/kits/tracker/Jamfile                  |   3 +-
src/system/libroot/os/image.cpp           | 218 ++++++++++++++++++++++++--
src/system/libroot/posix/unistd/exec.cpp  |   2 +-

----------------------------------------------------------------------------

diff --git a/headers/private/libroot/libroot_private.h 
b/headers/private/libroot/libroot_private.h
index 85bc14d1..7f6dcd5 100644
--- a/headers/private/libroot/libroot_private.h
+++ b/headers/private/libroot/libroot_private.h
@@ -29,8 +29,8 @@ status_t __get_next_image_dependency(image_id id, uint32 
*cookie,
                        const char **_name);
 status_t __test_executable(const char *path, char *invoker);
 status_t __flatten_process_args(const char* const* args, int32 argCount,
-                       const char* const* env, int32 envCount, char*** 
_flatArgs,
-                       size_t* _flatSize);
+                       const char* const* env, int32* envCount, const char* 
executablePath,
+                       char*** _flatArgs, size_t* _flatSize);
 void _call_atexit_hooks_for_range(addr_t start, addr_t size);
 void __init_env(const struct user_space_program_args *args);
 status_t __init_heap(void);
diff --git a/src/bin/debug/debug_utils.cpp b/src/bin/debug/debug_utils.cpp
index e91bf36..4bfc361 100644
--- a/src/bin/debug/debug_utils.cpp
+++ b/src/bin/debug/debug_utils.cpp
@@ -90,15 +90,15 @@ load_program(const char* const* args, int32 argCount, bool 
traceLoading)
        mutableArgs[0] = programPath.c_str();
 
        // count environment variables
-       int envCount = 0;
+       int32 envCount = 0;
        while (environ[envCount] != NULL)
                envCount++;
 
        // flatten the program args and environment
        char** flatArgs = NULL;
        size_t flatArgsSize;
-       error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
-               &flatArgs, &flatArgsSize);
+       error = __flatten_process_args(mutableArgs, argCount, environ, 
&envCount,
+               mutableArgs[0], &flatArgs, &flatArgsSize);
 
        // load the program
        thread_id thread;
diff --git a/src/kits/debug/TeamDebugger.cpp b/src/kits/debug/TeamDebugger.cpp
index cb92511..eb0abe6 100644
--- a/src/kits/debug/TeamDebugger.cpp
+++ b/src/kits/debug/TeamDebugger.cpp
@@ -134,15 +134,15 @@ BTeamDebugger::_LoadProgram(const char* const* args, 
int32 argCount,
        mutableArgs[0] = programPath.Path();
 
        // count environment variables
-       int envCount = 0;
+       int32 envCount = 0;
        while (environ[envCount] != NULL)
                envCount++;
 
        // flatten the program args and environment
        char** flatArgs = NULL;
        size_t flatArgsSize;
-       error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
-               &flatArgs, &flatArgsSize);
+       error = __flatten_process_args(mutableArgs, argCount, environ, 
&envCount,
+               mutableArgs[0], &flatArgs, &flatArgsSize);
 
        // load the program
        thread_id thread;
diff --git a/src/kits/tracker/FSUtils.cpp b/src/kits/tracker/FSUtils.cpp
index 790d286..63eda73 100644
--- a/src/kits/tracker/FSUtils.cpp
+++ b/src/kits/tracker/FSUtils.cpp
@@ -72,6 +72,8 @@ respective holders. All rights reserved.
 #include <sys/utsname.h>
 
 #include <AutoLocker.h>
+#include <libroot/libroot_private.h>
+#include <system/syscalls.h>
 
 #include "Attributes.h"
 #include "Bitmaps.h"
@@ -3334,13 +3336,6 @@ _TrackerLaunchAppWithDocuments(const entry_ref* appRef, 
const BMessage* refs,
 
 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
 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");
 
        // count environment variables
-       uint32 envCount = 0;
+       int32 envCount = 0;
        while (environ[envCount] != NULL)
                envCount++;
 
        char** flatArgs = NULL;
        size_t flatArgsSize;
        result = __flatten_process_args((const char**)argv, 1,
-               environ, envCount, &flatArgs, &flatArgsSize);
+               environ, &envCount, argv[0], &flatArgs, &flatArgsSize);
        if (result != B_OK)
                return result;
 
diff --git a/src/kits/tracker/Jamfile b/src/kits/tracker/Jamfile
index 45d6c4b..66a90ea 100644
--- a/src/kits/tracker/Jamfile
+++ b/src/kits/tracker/Jamfile
@@ -3,7 +3,8 @@ SubDir HAIKU_TOP src kits tracker ;
 SetSubDirSupportedPlatformsBeOSCompatible ;
 AddSubDirSupportedPlatforms libbe_test ;
 
-UsePrivateHeaders interface mount shared storage support system tracker ;
+UsePrivateHeaders interface mount shared storage support tracker ;
+UsePrivateSystemHeaders ;
 
 SubDirC++Flags
        -D_BUILDING_tracker=1
diff --git a/src/system/libroot/os/image.cpp b/src/system/libroot/os/image.cpp
index e338469..9f76a4a 100644
--- a/src/system/libroot/os/image.cpp
+++ b/src/system/libroot/os/image.cpp
@@ -9,7 +9,12 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <OS.h>
+#include <algorithm>
+#include <new>
+
+#include <fs_attr.h>
+
+#include <AutoDeleter.h>
 
 #include <libroot_private.h>
 #include <runtime_loader.h>
@@ -17,6 +22,183 @@
 #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
 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;
        size_t flatArgsSize;
-       status_t status = __flatten_process_args(args, argCount, environ, 
envCount,
-               &flatArgs, &flatArgsSize);
+       status_t status = __flatten_process_args(args, argCount, environ,
+               &envCount, args[0], &flatArgs, &flatArgsSize);
 
        if (status == B_OK) {
                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
        the strings of the arguments and environment, followed by the strings. 
Both
        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
 __flatten_process_args(const char* const* args, int32 argCount,
-       const char* const* env, int32 envCount, char*** _flatArgs,
-       size_t* _flatSize)
+       const char* const* env, int32* _envCount, const char* executablePath,
+       char*** _flatArgs, size_t* _flatSize)
 {
-       if (args == NULL || env == NULL)
+       if (args == NULL || env == NULL || _envCount == NULL)
                return B_BAD_VALUE;
 
+       int32 envCount = *_envCount;
+
        // determine total needed size
        int32 argSize = 0;
        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;
        }
 
-       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)
                return B_TOO_MANY_ARGS;
 
@@ -264,7 +458,7 @@ __flatten_process_args(const char* const* args, int32 
argCount,
                return B_NO_MEMORY;
 
        char** slot = flatArgs;
-       char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
+       char* stringSpace = (char*)(flatArgs + totalSlotCount);
 
        // copy arguments and environment
        for (int32 i = 0; i < argCount; i++) {
@@ -277,16 +471,18 @@ __flatten_process_args(const char* const* args, int32 
argCount,
        *slot++ = NULL;
 
        for (int32 i = 0; i < envCount; i++) {
-               int32 envSize = strlen(env[i]) + 1;
-               memcpy(stringSpace, env[i], envSize);
+               size_t envSize = envFilter.PrepareSlot(env[i], i, stringSpace);
                *slot++ = stringSpace;
                stringSpace += envSize;
        }
 
+       envFilter.PrepareAdditionalSlots(slot, stringSpace);
+
        *slot++ = NULL;
 
+       *_envCount = envCount + envFilter.AdditionalSlotsNeeded();
        *_flatArgs = flatArgs;
-       *_flatSize = size;
+       *_flatSize = stringSpace - (char*)flatArgs;
        return B_OK;
 }
 
diff --git a/src/system/libroot/posix/unistd/exec.cpp 
b/src/system/libroot/posix/unistd/exec.cpp
index 7c3e5d1..4f3b2a3 100644
--- a/src/system/libroot/posix/unistd/exec.cpp
+++ b/src/system/libroot/posix/unistd/exec.cpp
@@ -103,7 +103,7 @@ do_exec(const char *path, char * const args[], char * const 
environment[],
        char** flatArgs = NULL;
        size_t flatArgsSize;
        status = __flatten_process_args(newArgs ? newArgs : args, argCount,
-               environment, envCount, &flatArgs, &flatArgsSize);
+               environment, &envCount, path, &flatArgs, &flatArgsSize);
 
        if (status == B_OK) {
                __set_errno(_kern_exec(path, flatArgs, flatArgsSize, argCount, 
envCount,


Other related posts:

  • » [haiku-commits] haiku: hrev46468 - src/system/libroot/os src/kits/tracker src headers/private/libroot - ingo_weinhold