From patchwork Sat Apr 4 01:56:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3391 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 976C7629C1 for ; Sat, 4 Apr 2020 03:56:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="q/gCKq3A"; 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 26CE072E for ; Sat, 4 Apr 2020 03:56:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965398; bh=T4GRz7bsqexE0K9phDxLlMNfRNkL3v5KC7H/vE0YLFU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=q/gCKq3AT+ZmmwE1GPsfqCxaW691VEVTcwvo496ra8qdN40nuqFigjRlLsaxR3BsQ Apyz/ZCi640/v9WwcSAq0ZsS07zVqaf+IVMc73oGE0afQPY60GI0VBBDiHp3X8BrK9 wFK0RAuJbDxaREVfhvD+oIyj9/F7HVn02YbXWT3c= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:14 +0300 Message-Id: <20200404015624.30440-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:38 -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 Sat Apr 4 01:56:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3392 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DF324629C1 for ; Sat, 4 Apr 2020 03:56:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cjYp/zXZ"; 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 7DBFC321 for ; Sat, 4 Apr 2020 03:56:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965398; bh=m8sogttKWk7MWLQlKy0us7W1DEPhxapZHEOWCHvjoZY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=cjYp/zXZtHGy/bCT9KrV25JBxc6cBbEeq3RK5Uj/TCWRPpGXDVISoMveUqT8xtl8g t19woQxrnMXPlQ29Ca825vZgjTobeHGLzDHg1ptZrhDiRXEvZNXPmqoMlY4CkKgWoX yIv0hh/A0hRE7WpxJsadqSZyM7YtJ5F1TUMpqxdQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:15 +0300 Message-Id: <20200404015624.30440-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:39 -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 --- src/ipa/gen-ipa-priv-key.sh | 9 +++++++++ src/ipa/ipa-sign.sh | 10 ++++++++++ src/ipa/meson.build | 2 ++ src/ipa/rkisp1/meson.build | 25 +++++++++++++++++-------- src/ipa/vimc/meson.build | 12 +++++++++++- src/meson.build | 5 +++++ 6 files changed, 54 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..2b19c001d6c5 --- /dev/null +++ b/src/ipa/gen-ipa-priv-key.sh @@ -0,0 +1,9 @@ +#!/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 + +openssl genpkey -algorithm RSA -out "$1" -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..d41e67e00ad0 --- /dev/null +++ b/src/ipa/ipa-sign.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# SPDX-License-Identifier: GPL-2.0-or-later +# 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 Sat Apr 4 01:56:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3393 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 49988629C1 for ; Sat, 4 Apr 2020 03:56:39 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="qXgmwmSP"; 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 D817C72E for ; Sat, 4 Apr 2020 03:56:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965399; bh=9IhKv0aL3QaIvbCQ+TFSw0JMqYpPPHhygbZ1wTKgNiA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=qXgmwmSPvFSADtQIdC5zc0gOo9OB7XoJKMfRvCHw/CvSIYfgp+zpxu0xcWX0+0xuF F80r4IXTVVMN7FdeYBCdGIRy7JRhvwj0ey7NCyGnpJduepfMOD7XBfJjM0rmOOam8k vkOoHA14TKs1tw1uKzcyIWclnNMIacCWuArhOOiA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:16 +0300 Message-Id: <20200404015624.30440-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:39 -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 --- src/libcamera/file.cpp | 338 ++++++++++++++++++++++++++++++ src/libcamera/include/file.h | 69 ++++++ src/libcamera/include/meson.build | 1 + src/libcamera/meson.build | 1 + 4 files changed, 409 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..23cea4aa3101 --- /dev/null +++ b/src/libcamera/file.cpp @@ -0,0 +1,338 @@ +/* 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. + * + * \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); + 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 Sat Apr 4 01:56:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3394 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 C5DBF62DAF for ; Sat, 4 Apr 2020 03:56:39 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vJrOjRNV"; 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 3DBF5321 for ; Sat, 4 Apr 2020 03:56:39 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965399; bh=FxoS6dqLK/8Mjrrb8GguptpwO8UxZ3bBXwlRoXbB8uU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vJrOjRNVTSIFc9q6J8lWw0M9ofm12uI/fTPcCYWWawV36+EdNa2hg5jT0HnPzubD8 IS4UEOWRIbWvQ8mXuaiw+S+yR3bisXYu+IF3KPiq5EsU7N8ti/r8RNE8HPsmnyMNMC q1V6KStc1he2ZaVj2YjenA3zp3gBBdp5pTxi3HNs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:17 +0300 Message-Id: <20200404015624.30440-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:40 -0000 Add tests for the File class API. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- test/file.cpp | 285 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 286 insertions(+) create mode 100644 test/file.cpp diff --git a/test/file.cpp b/test/file.cpp new file mode 100644 index 000000000000..c046bced1c13 --- /dev/null +++ b/test/file.cpp @@ -0,0 +1,285 @@ +/* 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 "file.h" +#include "test.h" + +using namespace std; +using namespace libcamera; + +class FileTest : public Test +{ +protected: + int init() + { + fileName_ = "/tmp/libcamera.test." + std::to_string(getpid()); + + std::ofstream ostrm(fileName_, ios::binary); + ostrm << "libcamera"; + ostrm.close(); + + 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; + } + + /* 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 Sat Apr 4 01:56:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3395 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0C14C62D90 for ; Sat, 4 Apr 2020 03:56:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ukq98Cw6"; 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 93B5772E for ; Sat, 4 Apr 2020 03:56:39 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965399; bh=ifW0ACdZvc4+2qIx05JRtLgeNczXf7GhnLBEeopoaoI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=ukq98Cw6vfmICoJe6j4W6uzVQeAYND26BgWzZFivvPNjuyZ3u8fC5zVg33Or2E5Kn uCh0KZjfG5qilah41y/COgW28HKXRhb7mEVhWmyFnbcvE2Q8Nom5qXrLX48xeTCbkD 5U+yueJAi8oAQxtoGFhbNn6fc0j9swlTw4CIDtws= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:18 +0300 Message-Id: <20200404015624.30440-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:40 -0000 Create a 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 Sat Apr 4 01:56:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3396 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 6A37F62DBB for ; Sat, 4 Apr 2020 03:56:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fpJ0syZP"; 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 ED882321 for ; Sat, 4 Apr 2020 03:56:39 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965400; bh=5jbzYwS9/2pyby3ZYr68DA5pCiRfYY5490PS0up3toY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=fpJ0syZP2cFlkos8Q3gpj3ocPK2s5urVDpF2WQt1Pj9A0T9M29ENEZhGR+OcZdlh6 87hnKFbLG11zPQiEQHKMZPuaXOuESYHTGApmhIkgEC+fbweiJzivh4klSLydd9Pv8a TWEZBKzdYHrgC/RgZy7TtiqEn+u6kE4rda99jJws= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:19 +0300 Message-Id: <20200404015624.30440-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:42 -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 Sat Apr 4 01:56:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3397 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 BE43D62D75 for ; Sat, 4 Apr 2020 03:56:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="plxhs3b4"; 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 53C5972E for ; Sat, 4 Apr 2020 03:56:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965400; bh=Tjf4ysA5abCtPCGqTHgiPAFLJPzsHsoVi+vX8ZWT5r4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=plxhs3b4oWHNDxDYBoWxcMrL6Q4iH6RpXf97jyPHJhUW1BjZUZCGsiY49feWc/L86 Qd9uy7x2Eu/UkiNUjP43cIW0nQHr7DC9eY8ZgIyncKyrKgcqXxL7shW+3AzCe5qzG4 lgEPRjKEeB30ldSlUDJp6HvVLaJ8V4s1Yqvm5hl0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:20 +0300 Message-Id: <20200404015624.30440-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:43 -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 Sat Apr 4 01:56:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3398 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 21DA062E14 for ; Sat, 4 Apr 2020 03:56:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fIHZg9zz"; 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 AD914321 for ; Sat, 4 Apr 2020 03:56:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965400; bh=GPxg02ZDtpZc7tnUd0P5uXuNW7EAYzq+1lj7DtG5oas=; h=From:To:Subject:Date:In-Reply-To:References:From; b=fIHZg9zzqqJKKati22LdLe9jsFRGt8JIneVBheJfjhAIz0ualGvATk+o+5V/rsnVo zeuLamA4CAg8HvicSivO4trXX1IthF6jCS89k/0ZeGu3TAtnYrfCN3g0ygGqPtwbx7 liLA51e9zo6JnpdPZT972puP+GZx0kiPHVTXtiCQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:21 +0300 Message-Id: <20200404015624.30440-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:43 -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 --- src/libcamera/include/meson.build | 1 + src/libcamera/include/pub_key.h | 36 ++++++++++++ src/libcamera/meson.build | 7 +++ src/libcamera/pub_key.cpp | 97 +++++++++++++++++++++++++++++++ 4 files changed, 141 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..4d3bdd69bfd8 --- /dev/null +++ b/src/libcamera/include/pub_key.h @@ -0,0 +1,36 @@ +/* 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 + +struct gnutls_pubkey_st; + +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 Sat Apr 4 01:56:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3399 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7D54F62E17 for ; Sat, 4 Apr 2020 03:56:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aId/IjFz"; 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 1431472E for ; Sat, 4 Apr 2020 03:56:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965401; bh=94jrbmSUBFyOik7a64xeUeWbK3CieQXO7EyL16yFMts=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aId/IjFzLBPoZZ7HLLnf4EhCDh9jHYfddIxThDibi9L42Giou6/yfB3nmLkgqYvYa Lm3CQomUxifLcGQFtEeT0Ur1WWc1/cAWqK8Rqb8c2VFieC1v8kjw+iqnke1vc7Rum0 QCBzyM0e4Lpw4yRGzrkTWUG+alWacuOLMbmUzIgs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:22 +0300 Message-Id: <20200404015624.30440-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:44 -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 Sat Apr 4 01:56:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3400 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 CDCE062E02 for ; Sat, 4 Apr 2020 03:56:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vvw3+SUo"; 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 7009AA2A for ; Sat, 4 Apr 2020 03:56:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965401; bh=SxF22iZcQBP1rLFZrSkLgidiCzfszvJ+DXPtWxF3E2k=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vvw3+SUosbsB+Q8ClZZ6HFZK/cepg8qd1QDaseUKBQ6y+DxN5H7wb4VNkcx1gf/h2 /YANnbhpJFpGKeri5oOjAcbyRtnzrE+H1PjoIBdM1Xnwdiq8C+Z5vSxD2pjfc38q+G PH8S3ZxY+snfoN/J5kzNXb82zg/QlHTPP/CBl9FY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:23 +0300 Message-Id: <20200404015624.30440-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:44 -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 Sat Apr 4 01:56:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3401 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 303A662E16 for ; Sat, 4 Apr 2020 03:56:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MFpB2Wgc"; 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 C6FBD72E for ; Sat, 4 Apr 2020 03:56:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1585965401; bh=ddRQnxUQ2fcX1gOSnZU6X30ceRjd9XlsI0njwFL3J+U=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MFpB2WgcFA4wO9kjzusDULYllsNqfs8iuLIKW6f3LSVK+Mq7MjM0OA48MujHIkEsF HtdQJCf8qOUdfevy7ENqa5z2DhFqAKxRwSwelUEROjHMR7gLHysVINCFt+z518SV+8 lfP+PcB8au9xm78pkNqXF6aTaIaCfAbRoWuZwtY8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 4 Apr 2020 04:56:24 +0300 Message-Id: <20200404015624.30440-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> References: <20200404015624.30440-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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: Sat, 04 Apr 2020 01:56:44 -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);