aboutsummaryrefslogtreecommitdiffstats
path: root/meta-security/classes
diff options
context:
space:
mode:
Diffstat (limited to 'meta-security/classes')
-rw-r--r--meta-security/classes/deploy-files.bbclass68
-rw-r--r--meta-security/classes/xattr-images.bbclass137
2 files changed, 205 insertions, 0 deletions
diff --git a/meta-security/classes/deploy-files.bbclass b/meta-security/classes/deploy-files.bbclass
new file mode 100644
index 000000000..ec19323a3
--- /dev/null
+++ b/meta-security/classes/deploy-files.bbclass
@@ -0,0 +1,68 @@
+DEPLOY_FILES_DIR = "${WORKDIR}/deploy-files-${PN}"
+SSTATETASKS += "do_deploy_files"
+do_deploy_files[sstate-inputdirs] = "${DEPLOY_FILES_DIR}"
+do_deploy_files[sstate-outputdirs] = "${DEPLOY_DIR}/files/"
+
+python do_deploy_files_setscene () {
+ sstate_setscene(d)
+}
+addtask do_deploy_files_setscene
+do_deploy_files[dirs] = "${DEPLOY_FILES_DIR} ${B}"
+
+# Use like this:
+# DEPLOY_FILES = "abc xyz"
+# DEPLOY_FILES_FROM[abc] = "file-ab dir-c"
+# DEPLOY_FILES_TO[abc] = "directory-for-abc"
+# DEPLOY_FILES_FROM[xyz] = "file-xyz"
+# DEPLOY_FILES_TO[xyz] = "directory-for-xyz"
+#
+# The destination directory will be created inside
+# ${DEPLOYDIR}. The source files and directories
+# will be copied such that their name and (for
+# directories) the directory tree below it will
+# be preserved. Shell wildcards are supported.
+#
+# The default DEPLOY_FILES copies files for the native host
+# and the target into two different directories. Use that as follows:
+# DEPLOY_FILES_FROM_native = "native-file"
+# DEPLOY_FILES_FROM_target = "target-file"
+
+DEPLOY_FILES ?= "native target"
+DEPLOY_FILES_FROM[native] ?= ""
+DEPLOY_FILES_TO[native] = "native/${BUILD_ARCH}"
+DEPLOY_FILES_FROM[target] ?= ""
+DEPLOY_FILES_TO[target] = "target/${MACHINE}"
+
+# We have to use a Python function to access variable flags. Because
+# bitbake then does not know about the dependency on these variables,
+# we need to explicitly declare that. DEPLOYDIR may change without
+# invalidating the sstate, therefore it is not listed.
+do_deploy_files[vardeps] = "DEPLOY_FILES DEPLOY_FILES_FROM DEPLOY_FILES_TO"
+python do_deploy_files () {
+ import glob
+ import os
+ import shutil
+
+ for file in (d.getVar('DEPLOY_FILES', True) or '').split():
+ bb.note('file: %s' % file)
+ from_pattern = d.getVarFlag('DEPLOY_FILES_FROM', file, True)
+ bb.note('from: %s' % from_pattern)
+ if from_pattern:
+ to = os.path.join(d.getVar('DEPLOY_FILES_DIR', True), d.getVarFlag('DEPLOY_FILES_TO', file, True))
+ bb.note('to: %s' % to)
+ if not os.path.isdir(to):
+ os.makedirs(to)
+ for from_path in from_pattern.split():
+ for src in (glob.glob(from_path) or [from_path]):
+ bb.note('Deploying %s to %s' % (src, to))
+ if os.path.isdir(src):
+ src_dirname = shutil._basename(src)
+ to = os.path.join(to, src_dirname)
+ if os.path.exists(to):
+ bb.utils.remove(to, True)
+ shutil.copytree(src, to)
+ else:
+ shutil.copy(src, to)
+}
+
+addtask deploy_files before do_build after do_compile
diff --git a/meta-security/classes/xattr-images.bbclass b/meta-security/classes/xattr-images.bbclass
new file mode 100644
index 000000000..565a3fb6e
--- /dev/null
+++ b/meta-security/classes/xattr-images.bbclass
@@ -0,0 +1,137 @@
+# Both Smack and IMA/EVM rely on xattrs. Inheriting this class ensures
+# that these xattrs get preserved in tar and jffs2 images.
+#
+# It also fixes the rootfs so that the content of directories with
+# SMACK::TRANSMUTE is correctly labelled. This is because pseudo does
+# not know the special semantic of SMACK::TRANSMUTE and omits the
+# updating of the Smack label when creating entries inside such a directory,
+# for example /etc (see base-files_%.bbappend). Without the fixup,
+# files already installed during the image creation would have different (and
+# wrong) Smack labels.
+
+# xattr support is expected to be compiled into mtd-utils. We just need to
+# use it.
+EXTRA_IMAGECMD_jffs2_append = " --with-xattr"
+
+# By default, OE-core uses tar from the host, which may or may not have the
+# --xattrs parameter which was introduced in 1.27. For image building we
+# use a recent enough tar instead.
+#
+# The GNU documentation does not specify whether --xattrs-include is necessary.
+# In practice, it turned out to be not needed when creating archives and
+# required when extracting, but it seems prudent to use it in both cases.
+IMAGE_DEPENDS_tar_append = " tar-replacement-native"
+EXTRANATIVEPATH += "tar-native"
+IMAGE_CMD_TAR = "tar --xattrs --xattrs-include=*"
+
+xattr_images_fix_transmute[dirs] = "${IMAGE_ROOTFS}"
+python xattr_images_fix_transmute () {
+ # The recursive updating of the Smack label ensures that each entry
+ # has the label set for its parent directories if one of those was
+ # marked as transmuting.
+ #
+ # In addition, "_" is set explicitly on everything that would not
+ # have a label otherwise. This is a workaround for tools like swupd
+ # which transfers files from a rootfs onto a target device where Smack
+ # is active: on the target, each file gets assigned a label, typically
+ # the one from the process which creates it. swupd (or rather, the tools
+ # it is currently built on) knows how to set security.SMACK64="_" when
+ # it is set on the original files, but it does not know that it needs
+ # to remove that xattr when not set.
+ import os
+ import errno
+
+ if getattr(os, 'getxattr', None):
+ # Python 3: os has xattr support.
+ def lgetxattr(f, attr):
+ try:
+ value = os.getxattr(f, attr, follow_symlinks=False)
+ return value.decode('utf8')
+ except OSError as ex:
+ if ex.errno == errno.ENODATA:
+ return None
+
+ def lsetxattr(f, attr, value):
+ os.setxattr(f, attr.encode('utf8'), value.encode('utf8'), follow_symlinks=False)
+ else:
+ # Python 2: xattr support only in xattr module.
+ #
+ # Cannot use the 'xattr' module, it is not part of a standard Python
+ # installation. Instead re-implement using ctypes. Only has to be good
+ # enough for xattrs that are strings. Always operates on the symlinks themselves,
+ # not what they point to.
+ import ctypes
+
+ # We cannot look up the xattr functions inside libc. That bypasses
+ # pseudo, which overrides these functions via LD_PRELOAD. Instead we have to
+ # find the function address and then create a ctypes function from it.
+ libdl = ctypes.CDLL("libdl.so.2")
+ _dlsym = libdl.dlsym
+ _dlsym.restype = ctypes.c_void_p
+ RTLD_DEFAULT = ctypes.c_void_p(0)
+ _lgetxattr = ctypes.CFUNCTYPE(ctypes.c_ssize_t, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_size_t,
+ use_errno=True)(_dlsym(RTLD_DEFAULT, 'lgetxattr'))
+ _lsetxattr = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int,
+ use_errno=True)(_dlsym(RTLD_DEFAULT, 'lsetxattr'))
+
+ def lgetxattr(f, attr):
+ len = 32
+ while True:
+ buffer = ctypes.create_string_buffer('\000' * len)
+ res = _lgetxattr(f, attr, buffer, ctypes.c_size_t(len))
+ if res >= 0:
+ return buffer.value
+ else:
+ error = ctypes.get_errno()
+ if ctypes.get_errno() == errno.ERANGE:
+ len *= 2
+ elif error == errno.ENODATA:
+ return None
+ else:
+ raise IOError(error, 'lgetxattr(%s, %s): %d = %s = %s' %
+ (f, attr, error, errno.errorcode[error], os.strerror(error)))
+
+ def lsetxattr(f, attr, value):
+ res = _lsetxattr(f, attr, value, ctypes.c_size_t(len(value)), ctypes.c_int(0))
+ if res != 0:
+ error = ctypes.get_errno()
+ raise IOError(error, 'lsetxattr(%s, %s, %s): %d = %s = %s' %
+ (f, attr, value, error, errno.errorcode[error], os.strerror(error)))
+
+ def visit(path, deflabel, deftransmute):
+ isrealdir = os.path.isdir(path) and not os.path.islink(path)
+ curlabel = lgetxattr(path, 'security.SMACK64')
+ transmute = lgetxattr(path, 'security.SMACK64TRANSMUTE') == 'TRUE'
+
+ if not curlabel:
+ # Since swupd doesn't remove the label from an updated file assigned by
+ # the target device's kernel upon unpacking the file from an update,
+ # we have to set the floor label explicitly even though it is the default label
+ # and thus adding it would create additional overhead. Otherwise this
+ # would result in hash mismatches reported by `swupd verify`.
+ lsetxattr(path, 'security.SMACK64', deflabel)
+ if not transmute and deftransmute and isrealdir:
+ lsetxattr(path, 'security.SMACK64TRANSMUTE', 'TRUE')
+
+ # Identify transmuting directories and change the default Smack
+ # label inside them. In addition, directories themselves must become
+ # transmuting.
+ if isrealdir:
+ if transmute:
+ deflabel = lgetxattr(path, 'security.SMACK64')
+ deftransmute = True
+ if deflabel is None:
+ raise RuntimeError('%s: transmuting directory without Smack label' % path)
+ elif curlabel:
+ # Directory with explicit label set and not transmuting => do not
+ # change the content unless we run into another transmuting directory.
+ deflabel = '_'
+ deftransmute = False
+
+ for entry in os.listdir(path):
+ visit(os.path.join(path, entry), deflabel, deftransmute)
+
+ visit('.', '_', False)
+}
+# Same logic as in ima-evm-rootfs.bbclass: try to run as late as possible.
+IMAGE_PREPROCESS_COMMAND_append_with-lsm-smack = " xattr_images_fix_transmute ; "