Monday, January 14, 2013

OSX AuthorizationExecuteWithPrivileges example

Copyright © 2013, Steven E. Houchin. All rights reserved.

I've read various posts online about developers' travails with OSX's AuthorizationExecuteWithPrivileges API, and misunderstanding about how it works.  So, here is some of what I've learned about it.

Apple's documentation states that it "Runs an executable tool with root privileges."  But, users soon discover that the new process does not, in fact, run as root.  In reality, the new process executes at an elevated privilege level that allows it to become the root user by calling 'setuid(0)'.  For example:

// Fork a child process
pid_t child_pid = fork();
if(child_pid == 0)
{
  // This is done by the child process
           
  // Change to the root user
  uid_t userid = getuid();
  setuid(0);  // set root permissions 

  // Do things as root ... 

  // Restore normal permissions
  setuid(userid);
  exit(0);
}

Note that there is danger in using AuthorizationExecuteWithPrivileges.  For example, your app might invoke a helper tool named 'grok' that will execute with the elevated privileges.   If a hacker figures out that 'grok' is started this way, he can replace 'grok' with his own trojan binary, which can then make itself root and thus do nasty things to your system. It isn't really hard for a hacker to determine that 'grok' is invoked this way, because the MAC's Console utility logs that AuthorizationExecuteWithPrivileges was called to execute 'grok.'   So, if you must execute 'grok' this way, your app should first validate the 'grok' binary in some way to make sure it has not been tampered with.  What I did was to open 'grok' as a binary data file and then I scan it for a known string used in the code, such as an innocuous printf format string.

The first parameter to AuthorizationExecuteWithPrivileges is an AuthorizationRef object.  This is obtained via a call to AuthorizationCreate:

AuthorizationRef authorizationRef;
OSStatus status = AuthorizationCreate(NULL,
                       kAuthorizationEmptyEnvironment,
                       kAuthorizationFlagDefaults,
                       &authorizationRef);
if (status != errAuthorizationSuccess)
{
    // Notify user of the error ...
}

The actual elevated rights you request are specified via a call to AuthorizationCopyRights, at which time the user is prompted to enter his password.  Along with requesting certain rights, you can specify a custom icon and text for the password popup.  Note however that your icon will not appear if it resides in a directory beneath any ancestor directory that lacks Everyone access.  Here's what the icon specification looks like, which is passed as the AuthorizationEnvironment parameter to AuthorizationCopyRights:

AuthorizationItem kAuthEnv[1];
const char *iconPath = "/Applications/MyApp.app/Resources/myicon.icns";
kAuthEnv[0].name = kAuthorizationEnvironmentIcon;
kAuthEnv[0].valueLength = strlen(iconPath);
kAuthEnv[0].value = (void *)iconPath; // fully qualified path
kAuthEnv[0].flags = 0;
AuthorizationEnvironment authorizationEnvironment;
authorizationEnvironment.items = kAuthEnv;
authorizationEnvironment.count = 1;

Next, in order to use AuthorizationExecuteWithPrivileges, you must request the "system.privilege.admin" right.  You set this up as follows:

const char *grokPath = "/Utilities/grokUtil/grok";
AuthorizationItem executeRight = {
                        kAuthorizationRightExecute,
                        strlen(grokPath)
                        (void *)grokPath,
                        0};
AuthorizationRights rightsSet = {1, &executeRight};

Note that kAuthorizationRightExecute is defined as "system.privilege.admin" in the Security framework's AuthorizationTags.h.  This is then used in AuthorizationCopyRights to actually acquire the rights for the AuthorizationRef object:

AuthorizationFlags flags =
                  kAuthorizationFlagDefaults |
                  kAuthorizationFlagInteractionAllowed |
                  kAuthorizationFlagPreAuthorize |
                  kAuthorizationFlagExtendRights;

// Call AuthorizationCopyRights to determine
// or extend the allowable rights
OSStatus status = AuthorizationCopyRights(
                                authorizationRef,
                                &rightsSet,
                                &authorizationEnvironment,
                                flags,
                                NULL);
if (errAuthorizationCanceled == status)
{
    // User canceled authentication  ...
}
else if (status != errAuthorizationSuccess)
{
    // Notify the user of the error ...
}

All that's left at this point is to execute the privileged helper tool:

FILE *fpStdout = NULL;
status = AuthorizationExecuteWithPrivileges(
                        authorizationRef,
                        (const char *)grokPath,
                        kAuthorizationFlagDefaults,
                        argv,  // normal argv array of program args
                        &fpStdout);
bool success = (status == errAuthorizationSuccess);
pid_t newProcId;
if (success)
{
   // Get the new process id
   newProcId = fcntl(fileno(fpStdout), F_GETOWN, 0);
   fclose(fpStdout);
}
else
{
   // Notify user of the error ...
}

AuthorizationExecuteWithPrivileges returns as soon as the new process has started.  It does not execute it as a child of the current process, so a waitpid on the resulting process id gives an error.

Friday, February 10, 2012

Learning to hate AllocateAdapterChannel

Copyright © 2012, Steven E. Houchin. All rights reserved.

I have a scatter-gather device I'm supporting in a Windows PNP driver. Normally, a driver developer would use the GetScatterGatherList API to map multiple IRP buffers to a device's DMA capabilities. However, in my case, my device has peculiar buffer alignment requirements that I can't count on GetScatterGatherList to handle. But, no worries. The AllocateAdapterChannel API is available.

Wait! Not so fast. In order for my device to perform at peak speed, multiple Read and Write IRPs are simultaneously active and mapped to the DMA. What this means is, I can't wait for the occurrence of an interrupt and an IRP completion before mapping the next IRP to the DMA; I map dozens or hundreds of them to the DMA in advance.

GetScatterGatherList handles all this just fine as long as each IRP has its own associated separate DMA_ADAPTER object. In theory, AllocateAdapterChannel should be able to do the same, but it can't. There is this sneaky little note in the WDDK documentation that throws a fly into the oatmeal:

Only one DMA request can be queued for a device object at any one time. Therefore, the driver should not call AllocateAdapterChannel again for another DMA operation on the same device object until the AdapterControl routine has completed execution.

The key phrase there is "device object." DEVICE_OBJECT is a parameter to AllocateAdapterChannel. So, even if I have a separate DMA_ADAPTER object for each mapped IRP, it still uses just the one DEVICE_OBJECT. The note above blandly states "until the AdapterControl routine has completed execution." Exactly how do I know when it completes execution? If the driver is executing its assembly "ret" instruction, it is technically still in the AdapterControl callback, so anything I do inside it to notify another thread to proceed is too early.

I believe the issue here is that DEVICE_OBJECT is placed on a wait list by the kernel when the DMA is not immediately available. Thus, we can't have that object placed twice on a list. Maybe the answer is to create a separate, fake DEVICE_OBJECT for each IRP, just like I do with DMA_ADAPTER.

Charging ahead, I created a pool of DEVICE_OBJECTs, copied from the original, and used them round-robin for each simultaneous AllocateAdapterChannel, preventing any more calls if none available.

No luck. The failure manifests itself by the AdapterControl being called back twice in a row for the same IRP - i.e. two calls to AdapterControl for an IRPs single call to AllocateAdapterChannel. Now, maybe I am still doing something wrong managing my fake DEVICE_OBJECTs. For example, when do I really know that a DEVICE_OBJECT is available for reuse? It's the fly and oatmeal problem again with the AdapterControl callback: when has it really "completed execution?"

For now, I don't have a workable solution to this. I'll let you know if I figure it out.

Monday, October 24, 2011

Computing the viewport size within a WPF Border control

Copyright © 2011, Steven E. Houchin. All rights reserved.

I have a WPF application that renders a photo bitmap inside a System.Windows.Controls.Image control that is contained within a System.Windows.Controls.Border. If the photo bitmap is too large for the app window (either in the horizontal or vertical direction), I set the Image's corresponding size attribute(s) to 'Auto' (i.e. Double.NaN) within the Image's SizeChanged event handler. If the bitmap is smaller than the app window, I set the Image's size to the actual fixed size of the bitmap, so it doesn't get scaled.

But, that left a problem when I resized the app window smaller: a fixed-size Image was truncated by the border when the window shrank smaller than the photo's bitmap size. And, because the Image's width/height weren't set to Auto, its SizeChanged event wasn't firing.

However, the Border's SizeChanged event was firing. So, I added that handler for the Border control, planning to set the Image's proper width/height after resize.  That left another problem in this new event handler: how to calculate whether or not the Image control's width/height should be Auto or fixed.  Put another way, what was the size of the viewport inside the Border control where the Image would be rendered?

The Border's SizeChanged event handler is passed a SizeChangedEventArgs parameter that provides the new width/height of the Border control. The size available to the Image control inside that will clearly be smaller, but by how much? Here is the algorithm in C# that I came up with (keep in mind that a negative BorderThickness means the border is drawn outside the control's drawing area):

// Calculate the Border control's new viewport
// size within the drawn border where the Image control
// is rendered (add in any padding and non-negative
// border thickness).
Size viewport = new Size();
viewport.Width = e.NewSize.Width -
    (border.Padding.Left + border.Padding.Right) -
    ((border.BorderThickness.Left > 0) ?
        border.BorderThickness.Left : 0) -
    ((border.BorderThickness.Right > 0) ?
        border.BorderThickness.Right : 0);
viewport.Height = e.NewSize.Height -
    (border.Padding.Top + border.Padding.Bottom) -
    ((border.BorderThickness.Top > 0) ?
        border.BorderThickness.Top : 0) -
    ((border.BorderThickness.Bottom > 0) ?
        border.BorderThickness.Bottom : 0);
This viewport variable now holds the size available for the Image control inside the border. Now, all I have to do is determine if the Image needs to be scaled down in the viewport or set to a fixed size. One thing I discovered is that the Image's Margin value must be taken into account, since it is also rendered inside the viewport along with the photo bitmap. The code to determine the right sizing, in this case for the width is:

// Calculate the image's real width to determine if
// scaling is needed
double imageWidth = _bitmapActualSize.Width +
    image.Margin.Left + image.Margin.Right;
if (viewport.Width > imageWidth)
{
    // Restrict the Image control's width to the
    // bitmap's actual width
    image.Width = _bitmapActualSize.Width;
}
else if (viewport.Width < imageWidth)
{
    if (Double.NaN != image.Width)
    {
        // Set the Image control's width to 'Auto' so
        // it will scale down to fit
        image.Width = Double.NaN;
    }
}
The same calculation is done for the Image height immediately after. This results in the proper change to the photo bitmap size just at the right time.

Wednesday, August 31, 2011

Eliminating Visible Image Borders on Blogger

Copyright © 2011, Steven E. Houchin

Something that has driven me crazy for quite awhile about Blogger is its propensity to place a thick white border around any image I added to my postings. Editing the HTML of the img element to include border="0" or a style="border: none;" or anything else like that was simply ignored. What the heck was happening?

Then, I found a hint on another site, where it referred to Blogger's "template style sheet." After some poking around in Blogger, I stumbled across it. When logged in, navigate to the Dashboard page, then select the Design tab (or link), then click the Edit HTML link along the top. This brings up a screen that allows editing of your blog template, which contains the HTML, CSS, and Javascript that is the basis for every posting. On this template page, it suggests you download your existing template before messing with it, which sounds like good advice. Under the Edit Template heading is the text of the template which you can alter.

Okay. Now to the nuts and bolts of what I did to eliminate the image border. In my template, there was a CSS directive like this:

.post-body img,  .post-body .tr-caption-container { 
   padding: 8px;
}

The 8 pixels of padding is the border I saw, because it seems to inherit a white background color from elsewhere. My images are controlled by the ".post-body img" class. So, I deleted that class specification from the above and created a new one that had the padding and background specifications I wanted:

.post-body .tr-caption-container {
  padding: 8px;
}

.post-body img {
  padding: 8px;
  background: $(post.background.color);
}

This keeps the padding (which I like since it provides some separation between the image and the text) and makes the background color for the image's box the same as the post's color. The $(post.background.color) value is, I think, a variable handled by Blogger's XSL processing that is replaced in the final output with the actual color (or "transparent" in my case).

Once I saved these CSS changes to my template ... voila! The image borders in all my posts (new and old) vanished. In reality, all I really did was change the background color of the padding for just the images.

Thursday, August 11, 2011

Finding IWin32Window in WPF

Copyright © 2011, Steven E. Houchin

I'm developing a WPF desktop application (C# and .NET 3.5) that needs to pop up a dialog window allowing the user to browse for a folder.  .NET provides a convenient (and bland) dialog that does this: System.Windows.Forms.FolderBrowserDialog. To pop up this dialog as modal from my app, I must call its ShowDialog method. Since I want it to be a child of my main window, I need to pass it the parent window, which should be straightforward given the "owner" parameter to the method in question:

DialogResult ShowDialog(System.Windows.Forms.IWin32Window owner);

The problem is, the would-be parent window of that dialog is of type System.Window, not IWin32Window, so "this.Owner" won't match the datatype of ShowDialog's "owner" parameter.  So, given that I have a WPF System.Window-derived parent class, where do I obtain an IWin32Window object?

Well, it turns out I have to write a tiny bit of code for it. Specifically, I must implement the IWin32Window interface on the parent window's class:

public partial class Main : Window,
    System.Windows.Forms.IWin32Window
{
...
   #region IWin32Window implementation
   IntPtr System.Windows.Forms.IWin32Window.Handle
   {
      get
      {
         return ((HwndSource)
             PresentationSource.FromVisual(this)).Handle;
      }
   }
   #endregion
...
}

With the IWin32Window.Handle property now implemented in the parent class, I can simply call ShowDialog(this). Note that you must also include a "using System.Windows.Interop" for this to work.


Wednesday, September 22, 2010

Kernel Driver Signing - Part III

Copyright © 2010, Steven E. Houchin

In Parts I and II of this article, I discussed the requirement for driver signing, digital signatures, and how to go about testing signed drivers.

The last step is the actual signing of the binaries that you integrate into the customer product. In order to do this, you must first purchase a digital certificate from a reputable certificate authority (CA). In fact, for kernel mode drivers, you must purchase your digital certificate from Verisign. Certificates from other vendors can be used to sign the binaries, and Windows installs them, but it refuses to execute those binaries (as of Windows 7).

As I've mentioned in the earlier parts of this article, the step-by-step procedures for driver signing are contained in a document at the Windows WHDC site, and need not be repeated here. It contains a section titled "The Kernel-Mode Code-Signing Process." The important decision to make is whether to set up the digital signature via a catalog file (specified in the INF file), or to sign the binaries directly. A cartalog is preferable, especially if you are signing multiple files; but that won't work if your binaries start at boot time (see StartType in your INF fle). In that case, signing the binarys themselves is required. Microsoft has another site, titled "Signing Drivers for Public Release", that gives more details about the files you may receive from your CA.

When you distribute your product for the customer to install, the installer package must include, in addition to the binaries, the INF file, signed catalog files (if any), and the public key portion of your digital certificate. The public key digital certificate (.spc or .cer file) must be installed on your customer's system. Your original private key digital certificate (.pvk file) should be locked away, because it is used in the signing process.

Monday, August 9, 2010

Kernel Driver Signing - Part II

Copyright © 2010, Steven E. Houchin

In Part I of this article, I explained that all kernel drivers on 64-bit Windows systems must be digitally signed.

There are two ways of signing kernel drivers: embed the signature in the driver binaries themselves, or use a signed catalog file. To peform driver signing, you really must have the latest Microsoft WDK installed on your signing system.

For drivers that start at boot time (see StartType in your INF fle), the binary itself must be signed.  Use of a catalog file is not enough, though is also required if installing the driver package via INF file.  For other types of drivers - especially those that contain multiple files - a signed catalog file can be used to identify all the files in a driver package. 

Use of a catalog file requires that the driver package be installed via an INF file, because that is where the catalog file is specified. For example, ADriver.inf will have the following line included in its [Version] section:
CatalogFile=ADriver.cat
After your driver binaries are all built and copied to a "package" directory (which includes the INF file), a catalog file is created using the WDK's Inf2Cat utility. For example, if your package files are in C:\MyDriverPackage, the catalog file (in this case for Win2K and Win64 systems) is created via:
Inf2Cat /driver:C:\MyDriverPackage\ /os:2000,Server2003_X64
This utility will scan all INF files in the given directory and create catalog files for each one using the "CatalogFile" line.

Once the catalog files are created, they must be signed using WDK's SignTool utility and your digital certificate information.  The details for catalog file creation and signing, and driver binary signing, are at the Windows WHDC site, which contains white paper that has decent step-by-step procedures.

The catalog file and INF file go together as a pair wherever the signed driver package is to be installed.  If your INF file is also used for 32-bit drivers, then your 32-bit installer should comment out the "CatalogFile" line in the [Version] section so that a signing certificate isn't needed on those systems.