diff --git a/exec/exec.c b/exec/exec.c index ace62dd0191..7736c0dab27 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -863,25 +863,32 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs, -/* Format PID, a nonnegative process identifier, in base 10. - Place the result in *IN. Do not null-terminate the result. - Possibly modify the bytes in IN that are after the result. - Return a pointer to the byte after the result. */ +/* Format PID, an unsigned process identifier, in base 10. Place the + result in *IN, and return a pointer to the byte after the + result. REM should be NULL. */ char * -format_pid (char in[INT_STRLEN_BOUND (pid_t)], pid_t pid) +format_pid (char *in, unsigned int pid) { - char *pend = in + INT_STRLEN_BOUND (pid_t); - char *p = pend; + unsigned int digits[32], *fill; - do - *--p = '0' + pid % 10; - while ((pid /= 10) != 0); + fill = digits; - do - *in++ = *p++; - while (p < pend); + for (; pid != 0; pid = pid / 10) + *fill++ = pid % 10; + /* Insert 0 if the number would otherwise be empty. */ + + if (fill == digits) + *fill++ = 0; + + while (fill != digits) + { + --fill; + *in++ = '0' + *fill; + } + + *in = '\0'; return in; } @@ -897,13 +904,10 @@ format_pid (char in[INT_STRLEN_BOUND (pid_t)], pid_t pid) Finally, use REGS to add the required interpreter arguments to the caller's argv. - NAME must be a null-terminated string in a buffer of size PATH_MAX. - It might be updated to be a string no longer than PATH_MAX - 1. - Value is NULL upon failure, with errno set accordingly. */ char * -exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, +exec_0 (char *name, struct exec_tracee *tracee, size_t *size, USER_REGS_STRUCT *regs) { int fd, rc, i; @@ -912,13 +916,14 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, program_header program; USER_WORD entry, program_entry, offset; USER_WORD header_offset; - ptrdiff_t nlen; USER_WORD name_len, aligned_len; struct exec_jump_command jump; /* This also encompasses !__LP64__. */ #if defined __mips__ && !defined MIPS_NABI int fpu_mode; #endif /* defined __mips__ && !defined MIPS_NABI */ + char buffer[80], buffer1[PATH_MAX + 80], *rewrite; + ssize_t link_size; size_t remaining; /* If the process is trying to run /proc/self/exe, make it run @@ -926,13 +931,8 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, if (!strcmp (name, "/proc/self/exe") && tracee->exec_file) { - nlen = strnlen (tracee->exec_file, PATH_MAX); - if (PATH_MAX <= nlen) - { - errno = ENAMETOOLONG; - return NULL; - } - memcpy (name, tracee->exec_file, nlen + 1); + strncpy (name, tracee->exec_file, PATH_MAX - 1); + name[PATH_MAX] = '\0'; } else { @@ -940,45 +940,45 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, cwd. Do not use sprintf at it is not reentrant and it mishandles results longer than INT_MAX. */ - nlen = strlen (name); - if (name[0] && name[0] != '/') { - char buffer[sizeof "/proc//cwd" + INT_STRLEN_BOUND (pid_t)]; - char buffer1[PATH_MAX]; + /* Clear both buffers. */ + memset (buffer, 0, sizeof buffer); + memset (buffer1, 0, sizeof buffer1); - /* Copy over "/proc/", the PID, and "/cwd". */ - char *rewrite = stpcpy (buffer, "/proc/"); + /* Copy over /proc, the PID, and /cwd/. */ + rewrite = stpcpy (buffer, "/proc/"); rewrite = format_pid (rewrite, tracee->pid); strcpy (rewrite, "/cwd"); /* Resolve this symbolic link. */ - ssize_t link_size = readlink (buffer, buffer1, sizeof buffer1); + link_size = readlink (buffer, buffer1, + PATH_MAX + 1); + if (link_size < 0) return NULL; - /* Check that the link is reasonable. */ + /* Check that the name is a reasonable size. */ - if (link_size == 0 || buffer1[0] != '/') - { - errno = EINVAL; - return NULL; - } - - ptrdiff_t link_len = link_size - (buffer1[link_size - 1] == '/'); - if (PATH_MAX <= link_len + 1 + nlen) + if (link_size > PATH_MAX) { + /* The name is too long. */ errno = ENAMETOOLONG; return NULL; } - /* Replace name with link contents, - then '/' if needed, then name. */ - memmove (name + link_len + 1, name, nlen + 1); - memcpy (name, buffer1, link_len); - name[link_len] = '/'; - nlen += link_len + 1; + /* Add a directory separator if necessary. */ + + if (!link_size || buffer1[link_size - 1] != '/') + buffer1[link_size] = '/', link_size++; + + rewrite = buffer1 + link_size; + remaining = buffer1 + sizeof buffer1 - rewrite - 1; + memcpy (rewrite, name, strnlen (name, remaining)); + + /* Replace name with buffer1. */ + strcpy (name, buffer1); } } @@ -1151,7 +1151,7 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, loader_area_used += sizeof jump; /* Copy the length of NAME and NAME itself to the loader area. */ - name_len = nlen; + name_len = strlen (name); aligned_len = ((name_len + 1 + sizeof name_len - 1) & -sizeof name_len); if (sizeof loader_area - loader_area_used diff --git a/exec/trace.c b/exec/trace.c index d3d6f223eb8..da9ac96c6ff 100644 --- a/exec/trace.c +++ b/exec/trace.c @@ -732,7 +732,7 @@ check_signal (struct exec_tracee *tracee, int status) static int handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) { - char buffer[PATH_MAX], *area; + char buffer[PATH_MAX + 80], *area; USER_REGS_STRUCT original; size_t size, loader_size; USER_WORD loader;