From patchwork Mon Apr 13 13:30:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3434 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C52256279B for ; Mon, 13 Apr 2020 15:31:04 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="wbtM4jZU"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CC35BA42 for ; Mon, 13 Apr 2020 15:31:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784664; bh=Amlkw2VprPW1gZLRcrjNQGCwYpmPhBXlwPLt4HC4CDU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=wbtM4jZUge/mfhTxEvkLFRo5UcYuyyYWRm5L0rVBtWaG+rLvs48Zs/IQweJZlHyAQ 5iRrBoz4VYSlJCByrefMAcgaX3kR1fs7VoWkI0qf+21PZwhyEiAKYwk8+fzSyhf0Nz DFjS0UAXFjn84Ioi5FsmSBu93z4Z4vTilQojUUCI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:37 +0300 Message-Id: <20200413133047.11913-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 01/11] ipa: vimc: Remove isolated VIMC IPA module X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:05 -0000 The isolated VIMC module isn't used in any test. Remove it to prepare for the rework of IPA module isolation. The feature can be added back later alongside corresponding tests if needed. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/ipa/vimc/meson.build | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/ipa/vimc/meson.build b/src/ipa/vimc/meson.build index 435c7d3160be..e827e75f9f91 100644 --- a/src/ipa/vimc/meson.build +++ b/src/ipa/vimc/meson.build @@ -1,15 +1,8 @@ -ipa_vimc_sources = [ - ['ipa_vimc', 'LGPL-2.1-or-later'], - ['ipa_vimc_isolate', 'Proprietary'], -] - -foreach t : ipa_vimc_sources - ipa = shared_module(t[0], 'vimc.cpp', - name_prefix : '', - include_directories : [ipa_includes, libipa_includes], - dependencies : libcamera_dep, - link_with : libipa, - install : true, - install_dir : ipa_install_dir, - cpp_args : '-DLICENSE="' + t[1] + '"') -endforeach +ipa = shared_module('ipa_vimc', 'vimc.cpp', + name_prefix : '', + include_directories : [ipa_includes, libipa_includes], + dependencies : libcamera_dep, + link_with : libipa, + install : true, + install_dir : ipa_install_dir, + cpp_args : '-DLICENSE="LGPL-2.1-or-later"') From patchwork Mon Apr 13 13:30:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3436 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6215F6279B for ; Mon, 13 Apr 2020 15:31:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MJTytnih"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D20DF1227 for ; Mon, 13 Apr 2020 15:31:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784665; bh=S59zomYLDzVk6EOXCg9yZaC0oaITFCIPd+Whg3BWzVE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MJTytnihhNQynjW127fCb/19VTwnjrM7v+twypxQnSV8jAB6JvxMGv09/cTRbmOb8 VwovTftPkdzfIDcvoSBQ50KgjxWnv6neWba0mQzqmFtf4P1hKc/ENSfDDUmQuuHYqM L3Z6W0Z4wJvYDRyEHTvteyVMa510u5uwrWHUG2yw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:38 +0300 Message-Id: <20200413133047.11913-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 02/11] libcamera: Add IPA module signing infrastructure X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:05 -0000 Add infrastructure to generate an RSA private key and sign IPA modules. The signatures are stored in separate files with a .sign suffix. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v1: - Use named variable to store $1 in gen-ipa-priv-key.sh - Add copyright notice to ipa-sign.h --- src/ipa/gen-ipa-priv-key.sh | 11 +++++++++++ src/ipa/ipa-sign.sh | 13 +++++++++++++ src/ipa/meson.build | 2 ++ src/ipa/rkisp1/meson.build | 25 +++++++++++++++++-------- src/ipa/vimc/meson.build | 12 +++++++++++- src/meson.build | 5 +++++ 6 files changed, 59 insertions(+), 9 deletions(-) create mode 100755 src/ipa/gen-ipa-priv-key.sh create mode 100755 src/ipa/ipa-sign.sh diff --git a/src/ipa/gen-ipa-priv-key.sh b/src/ipa/gen-ipa-priv-key.sh new file mode 100755 index 000000000000..919751f25b71 --- /dev/null +++ b/src/ipa/gen-ipa-priv-key.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2020, Google Inc. +# +# Author: Laurent Pinchart +# +# gen-ipa-priv-key.sh - Generate an RSA private key to sign IPA modules + +key="$1" + +openssl genpkey -algorithm RSA -out "${key}" -pkeyopt rsa_keygen_bits:2048 diff --git a/src/ipa/ipa-sign.sh b/src/ipa/ipa-sign.sh new file mode 100755 index 000000000000..8673dad18751 --- /dev/null +++ b/src/ipa/ipa-sign.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2020, Google Inc. +# +# Author: Laurent Pinchart +# +# ipa-sign.sh - Generate a signature for an IPA module + +key="$1" +input="$2" +output="$3" + +openssl dgst -sha256 -sign "${key}" -out "${output}" "${input}" diff --git a/src/ipa/meson.build b/src/ipa/meson.build index 73278a60a99f..cb4e3ab3388f 100644 --- a/src/ipa/meson.build +++ b/src/ipa/meson.build @@ -10,6 +10,8 @@ config_h.set('IPA_MODULE_DIR', subdir('libipa') +ipa_sign = find_program('ipa-sign.sh') + ipas = ['rkisp1', 'vimc'] foreach pipeline : get_option('pipelines') diff --git a/src/ipa/rkisp1/meson.build b/src/ipa/rkisp1/meson.build index 521518bd1237..6ccadcfbbe64 100644 --- a/src/ipa/rkisp1/meson.build +++ b/src/ipa/rkisp1/meson.build @@ -1,8 +1,17 @@ -rkisp1_ipa = shared_module('ipa_rkisp1', - 'rkisp1.cpp', - name_prefix : '', - include_directories : [ipa_includes, libipa_includes], - dependencies : libcamera_dep, - link_with : libipa, - install : true, - install_dir : ipa_install_dir) +ipa_name = 'ipa_rkisp1' + +mod = shared_module(ipa_name, + 'rkisp1.cpp', + name_prefix : '', + include_directories : [ipa_includes, libipa_includes], + dependencies : libcamera_dep, + link_with : libipa, + install : true, + install_dir : ipa_install_dir) + +custom_target(ipa_name + '.so.sign', + input : mod, + output : ipa_name + '.so.sign', + command : [ ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@' ], + install : true, + install_dir : ipa_install_dir) diff --git a/src/ipa/vimc/meson.build b/src/ipa/vimc/meson.build index e827e75f9f91..3097a12f964a 100644 --- a/src/ipa/vimc/meson.build +++ b/src/ipa/vimc/meson.build @@ -1,4 +1,7 @@ -ipa = shared_module('ipa_vimc', 'vimc.cpp', +ipa_name = 'ipa_vimc' + +mod = shared_module(ipa_name, + 'vimc.cpp', name_prefix : '', include_directories : [ipa_includes, libipa_includes], dependencies : libcamera_dep, @@ -6,3 +9,10 @@ ipa = shared_module('ipa_vimc', 'vimc.cpp', install : true, install_dir : ipa_install_dir, cpp_args : '-DLICENSE="LGPL-2.1-or-later"') + +custom_target(ipa_name + '.so.sign', + input : mod, + output : ipa_name + '.so.sign', + command : [ ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@' ], + install : true, + install_dir : ipa_install_dir) diff --git a/src/meson.build b/src/meson.build index d818d8b86d93..dc0e0c82b900 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,6 +2,11 @@ if get_option('android') subdir('android') endif +ipa_gen_priv_key = find_program('ipa/gen-ipa-priv-key.sh') +ipa_priv_key = custom_target('ipa-priv-key', + output : [ 'ipa-priv-key.pem' ], + command : [ ipa_gen_priv_key, '@OUTPUT@' ]) + subdir('libcamera') subdir('ipa') subdir('cam') From patchwork Mon Apr 13 13:30:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3437 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B53D36279B for ; Mon, 13 Apr 2020 15:31:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LITCtkr9"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5314124B for ; Mon, 13 Apr 2020 15:31:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784665; bh=xhfGgGeZtJQa3TVUEFsi/9eIzNIz9s++eT1AwcnuteQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=LITCtkr9FO09ZrPTX9OameNI7xMvhZ9Ry+4MofQGHdv/ILZx7G0NNmJmhqD54TY9I 1oPTabrriUiyRr5Z2Fz1jHRWPyOXxQwLhVvcGEaXM/PyOs7ga4z6Wy+sQY/VzWDekd pM84BpFgKKgcSXXKXILQL/U2TJx4k8qCcIjiGsOE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:39 +0300 Message-Id: <20200413133047.11913-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 03/11] libcamera: Add File helper class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:05 -0000 The File helper class is a RAII wrapper for a file to manage the file handle and memory-mapped regions. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v1: - Set error_ to 0 un successful unmap() - Document error() usage for open() --- src/libcamera/file.cpp | 342 ++++++++++++++++++++++++++++++ src/libcamera/include/file.h | 69 ++++++ src/libcamera/include/meson.build | 1 + src/libcamera/meson.build | 1 + 4 files changed, 413 insertions(+) create mode 100644 src/libcamera/file.cpp create mode 100644 src/libcamera/include/file.h diff --git a/src/libcamera/file.cpp b/src/libcamera/file.cpp new file mode 100644 index 000000000000..8f7466099222 --- /dev/null +++ b/src/libcamera/file.cpp @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * file.cpp - File I/O operations + */ + +#include "file.h" + +#include +#include +#include +#include +#include +#include + +#include "log.h" + +/** + * \file file.h + * \brief File I/O operations + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(File); + +/** + * \class File + * \brief Interface for I/O operations on files + * + * The File class provides an interface to perform I/O operations on files. It + * wraps opening, closing and mapping files in memory, and handles the cleaning + * of allocated resources. + * + * File instances are usually constructed with a file name, but the name can be + * set later through the setFileName() function. Instances are not automatically + * opened when constructed, and shall be opened explictly with open(). + * + * Files can be mapped to the process memory with map(). Mapped regions can be + * unmapped manually with munmap(), and are automatically unmapped when the File + * is destroyed. + */ + +/** + * \enum File::MapFlag + * \brief Flags for the File::map() function + * \var File::MapNoOption + * \brief No option (used as default value) + * \var File::MapPrivate + * \brief The memory region is mapped as private, changes are not reflected in + * the file constents + */ + +/** + * \enum File::OpenMode + * \brief Mode in which a file is opened + * \var File::NotOpen + * \brief The file is not open + * \var File::ReadOnly + * \brief The file is open for reading + * \var File::WriteOnly + * \brief The file is open for writing + * \var File::ReadWrite + * \brief The file is open for reading and writing + */ + +/** + * \brief Construct a File to represent the file \a name + * \param[in] name The file name + * + * Upon construction the File object is closed and shall be opened with open() + * before performing I/O operations. + */ +File::File(const std::string &name) + : name_(name), fd_(-1), mode_(NotOpen), error_(0) +{ +} + +/** + * \brief Construct a File without an associated name + * + * Before being used for any purpose, the file name shall be set with + * setFileName(). + */ +File::File() + : fd_(-1), mode_(NotOpen), error_(0) +{ +} + +/** + * \brief Destroy a File instance + * + * Any memory mapping associated with the File is unmapped, and the File is + * closed if it is open. + */ +File::~File() +{ + for (const auto &map : maps_) + munmap(map.first, map.second); + + close(); +} + +/** + * \fn const std::string &File::fileName() const + * \brief Retrieve the file name + * \return The file name + */ + +/** + * \brief Set the name of the file + * \param[in] name The name of the file + * + * The \a name can contain an absolute path, a relative path or no path at all. + * Calling this function on an open file results in undefined behaviour. + */ +void File::setFileName(const std::string &name) +{ + if (isOpen()) { + LOG(File, Error) + << "Can't set file name on already open file " << name_; + return; + } + + name_ = name; +} + +/** + * \brief Check if the file specified by fileName() exists + * + * This function checks if the file specified by fileName() exists. The File + * instance doesn't need to be open to check for file existence, and this + * function may return false even if the file is open, if it was deleted from + * the file system. + * + * \return True if the the file exists, false otherwise + */ +bool File::exists() const +{ + return exists(name_); +} + +/** + * \brief Open the file in the given mode + * \param[in] mode The open mode + * + * This function opens the file specified by fileName() in \a mode. If the file + * doesn't exist and the mode is WriteOnly or ReadWrite, this + * function will attempt to create the file. + * + * The error() status is updated. + * + * \return True on success, false otherwise + */ +bool File::open(File::OpenMode mode) +{ + if (isOpen()) { + LOG(File, Error) << "File " << name_ << " is already open"; + return false; + } + + int flags = (mode & ReadWrite) - 1; + + fd_ = ::open(name_.c_str(), flags); + if (fd_ < 0) { + error_ = -errno; + return false; + } + + mode_ = mode; + error_ = 0; + return true; +} + +/** + * \fn bool File::isOpen() const + * \brief Check if the file is open + * \return True if the file is open, false otherwise + */ + +/** + * \fn OpenMode File::openMode() const + * \brief Retrieve the file open mode + * \return The file open mode + */ + +/** + * \brief Close the file + * + * This function closes the File. If the File is not open, it performs no + * operation. Memory mappings created with map() are not destroyed when the + * file is closed. + */ +void File::close() +{ + if (fd_ == -1) + return; + + ::close(fd_); + fd_ = -1; + mode_ = NotOpen; +} + +/** + * \fn int File::error() const + * \brief Retrieve the file error status + * + * This function retrieves the error status from the last file open or I/O + * operation. The error status is a negative number as defined by errno.h. If + * no error occurred, this function returns 0. + * + * \return The file error status + */ + +/** + * \brief Retrieve the file size + * + * This function retrieves the size of the file on the filesystem. The File + * instance shall be open to retrieve its size. The error() status is not + * modified, error codes are returned directly on failure. + * + * \return The file size in bytes on success, or a negative error code otherwise + */ +ssize_t File::size() const +{ + if (!isOpen()) + return -EINVAL; + + struct stat st; + int ret = fstat(fd_, &st); + if (ret < 0) + return -errno; + + return st.st_size; +} + +/** + * \brief Map a region of the file in the process memory + * \param[in] offset The region offset within the file + * \param[in] size The region sise + * \param[in] flags The mapping flags + * + * This function maps a region of \a size bytes of the file starting at \a + * offset into the process memory. The File instance shall be open, but may be + * closed after mapping the region. Mappings stay valid when the File is + * closed, and are destroyed automatically when the File is deleted. + * + * If \a size is a negative value, this function maps the region starting at \a + * offset until the end of the file. + * + * The mapping memory protection is controlled by the file open mode, unless \a + * flags contains MapPrivate in which case the region is mapped in read/write + * mode. + * + * The error() status is updated. + * + * \return The mapped memory on success, or an empty span otherwise + */ +Span File::map(off_t offset, ssize_t size, enum File::MapFlag flags) +{ + if (!isOpen()) { + error_ = -EBADF; + return {}; + } + + if (size < 0) { + size = File::size(); + if (size < 0) { + error_ = size; + return {}; + } + + size -= offset; + } + + int mmapFlags = flags & MapPrivate ? MAP_PRIVATE : MAP_SHARED; + + int prot = 0; + if (mode_ & ReadOnly) + prot |= PROT_READ; + if (mode_ & WriteOnly) + prot |= PROT_WRITE; + if (flags & MapPrivate) + prot |= PROT_WRITE; + + void *map = mmap(NULL, size, prot, mmapFlags, fd_, offset); + if (map == MAP_FAILED) { + error_ = -errno; + return {}; + } + + maps_.emplace(map, size); + + error_ = 0; + return { static_cast(map), static_cast(size) }; +} + +/** + * \brief Unmap a region mapped with map() + * \param[in] addr The region address + * + * The error() status is updated. + * + * \return True on success, or false if an error occurs + */ +bool File::unmap(uint8_t *addr) +{ + auto iter = maps_.find(static_cast(addr)); + if (iter == maps_.end()) { + error_ = -ENOENT; + return false; + } + + int ret = munmap(addr, iter->second); + if (ret < 0) { + error_ = -errno; + return false; + } + + maps_.erase(iter); + + error_ = 0; + return true; +} + +/** + * \brief Check if the file specified by \a name exists + * \param[in] name The file name + * \return True if the file exists, false otherwise + */ +bool File::exists(const std::string &name) +{ + struct stat st; + int ret = stat(name.c_str(), &st); + if (ret < 0) + return false; + + return true; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/include/file.h b/src/libcamera/include/file.h new file mode 100644 index 000000000000..ea6f121cb6c5 --- /dev/null +++ b/src/libcamera/include/file.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * file.h - File I/O operations + */ +#ifndef __LIBCAMERA_FILE_H__ +#define __LIBCAMERA_FILE_H__ + +#include +#include +#include + +#include + +namespace libcamera { + +class File +{ +public: + enum MapFlag { + MapNoOption = 0, + MapPrivate = (1 << 0), + }; + + enum OpenMode { + NotOpen = 0, + ReadOnly = (1 << 0), + WriteOnly = (1 << 1), + ReadWrite = ReadOnly | WriteOnly, + }; + + File(const std::string &name); + File(); + ~File(); + + File(const File &) = delete; + File &operator=(const File &) = delete; + + const std::string &fileName() const { return name_; } + void setFileName(const std::string &name); + bool exists() const; + + bool open(OpenMode mode); + bool isOpen() const { return fd_ != -1; } + OpenMode openMode() const { return mode_; } + void close(); + + int error() const { return error_; } + ssize_t size() const; + + Span map(off_t offset = 0, ssize_t size = -1, + MapFlag flags = MapNoOption); + bool unmap(uint8_t *addr); + + static bool exists(const std::string &name); + +private: + std::string name_; + int fd_; + OpenMode mode_; + + int error_; + std::map maps_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_FILE_H__ */ diff --git a/src/libcamera/include/meson.build b/src/libcamera/include/meson.build index 17e2bed93fba..921ed5a063cb 100644 --- a/src/libcamera/include/meson.build +++ b/src/libcamera/include/meson.build @@ -8,6 +8,7 @@ libcamera_headers = files([ 'device_enumerator_sysfs.h', 'device_enumerator_udev.h', 'event_dispatcher_poll.h', + 'file.h', 'formats.h', 'ipa_context_wrapper.h', 'ipa_manager.h', diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 87fa09cde63d..4f5c41678781 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -14,6 +14,7 @@ libcamera_sources = files([ 'event_dispatcher.cpp', 'event_dispatcher_poll.cpp', 'event_notifier.cpp', + 'file.cpp', 'file_descriptor.cpp', 'formats.cpp', 'framebuffer_allocator.cpp', From patchwork Mon Apr 13 13:30:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3438 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0911A6279B for ; Mon, 13 Apr 2020 15:31:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="O0EeYu5G"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A5231A42 for ; Mon, 13 Apr 2020 15:31:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784665; bh=3vjkyhzAgooy6N+mAEkoE8z1/M7zDgPtGCd5Tgg527E=; h=From:To:Subject:Date:In-Reply-To:References:From; b=O0EeYu5GZbvO1byfc3GDbQUnqmRZcKfC3mnjOI68oXu59xAgWWCUk/+PSU07MnM1K Y96NMfHezM9P8XXslRrBvyFKImT86Mwi0bRFT42BA3Tb3j2ENVQPjb4ffD0Rv8IqgB yei49nYUJb0gdX/Z6hddUGOvJE4mVFS0o/WeRHzU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:40 +0300 Message-Id: <20200413133047.11913-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 04/11] test: Add File class tests X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:06 -0000 Add tests for the File class API. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v1: - Use mkstemp() to generate temporary file name - Add error() test --- test/file.cpp | 293 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 294 insertions(+) create mode 100644 test/file.cpp diff --git a/test/file.cpp b/test/file.cpp new file mode 100644 index 000000000000..6558399808f8 --- /dev/null +++ b/test/file.cpp @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * file.cpp - File I/O operations tests + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "file.h" +#include "test.h" + +using namespace std; +using namespace libcamera; + +class FileTest : public Test +{ +protected: + int init() + { + fileName_ = "/tmp/libcamera.test.XXXXXX"; + int fd = mkstemp(&fileName_.front()); + if (fd == -1) + return TestFail; + + write(fd, "libcamera", 9); + close(fd); + + return TestPass; + } + + int run() + { + /* Test static functions. */ + if (!File::exists("/dev/null")) { + cerr << "Valid file not found" << endl; + return TestFail; + } + + if (File::exists("/dev/null/invalid")) { + cerr << "Invalid file should not exist" << endl; + return TestFail; + } + + /* Test unnamed file. */ + File file; + + if (!file.fileName().empty()) { + cerr << "Unnamed file has non-empty file name" << endl; + return TestFail; + } + + if (file.exists()) { + cerr << "Unnamed file exists" << endl; + return TestFail; + } + + if (file.isOpen()) { + cerr << "File is open after construction" << endl; + return TestFail; + } + + if (file.openMode() != File::NotOpen) { + cerr << "File has invalid open mode after construction" + << endl; + return TestFail; + } + + if (file.size() >= 0) { + cerr << "Unnamed file has a size" << endl; + return TestFail; + } + + if (file.open(File::ReadWrite)) { + cerr << "Opening unnamed file succeeded" << endl; + return TestFail; + } + + if (file.error() == 0) { + cerr << "Open failure didn't set error" << endl; + return TestFail; + } + + /* Test named file referring to an invalid file. */ + file.setFileName("/dev/null/invalid"); + + if (file.fileName() != "/dev/null/invalid") { + cerr << "File reports incorrect file name" << endl; + return TestFail; + } + + if (file.exists()) { + cerr << "Invalid file exists" << endl; + return TestFail; + } + + if (file.isOpen()) { + cerr << "Invalid file is open after construction" << endl; + return TestFail; + } + + if (file.openMode() != File::NotOpen) { + cerr << "Invalid file has invalid open mode after construction" + << endl; + return TestFail; + } + + if (file.size() >= 0) { + cerr << "Invalid file has a size" << endl; + return TestFail; + } + + if (file.open(File::ReadWrite)) { + cerr << "Opening invalid file succeeded" << endl; + return TestFail; + } + + /* Test named file referring to a valid file. */ + file.setFileName("/dev/null"); + + if (!file.exists()) { + cerr << "Valid file does not exist" << endl; + return TestFail; + } + + if (file.isOpen()) { + cerr << "Valid file is open after construction" << endl; + return TestFail; + } + + if (file.openMode() != File::NotOpen) { + cerr << "Valid file has invalid open mode after construction" + << endl; + return TestFail; + } + + if (file.size() >= 0) { + cerr << "Invalid file has a size" << endl; + return TestFail; + } + + /* Test open and close. */ + if (!file.open(File::ReadWrite)) { + cerr << "Opening file failed" << endl; + return TestFail; + } + + if (!file.isOpen()) { + cerr << "Open file reported as closed" << endl; + return TestFail; + } + + if (file.openMode() != File::ReadWrite) { + cerr << "Open file has invalid open mode" << endl; + return TestFail; + } + + file.close(); + + if (file.isOpen()) { + cerr << "Closed file reported as open" << endl; + return TestFail; + } + + if (file.openMode() != File::NotOpen) { + cerr << "Closed file has invalid open mode" << endl; + return TestFail; + } + + /* Test size(). */ + file.setFileName("/proc/self/exe"); + + if (file.size() >= 0) { + cerr << "File has valid size before open" << endl; + return TestFail; + } + + file.open(File::ReadOnly); + + ssize_t size = file.size(); + if (size <= 0) { + cerr << "File has invalid size after open" << endl; + return TestFail; + } + + /* Test mapping and unmapping. */ + Span data = file.map(); + if (data.empty()) { + cerr << "Mapping of complete file failed" << endl; + return TestFail; + } + + if (data.size() != static_cast(size)) { + cerr << "Mapping of complete file has invalid size" << endl; + return TestFail; + } + + if (!file.unmap(data.data())) { + cerr << "Unmapping of complete file failed" << endl; + return TestFail; + } + + data = file.map(4096, 8192); + if (data.empty()) { + cerr << "Mapping of file region failed" << endl; + return TestFail; + } + + if (data.size() != 8192) { + cerr << "Mapping of file region has invalid size" << endl; + return TestFail; + } + + if (!file.unmap(data.data())) { + cerr << "Unmapping of file region failed" << endl; + return TestFail; + } + + file.close(); + + /* Test private mapping. */ + file.setFileName(fileName_); + file.open(File::ReadWrite); + + data = file.map(0, -1, File::MapPrivate); + if (data.empty()) { + cerr << "Private mapping failed" << endl; + return TestFail; + } + + std::string str{ reinterpret_cast(data.data()), data.size() }; + if (str != "libcamera") { + cerr << "Invalid contents of private mapping" << endl; + return TestFail; + } + + memcpy(data.data(), "LIBCAMERA", 9); + + if (!file.unmap(data.data())) { + cerr << "Private unmapping failed" << endl; + return TestFail; + } + + data = file.map(); + + str = { reinterpret_cast(data.data()), data.size() }; + if (str != "libcamera") { + cerr << "Private mapping changed file contents" << endl; + return TestFail; + } + + /* Test shared mapping. */ + data = file.map(); + if (data.empty()) { + cerr << "Shared mapping failed" << endl; + return TestFail; + } + + memcpy(data.data(), "LIBCAMERA", 9); + + if (!file.unmap(data.data())) { + cerr << "Shared unmapping failed" << endl; + return TestFail; + } + + data = file.map(); + + str = { reinterpret_cast(data.data()), data.size() }; + if (str != "LIBCAMERA") { + cerr << "Shared mapping failed to change file contents" + << endl; + return TestFail; + } + + return TestPass; + } + + void cleanup() + { + unlink(fileName_.c_str()); + } + +private: + std::string fileName_; +}; + +TEST_REGISTER(FileTest) diff --git a/test/meson.build b/test/meson.build index 8ab58ac15a2a..5a45a85effd3 100644 --- a/test/meson.build +++ b/test/meson.build @@ -26,6 +26,7 @@ internal_tests = [ ['event', 'event.cpp'], ['event-dispatcher', 'event-dispatcher.cpp'], ['event-thread', 'event-thread.cpp'], + ['file', 'file.cpp'], ['file-descriptor', 'file-descriptor.cpp'], ['message', 'message.cpp'], ['object', 'object.cpp'], From patchwork Mon Apr 13 13:30:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3439 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 66C4D62DFB for ; Mon, 13 Apr 2020 15:31:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XcWeMnF1"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0292A24B for ; Mon, 13 Apr 2020 15:31:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784666; bh=2V91YychmFFeYx9gcuCQcxpOTJvJzn3HRPNbrX8BeNs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=XcWeMnF1asAlhgJlhN/rLkY0N1Rn3B04lqv6BD/hGKwOq4K7tLgXDZwu9BRQ+hywU FYGBm/kLvs6qdPQDcYoAX1SxRzzs6xaNzrU/LOh4gIZIMLK15nIcJUTW/hmtOJH9jw UUVmL2cSrzwqf7KjPSADzBT3/4nrVyIJWY6keQsQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:41 +0300 Message-Id: <20200413133047.11913-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 05/11] libcamera: ipa_module: Simplify error handling in loadIPAModuleInfo() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:08 -0000 Use the File helper class to handle cleanup of the mapped file to simplify error handling in loadIPAModuleInfo(). Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/ipa_module.cpp | 58 +++++++++++++----------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index a01d0757ff8f..d1c411e14ba9 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -21,6 +21,7 @@ #include #include +#include "file.h" #include "log.h" #include "pipeline_handler.h" #include "utils.h" @@ -283,55 +284,38 @@ IPAModule::~IPAModule() int IPAModule::loadIPAModuleInfo() { - int fd = open(libPath_.c_str(), O_RDONLY); - if (fd < 0) { - int ret = -errno; + File file{ libPath_ }; + if (!file.open(File::ReadOnly)) { LOG(IPAModule, Error) << "Failed to open IPA library: " - << strerror(-ret); - return ret; + << strerror(-file.error()); + return file.error(); } - void *data = nullptr; - size_t dataSize; - void *map; - size_t soSize; - struct stat st; - int ret = fstat(fd, &st); - if (ret < 0) - goto close; - soSize = st.st_size; - map = mmap(NULL, soSize, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - ret = -errno; - goto close; + Span data = file.map(0, -1, File::MapPrivate); + int ret = elfVerifyIdent(data.data(), data.size()); + if (ret) { + LOG(IPAModule, Error) << "IPA module is not an ELF file"; + return ret; } - ret = elfVerifyIdent(map, soSize); - if (ret) - goto unmap; + void *info = nullptr; + size_t infoSize; - std::tie(data, dataSize) = elfLoadSymbol(map, soSize, "ipaModuleInfo"); - - if (data && dataSize == sizeof(info_)) - memcpy(&info_, data, dataSize); + std::tie(info, infoSize) = elfLoadSymbol(data.data(), data.size(), + "ipaModuleInfo"); + if (!info || infoSize != sizeof(info_)) { + LOG(IPAModule, Error) << "IPA module has no valid info"; + return -EINVAL; + } - if (!data) - goto unmap; + memcpy(&info_, info, infoSize); if (info_.moduleAPIVersion != IPA_MODULE_API_VERSION) { LOG(IPAModule, Error) << "IPA module API version mismatch"; - ret = -EINVAL; + return -EINVAL; } -unmap: - munmap(map, soSize); -close: - if (ret || !data) - LOG(IPAModule, Error) - << "Error loading IPA module info for " << libPath_; - - close(fd); - return ret; + return 0; } /** From patchwork Mon Apr 13 13:30:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3440 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D071062E08 for ; Mon, 13 Apr 2020 15:31:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vgTTbszQ"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 53118A42 for ; Mon, 13 Apr 2020 15:31:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784666; bh=mDMFBxDOFHt8mjIXkU1WLDMXbiXth2FTPKh9rV5EfPc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vgTTbszQpO4rXKmaH64x7tm4u+DNgW813xSw9sYn6y9U5K2nsEzsze7OOMHChZDSa eg/Bge+ZryRlBINIrHKX1vERVgZ+MVSmAXc5pcBYA9QUYBewveLsiC5Nx9YdSw/84v 3AoBkkzBoJ7s4vXgWgk6ysKSh4zejCS6YXWaXqmE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:42 +0300 Message-Id: <20200413133047.11913-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 06/11] libcamera: ipa_module: Use Span class to tie data and size X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:09 -0000 The IPAModule class passes pointers to data and the corresponding size as thwo different variables to several functions. Tie them together in a Span. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/ipa_module.cpp | 87 +++++++++++++++++------------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index d1c411e14ba9..5b6af15f2593 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -18,9 +18,10 @@ #include #include #include -#include #include +#include + #include "file.h" #include "log.h" #include "pipeline_handler.h" @@ -43,27 +44,26 @@ LOG_DEFINE_CATEGORY(IPAModule) namespace { template -typename std::remove_extent_t *elfPointer(void *map, off_t offset, - size_t fileSize, size_t objSize) +typename std::remove_extent_t *elfPointer(Span elf, off_t offset, + size_t objSize) { size_t size = offset + objSize; - if (size > fileSize || size < objSize) + if (size > elf.size() || size < objSize) return nullptr; return reinterpret_cast *> - (static_cast(map) + offset); + (reinterpret_cast(elf.data()) + offset); } template -typename std::remove_extent_t *elfPointer(void *map, off_t offset, - size_t fileSize) +typename std::remove_extent_t *elfPointer(Span elf, off_t offset) { - return elfPointer(map, offset, fileSize, sizeof(T)); + return elfPointer(elf, offset, sizeof(T)); } -int elfVerifyIdent(void *map, size_t soSize) +int elfVerifyIdent(Span elf) { - char *e_ident = elfPointer(map, 0, soSize); + char *e_ident = elfPointer(elf, 0); if (!e_ident) return -ENOEXEC; @@ -89,38 +89,36 @@ int elfVerifyIdent(void *map, size_t soSize) /** * \brief Retrieve address and size of a symbol from an mmap'ed ELF file - * \param[in] map Address of mmap'ed ELF file - * \param[in] soSize Size of mmap'ed ELF file (in bytes) + * \param[in] elf Address and size of mmap'ed ELF file * \param[in] symbol Symbol name * - * \return zero or error code, address or nullptr, size of symbol or zero, - * respectively + * \return The memory region storing the symbol on success, or an empty span + * otherwise */ -std::tuple -elfLoadSymbol(void *map, size_t soSize, const char *symbol) +Span elfLoadSymbol(Span elf, const char *symbol) { - ElfW(Ehdr) *eHdr = elfPointer(map, 0, soSize); + ElfW(Ehdr) *eHdr = elfPointer(elf, 0); if (!eHdr) - return std::make_tuple(nullptr, 0); + return {}; off_t offset = eHdr->e_shoff + eHdr->e_shentsize * eHdr->e_shstrndx; - ElfW(Shdr) *sHdr = elfPointer(map, offset, soSize); + ElfW(Shdr) *sHdr = elfPointer(elf, offset); if (!sHdr) - return std::make_tuple(nullptr, 0); + return {}; off_t shnameoff = sHdr->sh_offset; /* Locate .dynsym section header. */ ElfW(Shdr) *dynsym = nullptr; for (unsigned int i = 0; i < eHdr->e_shnum; i++) { offset = eHdr->e_shoff + eHdr->e_shentsize * i; - sHdr = elfPointer(map, offset, soSize); + sHdr = elfPointer(elf, offset); if (!sHdr) - return std::make_tuple(nullptr, 0); + return {}; offset = shnameoff + sHdr->sh_name; - char *name = elfPointer(map, offset, soSize); + char *name = elfPointer(elf, offset); if (!name) - return std::make_tuple(nullptr, 0); + return {}; if (sHdr->sh_type == SHT_DYNSYM && !strcmp(name, ".dynsym")) { dynsym = sHdr; @@ -130,13 +128,13 @@ elfLoadSymbol(void *map, size_t soSize, const char *symbol) if (dynsym == nullptr) { LOG(IPAModule, Error) << "ELF has no .dynsym section"; - return std::make_tuple(nullptr, 0); + return {}; } offset = eHdr->e_shoff + eHdr->e_shentsize * dynsym->sh_link; - sHdr = elfPointer(map, offset, soSize); + sHdr = elfPointer(elf, offset); if (!sHdr) - return std::make_tuple(nullptr, 0); + return {}; off_t dynsym_nameoff = sHdr->sh_offset; /* Locate symbol in the .dynsym section. */ @@ -144,15 +142,14 @@ elfLoadSymbol(void *map, size_t soSize, const char *symbol) unsigned int dynsym_num = dynsym->sh_size / dynsym->sh_entsize; for (unsigned int i = 0; i < dynsym_num; i++) { offset = dynsym->sh_offset + dynsym->sh_entsize * i; - ElfW(Sym) *sym = elfPointer(map, offset, soSize); + ElfW(Sym) *sym = elfPointer(elf, offset); if (!sym) - return std::make_tuple(nullptr, 0); + return {}; offset = dynsym_nameoff + sym->st_name; - char *name = elfPointer(map, offset, soSize, - strlen(symbol) + 1); + char *name = elfPointer(elf, offset, strlen(symbol) + 1); if (!name) - return std::make_tuple(nullptr, 0); + return {}; if (!strcmp(name, symbol) && sym->st_info & STB_GLOBAL) { @@ -163,22 +160,22 @@ elfLoadSymbol(void *map, size_t soSize, const char *symbol) if (targetSymbol == nullptr) { LOG(IPAModule, Error) << "Symbol " << symbol << " not found"; - return std::make_tuple(nullptr, 0); + return {}; } /* Locate and return data of symbol. */ if (targetSymbol->st_shndx >= eHdr->e_shnum) - return std::make_tuple(nullptr, 0); + return {}; offset = eHdr->e_shoff + targetSymbol->st_shndx * eHdr->e_shentsize; - sHdr = elfPointer(map, offset, soSize); + sHdr = elfPointer(elf, offset); if (!sHdr) - return std::make_tuple(nullptr, 0); + return {}; offset = sHdr->sh_offset + (targetSymbol->st_value - sHdr->sh_addr); - char *data = elfPointer(map, offset, soSize, targetSymbol->st_size); + uint8_t *data = elfPointer(elf, offset, targetSymbol->st_size); if (!data) - return std::make_tuple(nullptr, 0); + return {}; - return std::make_tuple(data, targetSymbol->st_size); + return { data, targetSymbol->st_size }; } } /* namespace */ @@ -292,23 +289,19 @@ int IPAModule::loadIPAModuleInfo() } Span data = file.map(0, -1, File::MapPrivate); - int ret = elfVerifyIdent(data.data(), data.size()); + int ret = elfVerifyIdent(data); if (ret) { LOG(IPAModule, Error) << "IPA module is not an ELF file"; return ret; } - void *info = nullptr; - size_t infoSize; - - std::tie(info, infoSize) = elfLoadSymbol(data.data(), data.size(), - "ipaModuleInfo"); - if (!info || infoSize != sizeof(info_)) { + Span info = elfLoadSymbol(data, "ipaModuleInfo"); + if (info.size() != sizeof(info_)) { LOG(IPAModule, Error) << "IPA module has no valid info"; return -EINVAL; } - memcpy(&info_, info, infoSize); + memcpy(&info_, info.data(), info.size()); if (info_.moduleAPIVersion != IPA_MODULE_API_VERSION) { LOG(IPAModule, Error) << "IPA module API version mismatch"; From patchwork Mon Apr 13 13:30:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3441 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2146E62E17 for ; Mon, 13 Apr 2020 15:31:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aqj9vA1o"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BEA0924B for ; Mon, 13 Apr 2020 15:31:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784666; bh=TJnWAwIRmr63ZViJXOO5IvICSVVIB+uo4PmF/VOexgw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aqj9vA1oSYdZq5Vi4RA/7irWgQs7cuJjPocjMKBe3Typ6+YGcZdJaP64sV5TF0B7Z YI2hwsUlgQHe/vcryaHo6v5ZK4GjYQ5p7tCDQ2Ou7Wp+IpWMDQepiFbOUBUMR+BSEU 1mcCAdH74dP8LyeP2lW1obLdLTmUzXg649PiG7t0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:43 +0300 Message-Id: <20200413133047.11913-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 07/11] libcamera: ipa_module: Load IPA module signature X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:09 -0000 Load the signature from the .sign file, if available, when loading the IPA module information and store it in the IPAModule class. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/include/ipa_module.h | 4 ++++ src/libcamera/ipa_module.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/libcamera/include/ipa_module.h b/src/libcamera/include/ipa_module.h index 2028b76a1913..ec3671857a61 100644 --- a/src/libcamera/include/ipa_module.h +++ b/src/libcamera/include/ipa_module.h @@ -7,7 +7,9 @@ #ifndef __LIBCAMERA_IPA_MODULE_H__ #define __LIBCAMERA_IPA_MODULE_H__ +#include #include +#include #include #include @@ -25,6 +27,7 @@ public: bool isValid() const; const struct IPAModuleInfo &info() const; + const std::vector signature() const; const std::string &path() const; bool load(); @@ -38,6 +41,7 @@ public: private: struct IPAModuleInfo info_; + std::vector signature_; std::string libPath_; bool valid_; diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index 5b6af15f2593..51b238a698f2 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -308,6 +308,20 @@ int IPAModule::loadIPAModuleInfo() return -EINVAL; } + /* Load the signature. Failures are not fatal. */ + File sign{ libPath_ + ".sign" }; + if (!sign.open(File::ReadOnly)) { + LOG(IPAModule, Debug) + << "IPA module " << libPath_ << " is not signed"; + return 0; + } + + data = sign.map(0, -1, File::MapPrivate); + signature_.resize(data.size()); + memcpy(signature_.data(), data.data(), data.size()); + + LOG(IPAModule, Debug) << "IPA module " << libPath_ << " is signed"; + return 0; } @@ -339,6 +353,21 @@ const struct IPAModuleInfo &IPAModule::info() const return info_; } +/** + * \brief Retrieve the IPA module signature + * + * The IPA module signature is stored alongside the IPA module in a file with a + * '.sign' suffix, and is loaded when the IPAModule instance is created. This + * function returns the signature without verifying it. If the signature is + * missing, the returned vector will be empty. + * + * \return The IPA module signature + */ +const std::vector IPAModule::signature() const +{ + return signature_; +} + /** * \brief Retrieve the IPA module path * From patchwork Mon Apr 13 13:30:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3445 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B842662DE4 for ; Mon, 13 Apr 2020 15:31:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="G2iXcS/I"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1E8731227 for ; Mon, 13 Apr 2020 15:31:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784667; bh=AxO0nZQ6d9fVCxUDKBOnPH/O6PjuHIL8cMXHju01h5k=; h=From:To:Subject:Date:In-Reply-To:References:From; b=G2iXcS/Ipyf3qkl2U08wPEcj8vt5EwhEWClVUy9uo7IAyFNez8i1buVFYt2uGlGsC SyYb1XDzwuL2PPoyXb0Qsq0JFHfN4vf5KPNbLdldYTPXvBkcf4rPfVm6HXKPEFN3zA J5H/efAoJd+ipgfuyFTa/N7VyksGQQ+jAaQsa3UY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:44 +0300 Message-Id: <20200413133047.11913-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 08/11] libcamera: Add PubKey class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:10 -0000 Add a new PubKey class to handle public key signature verification. The implementation is based on the gnutls library, which is added as an optional dependency. If gnutls is not found, signature verification will unconditionally fail. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v1: - Guard forward declaration of struct gnutls_pubkey_st with #ifdef HAVE_GNUTLS --- src/libcamera/include/meson.build | 1 + src/libcamera/include/pub_key.h | 38 ++++++++++++ src/libcamera/meson.build | 7 +++ src/libcamera/pub_key.cpp | 97 +++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 src/libcamera/include/pub_key.h create mode 100644 src/libcamera/pub_key.cpp diff --git a/src/libcamera/include/meson.build b/src/libcamera/include/meson.build index 921ed5a063cb..5aaa99472e4a 100644 --- a/src/libcamera/include/meson.build +++ b/src/libcamera/include/meson.build @@ -21,6 +21,7 @@ libcamera_headers = files([ 'message.h', 'pipeline_handler.h', 'process.h', + 'pub_key.h', 'semaphore.h', 'thread.h', 'utils.h', diff --git a/src/libcamera/include/pub_key.h b/src/libcamera/include/pub_key.h new file mode 100644 index 000000000000..f35bf3738c6f --- /dev/null +++ b/src/libcamera/include/pub_key.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * pub_key.h - Public key signature verification + */ +#ifndef __LIBCAMERA_PUB_KEY_H__ +#define __LIBCAMERA_PUB_KEY_H__ + +#include + +#include + +#if HAVE_GNUTLS +struct gnutls_pubkey_st; +#endif + +namespace libcamera { + +class PubKey +{ +public: + PubKey(Span key); + ~PubKey(); + + bool isValid() const { return valid_; } + bool verify(Span data, Span sig) const; + +private: + bool valid_; +#if HAVE_GNUTLS + struct gnutls_pubkey_st *pubkey_; +#endif +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PUB_KEY_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 4f5c41678781..c2a657e4938c 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -34,6 +34,7 @@ libcamera_sources = files([ 'pipeline_handler.cpp', 'pixelformats.cpp', 'process.cpp', + 'pub_key.cpp', 'request.cpp', 'semaphore.cpp', 'signal.cpp', @@ -61,8 +62,13 @@ subdir('proxy') libatomic = cc.find_library('atomic', required : false) libdl = cc.find_library('dl') +libgnutls = cc.find_library('gnutls', required : false) libudev = dependency('libudev', required : false) +if libgnutls.found() + config_h.set('HAVE_GNUTLS', 1) +endif + if libudev.found() config_h.set('HAVE_LIBUDEV', 1) libcamera_sources += files([ @@ -98,6 +104,7 @@ libcamera_sources += version_cpp libcamera_deps = [ libatomic, libdl, + libgnutls, libudev, dependency('threads'), ] diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp new file mode 100644 index 000000000000..064d2dd200e1 --- /dev/null +++ b/src/libcamera/pub_key.cpp @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * pub_key.cpp - Public key signature verification + */ + +#include "pub_key.h" + +#if HAVE_GNUTLS +#include +#endif + +/** + * \file pub_key.h + * \brief Public key signature verification + */ + +namespace libcamera { + +/** + * \class PubKey + * \brief Public key wrapper for signature verification + * + * The PubKey class wraps a public key and implements signature verification. It + * only supports RSA keys and the RSA-SHA256 signature algorithm. + */ + +/** + * \brief Construct a PubKey from key data + * \param[in] key Key data encoded in DER format + */ +PubKey::PubKey(Span key) + : valid_(false) +{ +#if HAVE_GNUTLS + int ret = gnutls_pubkey_init(&pubkey_); + if (ret < 0) + return; + + const gnutls_datum_t gnuTlsKey{ + const_cast(key.data()), + static_cast(key.size()) + }; + ret = gnutls_pubkey_import(pubkey_, &gnuTlsKey, GNUTLS_X509_FMT_DER); + if (ret < 0) + return; + + valid_ = true; +#endif +} + +PubKey::~PubKey() +{ +#if HAVE_GNUTLS + gnutls_pubkey_deinit(pubkey_); +#endif +} + +/** + * \fn bool PubKey::isValid() const + * \brief Check is the public key is valid + * \return True if the public key is valid, false otherwise + */ + +/** + * \brief Verify signature on data + * \param[in] data The signed data + * \param[in] sig The signature + * + * Verify that the signature \a sig matches the signed \a data for the public + * key. The signture algorithm is hardcoded to RSA-SHA256. + * + * \return True if the signature is valid, false otherwise + */ +bool PubKey::verify(Span data, Span sig) const +{ +#if HAVE_GNUTLS + const gnutls_datum_t gnuTlsData{ + const_cast(data.data()), + static_cast(data.size()) + }; + + const gnutls_datum_t gnuTlsSig{ + const_cast(sig.data()), + static_cast(sig.size()) + }; + + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0, + &gnuTlsData, &gnuTlsSig); + return ret >= 0; +#else + return false; +#endif +} + +} /* namespace libcamera */ From patchwork Mon Apr 13 13:30:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3442 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D126A62E1D for ; Mon, 13 Apr 2020 15:31:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tVtX70Ze"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6D7E224B for ; Mon, 13 Apr 2020 15:31:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784667; bh=WQKDBRT4Y4nfWhIaQV8LNqdBNQ9aHt8YHLpCS4m4XR8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=tVtX70Ze+WhYMjjG7qtsF6iYglROZiCe4qSRSrlYokL+lRiNlAliLowETtrpn0n+n x4duxFi6ZSPQPaNe/26DEAXhzQDx6vLry+G8ZFaHWzLWC1so2gAYR229X40ASQnLG2 kTKYIONm6nsCU68H7v34jTxsac5FCAFZG4c9PJ2c= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:45 +0300 Message-Id: <20200413133047.11913-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 09/11] libcamera: ipa_manager: Embed IPA module signing public key X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:10 -0000 In preparation for verifying the signature of IPA modules, generate a public key from the private signing key and embed it in the IPAManager class. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/gen-ipa-pub-key.py | 46 +++++++++++++++++++++++++++++ src/libcamera/include/ipa_manager.h | 5 ++++ src/libcamera/ipa_pub_key.cpp.in | 20 +++++++++++++ src/libcamera/meson.build | 8 +++++ 4 files changed, 79 insertions(+) create mode 100755 src/libcamera/gen-ipa-pub-key.py create mode 100644 src/libcamera/ipa_pub_key.cpp.in diff --git a/src/libcamera/gen-ipa-pub-key.py b/src/libcamera/gen-ipa-pub-key.py new file mode 100755 index 000000000000..ad575b18c922 --- /dev/null +++ b/src/libcamera/gen-ipa-pub-key.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2020, Google Inc. +# +# Author: Laurent Pinchart +# +# ipa-gen-key.py - Generate the IPA module signing public key + +import string +import subprocess +import sys + + +def main(argv): + if len(argv) != 4: + print('Usage: %s priv-key template output' % argv[0]) + return 1 + + priv_key = argv[1] + template = argv[2] + output = argv[3] + + try: + ret = subprocess.run(['openssl', 'rsa', '-pubout', '-in', priv_key, + '-outform', 'DER'], + stdout=subprocess.PIPE) + except FileNotFoundError: + print('Please install openssl to sign IPA modules') + return 1 + + ipa_key = ', '.join(['0x%02x' % c for c in ret.stdout]) + data = {'ipa_key': ipa_key} + + template = open(template, 'rb').read() + template = template.decode('utf-8') + template = string.Template(template) + + f = open(output, 'wb') + f.write(template.substitute(data).encode('utf-8')) + f.close() + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/src/libcamera/include/ipa_manager.h b/src/libcamera/include/ipa_manager.h index 467658e40ce9..26edf087461e 100644 --- a/src/libcamera/include/ipa_manager.h +++ b/src/libcamera/include/ipa_manager.h @@ -7,6 +7,7 @@ #ifndef __LIBCAMERA_IPA_MANAGER_H__ #define __LIBCAMERA_IPA_MANAGER_H__ +#include #include #include @@ -14,6 +15,7 @@ #include "ipa_module.h" #include "pipeline_handler.h" +#include "pub_key.h" namespace libcamera { @@ -35,6 +37,9 @@ private: void parseDir(const char *libDir, unsigned int maxDepth, std::vector &files); unsigned int addDir(const char *libDir, unsigned int maxDepth = 0); + + static const uint8_t publicKeyData_[]; + static const PubKey pubKey_; }; } /* namespace libcamera */ diff --git a/src/libcamera/ipa_pub_key.cpp.in b/src/libcamera/ipa_pub_key.cpp.in new file mode 100644 index 000000000000..e1fe287c160e --- /dev/null +++ b/src/libcamera/ipa_pub_key.cpp.in @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Laurent Pinchart + * + * ipa_key.cpp - IPA module signing public key + * + * This file is auto-generated. Do not edit. + */ + +#include "ipa_manager.h" + +namespace libcamera { + +const uint8_t IPAManager::publicKeyData_[] = { + ${ipa_key} +}; + +const PubKey IPAManager::pubKey_{ { IPAManager::publicKeyData_ } }; + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index c2a657e4938c..c502450c4b2d 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -101,6 +101,14 @@ version_cpp = vcs_tag(command : [gen_version, meson.build_root()], libcamera_sources += version_cpp +gen_ipa_pub_key = files('gen-ipa-pub-key.py') +ipa_pub_key_cpp = custom_target('ipa_pub_key_cpp', + input : [ ipa_priv_key, 'ipa_pub_key.cpp.in' ], + output : 'ipa_pub_key.cpp', + command : [ gen_ipa_pub_key, '@INPUT@', '@OUTPUT@' ]) + +libcamera_sources += ipa_pub_key_cpp + libcamera_deps = [ libatomic, libdl, From patchwork Mon Apr 13 13:30:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3443 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F32762E1E for ; Mon, 13 Apr 2020 15:31:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="OAE1BORj"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C26441288 for ; Mon, 13 Apr 2020 15:31:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784667; bh=c31/qGx1F09SD/xDe8w1XQf/8OBZG7pM4ZZeEYPC448=; h=From:To:Subject:Date:In-Reply-To:References:From; b=OAE1BORjL6wq18D3pdGacRx541YEJvbb+muBGiQLcDi3rPz5B8DtwJ+G3KwjjQF4f InmF3KjkDa0NQ8cA0DxkSaTDqsoGqr2LGxWNTXUGaEZFgno0iovZW7upREkd3JxQYp UsCT7QUbAObD9aMfAvJUSw6YFarvoZA75+VwnmpA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:46 +0300 Message-Id: <20200413133047.11913-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 10/11] libcamera: ipa_manager: Verify IPA module signature X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:10 -0000 Decide whether to isolate the IPA module using the module signature instead of its license. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/include/ipa_manager.h | 2 ++ src/libcamera/include/ipa_module.h | 2 -- src/libcamera/ipa_manager.cpp | 22 +++++++++++++++++++++- src/libcamera/ipa_module.cpp | 25 ------------------------- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/libcamera/include/ipa_manager.h b/src/libcamera/include/ipa_manager.h index 26edf087461e..0b5fd2ac1f12 100644 --- a/src/libcamera/include/ipa_manager.h +++ b/src/libcamera/include/ipa_manager.h @@ -38,6 +38,8 @@ private: std::vector &files); unsigned int addDir(const char *libDir, unsigned int maxDepth = 0); + bool isSignatureValid(IPAModule *ipa) const; + static const uint8_t publicKeyData_[]; static const PubKey pubKey_; }; diff --git a/src/libcamera/include/ipa_module.h b/src/libcamera/include/ipa_module.h index ec3671857a61..a9a3511701d4 100644 --- a/src/libcamera/include/ipa_module.h +++ b/src/libcamera/include/ipa_module.h @@ -37,8 +37,6 @@ public: bool match(PipelineHandler *pipe, uint32_t minVersion, uint32_t maxVersion) const; - bool isOpenSource() const; - private: struct IPAModuleInfo info_; std::vector signature_; diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index bcaae3564ea1..2b0112885274 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -12,6 +12,7 @@ #include #include +#include "file.h" #include "ipa_context_wrapper.h" #include "ipa_module.h" #include "ipa_proxy.h" @@ -271,7 +272,7 @@ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, if (!m) return nullptr; - if (!m->isOpenSource()) { + if (!isSignatureValid(m)) { IPAProxyFactory *pf = nullptr; std::vector &factories = IPAProxyFactory::factories(); @@ -307,4 +308,23 @@ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, return std::make_unique(ctx); } +bool IPAManager::isSignatureValid(IPAModule *ipa) const +{ + File file{ ipa->path() }; + if (!file.open(File::ReadOnly)) + return false; + + Span data = file.map(); + if (data.empty()) + return false; + + bool valid = pubKey_.verify(data, ipa->signature()); + + LOG(IPAManager, Debug) + << "IPA module " << ipa->path() << " signature is " + << (valid ? "valid" : "not valid"); + + return valid; +} + } /* namespace libcamera */ diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index 51b238a698f2..96b44f13192c 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -472,29 +472,4 @@ bool IPAModule::match(PipelineHandler *pipe, !strcmp(info_.pipelineName, pipe->name()); } -/** - * \brief Verify if the IPA module is open source - * - * \sa IPAModuleInfo::license - */ -bool IPAModule::isOpenSource() const -{ - static const char *osLicenses[] = { - "GPL-2.0-only", - "GPL-2.0-or-later", - "GPL-3.0-only", - "GPL-3.0-or-later", - "LGPL-2.1-only", - "LGPL-2.1-or-later", - "LGPL-3.0-only", - "LGPL-3.0-or-later", - }; - - for (unsigned int i = 0; i < ARRAY_SIZE(osLicenses); i++) - if (!strcmp(osLicenses[i], info_.license)) - return true; - - return false; -} - } /* namespace libcamera */ From patchwork Mon Apr 13 13:30:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3444 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 84B8362E1F for ; Mon, 13 Apr 2020 15:31:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XAYQUunW"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2078F24B for ; Mon, 13 Apr 2020 15:31:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1586784668; bh=VgmpQ5nVJZh70lhImecWaj6/sIBIpmiJZ+ma97RsmtM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=XAYQUunWYaSOOI6qll1GZmOeQbLRUyYGNIgLquSym5ORUyh269+UZ+YFT7SerSQip CTjxFLN/mxHLLiNhD++CV6TMd1YFdDhqXAI42XQ831/RSu3UxrEMqVfN0to9+UDw9Z hx/kF5H8RGVE667VmJJaCBSzSErisQYIuFwfjSY8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 13 Apr 2020 16:30:47 +0300 Message-Id: <20200413133047.11913-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> References: <20200413133047.11913-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 11/11] libcamera: ipa: Remove IPAModuleInfo license field X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Apr 2020 13:31:10 -0000 The IPAModuleInfo license field isn't needed anymore now that modules are cryptographically signed. Remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/ipa/ipa_module_info.h | 1 - src/ipa/rkisp1/rkisp1.cpp | 1 - src/ipa/vimc/meson.build | 3 +-- src/ipa/vimc/vimc.cpp | 1 - src/libcamera/ipa_module.cpp | 21 --------------------- test/ipa/ipa_module_test.cpp | 1 - 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/include/ipa/ipa_module_info.h b/include/ipa/ipa_module_info.h index 7ecd149566be..3b1c37d2a7f1 100644 --- a/include/ipa/ipa_module_info.h +++ b/include/ipa/ipa_module_info.h @@ -18,7 +18,6 @@ struct IPAModuleInfo { uint32_t pipelineVersion; char pipelineName[256]; char name[256]; - char license[64]; } __attribute__((packed)); extern "C" { diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index 438b3c66f77a..ffa7191ba21e 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -273,7 +273,6 @@ const struct IPAModuleInfo ipaModuleInfo = { 1, "PipelineHandlerRkISP1", "RkISP1 IPA", - "LGPL-2.1-or-later", }; struct ipa_context *ipaCreate() diff --git a/src/ipa/vimc/meson.build b/src/ipa/vimc/meson.build index 3097a12f964a..3c932aa7aaad 100644 --- a/src/ipa/vimc/meson.build +++ b/src/ipa/vimc/meson.build @@ -7,8 +7,7 @@ mod = shared_module(ipa_name, dependencies : libcamera_dep, link_with : libipa, install : true, - install_dir : ipa_install_dir, - cpp_args : '-DLICENSE="LGPL-2.1-or-later"') + install_dir : ipa_install_dir) custom_target(ipa_name + '.so.sign', input : mod, diff --git a/src/ipa/vimc/vimc.cpp b/src/ipa/vimc/vimc.cpp index 6e2095b56bbc..b11d42c57696 100644 --- a/src/ipa/vimc/vimc.cpp +++ b/src/ipa/vimc/vimc.cpp @@ -107,7 +107,6 @@ const struct IPAModuleInfo ipaModuleInfo = { 0, "PipelineHandlerVimc", "Dummy IPA for Vimc", - LICENSE, }; struct ipa_context *ipaCreate() diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index 96b44f13192c..958ede74688e 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -216,27 +216,6 @@ Span elfLoadSymbol(Span elf, const char *symbol) * \var IPAModuleInfo::name * \brief The name of the IPA module * - * \var IPAModuleInfo::license - * \brief License of the IPA module - * - * This license is used to determine whether to force isolation of the IPA in - * a separate process. If the license is "Proprietary", then the IPA will - * be isolated. If the license is open-source, then the IPA will be allowed to - * run without isolation if the user enables it. The license should be an - * SPDX license string. The following licenses are currently available to - * allow the IPA to run unisolated: - * - * - GPL-2.0-only - * - GPL-2.0-or-later - * - GPL-3.0-only - * - GPL-3.0-or-later - * - LGPL-2.1-only - * - LGPL-2.1-or-later - * - LGPL-3.0-only - * - LGPL-3.0-or-later - * - * Any other license will cause the IPA to be run isolated. - * * \todo Allow user to choose to isolate open source IPAs */ diff --git a/test/ipa/ipa_module_test.cpp b/test/ipa/ipa_module_test.cpp index 287e53fdaa8e..d22c302fa726 100644 --- a/test/ipa/ipa_module_test.cpp +++ b/test/ipa/ipa_module_test.cpp @@ -59,7 +59,6 @@ protected: 0, "PipelineHandlerVimc", "Dummy IPA for Vimc", - "GPL-2.0-or-later", }; count += runTest("src/ipa/vimc/ipa_vimc.so", testInfo);