{"id":24,"date":"2012-07-23T13:16:56","date_gmt":"2012-07-23T12:16:56","guid":{"rendered":"http:\/\/sysprogs.com\/blog\/?p=24"},"modified":"2012-07-23T13:21:50","modified_gmt":"2012-07-23T12:21:50","slug":"beware-a-buggy-memcpy-in-macos-10-7-kernel","status":"publish","type":"post","link":"https:\/\/sysprogs.com\/w\/beware-a-buggy-memcpy-in-macos-10-7-kernel\/","title":{"rendered":"Beware: a bug in memcpy() in MacOS 10.7 Kernel"},"content":{"rendered":"<p>I was just creating a truncated port of STLPort for MacOS kernel environment for one of our Mac drivers and stumbled upon a nasty bug. Any attempt to initialize an std::string immediately caused a kernel panic.<\/p>\n<p>Investigating the problem revealed that the <strong>memcpy()<\/strong> function that is manually coded in assembly does not actually care about the return value. Makes sense, how often did you use the return value of <strong>memcpy()<\/strong>? I never did. Just until finding out that STLPort heavily does and crashes in case it&#8217;s wrong.<\/p>\n<p>I&#8217;ve created a simple test case to reproduce the bug:<\/p>\n<p><a href=\"http:\/\/sysprogs.com\/blog\/wp-content\/uploads\/2012\/07\/ucopy.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-28\" title=\"ucopy\" src=\"http:\/\/sysprogs.com\/blog\/wp-content\/uploads\/2012\/07\/ucopy.png\" alt=\"\" width=\"699\" height=\"359\" srcset=\"https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/ucopy.png 699w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/ucopy-300x154.png 300w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/ucopy-500x256.png 500w\" sizes=\"(max-width: 699px) 100vw, 699px\" \/><\/a>The <strong>__ucopy_trivial()<\/strong> function that is supposed to return the pointer to the end of the destination array actually returns 0x02. Looking more into the <strong>memcpy()<\/strong> function shows that the authors have simply forgotten to do anything with the <strong>$rax<\/strong> register holding the return value:<\/p>\n<p><a href=\"http:\/\/sysprogs.com\/blog\/wp-content\/uploads\/2012\/07\/memcpy.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-29\" title=\"memcpy\" src=\"http:\/\/sysprogs.com\/blog\/wp-content\/uploads\/2012\/07\/memcpy.png\" alt=\"\" width=\"553\" height=\"327\" srcset=\"https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/memcpy.png 553w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/memcpy-300x177.png 300w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/memcpy-500x295.png 500w\" sizes=\"(max-width: 553px) 100vw, 553px\" \/><\/a>That&#8217;s consistent wit the contents of the <strong>xnu-1699.22.81\/osfmk\/x86_64\/bcopy.s<\/strong> file:<\/p>\n<pre>\/* void *memcpy((void *) to, (const void *) from, (size_t) bcount) *\/\r\n\/*\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0rdi,\u00a0\u00a0 \u00a0 \u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 rsi,\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rdx\u00a0\u00a0 *\/\r\n\/*\r\n\u00a0* Note: memcpy does not support overlapping copies\r\n\u00a0*\/\r\nENTRY(memcpy)\r\n\u00a0\u00a0 \u00a0movq\u00a0\u00a0 \u00a0%rdx,%rcx\r\n\u00a0\u00a0 \u00a0shrq\u00a0\u00a0 \u00a0$3,%rcx\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/* copy by 64-bit words *\/\r\n\u00a0\u00a0 \u00a0cld\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/* copy forwards *\/\r\n\u00a0\u00a0 \u00a0rep\r\n\u00a0\u00a0 \u00a0movsq\r\n\u00a0\u00a0 \u00a0movq\u00a0\u00a0 \u00a0%rdx,%rcx\r\n\u00a0\u00a0 \u00a0andq\u00a0\u00a0 \u00a0$7,%rcx\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/* any bytes left? *\/\r\n\u00a0\u00a0 \u00a0rep\r\n\u00a0\u00a0 \u00a0movsb\r\n\u00a0\u00a0 \u00a0ret<\/pre>\n<p>Oops, what <strong>%rax<\/strong>? \ud83d\ude42<\/p>\n<p>I believe one of the reasons reason why this bug has not been immediately discovered is because in most of the cases when you call <strong>memcpy()<\/strong>, gcc will use the <strong>$rax<\/strong> register to hold the first argument before placing it to <strong>$rdi<\/strong>. Thus if you try to reproduce the bug with a simple call to memcpy() alone, you won&#8217;t see any problem:<\/p>\n<p><a href=\"http:\/\/sysprogs.com\/blog\/wp-content\/uploads\/2012\/07\/dbg.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-30\" title=\"dbg\" src=\"http:\/\/sysprogs.com\/blog\/wp-content\/uploads\/2012\/07\/dbg-1024x724.png\" alt=\"\" width=\"584\" height=\"412\" srcset=\"https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/dbg-1024x724.png 1024w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/dbg-300x212.png 300w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/dbg-424x300.png 424w, https:\/\/sysprogs.com\/w\/wp-content\/uploads\/2012\/07\/dbg.png 1193w\" sizes=\"(max-width: 584px) 100vw, 584px\" \/><\/a><\/p>\n<h2>The solution<\/h2>\n<p>The solution is simple: just make a wrapper around memcpy() and put it somewhere in your global header files so that the memcpy()-related code will actually use it:<\/p>\n<pre>static inline void *memcpy_workaround(void *dst, \r\n                                      const void *src, size_t len)\r\n{\r\n\u00a0\u00a0 \u00a0memcpy(dst, src, len);\r\n\u00a0\u00a0 \u00a0return dst;\r\n}\r\n\r\n#define memcpy memcpy_workaround<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was just creating a truncated port of STLPort for MacOS kernel environment for one of our Mac drivers and stumbled upon a nasty bug. Any attempt to initialize an std::string immediately caused a kernel panic. Investigating the problem revealed that the memcpy() function that is manually coded in assembly does not actually care about &hellip; <a href=\"https:\/\/sysprogs.com\/w\/beware-a-buggy-memcpy-in-macos-10-7-kernel\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Beware: a bug in memcpy() in MacOS 10.7 Kernel<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/posts\/24"}],"collection":[{"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":4,"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"predecessor-version":[{"id":33,"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/posts\/24\/revisions\/33"}],"wp:attachment":[{"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sysprogs.com\/w\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}