Files
mckernel/lib/string.c
Dominique Martinet b1681f4a3a mcexec/execve: fix shebangs handling
There were mainly two problems with shebangs:
 - Suffix arguments handling e.g. '#!/bin/sh -x'
 - Recursive handling e.g. script1 fetchs '#!/path/to/script2'
and script2 itself has a shebang
 - (did I say two?) running shebang would replace argv[optind] instead
of appending e.g. script with '#!/bin/sh' and running './script -c'
would run '/bin/sh -c' instead of '/bin/sh ./script -c'

There also are two places where this needs parsing:
 - starting a fresh program from mcexec
 - starting a new program from execve in mcexec

The first was easy to fix as we already had argv around, but the later
required a new way to transfer the 'new argv elements from the script'
to mckernel to append before its argv -- it used to be 'desc->shell_path'
but that was no longer used at some point and just one keyword is not
enough to handle this properly.

This commit does:
 - Refactors the lookup_path + load_elf_desc that was only done at most
twice in its own function that loops indefinitely and use that in both
situations described above
 - Transmits the argv addition in the transfer to mckernel after the
desc; mckernel allocates 4 pages (hardcoded) for the descs and we will
hopefully have room for the script arguments on top of that... (there is
no guard!!!)
 - Change flatten_strings to allow prepending a flattened string instead
of a single string.
Note that the flatten_string change also brought in a difference in the
format, to have the full length embedded within the string, the latest
slot that used to be zeroes now contains the position of the end of the
buffer (where the last+1 string would be if there had been one)
This required a trivial change in mckernel prepare args function that
used this property for no real reason.

Hopefully things work™, this probably warrants adding a couple of new
ostests...
 - create a couple of scripts with recursive invocation/arguments and
check their own argv.
 - execute "mcexec script args" and "mcexec sh -c 'script args'"

Change-Id: I2cf9cde5c07c9293f730de89c9731bd93dbfa789
Refs: #1115
2018-10-04 14:31:02 +09:00

338 lines
5.9 KiB
C

