Skip to content

Commit

Permalink
Fix commandline handling for ARM semihosted executables
Browse files Browse the repository at this point in the history
Use the copy of the command line that loader_build_argptr() sets up in guest
memory as the command line to return from the ARM SYS_GET_CMDLINE semihosting
call. Previously we were using a pointer to memory which had already been
freed before the guest program started.

This fixes https://bugs.launchpad.net/qemu/+bug/673613 .

Signed-off-by: Wolfgang Schildbach <wschi@dolby.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
  • Loading branch information
wschidol authored and suihkulokki committed Jan 7, 2011
1 parent 3ebe80c commit 2e8785a
Showing 1 changed file with 49 additions and 30 deletions.
79 changes: 49 additions & 30 deletions arm-semi.c
Expand Up @@ -373,45 +373,64 @@ uint32_t do_arm_semihosting(CPUState *env)
#ifdef CONFIG_USER_ONLY
/* Build a commandline from the original argv. */
{
char **arg = ts->info->host_argv;
int len = ARG(1);
/* lock the buffer on the ARM side */
char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
char *arm_cmdline_buffer;
const char *host_cmdline_buffer;

if (!cmdline_buffer)
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
unsigned int i;
unsigned int arm_cmdline_len = ARG(1);
unsigned int host_cmdline_len =
ts->info->arg_end-ts->info->arg_start;

if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) {
return -1; /* not enough space to store command line */
}

s = cmdline_buffer;
while (*arg && len > 2) {
int n = strlen(*arg);
if (!host_cmdline_len) {
/* We special-case the "empty command line" case (argc==0).
Just provide the terminating 0. */
arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0);
arm_cmdline_buffer[0] = 0;
unlock_user(arm_cmdline_buffer, ARG(0), 1);

if (s != cmdline_buffer) {
*(s++) = ' ';
len--;
}
if (n >= len)
n = len - 1;
memcpy(s, *arg, n);
s += n;
len -= n;
arg++;
/* Adjust the commandline length argument. */
SET_ARG(1, 0);
return 0;
}
/* Null terminate the string. */
*s = 0;
len = s - cmdline_buffer;

/* Unlock the buffer on the ARM side. */
unlock_user(cmdline_buffer, ARG(0), len);
/* lock the buffers on the ARM side */
arm_cmdline_buffer =
lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0);
host_cmdline_buffer =
lock_user(VERIFY_READ, ts->info->arg_start,
host_cmdline_len, 1);

/* Adjust the commandline length argument. */
SET_ARG(1, len);
if (arm_cmdline_buffer && host_cmdline_buffer)
{
/* the last argument is zero-terminated;
no need for additional termination */
memcpy(arm_cmdline_buffer, host_cmdline_buffer,
host_cmdline_len);

/* Return success if commandline fit into buffer. */
return *arg ? -1 : 0;
/* separate arguments by white spaces */
for (i = 0; i < host_cmdline_len-1; i++) {
if (arm_cmdline_buffer[i] == 0) {
arm_cmdline_buffer[i] = ' ';
}
}

/* Adjust the commandline length argument. */
SET_ARG(1, host_cmdline_len-1);
}

/* Unlock the buffers on the ARM side. */
unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len);
unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0);

/* Return success if we could return a commandline. */
return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1;
}
#else
return -1;
return -1;
#endif
case SYS_HEAPINFO:
{
Expand Down

0 comments on commit 2e8785a

Please sign in to comment.