Registry Filters and Symbolic Links

I ran into an interesting case while working on a registry filter driver the other day. Boiled down to its most basic form, my driver is blocking access to registry keys by name. I watch for a name that matches one in my list then fail the open/create. The interesting case is when a registry key is a symbolic link (I.e., was created with REG_CREATE_LINK and has a REG_LINK value named SymbolicLinkValue that points to a second key).

All my filtering work takes place in the Pre-Open/Create path, and because the name coming in doesn’t actually represent what really will be opened, I can’t exactly rely on the name. So after digging into how these operations get handled, I have found some very odd behavior. I see two different behaviors for an open/create under these conditions. I created a sample filter driver to test this and tested on Windows 8 x64 and Windows 7 x64.

  1. When I try to open the link source (the key that links to a second key), I see the following:
  1. RegNtPreOpenKeyEx with CompleteName containing the name of the key – I return STATUS_SUCCESS to allow processing to continue.
  2. RegNtPostOpenKeyEx with PreInformation->CompleteName containing the key name from the SymbolicLinkValue. Status contains STATUS_REPARSE.
  3. RegNtPreOpenKeyEx with Complete Name containing the key name of the link target (from step b).
  4. RegNtPostOpenKeyEx with Status equal to STATUS_SUCCESS.
  • After a small number of repetitions (usually 2) the above behavior stops, and is replaced with the following:
    1. RegNtPreOpenKeyEx with CompleteName containing the name of the key – I return STATUS_SUCCESS to allow processing to continue.
    2. RegNtPostOpenKeyEx with Status equal to STATUS_SUCCESS. PreInformation->CompleteName contains the original name from step a, but the Object contains a pointer to a registry object for the link target key.

    Additionally, the behaviors above seem to revert after some period of time. If I run a simple registry open command for the link source a hundred times, I see behavior #1 twice and then #2 the remainder of the time. But after doing that if I let the machine sit idle for 4-5 minutes and run it again, I will again see behavior #1 twice, followed by #2 for as many times as I care to repeat it.

    I e-mailed some contacts at Microsoft and they confirmed what I have been seeing. The registry maintains a key lookup cache that is intended to speed up open/create operations. One thing that the cache can do is remember symbolic links and avoid the need to reparse them every time they are opened. This is a bit frustrating for me, but it probably makes a significant difference in registry performance (which, incidentally is a heck of a lot faster than file system performance).

    Unfortunately it would seem that the way to solve this problem is to store some of the data I need internally to my driver based on watching the systems behavior. So, for example, I can watch for the STATUS_REPARSE result to come back, and do something with the CompleteName value. So I could add a context to the call in the pre-open, put the original complete name in the context, then in the post-open when I see STATUS_REPARSE, I can add an entry to a list that says “Name A links to Name B”, which I can thereafter use in my pre-open. I then also have to deal with cases where the link key gets removed (I can watch for a pre-open with OBJ_OPENLINK, place a context on the object, then watch for the delete, and clean up my internal cache). I also have to deal with the case where the link gets retargeted to something else (I can watch for the pre-open with OBJ_OPENLINK, context the object, watch for the pre-set-value for REG_LINK named SymbolicLinkValue and update my cache).

    I won’t show the solution code here, since its fairly complicated, and it is the intellectual property of my company, but the solution is fairly straight-forward once you understand what needs to be done. I will, however, show some of the code that I actually used to test this and grok the behavior.

    Continue reading “Registry Filters and Symbolic Links”

    Creating and Viewing Registry Links with NativeTest

    A while back I wrote a tool called NativeTest and open-sourced it on CodePlex. You can view the original post about this at the FSLogix Blog. Today I was troubleshooting a problem with registry links that required me to look at what was really going on in the registry, without it redirecting me through symbolic links. So I turned to the NativeTest project, which was able to help out.

    For those who don’t already know, the registry can have symbolic links where a key actually is just a pointer to another key. So, for example, the HKLM\Software\CurrentControlSet key is a symbolic link created during system boot that points to HKLM\Software\CurrentControlSet001 (or some other numbered control set, depending on your hardware configuration).

    Viewing a registry symbolic link involves opening the key with a special flag (REG_OPTION_OPEN_LINK) and then querying the value named “SymbolicLinkValue”. The value’s data will be a fully qualified native path to another registry key. The only difficult part about doing this with NativeTest is figuring out that the numeric option for REG_OPTION_OPEN_LINK is equivalent to 8, which you can find in the Windows SDK header files.

    The NativeTest session for viewing the link at HKLM\System\ControlSet001\Control\Print\Printers is as follows:

    > openkeyex -name \registry\machine\system\controlset001\control\print\printers -access kr -options 8
    Status = 0x00000000
    Handle = 40 (AUTO-0)
    
    > enumvaluekey -handle AUTO-0 -index 0 -class full -bufferlen 256
    AUTO-HANDLE: 40
    Status = 0x00000000
    ResultLength = 210
    00 00 00 00 06 00 00 00     ........
    38 00 00 00 9a 00 00 00     8.......
    22 00 00 00 53 00 79 00     "...S.y.
    6d 00 62 00 6f 00 6c 00     m.b.o.l.
    69 00 63 00 4c 00 69 00     i.c.L.i.
    6e 00 6b 00 56 00 61 00     n.k.V.a.
    6c 00 75 00 65 00 46 00     l.u.e.F.
    5c 00 52 00 65 00 67 00     \.R.e.g.
    69 00 73 00 74 00 72 00     i.s.t.r.
    79 00 5c 00 4d 00 61 00     y.\.M.a.
    63 00 68 00 69 00 6e 00     c.h.i.n.
    65 00 5c 00 53 00 6f 00     e.\.S.o.
    66 00 74 00 77 00 61 00     f.t.w.a.
    72 00 65 00 5c 00 4d 00     r.e.\.M.
    69 00 63 00 72 00 6f 00     i.c.r.o.
    73 00 6f 00 66 00 74 00     s.o.f.t.
    5c 00 57 00 69 00 6e 00     \.W.i.n.
    64 00 6f 00 77 00 73 00     d.o.w.s.
    20 00 4e 00 54 00 5c 00      .N.T.\.
    43 00 75 00 72 00 72 00     C.u.r.r.
    65 00 6e 00 74 00 56 00     e.n.t.V.
    65 00 72 00 73 00 69 00     e.r.s.i.
    6f 00 6e 00 5c 00 50 00     o.n.\.P.
    72 00 69 00 6e 00 74 00     r.i.n.t.
    5c 00 50 00 72 00 69 00     \.P.r.i.
    6e 00 74 00 65 00 72 00     n.t.e.r.
    73 00                       s.
    
    > closekey -handle auto-0
    AUTO-HANDLE: 40
    Status = 0x00000000

    As you can see, this key is really just a pointer to HKLM\Software\Microsoft\Windows NT\CurrentVersion\Print\Printers.

    The next task is how can I actually create one of these links for my own testing, just so I don’t accidentally mess up one of the system keys. Creating a symbolic registry link is pretty easy. You just have to create they key with a certain option (REG_OPTION_CREATE_LINK), and then set the value named “SymbolicLinkValue”, which needs to be of type REG_LINK. Again, the hard part is figuring out that REG_OPTION_CREATE_LINK is the equivalent of 2.

    The session looks like this:

    > createkey -name \registry\machine\software\Test -access ka -options 2
    Status = 0x00000000
    Disposition = Created
    Handle = 48 (AUTO-0)
    
    > setvaluekey -handle auto-0 -name SymbolicLinkValue -type link -data \\Registry\\Machine\\Software\\Test2
    AUTO-HANDLE: 48
    Status = 0x00000000
    
    > queryvaluekey -handle auto-0 -name SymbolicLinkValue -class full -bufferlen 512
    AUTO-HANDLE: 48
    Status = 0x00000000
    ResultLength = 120
    00 00 00 00 06 00 00 00     ........
    38 00 00 00 44 00 00 00     8...D...
    22 00 00 00 53 00 79 00     "...S.y.
    6d 00 62 00 6f 00 6c 00     m.b.o.l.
    69 00 63 00 4c 00 69 00     i.c.L.i.
    6e 00 6b 00 56 00 61 00     n.k.V.a.
    6c 00 75 00 65 00 00 00     l.u.e...
    5c 00 52 00 65 00 67 00     \.R.e.g.
    69 00 73 00 74 00 72 00     i.s.t.r.
    79 00 5c 00 4d 00 61 00     y.\.M.a.
    63 00 68 00 69 00 6e 00     c.h.i.n.
    65 00 5c 00 53 00 6f 00     e.\.S.o.
    66 00 74 00 77 00 61 00     f.t.w.a.
    72 00 65 00 5c 00 46 00     r.e.\.T.
    53 00 4c 00 6f 00 67 00     e.s.t.2.
    
    > closekey -handle auto-0
    AUTO-HANDLE: 48
    Status = 0x00000000

    Once you have created it, it’s kind of fun to poke around at the key with regedit. If you, like me, decide to clean up your test key and delete it in regedit, you will find that deleting the link source actually follows the link and deletes the target. The link source remains and now displays an error about the system cannot find the file specified. In my testing, it seems to be impossible to delete the link source in regedit, so we need to look at one more thing in NativeTest: deleting the link source key. The only trick here is that you have to open the key with REG_OPTION_OPEN_LINK so that the system doesn’t try to follow the link (which, incidentally is what regedit is doing).

    The session looks like this:

    > openkeyex -name \registry\machine\software\test -access ka -options 8
    Status = 0x00000000
    Handle = 52 (AUTO-0)
    
    > deletekey -handle auto-0
    AUTO-HANDLE: 52
    Status = 0x00000000
    
    > closekey -handle auto-0
    AUTO-HANDLE: 52
    Status = 0x00000000