diff --git a/contrib/android/dac_config.cpp b/contrib/android/dac_config.cpp new file mode 100644 index 00000000..422e0d52 --- /dev/null +++ b/contrib/android/dac_config.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2021 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. + */ + +#define __cpluscplus +#include "dac_config.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace { +struct DacConfig { + unsigned int uid; + unsigned int gid; + unsigned int mode; + uint64_t capabilities; + string path; + + DacConfig() : uid(0), gid(0), mode(0), capabilities(0), path("") {} + DacConfig(unsigned int m, unsigned int u, unsigned int g, uint64_t c, string p) : + uid(u), + gid(g), + mode(m), + capabilities(c), + path(p) {} + + void SetDefault(unsigned int m, unsigned int u, unsigned int g, uint64_t c, string p) + { + this->uid = u; + this->gid = g; + this->mode = m; + this->capabilities = c; + this->path = p; + } +}; + +unordered_map g_configMap; + +static string Trim(const string& s) +{ + if (s.size() == 0) { + return s; + } + + size_t start = 0; + size_t end = s.size() - 1; + + while (start < s.size() && isspace(s[start])) { + start++; + } + + while (end >= start && isspace(s[end])) { + end--; + } + + if (end < start) { + return ""; + } + + return s.substr(start, end - start + 1); +} + +unordered_map g_capStrCapNum = { + { "CAP_CHOWN", CAP_CHOWN }, + { "CAP_DAC_OVERRIDE", CAP_DAC_OVERRIDE }, + { "CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH }, + { "CAP_FOWNER", CAP_FOWNER }, + { "CAP_FSETID", CAP_FSETID }, + { "CAP_KILL", CAP_KILL }, + { "CAP_SETGID", CAP_SETGID }, + { "CAP_SETUID", CAP_SETUID }, + { "CAP_LINUX_IMMUTABLE", CAP_LINUX_IMMUTABLE }, + { "CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE }, + { "CAP_NET_BROADCAST", CAP_NET_BROADCAST }, + { "CAP_NET_ADMIN", CAP_NET_ADMIN }, + { "CAP_NET_RAW", CAP_NET_RAW }, + { "CAP_IPC_LOCK", CAP_IPC_LOCK }, + { "CAP_IPC_OWNER", CAP_IPC_OWNER }, + { "CAP_SYS_MODULE", CAP_SYS_MODULE }, + { "CAP_SYS_RAWIO", CAP_SYS_RAWIO }, + { "CAP_SYS_CHROOT", CAP_SYS_CHROOT }, + { "CAP_SYS_PTRACE", CAP_SYS_PTRACE }, + { "CAP_SYS_PACCT", CAP_SYS_PACCT }, + { "CAP_SYS_ADMIN", CAP_SYS_ADMIN }, + { "CAP_SYS_ROOT", CAP_SYS_BOOT }, + { "CAP_SYS_NICE", CAP_SYS_NICE }, + { "CAP_SYS_RESOURCE", CAP_SYS_RESOURCE }, + { "CAP_SYS_TIME", CAP_SYS_TIME }, + { "CAP_SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG }, + { "CAP_MKNOD", CAP_MKNOD }, + { "CAP_LEASE", CAP_LEASE }, + { "CAP_AUDIT_WRITE", CAP_AUDIT_WRITE }, + { "CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL }, + { "CAP_SETFCAP", CAP_SETFCAP }, + { "CAP_MAC_OVERRIDE", CAP_MAC_OVERRIDE }, + { "CAP_MAC_ADMIN", CAP_MAC_ADMIN }, + { "CAP_SYSLOG", CAP_SYSLOG }, + { "CAP_WAKE_ALARM", CAP_WAKE_ALARM }, + { "CAP_BLOCK_SUSPEND", CAP_BLOCK_SUSPEND }, +}; + +static uint64_t GetCap(string cap) +{ + if (isdigit(cap[0])) { + return stoll(cap); + } + + stringstream ss(cap); + string value; + uint64_t c = 0; + while (getline(ss, value, '|')) { + value = Trim(value); + if (g_capStrCapNum.count(value)) { + c |= (1ULL << g_capStrCapNum[value]); + } + } + + return c; +} + +enum { + DAC_PATH_IDX = 0, + DAC_MODE_IDX, + DAC_UID_IDX, + DAC_GID_IDX, + DAC_CAP_IDX, + DAC_NUM +}; + +extern "C" { + int LoadDacConfig(const char* fn) + { + ifstream readFile(fn); + if (readFile.fail()) { + return -1; + } + + string str; + vector values(DAC_NUM, ""); // path, mode, uid, gid, cap + while (getline(readFile, str)) { + str = Trim(str); + if (str.empty() || str[0] == '#') { + continue; + } + + stringstream ss(str); + string value; + int i = 0; + while (getline(ss, value, ',')) { + if (i >= DAC_NUM) { + break; + } + + value = Trim(value); + if (value.empty()) { + continue; + } + values[i++] = value; + } + + if (i != DAC_NUM) { + continue; + } + + int uid = 0; + if (isdigit(values[DAC_UID_IDX][0])) { + uid = stoi(values[DAC_UID_IDX]); + } + + int gid = 0; + if (isdigit(values[DAC_GID_IDX][0])) { + gid = stoi(values[DAC_GID_IDX]); + } + + uint64_t cap = GetCap(values[DAC_CAP_IDX]); + DacConfig dacConfig(stoi(values[DAC_MODE_IDX], 0, 8), uid, gid, cap, values[DAC_PATH_IDX]); // 8 oct + g_configMap[dacConfig.path] = dacConfig; + } + + return 0; + } + + void GetDacConfig(const char* path, int dir, char* targetOutPath, + unsigned* uid, unsigned* gid, unsigned* mode, + uint64_t* capabilities) + { + if (path && path[0] == '/') { + path++; + } + + (void)targetOutPath; + string str = path; + string str2; + DacConfig dacConfig(00755, 0, 0, 0, ""); + + if (dir == 0) { + dacConfig.SetDefault(00644, 0, 0, 0, ""); + } + + if (g_configMap.count(str)) { + dacConfig = g_configMap[str]; + } else if (dir == 0 && !str.empty()) { + for (auto i = str.size() - 1; i >= 0; i--) { + if (str[i] == '/') { + break; + } else { + str2 = str.substr(0, i) + "*"; + if (g_configMap.count(str2)) { + dacConfig = g_configMap[str2]; + break; + } + } + } + } + + *uid = dacConfig.uid; + *gid = dacConfig.gid; + *mode = dacConfig.mode; + *capabilities = dacConfig.capabilities; + } +} +} diff --git a/contrib/android/dac_config.h b/contrib/android/dac_config.h new file mode 100644 index 00000000..45b89393 --- /dev/null +++ b/contrib/android/dac_config.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef __DAC_CONFIG +#define __DAC_CONFIG +#include + +#ifdef __cpluscplus +extern "C" { +#endif + +int LoadDacConfig(const char* fn); +void GetDacConfig(const char* path, int dir, char* targetOutPath, + unsigned* uid, unsigned* gid, unsigned* mode, + uint64_t* capabilities); + +#ifdef __cpluscplus +} +#endif +#endif diff --git a/contrib/android/perms.c b/contrib/android/perms.c index 9c5ec05b..680d348e 100644 --- a/contrib/android/perms.c +++ b/contrib/android/perms.c @@ -358,16 +358,25 @@ errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out, /* Load the FS config */ if (fs_config_file) { +#if defined(__ANDROID__) retval = load_canned_fs_config(fs_config_file); +#else + retval = LoadDacConfig(fs_config_file); +#endif if (retval < 0) { com_err(__func__, retval, _("while loading fs_config \"%s\""), fs_config_file); return retval; } +#if defined(__ANDROID__) fs_config_func = canned_fs_config; } else if (mountpoint) fs_config_func = fs_config; +#else + fs_config_func = GetDacConfig; + } +#endif return __android_configure_fs(fs, src_dir, target_out, mountpoint, fs_config_func, sehnd, fixed_time, diff --git a/contrib/android/perms.h b/contrib/android/perms.h index 6d6a2129..2bb0021f 100644 --- a/contrib/android/perms.h +++ b/contrib/android/perms.h @@ -48,11 +48,12 @@ static inline errcode_t android_configure_fs(ext2_filsys fs, # include # if defined(__ANDROID__) # include -# endif # include # include # include - +# else /* !__ANDROID__ */ +#include "dac_config.h" +# endif errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out, char *mountpoint, -- diff --git a/contrib/android/dac_config.cpp b/contrib/android/dac_config.cpp index 422e0d52280ff4f142b278c5fedb04790846b9ee..1c76dfd7e7d1b067941b79e73311144d548a3179 100644 --- a/contrib/android/dac_config.cpp +++ b/contrib/android/dac_config.cpp @@ -35,14 +35,14 @@ struct DacConfig { string path; DacConfig() : uid(0), gid(0), mode(0), capabilities(0), path("") {} - DacConfig(unsigned int m, unsigned int u, unsigned int g, uint64_t c, string p) : + DacConfig(unsigned int m, unsigned int u, unsigned int g, uint64_t c, const string &p) : uid(u), gid(g), mode(m), capabilities(c), path(p) {} - void SetDefault(unsigned int m, unsigned int u, unsigned int g, uint64_t c, string p) + void SetDefault(unsigned int m, unsigned int u, unsigned int g, uint64_t c, const string &p) { this->uid = u; this->gid = g; @@ -198,33 +198,28 @@ extern "C" { return 0; } - void GetDacConfig(const char* path, int dir, char* targetOutPath, + void GetDacConfig(const char* path, int dir, char*, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { - if (path && path[0] == '/') { - path++; - } - - (void)targetOutPath; - string str = path; - string str2; + string str = (path != nullptr && *path == '/') ? path + 1 : path; DacConfig dacConfig(00755, 0, 0, 0, ""); if (dir == 0) { dacConfig.SetDefault(00644, 0, 0, 0, ""); } - if (g_configMap.count(str)) { - dacConfig = g_configMap[str]; + auto it = g_configMap.find(str); + if (it != g_configMap.end()) { + dacConfig = it->second; } else if (dir == 0 && !str.empty()) { - for (auto i = str.size() - 1; i >= 0; i--) { + for (int i = static_cast(str.size()) - 1; i >= 0; i--) { if (str[i] == '/') { break; } else { - str2 = str.substr(0, i) + "*"; - if (g_configMap.count(str2)) { - dacConfig = g_configMap[str2]; + it = g_configMap.find(str.substr(0, i) + "*"); + if (it != g_configMap.end()) { + dacConfig = it->second; break; } }