/**
* \file page_alloc.c
* License details are found in the file LICENSE.
* \brief
* Manipulate strings.
* \author Taku Shimosawa <shimosawa@is.s.u-tokyo.ac.jp> \par
* Copyright (C) 2011 - 2012 Taku Shimosawa
*/
/*
* HISTORY
*/
#include <kmalloc.h>
#include <string.h>
#include <memory.h>
#include <arch-string.h>
size_t strlen(const char *p)
{
const char *head = p;
while(*p){
p++;
}
return p - head;
}
size_t strnlen(const char *p, size_t maxlen)
{
const char *head = p;
while(*p && maxlen > 0){
p++;
maxlen--;
}
return p - head;
}
char *strcpy(char *dest, const char *src)
{
char *head = dest;
while((*(dest++) = *(src++)));
return head;
}
char *strncpy(char *dest, const char *src, size_t maxlen)
{
char *head = dest;
ssize_t len = maxlen;
if(len <= 0)
return head;
while((*(dest++) = *(src++)) && --len);
if(len > 0){
while(--len){
*(dest++) = '\0';
}
}
return head;
}
int strcmp(const char *s1, const char *s2)
{
while(*s1 && *s1 == *s2){
s1++;
s2++;
}
return *s1 - *s2;
}
int strncmp(const char *s1, const char *s2, size_t n)
{
while(*s1 && *s1 == *s2 && n > 1){
s1++;
s2++;
n--;
}
return *s1 - *s2;
}
char *strchr(const char *s, int n) {
char *p = (char *)s;
while (1) {
if (*p == n)
{
return p;
} else if (*p == '\0') {
break;
}
++p;
}
return NULL;
}
char *
strrchr(const char *s, int c)
{
const char *last = NULL;
do {
if (*s == c) {
last = s;
}
} while (*(s++));
return (char *)last;
} /* strrchr() */
char *strpbrk(const char *s, const char *accept)
{
const char *a;
do {
for (a = accept; *a; a++)
if (*s == *a)
return (char *)s;
} while (*(s++));
return NULL;
}
char *strstr(const char *haystack, const char *needle)
{
int len = strlen(needle);
while(*haystack){
if(!strncmp(haystack, needle, len)){
return (char *)haystack;
}
haystack++;
}
return NULL;
}
void *memcpy(void *dest, const void *src, size_t n)
{
const char *p1 = src;
char *p2 = dest;
while(n > 0){
*p2 = *p1;
p1++;
p2++;
n--;
}
return dest;
}
void *memcpy_long(void *dest, const void *src, size_t n)
{
const unsigned long *p1 = src;
unsigned long *p2 = dest;
n /= sizeof(unsigned long);
while (n > 0) {
*(p2++) = *(p1++);
n--;
}
return dest;
}
#ifndef ARCH_FAST_MEMSET
void *memset(void *s, int c, size_t n)
{
char *s_aligned = (void *)(((unsigned long)s + 7) & ~7);
char *e_aligned = (void *)(((unsigned long)s + n) & ~7);
char *e = ((char *)s + n);
char *p;
unsigned long *l;
#define C ((unsigned long)(c & 0xff))
unsigned long pat = C | C << 8 | C << 16 | C << 24 | C << 32 |
C << 40 | C << 48 | C << 56;
#undef C
if(s_aligned < e_aligned){
p = s;
while(p < s_aligned){
*(p++) = (char)c;
}
l = (unsigned long *)s_aligned;
while((char *)l < e_aligned){
*(l++) = pat;
}
p = e_aligned;
while(p < e){
*(p++) = (char)c;
}
}else{
p = s;
while(p < e){
*(p++) = (char)c;
}
}
return s;
}
#endif
int memcmp(const void *s1, const void *s2, size_t n)
{
const char *p1 = s1;
const char *p2 = s2;
while(*p1 == *p2 && n > 1){
p1++;
p2++;
n--;
}
return *p1 - *p2;
}
/*
* Flatten out a (char **) string array into the following format:
* [nr_strings][char *offset of string_0]...[char *offset of string_n-1][char *offset of end of string][string0]...[stringn_1]
*
* sizes all are longs.
*
* NOTE: copy this string somewhere, add the address of the string to each offset
* and we get back a valid argv or envp array.
*
* pre_strings is already flattened, so we just need to manage counts and copy
* the string parts appropriately.
*
* returns the total length of the flat string and updates flat to
* point to the beginning.
*/
int flatten_strings_from_user(char *pre_strings, char **strings, char **flat)
{
int full_len, i;
int nr_strings = 0;
int pre_strings_count = 0;
int pre_strings_len = 0;
long *_flat;
long *pre_strings_flat;
char *p;
long r;
int ret;
/* When strings is NULL, make array one NULL */
if (!strings) {
full_len = sizeof(long) + sizeof(char *);
_flat = kmalloc(full_len, IHK_MC_AP_NOWAIT);
if (!_flat) {
return -ENOMEM;
}
memset(_flat, 0, full_len);
*flat = (char *)_flat;
return full_len;
}
/* How many strings do we have? */
for (;;) {
ret = getlong_user(&r, (void *)(strings + nr_strings));
if (ret < 0)
return ret;
if (r == 0)
break;
++nr_strings;
}
/* Count full length */
full_len = sizeof(long) + sizeof(char *); // Counter and terminating NULL
if (pre_strings) {
pre_strings_flat = (long *)pre_strings;
pre_strings_count = pre_strings_flat[0];
pre_strings_len = pre_strings_flat[pre_strings_count + 1];
pre_strings_len -= sizeof(long) * (pre_strings_count + 2);
full_len += pre_strings_count * sizeof(long) + pre_strings_len;
}
for (i = 0; i < nr_strings; ++i) {
char *userp;
int len;
ret = getlong_user((long *)&userp, (void *)(strings + i));
if (ret < 0)
return ret;
len = strlen_user(userp);
if(len < 0)
return len;
// Pointer + actual value
full_len += sizeof(char *) + len + 1;
}
full_len = (full_len + sizeof(long) - 1) & ~(sizeof(long) - 1);
_flat = kmalloc(full_len, IHK_MC_AP_NOWAIT);
if (!_flat) {
return -ENOMEM;
}
/* Number of strings */
_flat[0] = nr_strings + pre_strings_count;
// Actual offset
p = (char *)(_flat + nr_strings + pre_strings_count + 2);
if (pre_strings) {
for (i = 0; i < pre_strings_count; i++) {
_flat[i + 1] = pre_strings_flat[i + 1] +
nr_strings * sizeof(long);
}
memcpy(p, pre_strings + pre_strings_flat[1],
pre_strings_len);
p += pre_strings_len;
}
for (i = 0; i < nr_strings; ++i) {
char *userp;
_flat[i + pre_strings_count + 1] = p - (char *)_flat;
ret = getlong_user((long *)&userp, (void *)(strings + i));
if (ret < 0)
return ret;
strcpy_from_user(p, userp);
p = strchr(p, '\0') + 1;
}
_flat[nr_strings + pre_strings_count + 1] = p - (char *)_flat;
*flat = (char *)_flat;
return full_len;
}