{"id":108766,"date":"2023-09-14T07:00:00","date_gmt":"2023-09-14T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108766"},"modified":"2023-09-14T07:29:03","modified_gmt":"2023-09-14T14:29:03","slug":"20230914-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230914-00\/?p=108766","title":{"rendered":"I accidentally performed an operation on <CODE>INVALID_<WBR>HANDLE_<WBR>VALUE<\/CODE>, and it worked: What just happened?"},"content":{"rendered":"<p>Suppose you have some code that wants to open a file and share it with another process.<\/p>\n<pre>HANDLE file = CreateFile(...);\r\n\r\nHANDLE dup;\r\nif (DuplicateHandle(\r\n        GetCurrentProcess(), \/* source process *\/\r\n        file, \/* source handle *\/\r\n        targetProcess,\r\n        &amp;dup,\r\n        0,\r\n        FALSE, \/* no inherit *\/\r\n        DUPLICATE_SAME_ACCESS)) {\r\n    ... tell the other process to use \"dup\" ...\r\n}\r\n\r\nCloseHandle(file);\r\n<\/pre>\n<p>This code is missing some critical error handling: What if the <code>CreateFile<\/code> fails?<\/p>\n<p>If <code>CreateFile<\/code> fails, it returns <code>INVALID_<wbr \/>HANDLE_<wbr \/>VALUE<\/code>. This code then passes <code>INVALID_<wbr \/>HANDLE_<wbr \/>VALUE<\/code> as the source handle to duplicate into the other process. But instead of failing, the <code>Duplicate\u00adHandle<\/code> succeeds and produces a handle. What handle just got duplicated?<\/p>\n<p>Some time ago, we studied <a title=\"Why are HANDLE return values so inconsistent?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040302-00\/?p=40443\"> why <code>HANDLE<\/code> return values are so inconsistent<\/a>, and I mentioned that<\/p>\n<blockquote class=\"q\">\n<p>By coincidence, the value <code>INVALID_<wbr \/>HANDLE_<wbr \/>VALUE<\/code> happens to be numerically equal to the pseudohandle returned by <code>Get<wbr \/>Current<wbr \/>Process()<\/code>.<\/p>\n<\/blockquote>\n<p>Therefore, what happened is that we gave a copy of our own process handle to the other process.<\/p>\n<p>Oops.<\/p>\n<p>But wait, there&#8217;s more. The handle returned by <code>Get<wbr \/>Current<wbr \/>Process()<\/code> has <code>PROCESS_<wbr \/>ALL_<wbr \/>ACCESS<\/code> permission. Not only did you give the other process the wrong thing, you gave it possibly the worst possible thing: You gave it <i>full control over your own process<\/i>.<\/p>\n<p>Double oops.<\/p>\n<p>Why does <code>Get<wbr \/>Current<wbr \/>Process()<\/code> return a pseudo-handle value that matches a common error case that people could overlook? I don&#8217;t know, but I have an idea.<\/p>\n<p>Developer 1: &#8220;Hey, what fake handle value should <code>Get<wbr \/>Current<wbr \/>Process()<\/code> return?&#8221;<\/p>\n<p>Developer 2: &#8220;I dunno. We need to pick something that is guaranteed never to accidentally match a real handle value.&#8221;<\/p>\n<p>Developer 1: &#8220;Look, there&#8217;s this special value <code>INVALID_<wbr \/>HANDLE_<wbr \/>VALUE<\/code> that is returned to indicate that an error occurred. This is provably a handle value that can never match a real handle, since it is used to indicate a problem.&#8221;<\/p>\n<p>Developer 2: &#8220;Great, let&#8217;s use that!&#8221;<\/p>\n<p>It seemed like a good idea at the time. For a special value, use something that couldn&#8217;t possibly conflict with a normal value.<\/p>\n<p>Unfortunately, people are fallible, and bugs can occur like<\/p>\n<pre>HANDLE file = INVALID_HANDLE_VALUE;\r\n\r\nif (want_file) {\r\n    file = CreateFile(...);\r\n    if (file == INVALID_HANDLE_VALUE) {\r\n        error();\r\n        return;\r\n    }\r\n\r\n\/* other intervening code *\/\r\n\r\n\/\/ Okay, give the file to the other process.\r\nHANDLE dup;\r\nif (DuplicateHandle(\r\n        GetCurrentProcess(), \/* source process *\/\r\n        file, \/* source handle *\/\r\n        targetProcess,\r\n        &amp;dup,\r\n        0,\r\n        FALSE, \/* no inherit *\/\r\n        DUPLICATE_SAME_ACCESS)) {\r\n    ... tell the other process to use \"dup\" ...\r\n}\r\n\r\nCloseHandle(file);\r\n<\/pre>\n<p>The code that calls <code>Duplicate\u00adHandle<\/code> forgot to check whether <code>want_file<\/code> is set and inadvertently passed <code>INVALID_<wbr \/>HANDLE_<wbr \/>VALUE<\/code>. Oops, duplicated a full-access process handle.<\/p>\n<p>This pattern of &#8220;using an invalid value to carry a special alternate meaning&#8221; is actually quite common. For example, <code>Set\u00adWindows\u00adHook\u00adEx<\/code> uses a thread ID of zero to mean &#8220;global hook&#8221;, since zero is not a valid thread ID. And many functions imbue the special value <code>nullptr<\/code> with all sorts of special meaning.<\/p>\n<p>In retrospect, the choice to use <code>INVALID_<wbr \/>HANDLE_<wbr \/>VALUE<\/code> as a pseudohandle was unfortunate. But what happened happened. You can&#8217;t change the past, and in computer software, you have to live with your mistakes.<\/p>\n<p><b>Bonus chatter<\/b>: RPC has the <a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/midl\/system-handle\"> <code>system_handle<\/code> attribute<\/a> which lets you pass kernel handles via RPC, and you also have to say what kind of kernel handle you intend to pass. For files, you say <code>system_handle(<wbr \/>sh_file)<\/code>. If you pass the wrong kind of handle, the operation fails. There&#8217;s <a href=\"https:\/\/github.com\/microsoft\/Windows-classic-samples\/tree\/main\/Samples\/SystemHandlePassing\"> a sample in the Windows Classic Samples repo<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Coincidentally valid, but not what you think.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-108766","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Coincidentally valid, but not what you think.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108766","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=108766"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108766\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=108766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}