* Changed the _kern_exec() and _kern_load_image() syscalls. They expect
a flattened argument/environment buffer now. This simplifies the work for the kernel a bit, since it can just copy the buffer and check whether it looks OK instead of messing around with individual strings. The runtime loader also gets a flattened array. * Set the maximum size of the arguments/environment buffer to 128 KB. When more arguments are passed, we fail with a proper error code (instead of just truncating the arguments as before). * On exec*() the first argument was silently replaced by the given path name, which is not correct. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26119 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -51,16 +51,16 @@ struct user_thread* team_allocate_user_thread(struct team* team);
|
|||||||
void team_free_user_thread(struct thread* thread);
|
void team_free_user_thread(struct thread* thread);
|
||||||
|
|
||||||
// used in syscalls.c
|
// used in syscalls.c
|
||||||
thread_id _user_load_image(int32 argCount, const char **args, int32 envCount,
|
thread_id _user_load_image(const char* const* flatArgs, size_t flatArgsSize,
|
||||||
const char **env, int32 priority, uint32 flags,
|
int32 argCount, int32 envCount, int32 priority, uint32 flags,
|
||||||
port_id errorPort, uint32 errorToken);
|
port_id errorPort, uint32 errorToken);
|
||||||
status_t _user_wait_for_team(team_id id, status_t *_returnCode);
|
status_t _user_wait_for_team(team_id id, status_t *_returnCode);
|
||||||
void _user_exit_team(status_t returnValue);
|
void _user_exit_team(status_t returnValue);
|
||||||
status_t _user_kill_team(thread_id thread);
|
status_t _user_kill_team(thread_id thread);
|
||||||
thread_id _user_wait_for_child(thread_id child, uint32 flags, int32 *_reason,
|
thread_id _user_wait_for_child(thread_id child, uint32 flags, int32 *_reason,
|
||||||
status_t *_returnCode);
|
status_t *_returnCode);
|
||||||
status_t _user_exec(const char *path, int32 argc, char * const *argv,
|
status_t _user_exec(const char *path, const char* const* flatArgs,
|
||||||
int32 envCount, char * const *environment);
|
size_t flatArgsSize, int32 argCount, int32 envCount);
|
||||||
thread_id _user_fork(void);
|
thread_id _user_fork(void);
|
||||||
team_id _user_get_current_team(void);
|
team_id _user_get_current_team(void);
|
||||||
pid_t _user_process_info(pid_t process, int32 which);
|
pid_t _user_process_info(pid_t process, int32 which);
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ status_t __parse_invoke_line(char *invoker, char ***_newArgs,
|
|||||||
status_t __get_next_image_dependency(image_id id, uint32 *cookie,
|
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,
|
||||||
|
const char* const* env, int32 envCount, char*** _flatArgs,
|
||||||
|
size_t* _flatSize);
|
||||||
void __init_env(const struct user_space_program_args *args);
|
void __init_env(const struct user_space_program_args *args);
|
||||||
void __init_heap(void);
|
void __init_heap(void);
|
||||||
|
|
||||||
|
|||||||
@@ -91,17 +91,18 @@ extern status_t _kern_realtime_sem_wait(sem_id semID, bigtime_t timeout);
|
|||||||
|
|
||||||
/* team & thread syscalls */
|
/* team & thread syscalls */
|
||||||
|
|
||||||
extern thread_id _kern_load_image(int32 argCount, const char **args,
|
extern thread_id _kern_load_image(const char* const* flatArgs,
|
||||||
int32 envCount, const char **envp, int32 priority,
|
size_t flatArgsSize, int32 argCount, int32 envCount,
|
||||||
uint32 flags, port_id errorPort, uint32 errorToken);
|
int32 priority, uint32 flags, port_id errorPort,
|
||||||
|
uint32 errorToken);
|
||||||
extern void _kern_exit_team(status_t returnValue);
|
extern void _kern_exit_team(status_t returnValue);
|
||||||
extern status_t _kern_kill_team(team_id team);
|
extern status_t _kern_kill_team(team_id team);
|
||||||
extern team_id _kern_get_current_team();
|
extern team_id _kern_get_current_team();
|
||||||
extern status_t _kern_wait_for_team(team_id team, status_t *_returnCode);
|
extern status_t _kern_wait_for_team(team_id team, status_t *_returnCode);
|
||||||
extern thread_id _kern_wait_for_child(thread_id child, uint32 flags,
|
extern thread_id _kern_wait_for_child(thread_id child, uint32 flags,
|
||||||
int32 *_reason, status_t *_returnCode);
|
int32 *_reason, status_t *_returnCode);
|
||||||
extern status_t _kern_exec(const char *path, int32 argc, char * const *argv, int32 envCount,
|
extern status_t _kern_exec(const char *path, const char* const* flatArgs,
|
||||||
char * const *environment);
|
size_t flatArgsSize, int32 argCount, int32 envCount);
|
||||||
extern thread_id _kern_fork(void);
|
extern thread_id _kern_fork(void);
|
||||||
extern pid_t _kern_process_info(pid_t process, int32 which);
|
extern pid_t _kern_process_info(pid_t process, int32 which);
|
||||||
extern pid_t _kern_setpgid(pid_t process, pid_t group);
|
extern pid_t _kern_setpgid(pid_t process, pid_t group);
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
#define MAGIC_APP_NAME "_APP_"
|
#define MAGIC_APP_NAME "_APP_"
|
||||||
|
|
||||||
|
#define MAX_PROCESS_ARGS_SIZE (128 * 1024)
|
||||||
|
// maximal total size needed for process arguments and environment strings
|
||||||
|
|
||||||
|
|
||||||
struct user_space_program_args {
|
struct user_space_program_args {
|
||||||
char program_name[B_OS_NAME_LENGTH];
|
char program_name[B_OS_NAME_LENGTH];
|
||||||
char program_path[B_PATH_NAME_LENGTH];
|
char program_path[B_PATH_NAME_LENGTH];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ SubDir HAIKU_TOP src bin strace ;
|
|||||||
|
|
||||||
UsePrivateHeaders device ;
|
UsePrivateHeaders device ;
|
||||||
UsePrivateHeaders drivers ;
|
UsePrivateHeaders drivers ;
|
||||||
|
UsePrivateHeaders libroot ;
|
||||||
UsePrivateHeaders shared ;
|
UsePrivateHeaders shared ;
|
||||||
UsePrivateHeaders net ;
|
UsePrivateHeaders net ;
|
||||||
UsePrivateSystemHeaders ;
|
UsePrivateSystemHeaders ;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <debugger.h>
|
#include <debugger.h>
|
||||||
#include <image.h>
|
#include <image.h>
|
||||||
|
#include <libroot_private.h>
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
|
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
@@ -228,14 +229,25 @@ load_program(const char *const *args, int32 argCount, bool traceLoading)
|
|||||||
while (environ[envCount] != NULL)
|
while (environ[envCount] != NULL)
|
||||||
envCount++;
|
envCount++;
|
||||||
|
|
||||||
|
// flatten the program args and environment
|
||||||
|
char** flatArgs = NULL;
|
||||||
|
size_t flatArgsSize;
|
||||||
|
error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
|
||||||
|
&flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
// load the program
|
// load the program
|
||||||
error = _kern_load_image(argCount, mutableArgs, envCount,
|
thread_id thread;
|
||||||
(const char**)environ, B_NORMAL_PRIORITY,
|
if (error == B_OK) {
|
||||||
(traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
|
thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
|
||||||
|
B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
|
||||||
|
|
||||||
|
free(flatArgs);
|
||||||
|
} else
|
||||||
|
thread = error;
|
||||||
|
|
||||||
delete[] mutableArgs;
|
delete[] mutableArgs;
|
||||||
|
|
||||||
return error;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set_team_debugging_flags
|
// set_team_debugging_flags
|
||||||
|
|||||||
+212
-282
@@ -60,10 +60,11 @@ struct team_key {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct team_arg {
|
struct team_arg {
|
||||||
|
char *path;
|
||||||
|
char **flat_args;
|
||||||
|
size_t flat_args_size;
|
||||||
uint32 arg_count;
|
uint32 arg_count;
|
||||||
char **args;
|
|
||||||
uint32 env_count;
|
uint32 env_count;
|
||||||
char **env;
|
|
||||||
port_id error_port;
|
port_id error_port;
|
||||||
uint32 error_token;
|
uint32 error_token;
|
||||||
};
|
};
|
||||||
@@ -374,138 +375,6 @@ dump_teams(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Frees an array of strings in kernel space.
|
|
||||||
|
|
||||||
\param strings strings array
|
|
||||||
\param count number of strings in array
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
free_strings_array(char **strings, int32 count)
|
|
||||||
{
|
|
||||||
int32 i;
|
|
||||||
|
|
||||||
if (strings == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
free(strings[i]);
|
|
||||||
|
|
||||||
free(strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Copy an array of strings in kernel space
|
|
||||||
|
|
||||||
\param strings strings array to be copied
|
|
||||||
\param count number of strings in array
|
|
||||||
\param kstrings pointer to the kernel copy
|
|
||||||
\return \c B_OK on success, or an appropriate error code on
|
|
||||||
failure.
|
|
||||||
*/
|
|
||||||
static status_t
|
|
||||||
kernel_copy_strings_array(char * const *in, int32 count, char ***_strings)
|
|
||||||
{
|
|
||||||
status_t status;
|
|
||||||
char **strings;
|
|
||||||
int32 i = 0;
|
|
||||||
|
|
||||||
strings = (char **)malloc((count + 1) * sizeof(char *));
|
|
||||||
if (strings == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
for (; i < count; i++) {
|
|
||||||
strings[i] = strdup(in[i]);
|
|
||||||
if (strings[i] == NULL) {
|
|
||||||
status = B_NO_MEMORY;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strings[count] = NULL;
|
|
||||||
*_strings = strings;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
error:
|
|
||||||
free_strings_array(strings, i);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Copy an array of strings from user space to kernel space
|
|
||||||
|
|
||||||
\param strings userspace strings array
|
|
||||||
\param count number of strings in array
|
|
||||||
\param kstrings pointer to the kernel copy
|
|
||||||
\return \c B_OK on success, or an appropriate error code on
|
|
||||||
failure.
|
|
||||||
*/
|
|
||||||
static status_t
|
|
||||||
user_copy_strings_array(char * const *userStrings, int32 count, char ***_strings)
|
|
||||||
{
|
|
||||||
char *buffer;
|
|
||||||
char **strings;
|
|
||||||
status_t err;
|
|
||||||
int32 i = 0;
|
|
||||||
|
|
||||||
if (!IS_USER_ADDRESS(userStrings))
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
|
|
||||||
// buffer for safely accessing the user string
|
|
||||||
// TODO: maybe have a user_strdup() instead?
|
|
||||||
buffer = (char *)malloc(4 * B_PAGE_SIZE);
|
|
||||||
if (buffer == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
strings = (char **)malloc((count + 1) * sizeof(char *));
|
|
||||||
if (strings == NULL) {
|
|
||||||
err = B_NO_MEMORY;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = user_memcpy(strings, userStrings, count * sizeof(char *))) < B_OK)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
// scan all strings and copy to kernel space
|
|
||||||
|
|
||||||
for (; i < count; i++) {
|
|
||||||
err = user_strlcpy(buffer, strings[i], 4 * B_PAGE_SIZE);
|
|
||||||
if (err < B_OK)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
strings[i] = strdup(buffer);
|
|
||||||
if (strings[i] == NULL) {
|
|
||||||
err = B_NO_MEMORY;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strings[count] = NULL;
|
|
||||||
*_strings = strings;
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
error:
|
|
||||||
free_strings_array(strings, i);
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
TRACE(("user_copy_strings_array failed %ld\n", err));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
copy_strings_array(char * const *strings, int32 count, char ***_strings,
|
|
||||||
bool kernel)
|
|
||||||
{
|
|
||||||
if (kernel)
|
|
||||||
return kernel_copy_strings_array(strings, count, _strings);
|
|
||||||
|
|
||||||
return user_copy_strings_array(strings, count, _strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
team_struct_compare(void *_p, const void *_key)
|
team_struct_compare(void *_p, const void *_key)
|
||||||
{
|
{
|
||||||
@@ -938,19 +807,6 @@ delete_team_struct(struct team *team)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32
|
|
||||||
get_arguments_data_size(char **args, int32 argc)
|
|
||||||
{
|
|
||||||
uint32 size = 0;
|
|
||||||
int32 count;
|
|
||||||
|
|
||||||
for (count = 0; count < argc; count++)
|
|
||||||
size += strlen(args[count]) + 1;
|
|
||||||
|
|
||||||
return size + (argc + 1) * sizeof(char *) + sizeof(struct user_space_program_args);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
create_team_user_data(struct team* team)
|
create_team_user_data(struct team* team)
|
||||||
{
|
{
|
||||||
@@ -987,47 +843,97 @@ delete_team_user_data(struct team* team)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
copy_user_process_args(const char* const* userFlatArgs, size_t flatArgsSize,
|
||||||
|
int32 argCount, int32 envCount, char**& _flatArgs)
|
||||||
|
{
|
||||||
|
if (argCount < 0 || envCount < 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (flatArgsSize > MAX_PROCESS_ARGS_SIZE)
|
||||||
|
return B_TOO_MANY_ARGS;
|
||||||
|
if ((argCount + envCount + 2) * sizeof(char*) > flatArgsSize)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (!IS_USER_ADDRESS(userFlatArgs))
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
// allocate kernel memory
|
||||||
|
char** flatArgs = (char**)malloc(flatArgsSize);
|
||||||
|
if (flatArgs == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (user_memcpy(flatArgs, userFlatArgs, flatArgsSize) != B_OK) {
|
||||||
|
free(flatArgs);
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check and relocate the array
|
||||||
|
status_t error = B_OK;
|
||||||
|
const char* stringBase = (char*)flatArgs + argCount + envCount + 2;
|
||||||
|
const char* stringEnd = (char*)flatArgs + flatArgsSize;
|
||||||
|
for (int32 i = 0; i < argCount + envCount + 2; i++) {
|
||||||
|
if (i == argCount || i == argCount + envCount + 1) {
|
||||||
|
// check array null termination
|
||||||
|
if (flatArgs[i] != NULL) {
|
||||||
|
error = B_BAD_VALUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// check string
|
||||||
|
char* arg = (char*)flatArgs + (flatArgs[i] - (char*)userFlatArgs);
|
||||||
|
size_t maxLen = stringEnd - arg;
|
||||||
|
if (arg < stringBase || arg >= stringEnd
|
||||||
|
|| strnlen(arg, maxLen) == maxLen) {
|
||||||
|
error = B_BAD_VALUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
flatArgs[i] = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == B_OK)
|
||||||
|
_flatArgs = flatArgs;
|
||||||
|
else
|
||||||
|
free(flatArgs);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_team_arg(struct team_arg *teamArg)
|
free_team_arg(struct team_arg *teamArg)
|
||||||
{
|
{
|
||||||
free_strings_array(teamArg->args, teamArg->arg_count);
|
if (teamArg != NULL) {
|
||||||
free_strings_array(teamArg->env, teamArg->env_count);
|
free(teamArg->flat_args);
|
||||||
|
free(teamArg->path);
|
||||||
free(teamArg);
|
free(teamArg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
create_team_arg(struct team_arg **_teamArg, int32 argCount, char * const *args,
|
create_team_arg(struct team_arg **_teamArg, const char *path, char** flatArgs,
|
||||||
int32 envCount, char * const *env, port_id port, uint32 token, bool kernel)
|
size_t flatArgsSize, int32 argCount, int32 envCount, port_id port,
|
||||||
|
uint32 token)
|
||||||
{
|
{
|
||||||
status_t status;
|
struct team_arg *teamArg = (struct team_arg*)malloc(sizeof(team_arg));
|
||||||
char **argsCopy;
|
|
||||||
char **envCopy;
|
|
||||||
|
|
||||||
struct team_arg *teamArg = (struct team_arg *)malloc(sizeof(struct team_arg));
|
|
||||||
if (teamArg == NULL)
|
if (teamArg == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
teamArg->path = strdup(path);
|
||||||
|
if (teamArg->path == NULL) {
|
||||||
|
free(teamArg);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
// copy the args over
|
// copy the args over
|
||||||
|
|
||||||
status = copy_strings_array(args, argCount, &argsCopy, kernel);
|
teamArg->flat_args = flatArgs;
|
||||||
if (status != B_OK) {
|
teamArg->flat_args_size = flatArgsSize;
|
||||||
free(teamArg);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = copy_strings_array(env, envCount, &envCopy, kernel);
|
|
||||||
if (status != B_OK) {
|
|
||||||
free_strings_array(argsCopy, argCount);
|
|
||||||
free(teamArg);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
teamArg->arg_count = argCount;
|
teamArg->arg_count = argCount;
|
||||||
teamArg->args = argsCopy;
|
|
||||||
teamArg->env_count = envCount;
|
teamArg->env_count = envCount;
|
||||||
teamArg->env = envCopy;
|
|
||||||
teamArg->error_port = port;
|
teamArg->error_port = port;
|
||||||
teamArg->error_token = token;
|
teamArg->error_token = token;
|
||||||
|
|
||||||
@@ -1049,13 +955,12 @@ team_create_thread_start(void *args)
|
|||||||
uint32 sizeLeft;
|
uint32 sizeLeft;
|
||||||
char **userArgs;
|
char **userArgs;
|
||||||
char **userEnv;
|
char **userEnv;
|
||||||
char *userDest;
|
|
||||||
struct user_space_program_args *programArgs;
|
struct user_space_program_args *programArgs;
|
||||||
uint32 argCount, envCount, i;
|
uint32 argCount, envCount, i;
|
||||||
|
|
||||||
t = thread_get_current_thread();
|
t = thread_get_current_thread();
|
||||||
team = t->team;
|
team = t->team;
|
||||||
cache_node_launched(teamArgs->arg_count, teamArgs->args);
|
cache_node_launched(teamArgs->arg_count, teamArgs->flat_args);
|
||||||
|
|
||||||
TRACE(("team_create_thread_start: entry thread %ld\n", t->id));
|
TRACE(("team_create_thread_start: entry thread %ld\n", t->id));
|
||||||
|
|
||||||
@@ -1066,18 +971,19 @@ team_create_thread_start(void *args)
|
|||||||
|
|
||||||
// Main stack area layout is currently as follows (starting from 0):
|
// Main stack area layout is currently as follows (starting from 0):
|
||||||
//
|
//
|
||||||
// size | usage
|
// size | usage
|
||||||
// -----------------------------+--------------------------------
|
// ---------------------------------+--------------------------------
|
||||||
// USER_MAIN_THREAD_STACK_SIZE | actual stack
|
// USER_MAIN_THREAD_STACK_SIZE | actual stack
|
||||||
// TLS_SIZE | TLS data
|
// TLS_SIZE | TLS data
|
||||||
// ENV_SIZE | environment variables
|
// sizeof(user_space_program_args) | argument structure for the runtime
|
||||||
// arguments size | arguments passed to the team
|
// | loader
|
||||||
|
// flat arguments size | flat process arguments and environment
|
||||||
|
|
||||||
// ToDo: ENV_SIZE is a) limited, and b) not used after libroot copied it to the heap
|
// ToDo: ENV_SIZE is a) limited, and b) not used after libroot copied it to the heap
|
||||||
// ToDo: we could reserve the whole USER_STACK_REGION upfront...
|
// ToDo: we could reserve the whole USER_STACK_REGION upfront...
|
||||||
|
|
||||||
sizeLeft = PAGE_ALIGN(USER_MAIN_THREAD_STACK_SIZE + TLS_SIZE + ENV_SIZE +
|
sizeLeft = PAGE_ALIGN(USER_MAIN_THREAD_STACK_SIZE + TLS_SIZE
|
||||||
get_arguments_data_size(teamArgs->args, teamArgs->arg_count));
|
+ sizeof(struct user_space_program_args) + teamArgs->flat_args_size);
|
||||||
t->user_stack_base = USER_STACK_REGION + USER_STACK_REGION_SIZE - sizeLeft;
|
t->user_stack_base = USER_STACK_REGION + USER_STACK_REGION_SIZE - sizeLeft;
|
||||||
t->user_stack_size = USER_MAIN_THREAD_STACK_SIZE;
|
t->user_stack_size = USER_MAIN_THREAD_STACK_SIZE;
|
||||||
// the exact location at the end of the user stack area
|
// the exact location at the end of the user stack area
|
||||||
@@ -1099,57 +1005,13 @@ team_create_thread_start(void *args)
|
|||||||
envCount = teamArgs->env_count;
|
envCount = teamArgs->env_count;
|
||||||
|
|
||||||
programArgs = (struct user_space_program_args *)(t->user_stack_base
|
programArgs = (struct user_space_program_args *)(t->user_stack_base
|
||||||
+ t->user_stack_size + TLS_SIZE + ENV_SIZE);
|
+ t->user_stack_size + TLS_SIZE);
|
||||||
userArgs = (char **)(programArgs + 1);
|
|
||||||
userDest = (char *)(userArgs + argCount + 1);
|
|
||||||
|
|
||||||
TRACE(("addr: stack base = 0x%lx, userArgs = %p, userDest = %p, sizeLeft = %lu\n",
|
userArgs = (char**)(programArgs + 1);
|
||||||
t->user_stack_base, userArgs, userDest, sizeLeft));
|
userEnv = userArgs + argCount + 1;
|
||||||
|
path = teamArgs->path;
|
||||||
|
|
||||||
sizeLeft = t->user_stack_base + sizeLeft - (addr_t)userDest;
|
if (user_strlcpy(programArgs->program_path, path,
|
||||||
|
|
||||||
for (i = 0; i < argCount; i++) {
|
|
||||||
ssize_t length = user_strlcpy(userDest, teamArgs->args[i], sizeLeft);
|
|
||||||
if (length < B_OK) {
|
|
||||||
argCount = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
userArgs[i] = userDest;
|
|
||||||
userDest += ++length;
|
|
||||||
sizeLeft -= length;
|
|
||||||
}
|
|
||||||
userArgs[argCount] = NULL;
|
|
||||||
|
|
||||||
userEnv = (char **)(t->user_stack_base + t->user_stack_size + TLS_SIZE);
|
|
||||||
sizeLeft = ENV_SIZE;
|
|
||||||
userDest = (char *)userEnv + ENV_SIZE - 1;
|
|
||||||
// the environment variables are copied from back to front
|
|
||||||
|
|
||||||
TRACE(("team_create_thread_start: envc: %ld, env: %p\n",
|
|
||||||
teamArgs->env_count, (void *)teamArgs->env));
|
|
||||||
|
|
||||||
for (i = 0; i < envCount; i++) {
|
|
||||||
ssize_t length = strlen(teamArgs->env[i]) + 1;
|
|
||||||
userDest -= length;
|
|
||||||
if (userDest < (char *)&userEnv[envCount]) {
|
|
||||||
envCount = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
userEnv[i] = userDest;
|
|
||||||
|
|
||||||
if (user_memcpy(userDest, teamArgs->env[i], length) < B_OK) {
|
|
||||||
envCount = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sizeLeft -= length;
|
|
||||||
}
|
|
||||||
userEnv[envCount] = NULL;
|
|
||||||
|
|
||||||
path = teamArgs->args[0];
|
|
||||||
if (user_memcpy(programArgs->program_path, path,
|
|
||||||
sizeof(programArgs->program_path)) < B_OK
|
sizeof(programArgs->program_path)) < B_OK
|
||||||
|| user_memcpy(&programArgs->arg_count, &argCount, sizeof(int32)) < B_OK
|
|| user_memcpy(&programArgs->arg_count, &argCount, sizeof(int32)) < B_OK
|
||||||
|| user_memcpy(&programArgs->args, &userArgs, sizeof(char **)) < B_OK
|
|| user_memcpy(&programArgs->args, &userArgs, sizeof(char **)) < B_OK
|
||||||
@@ -1158,7 +1020,9 @@ team_create_thread_start(void *args)
|
|||||||
|| user_memcpy(&programArgs->error_port, &teamArgs->error_port,
|
|| user_memcpy(&programArgs->error_port, &teamArgs->error_port,
|
||||||
sizeof(port_id)) < B_OK
|
sizeof(port_id)) < B_OK
|
||||||
|| user_memcpy(&programArgs->error_token, &teamArgs->error_token,
|
|| user_memcpy(&programArgs->error_token, &teamArgs->error_token,
|
||||||
sizeof(uint32)) < B_OK) {
|
sizeof(uint32)) < B_OK
|
||||||
|
|| user_memcpy(userArgs, teamArgs->flat_args,
|
||||||
|
teamArgs->flat_args_size) < B_OK) {
|
||||||
// the team deletion process will clean this mess
|
// the team deletion process will clean this mess
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
@@ -1170,7 +1034,7 @@ team_create_thread_start(void *args)
|
|||||||
strlcpy(team->args, path, sizeof(team->args));
|
strlcpy(team->args, path, sizeof(team->args));
|
||||||
for (i = 1; i < argCount; i++) {
|
for (i = 1; i < argCount; i++) {
|
||||||
strlcat(team->args, " ", sizeof(team->args));
|
strlcat(team->args, " ", sizeof(team->args));
|
||||||
strlcat(team->args, teamArgs->args[i], sizeof(team->args));
|
strlcat(team->args, teamArgs->flat_args[i], sizeof(team->args));
|
||||||
}
|
}
|
||||||
|
|
||||||
free_team_arg(teamArgs);
|
free_team_arg(teamArgs);
|
||||||
@@ -1213,10 +1077,11 @@ team_create_thread_start(void *args)
|
|||||||
different parameters; we should not make it public.
|
different parameters; we should not make it public.
|
||||||
*/
|
*/
|
||||||
static thread_id
|
static thread_id
|
||||||
load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
load_image_etc(char**& _flatArgs, size_t flatArgsSize, int32 argCount,
|
||||||
char * const *env, int32 priority, uint32 flags,
|
int32 envCount, int32 priority, uint32 flags, port_id errorPort,
|
||||||
port_id errorPort, uint32 errorToken, bool kernel)
|
uint32 errorToken)
|
||||||
{
|
{
|
||||||
|
char** flatArgs = _flatArgs;
|
||||||
struct team *team, *parent;
|
struct team *team, *parent;
|
||||||
const char *threadName;
|
const char *threadName;
|
||||||
thread_id thread;
|
thread_id thread;
|
||||||
@@ -1225,13 +1090,15 @@ load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
|||||||
struct team_arg *teamArgs;
|
struct team_arg *teamArgs;
|
||||||
struct team_loading_info loadingInfo;
|
struct team_loading_info loadingInfo;
|
||||||
|
|
||||||
if (args == NULL || argCount == 0)
|
if (flatArgs == NULL || argCount == 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
TRACE(("load_image_etc: name '%s', args = %p, argCount = %ld\n",
|
const char* path = flatArgs[0];
|
||||||
args[0], args, argCount));
|
|
||||||
|
|
||||||
team = create_team_struct(args[0], false);
|
TRACE(("load_image_etc: name '%s', args = %p, argCount = %ld\n",
|
||||||
|
path, flatArgs, argCount));
|
||||||
|
|
||||||
|
team = create_team_struct(path, false);
|
||||||
if (team == NULL)
|
if (team == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -1247,7 +1114,7 @@ load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
|||||||
// Inherit the parent's user/group, but also check the executable's
|
// Inherit the parent's user/group, but also check the executable's
|
||||||
// set-user/group-id permission
|
// set-user/group-id permission
|
||||||
inherit_parent_user_and_group(team, parent);
|
inherit_parent_user_and_group(team, parent);
|
||||||
update_set_id_user_and_group(team, args[0]);
|
update_set_id_user_and_group(team, path);
|
||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
GRAB_TEAM_LOCK();
|
GRAB_TEAM_LOCK();
|
||||||
@@ -1260,11 +1127,15 @@ load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
|||||||
RELEASE_TEAM_LOCK();
|
RELEASE_TEAM_LOCK();
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
status = create_team_arg(&teamArgs, argCount, args, envCount, env,
|
status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount,
|
||||||
errorPort, errorToken, kernel);
|
envCount, errorPort, errorToken);
|
||||||
|
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
|
_flatArgs = NULL;
|
||||||
|
// args are owned by the team_arg structure now
|
||||||
|
|
||||||
// create a new io_context for this team
|
// create a new io_context for this team
|
||||||
team->io_context = vfs_new_io_context(parent->io_context);
|
team->io_context = vfs_new_io_context(parent->io_context);
|
||||||
if (!team->io_context) {
|
if (!team->io_context) {
|
||||||
@@ -1282,11 +1153,11 @@ load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
|||||||
goto err3;
|
goto err3;
|
||||||
|
|
||||||
// cut the path from the main thread name
|
// cut the path from the main thread name
|
||||||
threadName = strrchr(args[0], '/');
|
threadName = strrchr(path, '/');
|
||||||
if (threadName != NULL)
|
if (threadName != NULL)
|
||||||
threadName++;
|
threadName++;
|
||||||
else
|
else
|
||||||
threadName = args[0];
|
threadName = path;
|
||||||
|
|
||||||
// create the user data area
|
// create the user data area
|
||||||
status = create_team_user_data(team);
|
status = create_team_user_data(team);
|
||||||
@@ -1373,9 +1244,10 @@ err1:
|
|||||||
This function may only be called from user space.
|
This function may only be called from user space.
|
||||||
*/
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
exec_team(const char *path, int32 argCount, char * const *args,
|
exec_team(const char *path, char**& _flatArgs, size_t flatArgsSize,
|
||||||
int32 envCount, char * const *env)
|
int32 argCount, int32 envCount)
|
||||||
{
|
{
|
||||||
|
char** flatArgs = _flatArgs;
|
||||||
struct team *team = thread_get_current_thread()->team;
|
struct team *team = thread_get_current_thread()->team;
|
||||||
struct team_arg *teamArgs;
|
struct team_arg *teamArgs;
|
||||||
const char *threadName;
|
const char *threadName;
|
||||||
@@ -1385,7 +1257,9 @@ exec_team(const char *path, int32 argCount, char * const *args,
|
|||||||
thread_id nubThreadID = -1;
|
thread_id nubThreadID = -1;
|
||||||
|
|
||||||
TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld): team %ld\n",
|
TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld): team %ld\n",
|
||||||
args[0], argCount, envCount, team->id));
|
path, argCount, envCount, team->id));
|
||||||
|
|
||||||
|
T(ExecTeam(path, argCount, flatArgs, envCount, flatArgs + argCount + 1));
|
||||||
|
|
||||||
// switching the kernel at run time is probably not a good idea :)
|
// switching the kernel at run time is probably not a good idea :)
|
||||||
if (team == team_get_kernel_team())
|
if (team == team_get_kernel_team())
|
||||||
@@ -1422,17 +1296,14 @@ exec_team(const char *path, int32 argCount, char * const *args,
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = create_team_arg(&teamArgs, argCount, args, envCount, env,
|
status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount,
|
||||||
-1, 0, false);
|
envCount, -1, 0);
|
||||||
|
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
T(ExecTeam(path, teamArgs->arg_count, teamArgs->args, envCount, env));
|
_flatArgs = NULL;
|
||||||
// trace here, so we don't have to deal with the user addresses
|
// args are owned by the team_arg structure now
|
||||||
|
|
||||||
// replace args[0] with the path argument, just to be on the safe side
|
|
||||||
free(teamArgs->args[0]);
|
|
||||||
teamArgs->args[0] = strdup(path);
|
|
||||||
|
|
||||||
// ToDo: remove team resources if there are any left
|
// ToDo: remove team resources if there are any left
|
||||||
// thread_atkernel_exit() might not be called at all
|
// thread_atkernel_exit() might not be called at all
|
||||||
@@ -2740,15 +2611,59 @@ team_free_user_thread(struct thread* thread)
|
|||||||
thread_id
|
thread_id
|
||||||
load_image(int32 argCount, const char **args, const char **env)
|
load_image(int32 argCount, const char **args, const char **env)
|
||||||
{
|
{
|
||||||
|
// we need to flatten the args and environment
|
||||||
|
|
||||||
|
if (args == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// determine total needed size
|
||||||
|
int32 argSize = 0;
|
||||||
|
for (int32 i = 0; i < argCount; i++)
|
||||||
|
argSize += strlen(args[i]) + 1;
|
||||||
|
|
||||||
int32 envCount = 0;
|
int32 envCount = 0;
|
||||||
|
int32 envSize = 0;
|
||||||
|
while (env != NULL && env[envCount] != NULL)
|
||||||
|
envSize += strlen(env[envCount++]) + 1;
|
||||||
|
|
||||||
// count env variables
|
int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize;
|
||||||
while (env && env[envCount] != NULL)
|
if (size > MAX_PROCESS_ARGS_SIZE)
|
||||||
envCount++;
|
return B_TOO_MANY_ARGS;
|
||||||
|
|
||||||
return load_image_etc(argCount, (char * const *)args, envCount,
|
// allocate space
|
||||||
(char * const *)env, B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED,
|
char** flatArgs = (char**)malloc(size);
|
||||||
-1, 0, true);
|
if (flatArgs == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
char** slot = flatArgs;
|
||||||
|
char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
|
||||||
|
|
||||||
|
// copy arguments and environment
|
||||||
|
for (int32 i = 0; i < argCount; i++) {
|
||||||
|
int32 argSize = strlen(args[i]) + 1;
|
||||||
|
memcpy(stringSpace, args[i], argSize);
|
||||||
|
*slot++ = stringSpace;
|
||||||
|
stringSpace += argSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
*slot++ = NULL;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < envCount; i++) {
|
||||||
|
int32 envSize = strlen(env[i]) + 1;
|
||||||
|
memcpy(stringSpace, env[i], envSize);
|
||||||
|
*slot++ = stringSpace;
|
||||||
|
stringSpace += envSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
*slot++ = NULL;
|
||||||
|
|
||||||
|
thread_id thread = load_image_etc(flatArgs, size, argCount, envCount,
|
||||||
|
B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED, -1, 0);
|
||||||
|
|
||||||
|
free(flatArgs);
|
||||||
|
// load_image_etc() unset our variable if it took over ownership
|
||||||
|
|
||||||
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3031,21 +2946,28 @@ getsid(pid_t process)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
_user_exec(const char *userPath, int32 argCount, char * const *userArgs,
|
_user_exec(const char *userPath, const char* const* userFlatArgs,
|
||||||
int32 envCount, char * const *userEnvironment)
|
size_t flatArgsSize, int32 argCount, int32 envCount)
|
||||||
{
|
{
|
||||||
char path[B_PATH_NAME_LENGTH];
|
char path[B_PATH_NAME_LENGTH];
|
||||||
|
|
||||||
if (argCount < 1)
|
if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userFlatArgs)
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userArgs)
|
|
||||||
|| !IS_USER_ADDRESS(userEnvironment)
|
|
||||||
|| user_strlcpy(path, userPath, sizeof(path)) < B_OK)
|
|| user_strlcpy(path, userPath, sizeof(path)) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
return exec_team(path, argCount, userArgs, envCount, userEnvironment);
|
// copy and relocate the flat arguments
|
||||||
// this one only returns in case of error
|
char** flatArgs;
|
||||||
|
status_t error = copy_user_process_args(userFlatArgs, flatArgsSize,
|
||||||
|
argCount, envCount, flatArgs);
|
||||||
|
|
||||||
|
if (error == B_OK) {
|
||||||
|
error = exec_team(path, flatArgs, _ALIGN(flatArgsSize), argCount,
|
||||||
|
envCount);
|
||||||
|
// this one only returns in case of error
|
||||||
|
}
|
||||||
|
|
||||||
|
free(flatArgs);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3320,22 +3242,30 @@ _user_wait_for_team(team_id id, status_t *_userReturnCode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
team_id
|
thread_id
|
||||||
_user_load_image(int32 argCount, const char **userArgs, int32 envCount,
|
_user_load_image(const char* const* userFlatArgs, size_t flatArgsSize,
|
||||||
const char **userEnv, int32 priority, uint32 flags, port_id errorPort,
|
int32 argCount, int32 envCount, int32 priority, uint32 flags,
|
||||||
uint32 errorToken)
|
port_id errorPort, uint32 errorToken)
|
||||||
{
|
{
|
||||||
TRACE(("_user_load_image_etc: argc = %ld\n", argCount));
|
TRACE(("_user_load_image_etc: argc = %ld\n", argCount));
|
||||||
|
|
||||||
if (argCount < 1 || userArgs == NULL || userEnv == NULL)
|
if (argCount < 1)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (!IS_USER_ADDRESS(userArgs) || !IS_USER_ADDRESS(userEnv))
|
// copy and relocate the flat arguments
|
||||||
return B_BAD_ADDRESS;
|
char** flatArgs;
|
||||||
|
status_t error = copy_user_process_args(userFlatArgs, flatArgsSize,
|
||||||
|
argCount, envCount, flatArgs);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
return load_image_etc(argCount, (char * const *)userArgs,
|
thread_id thread = load_image_etc(flatArgs, _ALIGN(flatArgsSize), argCount,
|
||||||
envCount, (char * const *)userEnv, priority, flags, errorPort,
|
envCount, priority, flags, errorPort, errorToken);
|
||||||
errorToken, false);
|
|
||||||
|
free(flatArgs);
|
||||||
|
// load_image_etc() unset our variable if it took over ownership
|
||||||
|
|
||||||
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ MergeObject os_main.o :
|
|||||||
fs_info.c
|
fs_info.c
|
||||||
fs_query.cpp
|
fs_query.cpp
|
||||||
fs_volume.c
|
fs_volume.c
|
||||||
image.c
|
image.cpp
|
||||||
parsedate.cpp
|
parsedate.cpp
|
||||||
port.c
|
port.c
|
||||||
scheduler.c
|
scheduler.c
|
||||||
|
|||||||
@@ -43,8 +43,18 @@ load_image(int32 argCount, const char **args, const char **environ)
|
|||||||
while (environ[envCount] != NULL)
|
while (environ[envCount] != NULL)
|
||||||
envCount++;
|
envCount++;
|
||||||
|
|
||||||
thread = _kern_load_image(argCount, args, envCount, environ,
|
char** flatArgs = NULL;
|
||||||
B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED, -1, 0);
|
size_t flatArgsSize;
|
||||||
|
status_t status = __flatten_process_args(args, argCount, environ, envCount,
|
||||||
|
&flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
|
if (status == B_OK) {
|
||||||
|
thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
|
||||||
|
B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED, -1, 0);
|
||||||
|
|
||||||
|
free(flatArgs);
|
||||||
|
} else
|
||||||
|
thread = status;
|
||||||
|
|
||||||
free(newArgs);
|
free(newArgs);
|
||||||
return thread;
|
return thread;
|
||||||
@@ -159,7 +169,7 @@ __parse_invoke_line(char *invoker, char ***_newArgs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this is a shell script and requires special treatment
|
// this is a shell script and requires special treatment
|
||||||
newArgs = malloc((*_argCount + count + 1) * sizeof(void *));
|
newArgs = (char**)malloc((*_argCount + count + 1) * sizeof(void *));
|
||||||
if (newArgs == NULL)
|
if (newArgs == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -170,7 +180,7 @@ __parse_invoke_line(char *invoker, char ***_newArgs,
|
|||||||
}
|
}
|
||||||
for (i = 0; i < *_argCount; i++) {
|
for (i = 0; i < *_argCount; i++) {
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
newArgs[i + count] = arg0;
|
newArgs[i + count] = (char*)arg0;
|
||||||
else
|
else
|
||||||
newArgs[i + count] = (char *)(*_oldArgs)[i];
|
newArgs[i + count] = (char *)(*_oldArgs)[i];
|
||||||
}
|
}
|
||||||
@@ -199,7 +209,72 @@ __test_executable(const char *path, char *invoker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _call_init_routines_(void);
|
/*! Allocates a flat buffer and copies the argument and environment strings
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
__flatten_process_args(const char* const* args, int32 argCount,
|
||||||
|
const char* const* env, int32 envCount, char*** _flatArgs,
|
||||||
|
size_t* _flatSize)
|
||||||
|
{
|
||||||
|
if (args == NULL || env == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// determine total needed size
|
||||||
|
int32 argSize = 0;
|
||||||
|
for (int32 i = 0; i < argCount; i++) {
|
||||||
|
if (args[i] == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
argSize += strlen(args[i]) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 envSize = 0;
|
||||||
|
for (int32 i = 0; i < envCount; i++) {
|
||||||
|
if (env[i] == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
envSize += strlen(env[i]) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize;
|
||||||
|
if (size > MAX_PROCESS_ARGS_SIZE)
|
||||||
|
return B_TOO_MANY_ARGS;
|
||||||
|
|
||||||
|
// allocate space
|
||||||
|
char** flatArgs = (char**)malloc(size);
|
||||||
|
if (flatArgs == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
char** slot = flatArgs;
|
||||||
|
char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
|
||||||
|
|
||||||
|
// copy arguments and environment
|
||||||
|
for (int32 i = 0; i < argCount; i++) {
|
||||||
|
int32 argSize = strlen(args[i]) + 1;
|
||||||
|
memcpy(stringSpace, args[i], argSize);
|
||||||
|
*slot++ = stringSpace;
|
||||||
|
stringSpace += argSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
*slot++ = NULL;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < envCount; i++) {
|
||||||
|
int32 envSize = strlen(env[i]) + 1;
|
||||||
|
memcpy(stringSpace, env[i], envSize);
|
||||||
|
*slot++ = stringSpace;
|
||||||
|
stringSpace += envSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
*slot++ = NULL;
|
||||||
|
|
||||||
|
*_flatArgs = flatArgs;
|
||||||
|
*_flatSize = size;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void _call_init_routines_(void);
|
||||||
void
|
void
|
||||||
_call_init_routines_(void)
|
_call_init_routines_(void)
|
||||||
{
|
{
|
||||||
@@ -97,9 +97,18 @@ do_exec(const char *path, char * const args[], char * const environment[],
|
|||||||
path = newArgs[0];
|
path = newArgs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = _kern_exec(path, argCount, newArgs ? newArgs : args, envCount,
|
char** flatArgs = NULL;
|
||||||
environment);
|
size_t flatArgsSize;
|
||||||
// if this call returns, something definitely went wrong
|
status = __flatten_process_args(newArgs ? newArgs : args, argCount,
|
||||||
|
environment, envCount, &flatArgs, &flatArgsSize);
|
||||||
|
|
||||||
|
if (status == B_OK) {
|
||||||
|
errno = _kern_exec(path, flatArgs, flatArgsSize, argCount, envCount);
|
||||||
|
// if this call returns, something definitely went wrong
|
||||||
|
|
||||||
|
free(flatArgs);
|
||||||
|
} else
|
||||||
|
errno = status;
|
||||||
|
|
||||||
free(newArgs);
|
free(newArgs);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -370,6 +370,33 @@ runtime_loader(void *_args)
|
|||||||
|
|
||||||
gProgramArgs = (struct user_space_program_args *)_args;
|
gProgramArgs = (struct user_space_program_args *)_args;
|
||||||
|
|
||||||
|
// Relocate the args and env arrays -- they are organized in a contiguous
|
||||||
|
// buffer which the kernel just copied into user space without adjusting the
|
||||||
|
// pointers.
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
addr_t relocationOffset = 0;
|
||||||
|
|
||||||
|
if (gProgramArgs->arg_count > 0)
|
||||||
|
relocationOffset = (addr_t)gProgramArgs->args[0];
|
||||||
|
else if (gProgramArgs->env_count > 0)
|
||||||
|
relocationOffset = (addr_t)gProgramArgs->env[0];
|
||||||
|
|
||||||
|
// That's basically: <new buffer address> - <old buffer address>.
|
||||||
|
// It looks a little complicated, since we don't have the latter one at
|
||||||
|
// hand and thus need to reconstruct it (<first string pointer> -
|
||||||
|
// <arguments + environment array sizes>).
|
||||||
|
relocationOffset = (addr_t)gProgramArgs->args - relocationOffset
|
||||||
|
+ (gProgramArgs->arg_count + gProgramArgs->env_count + 2)
|
||||||
|
* sizeof(char*);
|
||||||
|
|
||||||
|
for (i = 0; i < gProgramArgs->arg_count; i++)
|
||||||
|
gProgramArgs->args[i] += relocationOffset;
|
||||||
|
|
||||||
|
for (i = 0; i < gProgramArgs->env_count; i++)
|
||||||
|
gProgramArgs->env[i] += relocationOffset;
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG_RLD
|
#if DEBUG_RLD
|
||||||
close(0); open("/dev/console", 0); /* stdin */
|
close(0); open("/dev/console", 0); /* stdin */
|
||||||
close(1); open("/dev/console", 0); /* stdout */
|
close(1); open("/dev/console", 0); /* stdout */
|
||||||
|
|||||||
Reference in New Issue
Block a user