Files
mckernel/lib/string.c
Dominique Martinet 525b90d028 flatten_string/process env: realign env and clear trailing bits
envs are stuck after args which are now possibly unaligned, and used
from a non-aligned pointer in prepare_process_ranges_args_envs (env)

The memory immediately after args/envs is copied anyway with memcpy_long,
so make sure the bits are initialized and realign env correctly

Fixes: 70e52faf36 ("flatten_strings: do not return unused trailing bits")
Change-Id: Ic747e947d151c0eea65dec36bc9c888cf6e0c394
2018-11-21 07:39:16 +00:00

341 lines
6.0 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, 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;
len = p - (char *)_flat;
if (len < full_len)
memset(p, 0, full_len - len);
return len;
}