Use generic isSelector

seapp_contexts supports multiple boolean attributes: isPrivApp,
isEphemeralApp, isIsolatedComputeApp, isSdkSandboxAudit,
isSdkSandboxNext, fromRunAs. Each of these exists to support a specific
labelling scenario from the framework. When a new predicate is required,
an update to libselinux is also required. This change generically
handles any attribute starting with "is" and maps it directly
(case-insensitive) to the same seinfo field.

It is assumed that only one of these is required at a time. An error is
raised if seapp_contexts contains multiple is-selector within one rule.
An error is raised if seinfo contains multiple is-selector.

The order for comparison between seapp_contexts is altered: an entry
with an is-selector will be prioritized over one with an unspecifed
is-selector. This is not quite the previous order (e.g., isPrivApp <
targetSdkVersion < fromRunAs), but it is understood that the previous
order was not intentional and emerged from the incremental contributions
to this library.

The boolean info.isPreinstalledApp is replaced by checking the first
byte of info.partition.

Test: atest --host libselinux_test
Bug: 307635909
Change-Id: Ice3b84870e3255f6d9357d9750acbe9691b45aad
This commit is contained in:
Thiébaud Weksteen 2023-11-21 20:36:32 +11:00
parent 7fd89c00f7
commit 3d85f1e116
3 changed files with 144 additions and 153 deletions

View file

@ -105,14 +105,7 @@ int seapp_context_reload_internal(const path_alts_t *context_paths);
/* A parsed seinfo */ /* A parsed seinfo */
struct parsed_seinfo { struct parsed_seinfo {
char base[SEINFO_BUFSIZ]; char base[SEINFO_BUFSIZ];
#define IS_PRIV_APP (1 << 0) char isSelector[SEINFO_BUFSIZ];
#define IS_FROM_RUN_AS (1 << 1)
#define IS_EPHEMERAL_APP (1 << 2)
#define IS_ISOLATED_COMPUTE_APP (1 << 3)
#define IS_SDK_SANDBOX_AUDIT (1 << 4)
#define IS_SDK_SANDBOX_NEXT (1 << 5)
int32_t is;
bool isPreinstalledApp;
char partition[SEINFO_BUFSIZ]; char partition[SEINFO_BUFSIZ];
int32_t targetSdkVersion; int32_t targetSdkVersion;
}; };

View file

