Check vendor_property_contexts namespaces
For devices launching with Android Q or later, vendor_property_contexts and odm_property_contexts should only contain vendor and odm properties. This checks property_contexts files in build time. To temporarily disable this check, users can set BUILD_BROKEN_VENDOR_PROPERTY_NAMESPACE := true in BoardConfig.mk. But VTS is still enforced, so users will have to fix the violations anyway. Bug: 175526482 Test: m vendor_property_contexts after making violations Change-Id: I99d6fff9033d78e1d276eed2682a2719dab84ae2
This commit is contained in:
parent
c281113ea8
commit
2bcc045724
3 changed files with 163 additions and 0 deletions
|
@ -364,7 +364,76 @@ func (m *selinuxContextsModule) buildHwServiceContexts(ctx android.ModuleContext
|
|||
return m.buildGeneralContexts(ctx, inputs)
|
||||
}
|
||||
|
||||
func (m *selinuxContextsModule) checkVendorPropertyNamespace(ctx android.ModuleContext, inputs android.Paths) android.Paths {
|
||||
shippingApiLevel := ctx.DeviceConfig().ShippingApiLevel()
|
||||
ApiLevelR := android.ApiLevelOrPanic(ctx, "R")
|
||||
|
||||
rule := android.NewRuleBuilder(pctx, ctx)
|
||||
|
||||
// This list is from vts_treble_sys_prop_test.
|
||||
allowedPropertyPrefixes := []string{
|
||||
"ctl.odm.",
|
||||
"ctl.vendor.",
|
||||
"ctl.start$odm.",
|
||||
"ctl.start$vendor.",
|
||||
"ctl.stop$odm.",
|
||||
"ctl.stop$vendor.",
|
||||
"init.svc.odm.",
|
||||
"init.svc.vendor.",
|
||||
"ro.boot.",
|
||||
"ro.hardware.",
|
||||
"ro.odm.",
|
||||
"ro.vendor.",
|
||||
"odm.",
|
||||
"persist.odm.",
|
||||
"persist.vendor.",
|
||||
"vendor.",
|
||||
}
|
||||
|
||||
// persist.camera is also allowed for devices launching with R or eariler
|
||||
if shippingApiLevel.LessThanOrEqualTo(ApiLevelR) {
|
||||
allowedPropertyPrefixes = append(allowedPropertyPrefixes, "persist.camera.")
|
||||
}
|
||||
|
||||
var allowedContextPrefixes []string
|
||||
|
||||
if shippingApiLevel.GreaterThanOrEqualTo(ApiLevelR) {
|
||||
// This list is from vts_treble_sys_prop_test.
|
||||
allowedContextPrefixes = []string{
|
||||
"vendor_",
|
||||
"odm_",
|
||||
}
|
||||
}
|
||||
|
||||
var ret android.Paths
|
||||
for _, input := range inputs {
|
||||
cmd := rule.Command().
|
||||
BuiltTool("check_prop_prefix").
|
||||
FlagWithInput("--property-contexts ", input).
|
||||
FlagForEachArg("--allowed-property-prefix ", proptools.ShellEscapeList(allowedPropertyPrefixes)). // contains shell special character '$'
|
||||
FlagForEachArg("--allowed-context-prefix ", allowedContextPrefixes)
|
||||
|
||||
if !ctx.DeviceConfig().BuildBrokenVendorPropertyNamespace() {
|
||||
cmd.Flag("--strict")
|
||||
}
|
||||
|
||||
out := android.PathForModuleGen(ctx, "namespace_checked").Join(ctx, input.String())
|
||||
rule.Command().Text("cp -f").Input(input).Output(out)
|
||||
ret = append(ret, out)
|
||||
}
|
||||
rule.Build("check_namespace", "checking namespace of "+ctx.ModuleName())
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *selinuxContextsModule) buildPropertyContexts(ctx android.ModuleContext, inputs android.Paths) android.Path {
|
||||
// vendor/odm properties are enforced for devices launching with Android Q or later. So, if
|
||||
// vendor/odm, make sure that only vendor/odm properties exist.
|
||||
shippingApiLevel := ctx.DeviceConfig().ShippingApiLevel()
|
||||
ApiLevelQ := android.ApiLevelOrPanic(ctx, "Q")
|
||||
if (ctx.SocSpecific() || ctx.DeviceSpecific()) && shippingApiLevel.GreaterThanOrEqualTo(ApiLevelQ) {
|
||||
inputs = m.checkVendorPropertyNamespace(ctx, inputs)
|
||||
}
|
||||
|
||||
builtCtxFile := m.buildGeneralContexts(ctx, inputs)
|
||||
|
||||
var apiFiles android.Paths
|
||||
|
|
|
@ -87,3 +87,8 @@ python_binary_host {
|
|||
],
|
||||
defaults: ["py2_only"],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
name: "check_prop_prefix",
|
||||
srcs: ["check_prop_prefix.py"],
|
||||
}
|
||||
|
|
89
tests/check_prop_prefix.py
Normal file
89
tests/check_prop_prefix.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2021 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
# A line should look like:
|
||||
# {prop_name} u:object_r:{context_name}:s0
|
||||
line_regex = re.compile(r'^(\S+)\s+u:object_r:([^:]+):s0.*$')
|
||||
|
||||
# Parses a line in property_contexts and return a (prop, ctx) tuple.
|
||||
# Raises an error for any malformed entries.
|
||||
def parse_line(line):
|
||||
matched = line_regex.match(line)
|
||||
if not matched:
|
||||
raise ValueError('malformed entry "' + line + '" in property_contexts')
|
||||
|
||||
return matched.group(1, 2)
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Finds any violations in property_contexts, with given allowed prefixes. "
|
||||
"If any violations are found, return a nonzero (failure) exit code.")
|
||||
parser.add_argument("--property-contexts", help="Path to property_contexts file.")
|
||||
parser.add_argument("--allowed-property-prefix", action="extend", nargs="*",
|
||||
help="Allowed property prefixes. If empty, any properties are allowed.")
|
||||
parser.add_argument("--allowed-context-prefix", action="extend", nargs="*",
|
||||
help="Allowed context prefixes. If empty, any contexts are allowed.")
|
||||
parser.add_argument('--strict', action='store_true',
|
||||
help="Make the script fail if any violations are found.")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
args = parse_args()
|
||||
|
||||
violations = []
|
||||
|
||||
with open(args.property_contexts, 'r') as f:
|
||||
lines = f.read().split('\n')
|
||||
|
||||
for line in lines:
|
||||
tokens = line.strip()
|
||||
# if this line empty or a comment, skip
|
||||
if tokens == '' or tokens[0] == '#':
|
||||
continue
|
||||
|
||||
prop, context = parse_line(line)
|
||||
|
||||
violated = False
|
||||
|
||||
if args.allowed_property_prefix and not prop.startswith(tuple(args.allowed_property_prefix)):
|
||||
violated = True
|
||||
|
||||
if args.allowed_context_prefix and not context.startswith(tuple(args.allowed_context_prefix)):
|
||||
violated = True
|
||||
|
||||
if violated:
|
||||
violations.append(line)
|
||||
|
||||
if len(violations) > 0:
|
||||
print('******************************')
|
||||
print('%d violations found:' % len(violations))
|
||||
print('\n'.join(violations))
|
||||
print('******************************')
|
||||
print('%s contains properties which are not properly namespaced.' % args.property_contexts)
|
||||
print('This is enforced by VTS, so please fix such offending properties.')
|
||||
if args.allowed_property_prefix:
|
||||
print('Allowed property prefixes for %s: %s' % (args.property_contexts, args.allowed_property_prefix))
|
||||
if args.allowed_context_prefix:
|
||||
print('Allowed context prefixes for %s: %s' % (args.property_contexts, args.allowed_context_prefix))
|
||||
if args.strict:
|
||||
print('You can temporarily disable this check with setting BUILD_BROKEN_VENDOR_PROPERTY_NAMESPACE := true in BoardConfig.mk.')
|
||||
print('But property namespace is enforced by VTS, and you will need to fix such violations to pass VTS.')
|
||||
print('See test/vts-testcase/security/system_property/vts_treble_sys_prop_test.py for the detail of the VTS.')
|
||||
sys.exit(1)
|
Loading…
Reference in a new issue