* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_exec_elf.h"
#ifdef LOSCFG_SHELL
#include "show.h"
#endif
#include "los_vm_phys.h"
#include "los_vm_map.h"
#include "los_vm_dump.h"
STATIC INT32 OsExecve(const ELFLoadInfo *loadInfo)
{
if ((loadInfo == NULL) || (loadInfo->elfEntry == 0)) {
return LOS_NOK;
}
return OsExecStart((TSK_ENTRY_FUNC)(loadInfo->elfEntry), (UINTPTR)loadInfo->stackTop,
loadInfo->stackBase, loadInfo->stackSize);
}
#ifdef LOSCFG_SHELL
STATIC INT32 OsGetRealPath(const CHAR *fileName, CHAR *buf, UINT32 maxLen)
{
CHAR *workingDirectory = NULL;
UINT32 len, workPathLen, newLen;
if (access(fileName, F_OK) < 0) {
workingDirectory = OsShellGetWorkingDirectory();
if (workingDirectory == NULL) {
goto ERR_FILE;
}
len = strlen(fileName);
workPathLen = strlen(workingDirectory);
newLen = len + 1 + workPathLen + 1;
if (newLen >= maxLen) {
return -ENOENT;
}
if (strncpy_s(buf, maxLen, workingDirectory, workPathLen) != EOK) {
PRINT_ERR("strncpy_s failed, errline: %d!\n", __LINE__);
return -ENOENT;
}
buf[workPathLen] = '/';
if (strncpy_s(buf + workPathLen + 1, maxLen - workPathLen - 1, fileName, len) != EOK) {
PRINT_ERR("strncpy_s failed, errline: %d!\n", __LINE__);
return -ENOENT;
}
buf[newLen] = '\0';
if (access(buf, F_OK) < 0) {
goto ERR_FILE;
}
}
return LOS_OK;
ERR_FILE:
return -ENOENT;
}
#endif
STATIC INT32 OsCopyUserParam(ELFLoadInfo *loadInfo, const CHAR *fileName, CHAR *kfileName, UINT32 maxSize)
{
UINT32 strLen;
errno_t err;
static UINT32 userFirstInitFlag = 0;
if (LOS_IsUserAddress((VADDR_T)(UINTPTR)fileName)) {
err = LOS_StrncpyFromUser(kfileName, fileName, PATH_MAX + 1);
if (err == -EFAULT) {
return err;
} else if (err > PATH_MAX) {
PRINT_ERR("%s[%d], filename len exceeds maxlen: %d\n", __FUNCTION__, __LINE__, PATH_MAX);
return -ENAMETOOLONG;
}
} else if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)fileName) && (userFirstInitFlag == 0)) {
* the first user process is created by the function OsUserInit->execve(/bin/init) in the kernel space
* after the first user process is created, this branch should not enter again
*/
userFirstInitFlag = 1;
strLen = strlen(fileName);
err = memcpy_s(kfileName, PATH_MAX, fileName, strLen);
if (err != EOK) {
PRINT_ERR("%s[%d], Copy failed! err: %d\n", __FUNCTION__, __LINE__, err);
return -EFAULT;
}
} else {
return -EINVAL;
}
loadInfo->fileName = kfileName;
return LOS_OK;
}
INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *envp)
{
ELFLoadInfo loadInfo = { 0 };
CHAR kfileName[PATH_MAX + 1] = { 0 };
INT32 ret;
#ifdef LOSCFG_SHELL
CHAR buf[PATH_MAX + 1] = { 0 };
#endif
if ((fileName == NULL) || ((argv != NULL) && !LOS_IsUserAddress((VADDR_T)(UINTPTR)argv)) ||
((envp != NULL) && !LOS_IsUserAddress((VADDR_T)(UINTPTR)envp))) {
return -EINVAL;
}
ret = OsCopyUserParam(&loadInfo, fileName, kfileName, PATH_MAX);
if (ret != LOS_OK) {
return ret;
}
#ifdef LOSCFG_SHELL
if (OsGetRealPath(kfileName, buf, (PATH_MAX + 1)) != LOS_OK) {
return -ENOENT;
}
if (buf[0] != '\0') {
loadInfo.fileName = buf;
}
#endif
loadInfo.newSpace = OsCreateUserVmSpace();
if (loadInfo.newSpace == NULL) {
PRINT_ERR("%s %d, failed to allocate new vm space\n", __FUNCTION__, __LINE__);
return -ENOMEM;
}
loadInfo.argv = argv;
loadInfo.envp = envp;
ret = OsLoadELFFile(&loadInfo);
if (ret != LOS_OK) {
return ret;
}
ret = OsExecRecycleAndInit(OsCurrProcessGet(), loadInfo.fileName, loadInfo.oldSpace, loadInfo.oldFiles);
if (ret != LOS_OK) {
(VOID)LOS_VmSpaceFree(loadInfo.oldSpace);
goto OUT;
}
ret = OsExecve(&loadInfo);
if (ret != LOS_OK) {
goto OUT;
}
return loadInfo.stackTop;
OUT:
(VOID)LOS_Exit(OS_PRO_EXIT_OK);
return ret;
}