@ -128,18 +128,14 @@ static void free_prefix_str(struct prefix_str *p)
struct seapp_context { struct seapp_context {
/* input selectors */ /* input selectors */
bool isSystemServer; bool isSystemServer;
bool isEphemeralAppSet;
bool isEphemeralApp;
struct prefix_str user; struct prefix_str user;
char *seinfo; char *seinfo;
struct prefix_str name; struct prefix_str name;
bool isPrivAppSet;
bool isPrivApp;
int32_t minTargetSdkVersion; int32_t minTargetSdkVersion;
bool fromRunAs; /* name of a boolean selector such as isPrivApp, fromRunAs,
bool isIsolatedComputeApp; * isIsolatedComputeApp, etc. */
bool isSdkSandboxAudit; char *isSelector;
bool isSdkSandboxNext; bool isSelectorValue;
/* outputs */ /* outputs */
char *domain; char *domain;
char *type; char *type;
@ -153,6 +149,7 @@ static void free_seapp_context(struct seapp_context *s)
if (!s) if (!s)
return; return;
free(s->isSelector);
free_prefix_str(&s->user); free_prefix_str(&s->user);
free(s->seinfo); free(s->seinfo);
free_prefix_str(&s->name); free_prefix_str(&s->name);
@ -181,11 +178,6 @@ static int seapp_context_cmp(const void *A, const void *B)
if (s1->isSystemServer != s2->isSystemServer) if (s1->isSystemServer != s2->isSystemServer)
return (s1->isSystemServer ? -1 : 1); return (s1->isSystemServer ? -1 : 1);
/* Give precedence to a specified isEphemeral= over an
* unspecified isEphemeral=. */
if (s1->isEphemeralAppSet != s2->isEphemeralAppSet)
return (s1->isEphemeralAppSet ? -1 : 1);
/* Give precedence to a specified user= over an unspecified user=. */ /* Give precedence to a specified user= over an unspecified user=. */
if (s1->user.str && !s2->user.str) if (s1->user.str && !s2->user.str)
return -1; return -1;
@ -224,9 +216,12 @@ static int seapp_context_cmp(const void *A, const void *B)
return (s1->name.len > s2->name.len) ? -1 : 1; return (s1->name.len > s2->name.len) ? -1 : 1;
} }
/* Give precedence to a specified isPrivApp= over an unspecified isPrivApp=. */ /* Give precedence to a specified isSelector (e.g., isPrivApp)
if (s1->isPrivAppSet != s2->isPrivAppSet) * over an unspecified isSelector. */
return (s1->isPrivAppSet ? -1 : 1); if(s1->isSelector && !s2->isSelector)
return -1;
if(!s1->isSelector && s2->isSelector)
return 1;
/* Give precedence to a higher minTargetSdkVersion= over a lower minTargetSdkVersion=. /* Give precedence to a higher minTargetSdkVersion= over a lower minTargetSdkVersion=.
* If unspecified, minTargetSdkVersion has a default value of 0. * If unspecified, minTargetSdkVersion has a default value of 0.
@ -236,10 +231,6 @@ static int seapp_context_cmp(const void *A, const void *B)
else if (s1->minTargetSdkVersion < s2->minTargetSdkVersion) else if (s1->minTargetSdkVersion < s2->minTargetSdkVersion)
return 1; return 1;
/* Give precedence to fromRunAs=true. */
if (s1->fromRunAs != s2->fromRunAs)
return (s1->fromRunAs ? -1 : 1);
/* Give precedence to platform side contexts */ /* Give precedence to platform side contexts */
bool isS1Platform = is_platform(s1->partition); bool isS1Platform = is_platform(s1->partition);
bool isS2Platform = is_platform(s2->partition); bool isS2Platform = is_platform(s2->partition);
@ -375,16 +366,6 @@ int seapp_context_reload_internal(const path_alts_t *context_paths)
free_seapp_context(cur); free_seapp_context(cur);
goto err; goto err;
} }
} else if (!strcasecmp(name, "isEphemeralApp")) {
cur->isEphemeralAppSet = true;
if (!strcasecmp(value, "true"))
cur->isEphemeralApp = true;
else if (!strcasecmp(value, "false"))
cur->isEphemeralApp = false;
else {
free_seapp_context(cur);
goto err;
}
} else if (!strcasecmp(name, "user")) { } else if (!strcasecmp(name, "user")) {
if (cur->user.str) { if (cur->user.str) {
free_seapp_context(cur); free_seapp_context(cur);
@ -485,55 +466,30 @@ int seapp_context_reload_internal(const path_alts_t *context_paths)
free_seapp_context(cur); free_seapp_context(cur);
goto oom; goto oom;
} }
} else if (!strcasecmp(name, "isPrivApp")) {
cur->isPrivAppSet = true;
if (!strcasecmp(value, "true"))
cur->isPrivApp = true;
else if (!strcasecmp(value, "false"))
cur->isPrivApp = false;
else {
free_seapp_context(cur);
goto err;
}
} else if (!strcasecmp(name, "minTargetSdkVersion")) { } else if (!strcasecmp(name, "minTargetSdkVersion")) {
cur->minTargetSdkVersion = get_minTargetSdkVersion(value); cur->minTargetSdkVersion = get_minTargetSdkVersion(value);
if (cur->minTargetSdkVersion < 0) { if (cur->minTargetSdkVersion < 0) {
free_seapp_context(cur); free_seapp_context(cur);
goto err; goto err;
} }
} else if (!strcasecmp(name, "fromRunAs")) { } else if ((!strncasecmp(name, "is", 2) && strlen(name) > 3) ||
if (!strcasecmp(value, "true")) !strcasecmp(name, "fromRunAs")) {
cur->fromRunAs = true; if (cur->isSelector) {
else if (!strcasecmp(value, "false")) selinux_log(SELINUX_ERROR, "%s: isSelector set twice %s",
cur->fromRunAs = false; __FUNCTION__, name);
else {
free_seapp_context(cur); free_seapp_context(cur);
goto err; goto err;
} }
} else if (!strcasecmp(name, "isIsolatedComputeApp")) { cur->isSelector = strdup(name);
if (!strcasecmp(value, "true")) if (!cur->isSelector) {
cur->isIsolatedComputeApp = true;
else if (!strcasecmp(value, "false"))
cur->isIsolatedComputeApp = false;
else {
free_seapp_context(cur); free_seapp_context(cur);
goto err; goto err;
} }
} else if (!strcasecmp(name, "isSdkSandboxAudit")) { if (!strcasecmp(value, "true")) {
if (!strcasecmp(value, "true")) cur->isSelectorValue = true;
cur->isSdkSandboxAudit = true; } else if (!strcasecmp(value, "false")) {
else if (!strcasecmp(value, "false")) cur->isSelectorValue = false;
cur->isSdkSandboxAudit = false; } else {
else {
free_seapp_context(cur);
goto err;
}
} else if (!strcasecmp(name, "isSdkSandboxNext")) {
if (!strcasecmp(value, "true"))
cur->isSdkSandboxNext = true;
else if (!strcasecmp(value, "false"))
cur->isSdkSandboxNext = false;
else {
free_seapp_context(cur); free_seapp_context(cur);
goto err; goto err;
} }
@ -547,8 +503,9 @@ int seapp_context_reload_internal(const path_alts_t *context_paths)
break; break;
} }
if (!cur->isPrivApp && cur->name.str && if ((!cur->isSelector || strcasecmp(cur->isSelector, "isPrivApp") || !cur->isSelectorValue) &&
(!cur->seinfo || !strcmp(cur->seinfo, "default"))) { cur->name.str &&
(!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n", selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n",
seapp_contexts_files[i], cur->name.str, lineno); seapp_contexts_files[i], cur->name.str, lineno);
free_seapp_context(cur); free_seapp_context(cur);
@ -582,11 +539,8 @@ int seapp_context_reload_internal(const path_alts_t *context_paths)
bool dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) && bool dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) &&
(!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) && (!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) &&
(!s1->name.str || !strcmp(s1->name.str, s2->name.str)) && (!s1->name.str || !strcmp(s1->name.str, s2->name.str)) &&
(!s1->isPrivAppSet || s1->isPrivApp == s2->isPrivApp) && (!s1->isSelector || !strcmp(s1->isSelector, s2->isSelector)) &&
(!s1->isEphemeralAppSet || s1->isEphemeralApp == s2->isEphemeralApp) && (s1->isSelectorValue == s2->isSelectorValue);
(s1->isIsolatedComputeApp == s2->isIsolatedComputeApp) &&
(s1->isSdkSandboxAudit == s2->isSdkSandboxAudit) &&
(s1->isSdkSandboxNext == s2->isSdkSandboxNext);
if (dup) { if (dup) {
selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n"); selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n");
@ -608,27 +562,21 @@ int seapp_context_reload_internal(const path_alts_t *context_paths)
int i; int i;
for (i = 0; i < nspec; i++) { for (i = 0; i < nspec; i++) {
cur = seapp_contexts[i]; cur = seapp_contexts[i];
selinux_log(SELINUX_INFO, "%s: isSystemServer=%s isEphemeralApp=%s " selinux_log(SELINUX_INFO, "%s: isSystemServer=%s %s=%s "
"isIsolatedComputeApp=%s isSdkSandboxAudit=%s isSdkSandboxNext=%s " "user=%s seinfo=%s name=%s minTargetSdkVersion=%d "
"user=%s seinfo=%s name=%s isPrivApp=%s minTargetSdkVersion=%d " " -> domain=%s type=%s level=%s levelFrom=%s",
"fromRunAs=%s -> domain=%s type=%s level=%s levelFrom=%s",
__FUNCTION__, __FUNCTION__,
cur->isSystemServer ? "true" : "false", cur->isSystemServer ? "true" : "false",
cur->isEphemeralAppSet ? (cur->isEphemeralApp ? "true" : "false") : "null", cur->isSelector ? cur->isSelector : "isX",
cur->isSelector ? (cur->isSelectorValue ? "true" : "false") : "null",
cur->user.str, cur->user.str,
cur->seinfo, cur->name.str, cur->seinfo, cur->name.str,
cur->isPrivAppSet ? (cur->isPrivApp ? "true" : "false") : "null",
cur->minTargetSdkVersion, cur->minTargetSdkVersion,
cur->fromRunAs ? "true" : "false",
cur->isIsolatedComputeApp ? "true" : "false",
cur->isSdkSandboxAudit ? "true" : "false",
cur->isSdkSandboxNext ? "true" : "false",
cur->domain, cur->type, cur->level, cur->domain, cur->type, cur->level,
levelFromName[cur->levelFrom]); levelFromName[cur->levelFrom]);
} }
} }
#endif #endif
ret = 0; ret = 0;
out: out:
@ -675,16 +623,21 @@ void selinux_android_seapp_context_init(void) {
*/ */
#define CAT_MAPPING_MAX_ID (0x1<<16) #define CAT_MAPPING_MAX_ID (0x1<<16)
#define PRIVILEGED_APP_STR "privapp"
#define ISOLATED_COMPUTE_APP_STR "isolatedComputeApp"
#define APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS_STR "isSdkSandboxAudit"
#define APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS_STR "isSdkSandboxNext"
#define EPHEMERAL_APP_STR "ephemeralapp"
#define TARGETSDKVERSION_STR "targetSdkVersion" #define TARGETSDKVERSION_STR "targetSdkVersion"
#define PARTITION_STR "partition" #define PARTITION_STR "partition"
#define FROM_RUNAS_STR "fromRunAs"
#define COMPLETE_STR "complete" #define COMPLETE_STR "complete"
/* Any selector from seapp_contexts starting with "is" is automatically mapped
* to an attribute of seinfo. For historical reasons, there are mappings that do
* not follow this convention. */
static char* selector_mappings[][2] = {
/* seinfo field, seapp_contexts selector */
{"privapp", "isPrivApp"},
{"isolatedComputeApp", "isIsolatedComputeApp"},
{"ephemeralapp", "isEphemeralApp"},
{"fromRunAs", "fromRunAs"}
};
static bool is_preinstalled_app_partition_valid(const char *app_policy, const char *app_partition) { static bool is_preinstalled_app_partition_valid(const char *app_policy, const char *app_partition) {
// We forbid system/system_ext/product installed apps from being labeled with vendor sepolicy. // We forbid system/system_ext/product installed apps from being labeled with vendor sepolicy.
// So, either the app shouldn't be platform, or the spec should be platform. // So, either the app shouldn't be platform, or the spec should be platform.
@ -725,6 +678,8 @@ int set_range_from_level(context_t ctx, enum levelFrom levelFrom, uid_t userid,
return 0; return 0;
} }
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
int parse_seinfo(const char* seinfo, struct parsed_seinfo* info) { int parse_seinfo(const char* seinfo, struct parsed_seinfo* info) {
char local_seinfo[SEINFO_BUFSIZ]; char local_seinfo[SEINFO_BUFSIZ];
@ -747,28 +702,29 @@ int parse_seinfo(const char* seinfo, struct parsed_seinfo* info) {
first = false; first = false;
continue; continue;
} }
if (!strcmp(token, PRIVILEGED_APP_STR)) { bool matched = false;
info->is |= IS_PRIV_APP; for (int i=0; i < ARRAY_SIZE(selector_mappings); i++) {
if (!strcmp(token, selector_mappings[i][0])) {
if(info->isSelector[0]) {
selinux_log(SELINUX_ERROR, "%s: isSelector already populated: %s in %s\n",
__FUNCTION__, token, seinfo);
return -1;
}
strcpy(info->isSelector, selector_mappings[i][1]);
matched = true;
break;
}
}
if (matched) {
continue; continue;
} }
if (!strcmp(token, EPHEMERAL_APP_STR)) { if (!strncmp(token, "is", 2)) {
info->is |= IS_EPHEMERAL_APP; if(info->isSelector[0]) {
continue; selinux_log(SELINUX_ERROR, "%s: isSelector already populated: %s in %s\n",
} __FUNCTION__, token, seinfo);
if (!strcmp(token, ISOLATED_COMPUTE_APP_STR)) { return -1;
info->is |= IS_ISOLATED_COMPUTE_APP; }
continue; strncpy(info->isSelector, token, strlen(token));
}
if (!strcmp(token, APPLY_SDK_SANDBOX_AUDIT_RESTRICTIONS_STR)) {
info->is |= IS_SDK_SANDBOX_AUDIT;
continue;
}
if (!strcmp(token, APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS_STR)) {
info->is |= IS_SDK_SANDBOX_NEXT;
continue;
}
if (!strcmp(token, FROM_RUNAS_STR)) {
info->is |= IS_FROM_RUN_AS;
continue; continue;
} }
if (!strncmp(token, TARGETSDKVERSION_STR, strlen(TARGETSDKVERSION_STR))) { if (!strncmp(token, TARGETSDKVERSION_STR, strlen(TARGETSDKVERSION_STR))) {
@ -792,7 +748,6 @@ int parse_seinfo(const char* seinfo, struct parsed_seinfo* info) {
__FUNCTION__, token, seinfo); __FUNCTION__, token, seinfo);
return -1; return -1;
} }
info->isPreinstalledApp = true;
strncpy(info->partition, subtoken, strlen(subtoken)); strncpy(info->partition, subtoken, strlen(subtoken));
continue; continue;
} }
@ -868,9 +823,6 @@ int seapp_context_lookup_internal(enum seapp_kind kind,
if (cur->isSystemServer != isSystemServer) if (cur->isSystemServer != isSystemServer)
continue; continue;
if (cur->isEphemeralAppSet && cur->isEphemeralApp != ((info.is & IS_EPHEMERAL_APP) != 0))
continue;
if (cur->user.str) { if (cur->user.str) {
if (cur->user.is_prefix) { if (cur->user.is_prefix) {
if (strncasecmp(username, cur->user.str, cur->user.len-1)) if (strncasecmp(username, cur->user.str, cur->user.len-1))
@ -899,23 +851,16 @@ int seapp_context_lookup_internal(enum seapp_kind kind,
} }
} }
if (cur->isPrivAppSet && cur->isPrivApp != ((info.is & IS_PRIV_APP) != 0))
continue;
if (cur->minTargetSdkVersion > info.targetSdkVersion) if (cur->minTargetSdkVersion > info.targetSdkVersion)
continue; continue;
if (cur->fromRunAs != ((info.is & IS_FROM_RUN_AS) != 0)) if (cur->isSelector && cur->isSelectorValue) {
continue; if (!info.isSelector[0])
continue;
if (cur->isIsolatedComputeApp != ((info.is & IS_ISOLATED_COMPUTE_APP) != 0)) if (strcasecmp(info.isSelector, cur->isSelector)) {
continue; continue;
}
if (cur->isSdkSandboxAudit != ((info.is & IS_SDK_SANDBOX_AUDIT) != 0)) }
continue;
if (cur->isSdkSandboxNext != ((info.is & IS_SDK_SANDBOX_NEXT) != 0))
continue;
if (kind == SEAPP_TYPE && !cur->type) if (kind == SEAPP_TYPE && !cur->type)
continue; continue;
@ -940,7 +885,7 @@ int seapp_context_lookup_internal(enum seapp_kind kind,
goto oom; goto oom;
} }
if (info.isPreinstalledApp if (info.partition[0]
&& !is_preinstalled_app_partition_valid(cur->partition, info.partition)) { && !is_preinstalled_app_partition_valid(cur->partition, info.partition)) {
// TODO(b/280547417): make this an error after fixing violations // TODO(b/280547417): make this an error after fixing violations
selinux_log(SELINUX_WARNING, selinux_log(SELINUX_WARNING,

View file

@ -11,8 +11,17 @@ using android::base::WriteStringToFile;
using std::string; using std::string;
class AndroidSELinuxTest : public ::testing::Test { class AndroidSELinuxTest : public ::testing::Test {
protected: protected:
void SetUp() override {
default_seapp_context_ = StringPrintf("%s/seapp_contexts", tdir_.path);
default_seapp_path_alts_ = { .paths = {
{ default_seapp_context_.c_str() }
}};
}
TemporaryDir tdir_; TemporaryDir tdir_;
string default_seapp_context_;
path_alts_t default_seapp_path_alts_;
}; };
TEST_F(AndroidSELinuxTest, LoadAndLookupServiceContext) TEST_F(AndroidSELinuxTest, LoadAndLookupServiceContext)
@ -84,19 +93,13 @@ TEST_F(AndroidSELinuxTest, FailLoadingServiceContext)
TEST_F(AndroidSELinuxTest, LoadAndLookupSeAppContext) TEST_F(AndroidSELinuxTest, LoadAndLookupSeAppContext)
{ {
string seapp_contexts =
StringPrintf("%s/seapp_contexts", tdir_.path);
WriteStringToFile( WriteStringToFile(
"# some comment\n" "# some comment\n"
"user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user\n", "user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user\n",
seapp_contexts); default_seapp_context_);
const path_alts_t seapp_paths = { .paths = { EXPECT_EQ(seapp_context_reload_internal(&default_seapp_path_alts_), 0);
{ seapp_contexts.c_str() }
}};
EXPECT_EQ(seapp_context_reload_internal(&seapp_paths), 0);
context_t ctx = context_new("u:r:unknown"); context_t ctx = context_new("u:r:unknown");
int ret = seapp_context_lookup_internal(SEAPP_DOMAIN, 10001, false, "platform", "com.android.test1", ctx); int ret = seapp_context_lookup_internal(SEAPP_DOMAIN, 10001, false, "platform", "com.android.test1", ctx);
@ -111,6 +114,42 @@ TEST_F(AndroidSELinuxTest, LoadAndLookupSeAppContext)
context_free(ctx); context_free(ctx);
} }
TEST_F(AndroidSELinuxTest, LoadSeAppContextInsecure)
{
WriteStringToFile(
"user=_app name=com.android.test domain=platform_app type=app_data_file\n",
default_seapp_context_);
EXPECT_EQ(seapp_context_reload_internal(&default_seapp_path_alts_), -1);
WriteStringToFile(
"user=_app name=com.android.test isSdkSandbox=true domain=platform_app type=app_data_file\n",
default_seapp_context_);
EXPECT_EQ(seapp_context_reload_internal(&default_seapp_path_alts_), -1);
WriteStringToFile(
"user=_app isPrivApp=false name=com.android.test domain=platform_app type=app_data_file\n",
default_seapp_context_);
EXPECT_EQ(seapp_context_reload_internal(&default_seapp_path_alts_), -1);
}
TEST_F(AndroidSELinuxTest, LoadSeAppContextInsecureWithSeInfoOrPrivApp)
{
WriteStringToFile(
"user=_app isPrivApp=true name=com.android.test domain=platform_app type=app_data_file\n",
default_seapp_context_);
EXPECT_EQ(seapp_context_reload_internal(&default_seapp_path_alts_), 0);
WriteStringToFile(
"user=_app seinfo=platform name=com.android.test domain=platform_app type=app_data_file\n",
default_seapp_context_);
EXPECT_EQ(seapp_context_reload_internal(&default_seapp_path_alts_), 0);
}
TEST(AndroidSeAppTest, ParseValidSeInfo) TEST(AndroidSeAppTest, ParseValidSeInfo)
{ {
struct parsed_seinfo info; struct parsed_seinfo info;
@ -122,8 +161,7 @@ TEST(AndroidSeAppTest, ParseValidSeInfo)
EXPECT_EQ(ret, 0); EXPECT_EQ(ret, 0);
EXPECT_STREQ(info.base, "default"); EXPECT_STREQ(info.base, "default");
EXPECT_EQ(info.targetSdkVersion, 10000); EXPECT_EQ(info.targetSdkVersion, 10000);
EXPECT_EQ(info.is, IS_PRIV_APP); EXPECT_STREQ(info.isSelector, "isPrivApp");
EXPECT_EQ(info.isPreinstalledApp, true);
EXPECT_STREQ(info.partition, "system"); EXPECT_STREQ(info.partition, "system");
seinfo = "platform:ephemeralapp:partition=system:complete"; seinfo = "platform:ephemeralapp:partition=system:complete";
@ -132,8 +170,7 @@ TEST(AndroidSeAppTest, ParseValidSeInfo)
EXPECT_EQ(ret, 0); EXPECT_EQ(ret, 0);
EXPECT_STREQ(info.base, "platform"); EXPECT_STREQ(info.base, "platform");
EXPECT_EQ(info.targetSdkVersion, 0); EXPECT_EQ(info.targetSdkVersion, 0);
EXPECT_EQ(info.is, IS_EPHEMERAL_APP); EXPECT_STREQ(info.isSelector, "isEphemeralApp");
EXPECT_EQ(info.isPreinstalledApp, true);
EXPECT_STREQ(info.partition, "system"); EXPECT_STREQ(info.partition, "system");
seinfo = "bluetooth"; seinfo = "bluetooth";
@ -142,8 +179,16 @@ TEST(AndroidSeAppTest, ParseValidSeInfo)
EXPECT_EQ(ret, 0); EXPECT_EQ(ret, 0);
EXPECT_STREQ(info.base, "bluetooth"); EXPECT_STREQ(info.base, "bluetooth");
EXPECT_EQ(info.targetSdkVersion, 0); EXPECT_EQ(info.targetSdkVersion, 0);
EXPECT_EQ(info.isPreinstalledApp, false); EXPECT_STREQ(info.isSelector, "");
EXPECT_EQ(info.is, 0);
seinfo = "default:isSdkSandboxNext:partition=system:complete";
ret = parse_seinfo(seinfo.c_str(), &info);
EXPECT_EQ(ret, 0);
EXPECT_STREQ(info.base, "default");
EXPECT_EQ(info.targetSdkVersion, 0);
EXPECT_STREQ(info.isSelector, "isSdkSandboxNext");
EXPECT_STREQ(info.partition, "system");
} }
TEST(AndroidSeAppTest, ParseInvalidSeInfo) TEST(AndroidSeAppTest, ParseInvalidSeInfo)
@ -157,6 +202,14 @@ TEST(AndroidSeAppTest, ParseInvalidSeInfo)
seinfo = "default:targetSdkVersion=:complete"; seinfo = "default:targetSdkVersion=:complete";
ret = parse_seinfo(seinfo.c_str(), &info); ret = parse_seinfo(seinfo.c_str(), &info);
EXPECT_EQ(ret, -1); EXPECT_EQ(ret, -1);
seinfo = "default:privapp:ephemeralapp:complete";
ret = parse_seinfo(seinfo.c_str(), &info);
EXPECT_EQ(ret, -1);
seinfo = "default:isANewSelector:isAnotherOne:complete";
ret = parse_seinfo(seinfo.c_str(), &info);
EXPECT_EQ(ret, -1);
} }
TEST(AndroidSeAppTest, ParseOverflow) TEST(AndroidSeAppTest, ParseOverflow)