Skip to content

Conversation

Iristyle
Copy link
Contributor

@Iristyle Iristyle commented Dec 1, 2018

Previously, the Windows package provider would enumerate all
registry values affiliated with a given product.

Products are enumerated under
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

Where each individual product resides in a subkey, like 7-Zip

This could result in reading quite a bit of extraneous data.

  • In reality, there are only 9 key values that the package provider
    is interested in, so whitelist those values when enumerating
    for a given product.

  • This also fixes an issue where some products may install bad data
    into registry values (one such product stores binary data inside
    of a REG_SZ which breaks Puppets abiliy to interpret the value
    as a string).

    While this is really the fault of the product and not of Puppet,
    Puppet must be resilient to such bad data.


Alternate approach to #7244

 - When failing to retrieve a registry value, the API called to read
   the pointer of the name of the subkey was used improperly,
   resulting in a messsage like:

   Error: Could not run: wrong number of arguments (given 0, expected 1..3)
   C:/source/puppet-PUP-9312/lib/puppet/util/windows/api_types.rb:56:in `read_wide_string'

   Fix this, so the message is correctly emitted instead like:

   Error: Could not run: Failed to read registry value QuietDisplayName at Software\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip:  The operation completed successfully.
@puppetcla
Copy link

CLA signed by all contributors.

@glennsarti glennsarti force-pushed the PUP-9312-packages-when-registry-corrupt branch from 508f8db to bd2b5f2 Compare December 3, 2018 08:22
@glennsarti
Copy link
Contributor

@Iristyle I've updated the PR. Due the error handling in read it wasn't possible to easily tell the difference between a missing value or a legitimate error. So instead I introduced reg_enum_valuenames which lists all the valuenames for a key.

values_by_name can then iterate over that and decided whether to read the value or not based on the whitelist.

I also added a simple test for the values_by_name method.

I don't think this requires any test changes for the package provider code, only the registry portions.

@puppetcla
Copy link

CLA signed by all contributors.

@Iristyle
Copy link
Contributor Author

Iristyle commented Dec 3, 2018

@glennsarti so I was intentionally trying to avoid enumerating the keys given there's an API for retrieving by name - this ends up adding a fair amount more code. I initially looked at doing something like you ended up with, but decided on the direction in my PR.

I'll take a look at your concern about read and look for an alternate solution. I'm not sure that we even care about the type of error in this case.

 - Previous error handling for Win32 registry API calls were, in some
   cases, relying on FFI to call GetLastError behind the scenes when
   raising a new Puppet::Util::Windows::Error.

   However, Registry API calls do not use GetLastError and instead
   return error codes directly from their API calls.

   "
   If the function fails, the return value is a nonzero error code
   defined in Winerror.h. You can use the FormatMessage function with
   the FORMAT_MESSAGE_FROM_SYSTEM flag to get a generic description of
   the error.
   "

   The above is what Puppet::Util::Windows::Error does when given an
   explicit error code.

 - This fixes multiple problems with being able to inspect actual
   error codes from raised exceptions.

   In particular, it's helpful to know when RegQueryValueExW has
   returned a value of "2" which is ERROR_FILE_NOT_FOUND, meaning
   a registry value does not exist with the given name.

   This is important for the next commit.
@Iristyle Iristyle force-pushed the PUP-9312-packages-when-registry-corrupt branch 3 times, most recently from 6397070 to c3163fd Compare December 3, 2018 22:54
vals[name] = data
rescue Puppet::Util::Windows::Error => e
# ignore missing names, but raise other errors
raise e unless e.code == Puppet::Util::Windows::Error::ERROR_FILE_NOT_FOUND
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay!

 - Previously, the Windows package provider would enumerate all
   registry values affiliated with a given product.

   Products are enumerated under
   HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

   Where each individual product resides in a subkey, like 7-Zip

   This could result in reading quite a bit of extraneous data.

 - In reality, there are only 9 total key values that the package
   provider is interested in for either MSI or EXE packages, so
   whitelist those values when enumerating for a given product.

 - This also fixes an issue where some products may install bad data
   into registry values (one such product stores binary data inside
   of a REG_SZ which breaks Puppets abiliy to interpret the value
   as a string).

   While this is really the fault of the product and not of Puppet,
   Puppet must be resilient to such bad data.
@Iristyle Iristyle force-pushed the PUP-9312-packages-when-registry-corrupt branch from c3163fd to 65d1355 Compare December 3, 2018 23:14
Copy link
Contributor

@glennsarti glennsarti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mergin time

@michaeltlombardi michaeltlombardi merged commit 2b27922 into puppetlabs:5.5.x Dec 4, 2018
@Iristyle Iristyle deleted the PUP-9312-packages-when-registry-corrupt branch December 4, 2018 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants