From 0c2826fb465e147c62fb4c8995deaccd3afba3ba Mon Sep 17 00:00:00 2001 From: "sangwan.kwon" Date: Mon, 27 Mar 2017 19:16:46 +0900 Subject: [PATCH] Refine error/exception handling logic Change-Id: Idf22a826277c872c9a180cfc9196d2193d30d6f7 Signed-off-by: sangwan.kwon --- api/tanchor/error.h | 2 ++ api/tanchor/trust-anchor.h | 12 +++++++ src/certificate.cpp | 6 ++-- src/exception.cpp | 57 +++++++++++++++++++++++++------ src/exception.hxx | 41 ++++++++++++++++++++++ src/trust-anchor.cpp | 70 +++++++++++++++++++++++--------------- 6 files changed, 148 insertions(+), 40 deletions(-) diff --git a/api/tanchor/error.h b/api/tanchor/error.h index 68463a3..443e50c 100644 --- a/api/tanchor/error.h +++ b/api/tanchor/error.h @@ -43,6 +43,8 @@ typedef enum { TRUST_ANCHOR_ERROR_NONE = 0, TRUST_ANCHOR_ERROR_INVALID_PARAMETER = -EINVAL, TRUST_ANCHOR_ERROR_OUT_OF_MEMORY = -ENOMEM, + TRUST_ANCHOR_ERROR_PERMISSION_DENIED = -EACCES, + TRUST_ANCHOR_ERROR_NO_SUCH_FILE = -ENOENT, TRUST_ANCHOR_ERROR_INTERNAL = TRUST_ANCHOR_ERROR_BASE | 0x01 } trust_anchor_error_e; diff --git a/api/tanchor/trust-anchor.h b/api/tanchor/trust-anchor.h index 1ba2faa..522073a 100644 --- a/api/tanchor/trust-anchor.h +++ b/api/tanchor/trust-anchor.h @@ -45,6 +45,9 @@ extern "C" { * negative on error * @retval #TRUST_ANCHOR_ERROR_NONE Successful * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error + * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error + * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error + * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error * @see trust_anchor_global_launch() * @see trust_anchor_global_uninstall() @@ -66,6 +69,9 @@ int trust_anchor_global_install(const char *package_id, * negative on error * @retval #TRUST_ANCHOR_ERROR_NONE Successful * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error + * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error + * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error + * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error * @see trust_anchor_usr_launch() * @see trust_anchor_usr_uninstall() @@ -86,6 +92,9 @@ int trust_anchor_usr_install(const char *package_id, * negative on error * @retval #TRUST_ANCHOR_ERROR_NONE Successful * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error + * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error + * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error + * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error * @see trust_anchor_global_install() */ @@ -104,6 +113,9 @@ int trust_anchor_global_launch(const char *package_id, * negative on error * @retval #TRUST_ANCHOR_ERROR_NONE Successful * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error + * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error + * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error + * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error * @see trust_anchor_usr_install() */ diff --git a/src/certificate.cpp b/src/certificate.cpp index 0d9bdd5..a0b063e 100644 --- a/src/certificate.cpp +++ b/src/certificate.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include "exception.hxx" #include @@ -43,10 +43,10 @@ const int HASH_LENGTH = 8; } // namespace anonymous Certificate::Certificate(const std::string &path) : - m_fp(FilePtr(fopen(path.c_str(), "rb"), ::fclose)) + m_fp(FilePtr(::fopen(path.c_str(), "rb"), ::fclose)) { if (this->m_fp == nullptr) - throw std::invalid_argument("Faild to open certificate."); + throw std::invalid_argument("Failed to open [" + path + "]."); } std::string Certificate::getSubjectNameHash() const diff --git a/src/exception.cpp b/src/exception.cpp index be360ca..9608f9d 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -21,31 +21,68 @@ */ #include "exception.hxx" -#include - #include -#include namespace tanchor { int exceptionGuard(const std::function &func) { - // TODO add custom error code try { return func(); - } catch (runtime::Exception &e) { + } catch (const tanchor::Exception &e) { + std::string errStr; + switch (e.error()) { + case ENOENT: + errStr = "No such file or directory."; + break; + case ENOMEM: + errStr = "Out of memory."; + break; + case EACCES: + case EPERM: + errStr = "Permission denied."; + break; + default: + errStr = "Internal error."; + break; + } + ERROR(errStr + e.what()); + return e.error(); + } catch (const runtime::Exception &e) { ERROR(e.what()); - return -1; + return TRUST_ANCHOR_ERROR_INTERNAL; } catch (const std::invalid_argument &e) { - ERROR("Invalid argument: " << e.what()); - return -1; + ERROR(e.what()); + return TRUST_ANCHOR_ERROR_INVALID_PARAMETER; + } catch (const std::logic_error &e) { + ERROR(e.what()); + return TRUST_ANCHOR_ERROR_INTERNAL; } catch (const std::exception &e) { ERROR(e.what()); - return -1; + return TRUST_ANCHOR_ERROR_INTERNAL; } catch (...) { ERROR("Unknown exception occurred."); - return -1; + return TRUST_ANCHOR_ERROR_INTERNAL; } } +Exception::Exception(int ec, const char *file, const char *function, + unsigned int line, const std::string &message) noexcept : + m_ec(ec), + m_message(FORMAT("[" << file << ":" << line << " " << + function << "()]" << message)) +{ + ERROR(this->m_message); +} + +const char *Exception::what() const noexcept +{ + return this->m_message.c_str(); +} + +int Exception::error(void) const noexcept +{ + return this->m_ec; +} + } // namespace tanchor diff --git a/src/exception.hxx b/src/exception.hxx index 975cb3f..f0d5350 100644 --- a/src/exception.hxx +++ b/src/exception.hxx @@ -21,7 +21,13 @@ */ #pragma once +#include "tanchor/error.h" + #include +#include +#include + +#include #define EXCEPTION_GUARD_START return tanchor::exceptionGuard([&]() { #define EXCEPTION_GUARD_END }); @@ -30,4 +36,39 @@ namespace tanchor { int exceptionGuard(const std::function &); +class Exception : public std::exception { +public: + Exception(int ec, const char *file, const char *function, + unsigned int line, const std::string &message) noexcept; + virtual ~Exception() = default; + virtual const char* what() const noexcept override; + + int error(void) const noexcept; + +protected: + int m_ec; + std::string m_message; +}; + } // namespace tanchor + +#define __TANCHOR_THROW(ec, MESSAGE) \ + throw tanchor::Exception(ec, __FILE__, __FUNCTION__, \ + __LINE__, FORMAT(MESSAGE)) + +#define ThrowExc(ec, MESSAGE) __TANCHOR_THROW(ec, MESSAGE) + +#define ThrowErrno(ec, MESSAGE) \ + do { \ + switch (ec) { \ + case ENOENT: \ + ThrowExc(TRUST_ANCHOR_ERROR_NO_SUCH_FILE, MESSAGE); \ + case ENOMEM: \ + ThrowExc(TRUST_ANCHOR_ERROR_OUT_OF_MEMORY, MESSAGE); \ + case EACCES: \ + case EPERM: \ + ThrowExc(TRUST_ANCHOR_ERROR_PERMISSION_DENIED, MESSAGE); \ + default: \ + ThrowExc(TRUST_ANCHOR_ERROR_INTERNAL, MESSAGE); \ + } \ + } while (0) diff --git a/src/trust-anchor.cpp b/src/trust-anchor.cpp index 8f5610e..52166cc 100644 --- a/src/trust-anchor.cpp +++ b/src/trust-anchor.cpp @@ -75,6 +75,7 @@ private: std::string getUniqueHashName(const std::string &hashName) const; std::string getBundleName(void) const; bool isSystemCertsModified(void) const; + void checkFileValidity(const runtime::File &file) const; std::string m_packageId; std::string m_appCertsPath; @@ -126,8 +127,7 @@ void TrustAnchor::Impl::linkTo(const std::string &src, errno = 0; int ret = ::symlink(src.c_str(), dst.c_str()); if (ret != 0) - throw std::logic_error("Fail to link " + src + " -> " + dst + - "[" + std::to_string(errno) + "]"); + ThrowErrno(errno, "Failed to link " + src + " -> " + dst); } void TrustAnchor::Impl::preInstall(void) const @@ -146,9 +146,10 @@ void TrustAnchor::Impl::preInstall(void) const customBundleDir.makeDirectory(); runtime::File appCertsDir(this->m_appCertsPath); - if (!appCertsDir.exists() || !appCertsDir.isDirectory()) - throw std::invalid_argument("App custom certs path is wrong. : " + - m_appCertsPath); + this->checkFileValidity(appCertsDir); + if (!appCertsDir.isDirectory()) + throw std::invalid_argument("[" + this->m_appCertsPath + + "] should be directory."); DEBUG("Success to pre-install stage."); } @@ -188,7 +189,7 @@ int TrustAnchor::Impl::install(bool withSystemCerts) noexcept INFO("Success to install[" << this->m_packageId << "] to " << this->m_customBasePath); - return 0; + return TRUST_ANCHOR_ERROR_NONE; EXCEPTION_GUARD_END } @@ -199,27 +200,42 @@ int TrustAnchor::Impl::uninstall(bool isRollback) noexcept runtime::File customBaseDir(this->m_customBasePath); if (!customBaseDir.exists() && !isRollback) - throw std::invalid_argument("There is no installed anchor previous."); + throw std::logic_error("There is no installed anchor previous."); if (customBaseDir.exists()) customBaseDir.remove(true); INFO("Success to uninstall. : " << this->m_packageId); - return 0; + return TRUST_ANCHOR_ERROR_NONE; EXCEPTION_GUARD_END } +void TrustAnchor::Impl::checkFileValidity(const runtime::File &file) const +{ + if (!file.exists()) + ThrowExc(TRUST_ANCHOR_ERROR_NO_SUCH_FILE, + "File [" << file.getPath() << "] does not exist."); + + if (!file.canRead()) + ThrowExc(TRUST_ANCHOR_ERROR_PERMISSION_DENIED, + "No permission to read [" << file.getPath() << "]"); +} + bool TrustAnchor::Impl::isSystemCertsModified(void) const { struct stat systemAttr, customAttr; - stat(SYS_BUNDLE_PATH.c_str(), &systemAttr); - DEBUG("System bundle mtime : " << ::ctime(&systemAttr.st_mtime)); + errno = 0; + if (::stat(SYS_BUNDLE_PATH.c_str(), &systemAttr)) + ThrowErrno(errno, SYS_BUNDLE_PATH); auto customBundle = this->m_customBundlePath + "/" + this->getBundleName(); - stat(customBundle.c_str(), &customAttr); - DEBUG("Custom bundle mtime : " << ::ctime(&customAttr.st_mtime)); + if (::stat(customBundle.c_str(), &customAttr)) + ThrowErrno(errno, customBundle); + + DEBUG("System bundle mtime : " << ::ctime(&systemAttr.st_mtime) << ", " << + "Custom bundle mtime : " << ::ctime(&customAttr.st_mtime)); return systemAttr.st_mtime > customAttr.st_mtime; } @@ -234,19 +250,20 @@ int TrustAnchor::Impl::launch(bool withSystemCerts) errno = 0; // disassociate from the parent namespace if (::unshare(CLONE_NEWNS)) - throw std::logic_error("Failed to unshare namespace > " + - std::to_string(errno)); + ThrowErrno(errno, "Failed to unshare."); // convert it to a slave for preventing propagation if (::mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) - throw std::logic_error("Failed to disconnect root fs."); + ThrowErrno(errno, "Failed to mount."); if (::mount(this->m_customCertsPath.c_str(), MOUNT_POINT_CERTS.c_str(), NULL, MS_BIND, NULL)) - throw std::logic_error("Failed to mount certs."); + ThrowErrno(errno, "Failed to mount. src[" + + this->m_customCertsPath + "] to dst[" + + MOUNT_POINT_CERTS + "]"); auto bundle = this->m_customBundlePath + "/" + this->getBundleName(); if (::mount(bundle.c_str(), @@ -254,10 +271,11 @@ int TrustAnchor::Impl::launch(bool withSystemCerts) NULL, MS_BIND, NULL)) - throw std::logic_error("Failed to mount bundle."); + ThrowErrno(errno, "Failed to mount. src[" + bundle + + "] to dst[" + MOUNT_POINT_BUNDLE + "]"); INFO("Success to launch. : " << this->m_packageId); - return 0; + return TRUST_ANCHOR_ERROR_NONE; EXCEPTION_GUARD_END } @@ -296,13 +314,11 @@ void TrustAnchor::Impl::makeCustomBundle(bool withSystemCerts) DEBUG("Start to migrate previous bundle."); if (withSystemCerts) { runtime::File sysBundle(SYS_BUNDLE_PATH); - if (!sysBundle.exists()) - throw std::logic_error("There is no system bundle file."); + this->checkFileValidity(sysBundle); sysBundle.copyTo(this->m_customBundlePath); } else { runtime::File tanchorBundle(TANCHOR_BUNDLE_PATH); - if (!tanchorBundle.exists()) - throw std::logic_error("There is no tanchor bundle file."); + this->checkFileValidity(tanchorBundle); tanchorBundle.copyTo(this->m_customBundlePath); } DEBUG("Finish migrating previous bundle."); @@ -333,7 +349,7 @@ TrustAnchor::TrustAnchor(const std::string &packageId, m_pImpl(new Impl(packageId, certsDir, uid)) {} TrustAnchor::TrustAnchor(const std::string &packageId, - const std::string &certsDir) noexcept : + const std::string &certsDir) noexcept : m_pImpl(new Impl(packageId, certsDir)) {} TrustAnchor::~TrustAnchor(void) = default; @@ -341,11 +357,11 @@ TrustAnchor::~TrustAnchor(void) = default; int TrustAnchor::install(bool withSystemCerts) noexcept { if (this->m_pImpl == nullptr) - return -1; + return TRUST_ANCHOR_ERROR_OUT_OF_MEMORY; int ret = this->m_pImpl->install(withSystemCerts); - if (ret != 0) { + if (ret != TRUST_ANCHOR_ERROR_NONE) { ERROR("Failed to intall ACTA. Remove custom directory for rollback."); this->m_pImpl->uninstall(true); } @@ -356,7 +372,7 @@ int TrustAnchor::install(bool withSystemCerts) noexcept int TrustAnchor::uninstall(void) noexcept { if (this->m_pImpl == nullptr) - return -1; + return TRUST_ANCHOR_ERROR_OUT_OF_MEMORY; return this->m_pImpl->uninstall(); } @@ -364,7 +380,7 @@ int TrustAnchor::uninstall(void) noexcept int TrustAnchor::launch(bool withSystemCerts) noexcept { if (this->m_pImpl == nullptr) - return -1; + return TRUST_ANCHOR_ERROR_OUT_OF_MEMORY; return this->m_pImpl->launch(withSystemCerts); } -- 2.34.1