Imported Upstream version 17.5.0 upstream/17.5.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 2 Sep 2019 07:15:43 +0000 (16:15 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 2 Sep 2019 07:15:43 +0000 (16:15 +0900)
13 files changed:
VERSION.cmake
package/libzypp.changes
zypp/CountryCode.cc
zypp/FileChecker.h
zypp/LanguageCode.cc
zypp/ProvideFilePolicy.h
zypp/base/LogControl.cc
zypp/misc/CheckAccessDeleted.cc
zypp/repo/PackageProvider.cc
zypp/repo/RepoProvideFile.cc
zypp/target/HardLocksFile.h
zypp/ui/Selectable.cc
zypp/ui/Selectable.h

index 384393c..54534a5 100644 (file)
@@ -60,9 +60,9 @@
 #
 SET(LIBZYPP_MAJOR "17")
 SET(LIBZYPP_COMPATMINOR "2")
-SET(LIBZYPP_MINOR "4")
+SET(LIBZYPP_MINOR "5")
 SET(LIBZYPP_PATCH "0")
 #
-# LAST RELEASED: 17.4.0 (2)
+# LAST RELEASED: 17.5.0 (2)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
index b3534c0..69a4647 100644 (file)
@@ -1,4 +1,15 @@
 -------------------------------------------------------------------
+Mon Jul  9 14:43:15 CEST 2018 - ma@suse.de
+
+- HardLocksFile: Prevent against empty commit without Target having
+  been been loaded (bsc#1096803)
+- lsof: use '-K i' if lsof supports it (bsc#1099847)
+- PackageProvider: Validate deta rpms before caching (bsc#1091624)
+- PackageProvider: Validate downloaded rpm package signatures
+  before caching (bsc#1091624)
+- version 17.5.0 (2)
+
+-------------------------------------------------------------------
 Mon Jun 25 10:48:55 CEST 2018 - ma@suse.de
 
 - Flags: make it std=c++14 ready
index 0fff4db..e3c3959 100644 (file)
@@ -100,7 +100,7 @@ namespace zypp
            nval.second = link->second;
          }
        }
-       MIL << "Remember CountryCode '" << code_r << "': '" << nval.second << "'" << endl;
+       MIL << "Remember CountryCode '" << code_r << "': '" << (nval.second?nval.second:"Unknown country") << "'" << endl;
        return (_indexMap[index_r] = _codeMap.insert( nval ).first);
       }
 
index d3ddf2d..9ec04d5 100644 (file)
@@ -94,7 +94,6 @@ namespace zypp
    {
      public:
        typedef SignatureCheckException ExceptionType;
-       typedef function<void ( const SignatureFileChecker & checker,  const Pathname & file )> OnSigValidated;
 
      public:
       /**
index 851875d..c70bb05 100644 (file)
@@ -99,7 +99,7 @@ namespace zypp
            nval.second = link->second;
          }
        }
-       MIL << "Remember LanguageCode '" << code_r << "': '" << nval.second << "'" << endl;
+       MIL << "Remember LanguageCode '" << code_r << "': '" << (nval.second?nval.second:"Unknown language") << "'" << endl;
        return (_indexMap[index_r] = _codeMap.insert( nval ).first);
       }
 
index 30ef3c5..bad3296 100644 (file)
 
 #include "zypp/base/Function.h"
 #include "zypp/base/Functional.h"
+#include "zypp/FileChecker.h"
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////
-// CLASS NAME : ProvideFilePolicy
-  
-  /** Policy for \ref provideFile.
-    * Provides callback hook for progress reporting.
-    */
+{
+  ///////////////////////////////////////////////////////////////////
+  /// \class ProvideFilePolicy
+  /// \brief Policy for \ref provideFile and \ref RepoMediaAccess.
+  ///
+  /// Provides callback hook for progress reporting and an optional
+  /// \ref FileCecker passed down to the \ref Fetcher.
+  ///////////////////////////////////////////////////////////////////
   class ProvideFilePolicy
   {
   public:
@@ -38,9 +40,16 @@ namespace zypp
     bool progress( int value ) const;
 
   public:
-    typedef function<bool ()> FailOnChecksumErrorCB;   ///< Legacy to remain bincompat
+    /** Add a \ref FileCecker passed down to the \ref Fetcher */
+    ProvideFilePolicy & fileChecker( FileChecker fileChecker_r )
+    { _fileChecker = std::move(fileChecker_r); return *this; }
+
+    /** The \ref FileCecker. */
+    const FileChecker & fileChecker() const
+    { return _fileChecker; }
+
   private:
-    FailOnChecksumErrorCB _failOnChecksumErrorCB;      ///< Legacy to remain bincompat
+    FileChecker           _fileChecker;
     ProgressCB            _progressCB;
   };
 
index 3dda602..8bb087a 100644 (file)
@@ -319,7 +319,13 @@ namespace zypp
             {
               _streamtable[group_r][level_r].reset( new Loglinestream( group_r, level_r ) );
             }
-          return _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r );
+          std::ostream & ret( _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r ) );
+         if ( !ret )
+         {
+           ret.clear();
+           ret << "---<RESET LOGSTREAM FROM FAILED STATE]" << endl;
+         }
+          return ret;
         }
 
         /** Format and write out a logline from Loglinebuf. */
index 07eec6c..435b7db 100644 (file)
@@ -24,6 +24,7 @@
 #include "zypp/base/Regex.h"
 #include "zypp/base/IOStream.h"
 #include "zypp/base/InputStream.h"
+#include "zypp/target/rpm/librpmDb.h"
 
 #include "zypp/misc/CheckAccessDeleted.h"
 
@@ -74,6 +75,29 @@ namespace zypp
 
       ino_t pidNS;
     };
+
+    /** bsc#1099847: Check for lsof version < 4.90 which does not support '-K i'
+     * Just a quick check to allow code15 libzypp runnig in a code12 environment.
+     */
+    bool lsofNoOptKi()
+    {
+      using target::rpm::librpmDb;
+      // RpmDb access is blocked while the Target is not initialized.
+      // Launching the Target just for this query would be an overkill.
+      struct TmpUnblock {
+       TmpUnblock()
+       : _wasBlocked( librpmDb::isBlocked() )
+       { if ( _wasBlocked ) librpmDb::unblockAccess(); }
+       ~TmpUnblock()
+       { if ( _wasBlocked ) librpmDb::blockAccess(); }
+      private:
+       bool _wasBlocked;
+      } tmpUnblock;
+
+      librpmDb::db_const_iterator it;
+      return( it.findPackage( "lsof" ) && it->tag_edition() < Edition("4.90") );
+    }
+
   } //namespace
   /////////////////////////////////////////////////////////////////
 
@@ -312,10 +336,9 @@ namespace zypp
 
   CheckAccessDeleted::size_type CheckAccessDeleted::check( bool verbose_r  )
   {
-    static const char* argv[] =
-    {
-      "lsof", "-n", "-FpcuLRftkn0", NULL
-    };
+    static const char* argv[] = { "lsof", "-n", "-FpcuLRftkn0", "-K", "i", NULL };
+    if ( lsofNoOptKi() )
+      argv[3] = NULL;
 
     _pimpl->_verbose = verbose_r;
     _pimpl->_fromLsofFileMode = false;
index 371ae42..ef62861 100644 (file)
@@ -41,6 +41,27 @@ namespace zypp
   namespace repo
   {
     ///////////////////////////////////////////////////////////////////
+    /// \class RpmSigCheckException
+    /// \brief Exception thrown by \ref PackageProviderImpl::rpmSigFileChecker
+    ///////////////////////////////////////////////////////////////////
+    class RpmSigCheckException : public FileCheckException
+    {
+    public:
+      RpmSigCheckException( repo::DownloadResolvableReport::Action action_r, std::string msg_r = "RpmSigCheckException" )
+      : FileCheckException( std::move(msg_r) )
+      , _action( std::move(action_r) )
+      {}
+
+      /** Users final decision how to proceed */
+      const repo::DownloadResolvableReport::Action & action() const
+      { return _action; }
+
+    private:
+      repo::DownloadResolvableReport::Action _action;
+    };
+
+
+    ///////////////////////////////////////////////////////////////////
     // class PackageProviderPolicy
     ///////////////////////////////////////////////////////////////////
 
@@ -151,6 +172,7 @@ namespace zypp
 
        ProvideFilePolicy policy;
        policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
+       policy.fileChecker( bind( &Base::rpmSigFileChecker, this, _1 ) );
        return _access.provideFile( _package->repoInfo(), loc, policy );
       }
 
@@ -163,8 +185,72 @@ namespace zypp
       bool progressPackageDownload( int value ) const
       {        return report()->progress( value, _package ); }
 
+
+      /** \name Validate a rpm packages signature.
+       *
+       * This is the \ref FileChecker passed down to the \ref Fetcher to validate
+       * a provided rpm package. This builtin checker includes the workflow
+       * communicating with the user in case of a problem with the package
+       * signature.
+       *
+       * \throws RpmSigCheckException if the package is not accepted, propagating
+       * the users decision how to proceed (\ref DownloadResolvableReport::Action).
+       *
+       * \note This check is also needed, if the the rpm is built locally by using
+       * delta rpms! \ref \see RpmPackageProvider
+       */
+      //@{
+      void rpmSigFileChecker( const Pathname & file_r ) const
+      {
+       const RepoInfo & info = _package->repoInfo();
+       if ( info.pkgGpgCheck() )
+       {
+         UserData userData( "pkgGpgCheck" );
+         ResObject::constPtr roptr( _package );        // gcc6 needs it more explcit. Has problem deducing
+         userData.set( "ResObject", roptr );           // a type for '_package->asKind<ResObject>()'...
+         /*legacy:*/userData.set( "Package", roptr->asKind<Package>() );
+         userData.set( "Localpath", file_r );
+         RpmDb::CheckPackageResult res = packageSigCheck( file_r, info.pkgGpgCheckIsMandatory(), userData );
+
+         // publish the checkresult, even if it is OK. Apps may want to report something...
+         report()->pkgGpgCheck( userData );
+
+         if ( res != RpmDb::CHK_OK )
+         {
+           if ( userData.hasvalue( "Action" ) )        // pkgGpgCheck report provided an user error action
+           {
+             resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
+           }
+           else if ( userData.haskey( "Action" ) )     // pkgGpgCheck requests the default problem report (wo. details)
+           {
+             defaultReportSignatureError( res );
+           }
+           else                                        // no advice from user => usedefaults
+           {
+             switch ( res )
+             {
+               case RpmDb::CHK_OK:             // Signature is OK
+                 break;
+
+               case RpmDb::CHK_NOKEY:          // Public key is unavailable
+               case RpmDb::CHK_NOTFOUND:       // Signature is unknown type
+               case RpmDb::CHK_FAIL:           // Signature does not verify
+               case RpmDb::CHK_NOTTRUSTED:     // Signature is OK, but key is not trusted
+               case RpmDb::CHK_ERROR:          // File does not exist or can't be opened
+               case RpmDb::CHK_NOSIG:          // File is unsigned
+               default:
+                 // report problem (w. details), throw if to abort, else retry/ignore
+                 defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
+                 break;
+             }
+           }
+         }
+       }
+      }
+
       typedef target::rpm::RpmDb RpmDb;
 
+      /** Actual rpm package signature check. */
       RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, bool isMandatory_r, UserData & userData ) const
       {
        if ( !_target )
@@ -189,22 +275,20 @@ namespace zypp
        return ret;
       }
 
-      /** React on signature verification error user action
+      /** React on signature verification error user action.
        * \note: IGNORE == accept insecure file (no SkipRequestException!)
        */
       void resolveSignatureErrorAction( repo::DownloadResolvableReport::Action action_r ) const
       {
        switch ( action_r )
        {
-         case repo::DownloadResolvableReport::RETRY:
-           _retry = true;
-           break;
          case repo::DownloadResolvableReport::IGNORE:
            WAR << _package->asUserString() << ": " << "User requested to accept insecure file" << endl;
            break;
          default:
+         case repo::DownloadResolvableReport::RETRY:
          case repo::DownloadResolvableReport::ABORT:
-           ZYPP_THROW(AbortRequestException("User requested to abort"));
+           ZYPP_THROW(RpmSigCheckException(action_r,"Signature verification failed"));
            break;
        }
       }
@@ -218,6 +302,7 @@ namespace zypp
          msg << "\n" << detail_r;
        resolveSignatureErrorAction( report()->problem( _package, repo::DownloadResolvableReport::INVALID, msg.str() ) );
       }
+      //@}
 
     protected:
       PackageProviderPolicy    _policy;
@@ -307,70 +392,6 @@ namespace zypp
         try
           {
             ret = doProvidePackage();
-
-           if ( info.pkgGpgCheck() )
-           {
-             UserData userData( "pkgGpgCheck" );
-             ResObject::constPtr roptr( _package );    // gcc6 needs it more explcit. Has problem deducing
-             userData.set( "ResObject", roptr );       // a type for '_package->asKind<ResObject>()'...
-             /*legacy:*/userData.set( "Package", roptr->asKind<Package>() );
-             userData.set( "Localpath", ret.value() );
-#if ( 1 )
-             bool pkgGpgCheckIsMandatory = info.pkgGpgCheckIsMandatory();
-             if ( str::startsWith( VERSION, "16.15." ) )
-             {
-               // BSC#1038984: For a short period of time, libzypp-16.15.x
-               // will silently accept unsigned packages IFF a repositories gpgcheck
-               // configuration is explicitly turned OFF like this:
-               //     gpgcheck      = 0
-               //     repo_gpgcheck = 0
-               //     pkg_gpgcheck  = 1
-               // This will allow some already released products to adapt to the behavioral
-               // changes introduced by fixing BSC#1038984, while systems with a default
-               // configuration (gpgcheck = 1) already benefit from the fix.
-               // With libzypp-16.16.x the above configuration will reject unsigned packages
-               // as it should.
-               if ( pkgGpgCheckIsMandatory && !info.gpgCheck() && !info.repoGpgCheck() )
-                 pkgGpgCheckIsMandatory = false;
-             }
-             RpmDb::CheckPackageResult res = packageSigCheck( ret, pkgGpgCheckIsMandatory, userData );
-#else
-             RpmDb::CheckPackageResult res = packageSigCheck( ret, info.pkgGpgCheckIsMandatory(), userData );
-#endif
-             // publish the checkresult, even if it is OK. Apps may want to report something...
-             report()->pkgGpgCheck( userData );
-
-             if ( res != RpmDb::CHK_OK )
-             {
-               if ( userData.hasvalue( "Action" ) )    // pkgGpgCheck report provided an user error action
-               {
-                 resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
-               }
-               else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details)
-               {
-                 defaultReportSignatureError( res );
-               }
-               else                                    // no advice from user => usedefaults
-               {
-                 switch ( res )
-                 {
-                   case RpmDb::CHK_OK:         // Signature is OK
-                     break;
-
-                   case RpmDb::CHK_NOKEY:      // Public key is unavailable
-                   case RpmDb::CHK_NOTFOUND:   // Signature is unknown type
-                   case RpmDb::CHK_FAIL:       // Signature does not verify
-                   case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
-                   case RpmDb::CHK_ERROR:      // File does not exist or can't be opened
-                   case RpmDb::CHK_NOSIG:      // File is unsigned
-                   default:
-                     // report problem (w. details), throw if to abort, else retry/ignore
-                     defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
-                     break;
-                 }
-               }
-             }
-           }
           }
         catch ( const UserRequestException & excpt )
           {
@@ -378,6 +399,28 @@ namespace zypp
            if ( ! _retry )
              ZYPP_RETHROW( excpt );
           }
+       catch ( const RpmSigCheckException & excpt )
+         {
+           ERR << "Failed to provide Package " << _package << endl;
+           if ( ! _retry )
+           {
+             // Signature verification error was already reported by the
+             // rpmSigFileChecker. Just handle the users action decision:
+             switch ( excpt.action() )
+             {
+               case repo::DownloadResolvableReport::RETRY:
+                 _retry = true;
+                 break;
+               case repo::DownloadResolvableReport::IGNORE:
+                 ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
+                 break;
+               default:
+               case repo::DownloadResolvableReport::ABORT:
+                 ZYPP_THROW(AbortRequestException("User requested to abort"));
+                 break;
+             }
+           }
+         }
         catch ( const FileCheckException & excpt )
           {
            ERR << "Failed to provide Package " << _package << endl;
@@ -393,11 +436,10 @@ namespace zypp
                case repo::DownloadResolvableReport::IGNORE:
                  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
                  break;
+               default:
                case repo::DownloadResolvableReport::ABORT:
                  ZYPP_THROW(AbortRequestException("User requested to abort"));
                  break;
-               default:
-                 break;
              }
            }
          }
@@ -421,22 +463,16 @@ namespace zypp
                       case repo::DownloadResolvableReport::IGNORE:
                         ZYPP_THROW(SkipRequestException("User requested skip of file", excpt));
                         break;
+                      default:
                       case repo::DownloadResolvableReport::ABORT:
                         ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
                         break;
-                      default:
-                        ZYPP_RETHROW( excpt );
-                        break;
                 }
               }
           }
       } while ( _retry );
       } catch(...){
        // bsc#1045735: Be sure no invalid files stay in the cache!
-       // TODO: It would be better to provide a filechecker passed to the
-       // fetcher that performs the pkgGpgCheck. This way a bad file would be
-       // discarded before it's moved to the cache.
-       // For now make sure the file gets deleted (even if keeppackages=1).
        if ( ! ret->empty() )
          ret.setDispose( filesystem::unlink );
        throw;
@@ -487,17 +523,10 @@ namespace zypp
 
     ManagedFile RpmPackageProvider::doProvidePackage() const
     {
-      Url url;
-      RepoInfo info = _package->repoInfo();
-      // FIXME we only support the first url for now.
-      if ( info.baseUrlsEmpty() )
-        ZYPP_THROW(Exception("No url in repository."));
-      else
-        url = * info.baseUrlsBegin();
-
       // check whether to process patch/delta rpms
+      // FIXME we only check the first url for now.
       if ( ZConfig::instance().download_use_deltarpm()
-       && ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) )
+       && ( _package->repoInfo().url().schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) )
       {
        std::list<DeltaRpm> deltaRpms;
        _deltas.deltaRpms( _package ).swap( deltaRpms );
@@ -550,18 +579,28 @@ namespace zypp
           return ManagedFile();
         }
 
-      // build the package and put it into the cache
-      Pathname destination( _package->repoInfo().packagesPath() / _package->repoInfo().path() / _package->location().filename() );
+      // Build the package
+      Pathname cachedest( _package->repoInfo().packagesPath() / _package->repoInfo().path() / _package->location().filename() );
+      Pathname builddest( cachedest.extend( ".drpm" ) );
 
-      if ( ! applydeltarpm::provide( delta, destination,
+      if ( ! applydeltarpm::provide( delta, builddest,
                                      bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
         {
           report()->problemDeltaApply( _("applydeltarpm failed.") );
           return ManagedFile();
         }
+      ManagedFile builddestCleanup( builddest, filesystem::unlink );
       report()->finishDeltaApply();
 
-      return ManagedFile( destination, filesystem::unlink );
+      // Check and move it into the cache
+      // Here the rpm itself is ready. If the packages sigcheck fails, it
+      // makes no sense to return a ManagedFile() and fallback to download the
+      // full rpm. It won't be different. So let the exceptions escape...
+      rpmSigFileChecker( builddest );
+      if ( filesystem::hardlinkCopy( builddest, cachedest ) != 0 )
+       ZYPP_THROW( Exception( str::Str() << "Can't hardlink/copy " << builddest << " to " << cachedest ) );
+
+      return ManagedFile( cachedest, filesystem::unlink );
     }
 
     ///////////////////////////////////////////////////////////////////
index 380cfca..0f9658b 100644 (file)
@@ -307,7 +307,7 @@ namespace zypp
           MIL << "Providing file of repo '" << repo_r.alias() << "' from " << url << endl;
           shared_ptr<MediaSetAccess> access = _impl->mediaAccessForUrl( url, repo_r );
 
-         fetcher.enqueue( locWithPath );
+         fetcher.enqueue( locWithPath, policy_r.fileChecker() );
          fetcher.start( destinationDir, *access );
 
          // reached if no exception has been thrown, so this is the correct file
@@ -322,12 +322,10 @@ namespace zypp
         }
         catch ( const UserRequestException & excpt )
        {
-         ZYPP_CAUGHT( excpt );
          ZYPP_RETHROW( excpt );
        }
         catch ( const FileCheckException & excpt )
        {
-         ZYPP_CAUGHT( excpt );
          ZYPP_RETHROW( excpt );
        }
         catch ( const Exception &e )
index 70f9e9e..e90e4ac 100644 (file)
@@ -73,7 +73,11 @@ namespace zypp
         void setData( const Data & data_r )
         {
           if ( !_dataPtr )
+         {
+           if ( data_r.empty() )
+             return;   // bsc#1096803: Prevent against empty commit without Target having been been loaded (!_dataPtr )
             _dataPtr.reset( new Data );
+         }
 
           if ( differs( *_dataPtr, data_r ) )
           {
index 3edb181..b7549e5 100644 (file)
@@ -155,6 +155,20 @@ namespace zypp
     Selectable::picklist_iterator Selectable::picklistEnd() const
     { return _pimpl->picklistEnd(); }
 
+    Selectable::picklist_size_type Selectable::picklistPos( const PoolItem & pi_r ) const
+    { return picklistPos( pi_r.satSolvable() ); }
+
+    Selectable::picklist_size_type Selectable::picklistPos( const sat::Solvable & solv_r ) const
+    {
+      picklist_size_type idx = picklist_size_type(-1);
+      for ( const auto & pi : picklist() )
+      {
+       if ( pi == solv_r )
+         return ++idx;
+      }
+      return picklistNoPos;
+    }
+
     ////////////////////////////////////////////////////////////////////////
 
     bool Selectable::isUnmaintained() const
index 2b85f7f..abb6a90 100644 (file)
@@ -277,6 +277,18 @@ namespace zypp
       picklist_iterator picklistEnd() const;
       inline Iterable<picklist_iterator> picklist() const
       { return makeIterable( picklistBegin(), picklistEnd() ); }
+
+      /** Returned by \ref picklistPos if the Item does not belong to the picklist. */
+      static constexpr const picklist_size_type picklistNoPos = picklist_size_type(-1);
+
+      /** Return the position of \a pi_r in the piclist or \ref picklistNoPos.
+       * \note \ref picklistNoPos is returned if you pass an installed Poolitem,
+       * whci has an \ref identicalAvailableObj.
+       */
+      picklist_size_type picklistPos( const PoolItem & pi_r ) const;
+
+      /** \overload taking a sat::Solvable */
+      picklist_size_type picklistPos( const sat::Solvable & solv_r ) const;
       //@}
 
       ////////////////////////////////////////////////////////////////////////