mirror of
https://github.com/openharmony/startup_appspawn.git
synced 2026-08-27 04:21:16 -04:00
ccc01ac080
Signed-off-by: yangmaoquan <yangmaoquan4@h-partners.com> Change-Id: Iaa7e7f03c69414b6911e1ae227defecccca09a80
227 lines
8.2 KiB
C++
227 lines
8.2 KiB
C++
/*
|
|
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
#include <string>
|
|
#include <fstream>
|
|
#include <climits>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include "securec.h"
|
|
#include "appspawn_utils.h"
|
|
#include "appspawn_msg.h"
|
|
#include "appspawn_hook.h"
|
|
#include "appspawn_manager.h"
|
|
|
|
constexpr const char *ENV_FILE_PATH = "/etc/environment";
|
|
constexpr size_t MIN_QUOTED_VALUE_LENGTH = 2; // Minimum length for a quoted value (e.g., "x")
|
|
constexpr size_t QUOTE_LENGTH = 1; // Length of a single quote character
|
|
constexpr size_t TWO_QUOTE_LENGTH = 2 * QUOTE_LENGTH;
|
|
constexpr size_t MAX_ENV_LINE_LENGTH = 4096; // Maximum length for a single line
|
|
constexpr size_t MAX_ENV_FILE_LINES = 1000; // Maximum number of lines in the file
|
|
|
|
APPSPAWN_STATIC std::string_view TrimWhitespaceView(std::string_view str)
|
|
{
|
|
const char *ws = " \t\n\r";
|
|
auto start = str.find_first_not_of(ws);
|
|
if (start == std::string::npos) {
|
|
return std::string_view();
|
|
}
|
|
auto end = str.find_last_not_of(ws);
|
|
return std::string_view(str.data() + start, end - start + 1);
|
|
}
|
|
|
|
APPSPAWN_STATIC int32_t ParseEnvLine(const std::string &line, std::string &envName, std::string &envValue)
|
|
{
|
|
if (line.length() > MAX_ENV_LINE_LENGTH) {
|
|
APPSPAWN_LOGW("Environment line too long: %{public}zu bytes (max: %{public}zu)",
|
|
line.length(), MAX_ENV_LINE_LENGTH);
|
|
return APPSPAWN_ENV_FILE_FORMAT_ERROR;
|
|
}
|
|
|
|
std::string_view lineView(line);
|
|
lineView = TrimWhitespaceView(lineView);
|
|
if (lineView.empty() || lineView[0] == '#') {
|
|
return APPSPAWN_ENV_FILE_EMPTY;
|
|
}
|
|
|
|
size_t equalsPos = lineView.find('=');
|
|
if (equalsPos == std::string_view::npos) {
|
|
APPSPAWN_LOGW("Invalid environment variable format: %{public}s (missing '=')", line.c_str());
|
|
return APPSPAWN_ENV_FILE_FORMAT_ERROR;
|
|
}
|
|
|
|
std::string_view rawName = lineView.substr(0, equalsPos);
|
|
envName = std::string(TrimWhitespaceView(rawName));
|
|
if (envName.empty()) {
|
|
APPSPAWN_LOGW("Invalid environment variable: empty name");
|
|
return APPSPAWN_ENV_FILE_FORMAT_ERROR;
|
|
}
|
|
std::string_view rawValue = lineView.substr(equalsPos + 1);
|
|
std::string trimmedValue = std::string(TrimWhitespaceView(rawValue));
|
|
size_t valueLen = trimmedValue.length();
|
|
if (valueLen >= MIN_QUOTED_VALUE_LENGTH && (trimmedValue[0] == '"' || trimmedValue[0] == '\'') &&
|
|
trimmedValue[valueLen - 1] == trimmedValue[0]) {
|
|
envValue = trimmedValue.substr(QUOTE_LENGTH, valueLen - TWO_QUOTE_LENGTH);
|
|
} else {
|
|
envValue = trimmedValue;
|
|
}
|
|
return APPSPAWN_OK;
|
|
}
|
|
|
|
APPSPAWN_STATIC int32_t LoadCustomSandboxEnv(const char* envFilePath)
|
|
{
|
|
APPSPAWN_CHECK(envFilePath != nullptr, return APPSPAWN_ARG_INVALID, "envFilePath is nullptr.");
|
|
char normalizedPath[PATH_MAX] = {0};
|
|
int savedErrno = 0;
|
|
char *tmpPath = realpath(envFilePath, normalizedPath);
|
|
savedErrno = (tmpPath == nullptr) ? errno : 0;
|
|
APPSPAWN_CHECK(savedErrno != ENOENT, return APPSPAWN_OK, "Environment file %{public}s does not exist.",
|
|
envFilePath);
|
|
APPSPAWN_CHECK(tmpPath, return APPSPAWN_ARG_INVALID, "Failed to normalize path %{public}s, errno: %{public}d",
|
|
envFilePath, savedErrno);
|
|
|
|
std::ifstream file(normalizedPath);
|
|
bool isOpen = file.is_open();
|
|
savedErrno = (isOpen == false) ? errno : 0;
|
|
APPSPAWN_CHECK(savedErrno != ENOENT, return APPSPAWN_OK, "Environment file %{public}s does not exist.",
|
|
normalizedPath);
|
|
APPSPAWN_CHECK(isOpen, return APPSPAWN_ENV_FILE_READ_ERROR, "Failed to open %{public}s, errno: %{public}d",
|
|
normalizedPath, savedErrno);
|
|
|
|
std::string line;
|
|
std::string envName;
|
|
std::string envValue;
|
|
size_t lineCount = 0;
|
|
while (std::getline(file, line)) {
|
|
if (++lineCount > MAX_ENV_FILE_LINES) {
|
|
APPSPAWN_LOGE("Environment file exceeds maximum line count: %{public}zu (max: %{public}zu)",
|
|
lineCount, MAX_ENV_FILE_LINES);
|
|
return APPSPAWN_ENV_FILE_READ_ERROR;
|
|
}
|
|
|
|
int32_t parseRet = ParseEnvLine(line, envName, envValue);
|
|
if (parseRet != APPSPAWN_OK) {
|
|
continue;
|
|
}
|
|
|
|
// Set environment variable
|
|
int ret = setenv(envName.c_str(), envValue.c_str(), 1);
|
|
APPSPAWN_CHECK_LOGV(ret == 0, continue, "Failed to setenv %{public}s=%{public}s, errno: %{public}d",
|
|
envName.c_str(), envValue.c_str(), errno);
|
|
}
|
|
|
|
APPSPAWN_CHECK(!(file.fail() && !file.eof()), return APPSPAWN_ENV_FILE_READ_ERROR,
|
|
"Error reading %{public}s, errno: %{public}d", normalizedPath, errno);
|
|
return APPSPAWN_OK;
|
|
}
|
|
|
|
APPSPAWN_STATIC int SpawnSetCustomSandboxEnv(AppSpawnMgr *content, AppSpawningCtx *property)
|
|
{
|
|
APPSPAWN_LOGV("Spawning: set SpawnSetCustomSandboxEnv.");
|
|
if (CheckAppMsgFlagsSet(property, APP_FLAGS_CUSTOM_SANDBOX)) {
|
|
int32_t ret = LoadCustomSandboxEnv(ENV_FILE_PATH);
|
|
APPSPAWN_LOGV("Finished LoadCustomSandboxEnv result: %{public}d", ret);
|
|
}
|
|
return APPSPAWN_OK;
|
|
}
|
|
|
|
#define HM_ACCESS_TOKEN_ID_IOCTL_BASE 'A'
|
|
enum {
|
|
HM_GET_TOKEN_ID = 1,
|
|
HM_SET_TOKEN_ID,
|
|
HM_GET_FTOKEN_ID,
|
|
HM_SET_FTOKEN_ID,
|
|
HM_ADD_PERMISSION,
|
|
HM_REMOVE_PERMISSION,
|
|
HM_GET_PERMISSION,
|
|
HM_SET_PERMISSION,
|
|
HM_GET_CLOSEST_HAP_TOKENID,
|
|
HM_GET_FAMILY_TOKENIDS,
|
|
HM_GET_BINARY_PERMISSIONS,
|
|
HM_SET_USERID,
|
|
HM_GET_USERID,
|
|
HM_ACCESS_TOKENID_MAX_NR
|
|
};
|
|
|
|
#define ACCESS_TOKENID_SET_USERID _IOW(HM_ACCESS_TOKEN_ID_IOCTL_BASE, HM_SET_USERID, uint32_t)
|
|
#define ACCESS_TOKENID_GET_USERID _IOR(HM_ACCESS_TOKEN_ID_IOCTL_BASE, HM_GET_USERID, uint32_t)
|
|
|
|
constexpr const char* HDAC_DEV = "/dev/access_token_id";
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
int SetUserId(char *userIdStr)
|
|
{
|
|
APPSPAWN_CHECK(userIdStr != nullptr, return -1, "userIdStr == nullptr.");
|
|
APPSPAWN_LOGV("SetUserId called with userId=%{public}s", userIdStr);
|
|
char *endPtr = nullptr;
|
|
errno = 0;
|
|
const int numberBase = 10;
|
|
long long tmpUserId = strtoll(userIdStr, &endPtr, numberBase);
|
|
APPSPAWN_CHECK(endPtr != userIdStr, return -1,
|
|
"Failed to convert userId string '%s': no valid digits", userIdStr);
|
|
APPSPAWN_CHECK(*endPtr == '\0', return -1,
|
|
"Failed to convert userId string '%s': extra characters '%s'", userIdStr, endPtr);
|
|
APPSPAWN_CHECK(errno != ERANGE, return -1,
|
|
"UserId string '%s' causes long integer overflow/underflow", userIdStr);
|
|
if (tmpUserId < 0 || tmpUserId > UINT32_MAX) {
|
|
APPSPAWN_LOGE("UserId value %lld from string '%s' is out of uint32_t range [0, %u]",
|
|
tmpUserId, userIdStr, UINT32_MAX);
|
|
return -1;
|
|
}
|
|
|
|
uint32_t userId = static_cast<uint32_t>(tmpUserId);
|
|
int fdIoctl = open(HDAC_DEV, O_WRONLY);
|
|
APPSPAWN_CHECK(fdIoctl >= 0, return -1,
|
|
"Failed to open %{public}s: %{public}s", HDAC_DEV, strerror(errno));
|
|
int rc = ioctl(fdIoctl, ACCESS_TOKENID_SET_USERID, &userId);
|
|
if (rc < 0) {
|
|
APPSPAWN_LOGE("Failed to set userId=%{public}u: %{public}s", userId, strerror(errno));
|
|
}
|
|
close(fdIoctl);
|
|
return rc;
|
|
}
|
|
|
|
int GetUserId(uint32_t *userId)
|
|
{
|
|
APPSPAWN_CHECK(userId != nullptr, return -1, "userId == nullptr.");
|
|
errno = 0;
|
|
int fdIoctl = open(HDAC_DEV, O_RDONLY);
|
|
APPSPAWN_CHECK(fdIoctl >= 0, return -1,
|
|
"Failed to open %{public}s: %{public}s", HDAC_DEV, strerror(errno));
|
|
uint32_t userIdTmp = 0;
|
|
int rc = ioctl(fdIoctl, ACCESS_TOKENID_GET_USERID, &userIdTmp);
|
|
if (rc < 0) {
|
|
close(fdIoctl);
|
|
APPSPAWN_LOGE("Failed to get userId: %{public}s", strerror(errno));
|
|
return -1;
|
|
}
|
|
close(fdIoctl);
|
|
*userId = userIdTmp;
|
|
return rc;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
MODULE_CONSTRUCTOR(void)
|
|
{
|
|
const int32_t priority = HOOK_PRIO_COMMON + 2; // after SpawnSetAppEnv
|
|
AddAppSpawnHook(STAGE_CHILD_PRE_COLDBOOT, priority, SpawnSetCustomSandboxEnv);
|
|
}
|