Skip to content

Commit

Permalink
meta-luneos: Add latest ls2 classes from OSE
Browse files Browse the repository at this point in the history
Signed-off-by: Herman van Hazendonk <[email protected]>
  • Loading branch information
Herrie82 authored and shr-project committed Jan 19, 2024
1 parent 1130de5 commit 6136883
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 36 deletions.
17 changes: 17 additions & 0 deletions meta-luneos/classes/webos_ls2_api_info.bbclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2021-2024 LG Electronics, Inc.

LS2_DIR = "${IMAGE_ROOTFS}${datadir}/luna-service2"

webos_ls2_api_info_data () {
if [ -d "${LS2_DIR}" -a -n "${BUILDHISTORY_DIR_IMAGE}" ] ; then
cd ${LS2_DIR}
if [ -d ${BUILDHISTORY_DIR_IMAGE}/ls2_api ] ; then
rm -rf ${BUILDHISTORY_DIR_IMAGE}/ls2_api
fi
mkdir -p ${BUILDHISTORY_DIR_IMAGE}/ls2_api
cp -r ./* ${BUILDHISTORY_DIR_IMAGE}/ls2_api/
cd -
fi
}

ROOTFS_POSTPROCESS_COMMAND += "webos_ls2_api_info_data ;"
112 changes: 112 additions & 0 deletions meta-luneos/classes/webos_ls2_api_list.bbclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Copyright (c) 2022-2024 LG Electronics, Inc.
#
# write_ls2_api_list
#
# This class adds write_ls2_api_list task.
# write_ls2_api_list can be run by bitbake -c write_ls2_api_list <image>
# ls2_api_list.json files of build

LS2_API_LIST_FILENAME ?= "ls2_api_list.json"

# We need ls2_api_list.json image
addtask write_ls2_api_list after do_rootfs before do_image
do_write_ls2_api_list[doc] = "Collects ls2 api information of the image"

python do_write_ls2_api_list() {
import os,json,glob,re

def remove_comments_from_json(json_file):
with open(json_file, 'r') as file:
lines = file.readlines()

clean_lines = []
for line in lines:
# Remove single-line comments
line = re.sub(r'//.*', '', line)
# Remove multi-line comments
line = re.sub(r'/\*.*?\*/', '', line, flags=re.DOTALL)
clean_lines.append(line)

# Combine the cleaned lines back into a single string
clean_json = ''.join(clean_lines)
# Parse the cleaned JSON
try:
parsed_json = json.loads(clean_json)
return parsed_json
except json.JSONDecodeError as e:
bb.note('Error parsing JSON: {e}')
return None

root_image_path =d.getVar('IMAGE_ROOTFS');
bb.note("perform do_write_ls2_api_list on ROOTFS : " + root_image_path)
def read_ls2_manifests_directories(image_rootfs):
manifests_directories = []
with open(os.path.join(image_rootfs, 'etc', 'luna-service2', 'ls-hubd.conf'), 'r') as f:
ls_hubd_conf = f.read()
for line in ls_hubd_conf.splitlines():
line = line.strip()
#ignore empty lines and comments
if not line or line.startswith('#'):
continue
#ignore section likes [Security]
elif line.startswith('[') and line.endswith(']'):
continue
else:
key, value = line.split('=', 1)
key = key.strip()
value = value.strip()
if key == 'ManifestsDirectories':
manifests_directories = value.split(';')
break
return manifests_directories

def search_for_manifest_files(root_image_path,manifest_dir_path):
manifest_file_path=os.path.join(root_image_path,manifest_dir_path.lstrip('/'),'*.manifest.json')
bb.debug(1,'Gathering info on api permission file from manifest_file_path %s' % manifest_file_path)
return glob.glob(manifest_file_path)

def get_api_permissions_for_manifest_file(root_image_path,manifest_file):
bb.debug(1,'Gathering info on api permission file from manifest_file %s' % manifest_file)
apis_details=[];
with open(manifest_file, 'r') as f:
manifest_data = json.load(f)
if 'apiPermissionFiles' in manifest_data:
for api_permission_file in manifest_data['apiPermissionFiles']:
api_permission_file_path = os.path.join(root_image_path, api_permission_file.lstrip('/'))
if not os.path.isfile(api_permission_file_path) or 'compat.' in api_permission_file_path:
bb.note("File not found or Compat files excluded : " + api_permission_file_path)
continue
# Remove comments and parse JSON
api_permission_data = remove_comments_from_json(api_permission_file_path)
if api_permission_data is None:
bb.note('Failed to parse JSON due to comment removal.')
for key, value in api_permission_data.items():
apis_details.extend(value)
return apis_details


manifests_directories = read_ls2_manifests_directories(root_image_path)
bb.note('Manifests directories: %s' % manifests_directories)
ls_api_info_data = []
# Iterate over the manifests directories and check for manifest files
for manifests_dir in manifests_directories:
# make absolute manifest path to search for files ending with .manifest.json'
manifest_files =search_for_manifest_files (root_image_path,manifests_dir)

for manifest_file in manifest_files:
bb.note('Gathering info on api permission file from manifest_file %s' % manifest_file)
apis_details= get_api_permissions_for_manifest_file(root_image_path,manifest_file)
if apis_details:
ls_api_info_data.append({os.path.basename(manifest_file).replace(".manifest.json", ""): apis_details})
bb.note("webOS Release Code Name ::: " + d.getVar('WEBOS_DISTRO_RELEASE_CODENAME'))
bb.note("webOS Distro Name ::: " + d.getVar('DISTRO'))
ls_api_info= {'ls2_api_list': ls_api_info_data, 'release_code_name': d.getVar('WEBOS_DISTRO_RELEASE_CODENAME'), 'distro': d.getVar('DISTRO')}

#write ls_api_info to file
ls2_output_file = d.getVar("LS2_API_LIST_FILENAME")
output = os.path.join(d.getVar('BUILDHISTORY_DIR_IMAGE'), ls2_output_file)
json_info_as_string = json.dumps(ls_api_info).replace("'", '"')
with open(output, 'w') as f:
f.write(json_info_as_string)
bb.note("BUILD Path of ls2_api_list.json file : " + output)
}
91 changes: 55 additions & 36 deletions meta-luneos/classes/webos_ls2_conf_validate.bbclass
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Copyright (c) 2023 LG Electronics, Inc.
# Copyright (c) 2023-2024 LG Electronics, Inc.
#
# LS2 security configuration validation
#

inherit webos_filesystem_paths

WEBOS_LS2_CONF_VALIDATE_ERROR_ON_WARNING ?= "0"
WEBOS_LS2_CONF_VALIDATE_SKIP_GROUP ?= " \
allowedNames \
"
WEBOS_LS2_CONF_VALIDATE_SKIP_GROUP ?= ""

# For some reason, using expr directly doesn't work
accumulate() {
Expand Down Expand Up @@ -134,37 +132,53 @@ fakeroot python do_validate_ls2_acg() {
import os
import json

# List of group names to skip checking
skip_group = d.getVar("WEBOS_LS2_CONF_VALIDATE_SKIP_GROUP").split()
if len(skip_group) > 0:
bb.debug(1, "WEBOS_LS2_CONF_VALIDATE_SKIP_GROUP:")
for group in skip_group:
bb.debug(1, " %s" % group)

rootfs_groups_d = d.getVar("IMAGE_ROOTFS") + d.getVar("webos_sysbus_groupsdir")
rootfs_api_perms_d = d.getVar("IMAGE_ROOTFS") + d.getVar("webos_sysbus_apipermissionsdir")
rootfs_clientperms_dir = d.getVar("IMAGE_ROOTFS") + d.getVar("webos_sysbus_permissionsdir")

# There can be no sysbus directories in a tiny image
if not os.path.isdir(rootfs_groups_d):
bb.note("Directory '%s' is missing, skipping validation." % rootfs_groups_d)
return
if not os.path.isdir(rootfs_api_perms_d):
bb.note("Directory '%s' is missing, skipping validation." % rootfs_api_perms_d)
return
if not os.path.isdir(rootfs_clientperms_dir):
bb.note("Directory '%s' is missing, skipping validation." % rootfs_clientperms_dir)
return

# List of group names to skip checking
skip_group = d.getVar("WEBOS_LS2_CONF_VALIDATE_SKIP_GROUP").split()
if len(skip_group) > 0:
msg = "=== LIST BEGIN: Groups considered as exception ===\n"
for group in sorted(skip_group):
msg += " %s\n" % group
msg += "=== LIST END ===\n"
bb.warn(msg)
# Always skip 'allowedNames' which is being used a key in old-style groups.json
skip_group.append("allowedNames")

# Returns a set of group names defined in 'dir'.
# Json files in 'dir' are expected to have groups as keys.
def read_groups(dir):
bb.debug(1, "Reading groups from %s" % dir)
msg = "Reading groups from %s\n" % dir
groups = set()
with os.scandir(dir) as it:
for entry in it:
if entry.is_file():
bb.debug(1, " %s" % entry.name)
msg += " %s\n" % entry.name
with open(entry.path) as fp:
groups_json = json.load(fp)
groups.update(filter(lambda x: x not in skip_group, groups_json.keys()))
bb.debug(1, "Done reading groups from %s" % dir)
msg += "Done reading groups from %s\n" % dir
bb.debug(1, msg)
return groups

# Returns a set of group names used in 'perm_entry' but not in 'groups'.
# 'groups' is a set of group names to match and 'perm_entry' is an
# iterator entry of a file that refers groups in an array form.
def get_missing_groups_in_perm(groups, perm_entry):
bb.debug(1, "Checking groups in %s" % perm_entry.name)
msg = "Checking groups in %s\n" % perm_entry.name
missing_groups = set()
with open(perm_entry.path) as fp:
perm_json = json.load(fp)
Expand All @@ -173,40 +187,44 @@ fakeroot python do_validate_ls2_acg() {
if not group in groups:
missing_groups.add(group)
for group in sorted(missing_groups):
bb.debug(1, " %s%s" % (group, " => missing" if not group in groups else ""))
bb.debug(1, "Done checking groups in %s" % perm_entry.name)
msg += " %s%s" % (group, " => missing" if not group in groups else "\n")
msg += "Done checking groups in %s\n" % perm_entry.name
bb.debug(1, msg)
return missing_groups

# First, we build a set of groups defined in "groups.d".
groups_defined = read_groups(rootfs_groups_d)
bb.debug(2, "=== LIST BEGIN: Groups defined in groups.d(%s) ===" % rootfs_groups_d)
msg = "=== LIST BEGIN: Groups defined in groups.d(%s) ===\n" % rootfs_groups_d
for group in sorted(groups_defined):
bb.debug(2, " %s" % group)
bb.debug(2, "=== LIST END ===")
msg += " %s\n" % group
msg += "=== LIST END ===\n"

# Second, get groups from "api-permissions.d".
# Those groups are also considered as valid.
groups_defined2 = read_groups(rootfs_api_perms_d)
bb.debug(2, "=== LIST BEGIN: Groups used in api-permissions.d(%s) ===" % rootfs_api_perms_d)
msg += "=== LIST BEGIN: Groups used in api-permissions.d(%s) ===\n" % rootfs_api_perms_d
for group in sorted(groups_defined2):
bb.debug(2, " %s" % group)
bb.debug(2, "=== LIST END ===")
msg += " %s\n" % group
msg += "=== LIST END ===\n"
bb.debug(2, msg)

# Merge groups from "groups.d" and "api-permissions.d" with showing differences.
# Those differences are recommended to define in "groups.d".
groups_defined2.difference_update(groups_defined)
cnt = len(groups_defined2)
if cnt > 0:
bb.warn("Found %d group(s) that appear only in api-permissions.d, consider define them in groups.d" % cnt)
bb.warn("=== LIST BEGIN: Groups used in api-permissions.d but not defined in groups.d ===")
msg = "Found %d group(s) that appear only in api-permissions.d, consider define them in groups.d\n" % cnt
msg += "=== LIST BEGIN: Groups used in api-permissions.d but not defined in groups.d ===\n"
for group in sorted(groups_defined2):
bb.warn(" %s" % group)
bb.warn("=== LIST END ===")
msg += " %s\n" % group
msg += "=== LIST END ===\n"
bb.warn(msg)
groups_valid = groups_defined.union(groups_defined2)
bb.note("=== LIST BEGIN: Groups considered as valid ===")
msg = "=== LIST BEGIN: Groups considered as valid ===\n"
for group in sorted(groups_valid):
bb.note(" %s" % group)
bb.note("=== LIST END ===")
msg += " %s\n" % group
msg += "=== LIST END ===\n"
bb.note(msg)

# Iterate files in "client-permissions.d" and list up groups
# which don't appear in the set built above.
Expand All @@ -224,17 +242,18 @@ fakeroot python do_validate_ls2_acg() {
# Raise a warning or error(if enabled) if any missing group is found.
cnt = len(groups_missing)
if cnt > 0:
bb.warn("Found %d group(s) used in client-permissions.d but not defined" % cnt)
bb.warn("=== LIST BEGIN ===")
msg = "Found %d group(s) used in client-permissions.d but not defined\n" % cnt
msg += "=== LIST BEGIN ===\n"
for group in sorted(groups_missing):
bb.warn("'%s' being used in:" % group)
msg += "'%s' being used in:\n" % group
for entry in sorted(groups_missing[group]):
bb.warn(" %s" % entry)
bb.warn("=== LIST END =====")
msg += " %s\n" % entry
msg += "=== LIST END =====\n"
bb.warn(msg)
if d.getVar("WEBOS_LS2_CONF_VALIDATE_ERROR_ON_WARNING") != "0":
bb.fatal("Fatal error while checking groups, aborting!")
}

addtask do_validate_ls2_security_conf after do_rootfs before do_image
addtask do_validate_ls2_acg after do_validate_ls2_security_conf before do_image
do_validate_ls2_security_conf[depends] += "libpbnjson-native:do_populate_sysroot"
do_validate_ls2_security_conf[depends] += "libpbnjson-native:do_populate_sysroot"

0 comments on commit 6136883

Please sign in to comment.