1 00:00:00,327 --> 00:00:02,040 (crowd cheering and applauding) 2 00:00:02,040 --> 00:00:02,940 - All right. 3 00:00:02,940 --> 00:00:06,660 You are in track three for the PACMAN attack 4 00:00:06,660 --> 00:00:09,330 with Joseph Ravichandran. 5 00:00:09,330 --> 00:00:13,148 So welcome and he is a first time speaker. 6 00:00:13,148 --> 00:00:17,148 (crowd cheering and applauding) 7 00:00:18,120 --> 00:00:20,070 - Thank you all so much. 8 00:00:20,070 --> 00:00:20,903 All right, 9 00:00:20,903 --> 00:00:22,140 so welcome to PACMAN, 10 00:00:22,140 --> 00:00:25,380 breaking PAC on the Apple M1 with hardware attacks. 11 00:00:25,380 --> 00:00:27,210 And so my name is Joseph Ravichandran, 12 00:00:27,210 --> 00:00:28,260 I'm a first year student, 13 00:00:28,260 --> 00:00:30,150 just finished, got my first year at MIT. 14 00:00:30,150 --> 00:00:32,580 I just graduated last year from the University of Illinois, 15 00:00:32,580 --> 00:00:34,350 where I was a proud member of SIGPwny, 16 00:00:34,350 --> 00:00:35,570 which I believe is here. 17 00:00:35,570 --> 00:00:36,930 (crowd cheering) 18 00:00:36,930 --> 00:00:37,763 Let's go. 19 00:00:37,763 --> 00:00:38,760 - [Ian] We love you Joseph! 20 00:00:39,880 --> 00:00:41,520 - Thanks, Ian. 21 00:00:41,520 --> 00:00:44,430 And yeah, so I research hardware security at MIT. 22 00:00:44,430 --> 00:00:46,290 This project was a joint effort between me 23 00:00:46,290 --> 00:00:48,240 and my collaborators, Weon, Jay, 24 00:00:48,240 --> 00:00:50,490 and Mengjia, who is our fearless leader. 25 00:00:50,490 --> 00:00:51,840 And so in our group, 26 00:00:51,840 --> 00:00:53,040 what we do is try to focus on 27 00:00:53,040 --> 00:00:54,660 every aspect of hardware security 28 00:00:54,660 --> 00:00:56,910 from attacks like we're gonna do today, 29 00:00:56,910 --> 00:00:57,930 to defenses, 30 00:00:57,930 --> 00:00:58,890 formal verification, 31 00:00:58,890 --> 00:01:00,240 all sorts of good stuff. 32 00:01:00,240 --> 00:01:02,440 But like I said, today is an attack project. 33 00:01:03,600 --> 00:01:05,220 And so you might have seen our paper that came out 34 00:01:05,220 --> 00:01:06,660 about this a month ago 35 00:01:06,660 --> 00:01:07,890 in the ISCA conference. 36 00:01:07,890 --> 00:01:09,240 So Pacmanattack.com. 37 00:01:09,240 --> 00:01:11,250 You can get all the details from that. 38 00:01:11,250 --> 00:01:13,860 So this was our first introduction to the world 39 00:01:13,860 --> 00:01:15,570 about what PACMAN is, 40 00:01:15,570 --> 00:01:17,190 but it is my great pleasure today 41 00:01:17,190 --> 00:01:20,400 to explain or to introduce to you rather PACMAN version two. 42 00:01:20,400 --> 00:01:22,290 So this is not been publicly released yet, 43 00:01:22,290 --> 00:01:25,650 but we have a great new production of the attack, 44 00:01:25,650 --> 00:01:28,830 lots of improvements and lots of really cool stuff. 45 00:01:28,830 --> 00:01:32,070 And so Arm came out with this release about our project, 46 00:01:32,070 --> 00:01:34,620 talking about what PACMAN is and what's affected. 47 00:01:34,620 --> 00:01:37,500 And it turns out that it's actually not just limited to M1, 48 00:01:37,500 --> 00:01:41,010 but it actually affects a whole lot of other processors too. 49 00:01:41,010 --> 00:01:43,410 And so the PACMAN technique we think is actually quite 50 00:01:43,410 --> 00:01:44,580 a powerful technique 51 00:01:44,580 --> 00:01:45,840 and can be used for a lot of other things 52 00:01:45,840 --> 00:01:47,733 besides just pointer authentication. 53 00:01:49,440 --> 00:01:50,273 All right. 54 00:01:50,273 --> 00:01:51,840 So in the research literature, 55 00:01:51,840 --> 00:01:54,960 a lot of groups tend to focus on the software side of things 56 00:01:54,960 --> 00:01:56,550 or the hardware side of things. 57 00:01:56,550 --> 00:01:58,440 So you've got this great body of research 58 00:01:58,440 --> 00:02:01,830 in micro architectural attacks and in software attacks, 59 00:02:01,830 --> 00:02:03,240 like returner integer programming, 60 00:02:03,240 --> 00:02:04,560 all that good stuff, 61 00:02:04,560 --> 00:02:05,700 but what what's kind of lacking, 62 00:02:05,700 --> 00:02:07,440 or what we thought might could be improved 63 00:02:07,440 --> 00:02:10,140 is what happens when you bring these two worlds together. 64 00:02:10,140 --> 00:02:12,030 What kinds of new attacks are possible 65 00:02:12,030 --> 00:02:14,220 when you consider the cracks that lie 66 00:02:14,220 --> 00:02:16,140 between these two threat models? 67 00:02:16,140 --> 00:02:19,410 And so PACMAN is our vision of a synergistic attack, 68 00:02:19,410 --> 00:02:21,960 that combines both what's great about software 69 00:02:21,960 --> 00:02:23,643 and what's great about hardware. 70 00:02:24,870 --> 00:02:28,260 And so we call PACMAN a hardware, software co attack. 71 00:02:28,260 --> 00:02:31,080 And so PACMAN comes with three main contributions. 72 00:02:31,080 --> 00:02:33,150 The first is a new way of thinking 73 00:02:33,150 --> 00:02:35,050 about these compounding threat models. 74 00:02:35,970 --> 00:02:39,060 The second is a hardware bypass for pointer authentication. 75 00:02:39,060 --> 00:02:40,860 That's kind of the name of the game. 76 00:02:40,860 --> 00:02:43,470 And the third is a real implementation of this attack 77 00:02:43,470 --> 00:02:44,643 on the Apple M1 chip. 78 00:02:46,410 --> 00:02:48,780 And so today I kind of wanna come at the story of PACMAN 79 00:02:48,780 --> 00:02:50,400 from two different perspectives. 80 00:02:50,400 --> 00:02:52,020 So when we see dark slides, 81 00:02:52,020 --> 00:02:53,160 like the ones in the left, 82 00:02:53,160 --> 00:02:54,600 we're gonna be thinking like attackers. 83 00:02:54,600 --> 00:02:56,640 So when we see stuff like that, I want you to be thinking, 84 00:02:56,640 --> 00:02:58,020 how can we break this? 85 00:02:58,020 --> 00:03:01,320 But when we see things like a light slide on the right, 86 00:03:01,320 --> 00:03:03,540 we're gonna be thinking as CPU designers. 87 00:03:03,540 --> 00:03:06,810 So what kinds of choices could CPU architects have made 88 00:03:06,810 --> 00:03:08,490 that lead to attacks like this? 89 00:03:08,490 --> 00:03:11,073 So coming at the same idea from two perspectives. 90 00:03:12,450 --> 00:03:14,250 And so by the end of today's talk, 91 00:03:14,250 --> 00:03:15,390 I'd like you, the audience, 92 00:03:15,390 --> 00:03:17,340 to come up with an answer to this question, 93 00:03:17,340 --> 00:03:22,200 namely, is this a flaw or is PACMAN a consequence 94 00:03:22,200 --> 00:03:23,950 of multiple things coming together? 95 00:03:25,740 --> 00:03:27,600 And so instead of boring you with all the details 96 00:03:27,600 --> 00:03:30,120 about the attack and memory corruption, all that stuff, 97 00:03:30,120 --> 00:03:32,340 I'm gonna give you the entire idea in 60 seconds. 98 00:03:32,340 --> 00:03:33,723 So stay with me here. 99 00:03:34,860 --> 00:03:36,690 A lot of the memory corruption attacks that you see, 100 00:03:36,690 --> 00:03:38,760 they kind of all follow the same pattern. 101 00:03:38,760 --> 00:03:40,260 You get the ability to read and write memory 102 00:03:40,260 --> 00:03:41,190 that you shouldn't, 103 00:03:41,190 --> 00:03:42,720 you change a function pointer somewhere. 104 00:03:42,720 --> 00:03:46,110 So return pointer, vtable entry, something like that. 105 00:03:46,110 --> 00:03:48,750 And now you've got arbitrary code execution. 106 00:03:48,750 --> 00:03:50,940 And so the smart folks over at Arm said, 107 00:03:50,940 --> 00:03:53,010 Hey, this memory read/write memory thing 108 00:03:53,010 --> 00:03:54,180 has been around for 40 years. 109 00:03:54,180 --> 00:03:56,220 We've tried to solve it with all sorts of techniques 110 00:03:56,220 --> 00:03:57,210 and we just can't. 111 00:03:57,210 --> 00:04:00,360 So let's instead add a barrier at the end here 112 00:04:00,360 --> 00:04:01,650 that blocks this step. 113 00:04:01,650 --> 00:04:03,120 So changing function pointers 114 00:04:03,120 --> 00:04:05,543 now doesn't let you arbitrarily change the pointer 115 00:04:05,543 --> 00:04:07,230 because we're going to sign the pointers 116 00:04:07,230 --> 00:04:08,820 with a cryptographic hash. 117 00:04:08,820 --> 00:04:09,653 Okay. 118 00:04:10,500 --> 00:04:13,590 And so if you could find a way to forge these signatures, 119 00:04:13,590 --> 00:04:15,363 you could bypass this protection. 120 00:04:16,650 --> 00:04:17,790 And so you might be thinking, okay, 121 00:04:17,790 --> 00:04:19,110 why not just try them all? 122 00:04:19,110 --> 00:04:20,550 It's just a 16 bit signature. 123 00:04:20,550 --> 00:04:21,900 Why not just Brute force them? 124 00:04:21,900 --> 00:04:24,750 Well, the problem is if you try to evaluate 125 00:04:24,750 --> 00:04:26,190 an incorrectly signed pointer, 126 00:04:26,190 --> 00:04:28,080 so if you're trying to Brute force this code, 127 00:04:28,080 --> 00:04:29,160 you're going to crash. 128 00:04:29,160 --> 00:04:31,020 And since today's target is the kernel, 129 00:04:31,020 --> 00:04:32,790 you're actually going to crash your kernel, 130 00:04:32,790 --> 00:04:34,110 completely reboot your device. 131 00:04:34,110 --> 00:04:35,820 So that's not great. 132 00:04:35,820 --> 00:04:36,810 And our solution, 133 00:04:36,810 --> 00:04:38,580 this is the key takeaway from PACMAN 134 00:04:38,580 --> 00:04:41,010 is that you can actually avoid these crashes 135 00:04:41,010 --> 00:04:43,317 by doing your tests in the speculative regime. 136 00:04:43,317 --> 00:04:45,900 And so we're gonna talk about what speculation is 137 00:04:45,900 --> 00:04:47,913 and how to exploit it in this talk. 138 00:04:49,320 --> 00:04:50,340 And so that's kind of an overview 139 00:04:50,340 --> 00:04:52,230 of your mental roadmap of PACMAN. 140 00:04:52,230 --> 00:04:54,750 So we envision PACMAN as a BYOB, 141 00:04:54,750 --> 00:04:56,760 it's "bring your own bug". 142 00:04:56,760 --> 00:04:59,490 So if you look at back to this graph here, 143 00:04:59,490 --> 00:05:01,200 PACMAN or rather the attacker 144 00:05:01,200 --> 00:05:02,310 is gonna come up with this part. 145 00:05:02,310 --> 00:05:03,990 So find a read/write gadget 146 00:05:03,990 --> 00:05:05,370 and change some function pointer, 147 00:05:05,370 --> 00:05:06,840 and PACMAN's gonna handle this end. 148 00:05:06,840 --> 00:05:09,093 So defeating the PAC feature. 149 00:05:10,320 --> 00:05:12,540 And so today it is a great honor to introduce 150 00:05:12,540 --> 00:05:14,880 four brand new tools that we've developed in house 151 00:05:14,880 --> 00:05:15,930 for this research 152 00:05:15,930 --> 00:05:17,400 that we're gonna be sharing with you all today, 153 00:05:17,400 --> 00:05:21,150 as well as two proof of concept implementations. 154 00:05:21,150 --> 00:05:23,730 So the first tool is Pacman Kit, 155 00:05:23,730 --> 00:05:25,770 then we have PACMAN Finder, 156 00:05:25,770 --> 00:05:27,180 PACMAN Patcher, 157 00:05:27,180 --> 00:05:28,800 and PacmanOS. 158 00:05:28,800 --> 00:05:30,350 So let's start with Pacman Kit. 159 00:05:31,200 --> 00:05:33,030 So Pacman Kit is your best friend 160 00:05:33,030 --> 00:05:35,430 as a micro architectural security researcher, 161 00:05:35,430 --> 00:05:37,740 looking to do a tax on Apple Silicon, 162 00:05:37,740 --> 00:05:38,940 it's got everything you need. 163 00:05:38,940 --> 00:05:40,140 It's got the basics, 164 00:05:40,140 --> 00:05:41,040 kernel read/write, 165 00:05:41,040 --> 00:05:41,873 execute, 166 00:05:41,873 --> 00:05:42,810 all the stuff that you're looking for 167 00:05:42,810 --> 00:05:45,510 as someone looking to cross privileges and do some tests, 168 00:05:45,510 --> 00:05:46,980 but it also comes with the other tools 169 00:05:46,980 --> 00:05:47,970 that you might commonly need. 170 00:05:47,970 --> 00:05:49,440 So if you wanna read an address 171 00:05:49,440 --> 00:05:50,820 and see how long does it take the kernel 172 00:05:50,820 --> 00:05:52,640 to load this address, this can do that. 173 00:05:52,640 --> 00:05:54,480 If you wanna translate a virtual address 174 00:05:54,480 --> 00:05:56,190 from user space to its physical address 175 00:05:56,190 --> 00:05:57,810 for creating better eviction sets, 176 00:05:57,810 --> 00:05:58,770 this can do that. 177 00:05:58,770 --> 00:06:00,510 So it's got a lot of really great tools 178 00:06:00,510 --> 00:06:01,560 and it's battle tested. 179 00:06:01,560 --> 00:06:03,060 So there have been multiple nights 180 00:06:03,060 --> 00:06:05,100 when we're looking at coming up with some new graph 181 00:06:05,100 --> 00:06:07,350 or some new results for some deadline 182 00:06:07,350 --> 00:06:08,640 and Pacman Kit has just been there. 183 00:06:08,640 --> 00:06:11,340 It's quite reliable, and it does what it needs to do. 184 00:06:11,340 --> 00:06:12,870 So we think this is gonna be a great tool 185 00:06:12,870 --> 00:06:14,163 for security researchers. 186 00:06:15,630 --> 00:06:17,400 Next up is PACMAN Finder. 187 00:06:17,400 --> 00:06:19,170 So this is a Ghidra script 188 00:06:19,170 --> 00:06:22,620 that lets you search any binary for PACMAN gadgets. 189 00:06:22,620 --> 00:06:24,510 And so we ran this on the X and U kernel 190 00:06:24,510 --> 00:06:26,820 and we found around 55,000 gadgets, 191 00:06:26,820 --> 00:06:27,653 some data, 192 00:06:27,653 --> 00:06:28,486 some instruction, 193 00:06:28,486 --> 00:06:30,210 and you can kind of tune new parameters. 194 00:06:30,210 --> 00:06:32,340 So if you're looking for only a certain type of instruction, 195 00:06:32,340 --> 00:06:33,660 you can specify that. 196 00:06:33,660 --> 00:06:35,340 Do you wanna limit it just to the system calls 197 00:06:35,340 --> 00:06:36,600 or functions that you can reach? 198 00:06:36,600 --> 00:06:37,650 You can do that too. 199 00:06:37,650 --> 00:06:39,330 So we think PACMAN Finder is a great tool, 200 00:06:39,330 --> 00:06:40,800 and we're gonna see how to use this 201 00:06:40,800 --> 00:06:43,683 to find a real PACMAN gadget in just a few minutes. 202 00:06:45,450 --> 00:06:47,160 Next up is PACMAN Patcher. 203 00:06:47,160 --> 00:06:49,350 So we're gonna talk about the timing features 204 00:06:49,350 --> 00:06:50,183 of M1 in a minute, 205 00:06:50,183 --> 00:06:51,930 but the problem with M1 is 206 00:06:51,930 --> 00:06:54,750 that you don't have really great high performance timers 207 00:06:54,750 --> 00:06:55,890 in user space. 208 00:06:55,890 --> 00:06:57,660 And so when you're doing those deep reverse 209 00:06:57,660 --> 00:06:58,770 engineering tasks, 210 00:06:58,770 --> 00:07:01,320 trying to build up a model of how the system works, 211 00:07:01,320 --> 00:07:03,510 you need really fine grain timing. 212 00:07:03,510 --> 00:07:06,450 And so PACMAN Patcher is a patch to MacOS itself 213 00:07:06,450 --> 00:07:08,430 that enables these timers for user space. 214 00:07:08,430 --> 00:07:10,800 So no need to play any tricks, just run this once, 215 00:07:10,800 --> 00:07:12,183 and there you go. 216 00:07:14,310 --> 00:07:16,980 And lastly, PacmanOS is for those really, 217 00:07:16,980 --> 00:07:18,600 really deep reversing techniques 218 00:07:18,600 --> 00:07:20,910 where you really just need bare metal control. 219 00:07:20,910 --> 00:07:22,680 And so PacmanOS basically says, 220 00:07:22,680 --> 00:07:23,850 give me some Rust code 221 00:07:23,850 --> 00:07:25,470 and I'm gonna boot it right on the device. 222 00:07:25,470 --> 00:07:26,730 And so you're kind of left to your own. 223 00:07:26,730 --> 00:07:28,320 You can do whatever experiments you want, 224 00:07:28,320 --> 00:07:30,570 run right on the bare metal, that's PacmanOS. 225 00:07:31,552 --> 00:07:32,385 And so together, 226 00:07:32,385 --> 00:07:34,320 we think these four tools make up a really great suite 227 00:07:34,320 --> 00:07:36,900 of reverse engineering technologies that you could use 228 00:07:36,900 --> 00:07:40,113 to do Apple Silicon micro architectural analysis. 229 00:07:41,820 --> 00:07:44,040 So one other fun thing that you might wanna play with, 230 00:07:44,040 --> 00:07:45,210 this past semester, 231 00:07:45,210 --> 00:07:46,830 my lab and I just redesigned 232 00:07:46,830 --> 00:07:49,200 our secure hardware course at MIT. 233 00:07:49,200 --> 00:07:51,330 And so we released five brand new labs 234 00:07:51,330 --> 00:07:53,220 that let you do all sorts of really great stuff. 235 00:07:53,220 --> 00:07:54,930 So you can do the Row hammer attack, 236 00:07:54,930 --> 00:07:57,360 where you flip bits in the physical DRAM controller. 237 00:07:57,360 --> 00:07:58,800 You can do specter in the kernel 238 00:07:58,800 --> 00:08:01,530 and you can also implement an AI accelerated 239 00:08:01,530 --> 00:08:02,790 website fingerprinting attack 240 00:08:02,790 --> 00:08:04,080 that still works today. 241 00:08:04,080 --> 00:08:05,460 So if you wanna play with some of these, 242 00:08:05,460 --> 00:08:07,740 you can Google MIT Secure Hardware Design 243 00:08:07,740 --> 00:08:09,180 and find any one of those five labs 244 00:08:09,180 --> 00:08:11,310 and feel free to shoot me a tweet at Twitter 245 00:08:11,310 --> 00:08:12,810 if you try 'em out and you have a question, 246 00:08:12,810 --> 00:08:14,523 just feel free to reach out. 247 00:08:15,450 --> 00:08:16,561 All right. 248 00:08:16,561 --> 00:08:19,680 So PACMAN I was what we released in ISCA a few months ago. 249 00:08:19,680 --> 00:08:21,540 And today we're gonna announce PACMAN II. 250 00:08:21,540 --> 00:08:23,640 So PACMAN II is a complete reimplementation 251 00:08:23,640 --> 00:08:26,310 of the first attack without some of its shortcomings, 252 00:08:26,310 --> 00:08:29,340 and it's significantly more efficient as well. 253 00:08:29,340 --> 00:08:30,173 So with PACMAN I, 254 00:08:30,173 --> 00:08:32,640 what we wanted to do was show that this attack is possible. 255 00:08:32,640 --> 00:08:34,080 So we built a proof of concept 256 00:08:34,080 --> 00:08:36,870 that proves the hardware behaves the way we think it does. 257 00:08:36,870 --> 00:08:38,760 But with PACMAN II, we wanna show it in action. 258 00:08:38,760 --> 00:08:39,750 So what can this thing do 259 00:08:39,750 --> 00:08:42,540 when you really push it to the extremes? 260 00:08:42,540 --> 00:08:44,340 PACMAN I, we've got a very simple victim. 261 00:08:44,340 --> 00:08:46,110 Just again, we wanna show it works. 262 00:08:46,110 --> 00:08:48,120 PACMAN II, we're gonna do it on a realistic victim 263 00:08:48,120 --> 00:08:49,670 and we'll see that in a second. 264 00:08:50,610 --> 00:08:52,320 PACMAN I takes around three minutes or so 265 00:08:52,320 --> 00:08:53,250 to forge a pointer. 266 00:08:53,250 --> 00:08:55,713 PACMAN II can do it in as little as 11 seconds. 267 00:08:57,180 --> 00:08:59,370 PACMAN I is a bare bone C implementation. 268 00:08:59,370 --> 00:09:01,110 So one of the things we wanted to do 269 00:09:01,110 --> 00:09:03,870 was make sure that our tools we provide to the community 270 00:09:03,870 --> 00:09:06,175 are extensible and can be played with. 271 00:09:06,175 --> 00:09:09,240 PACMAN I is more of just an imperative C reference, 272 00:09:09,240 --> 00:09:10,860 reference implementation. 273 00:09:10,860 --> 00:09:12,423 So messing with this and trying to change it 274 00:09:12,423 --> 00:09:13,770 is a little bit difficult. 275 00:09:13,770 --> 00:09:14,910 With PACMAN II, 276 00:09:14,910 --> 00:09:17,550 we've rewritten it all in Rust with an extensible framework 277 00:09:17,550 --> 00:09:19,740 that you can use to build your own PACMAN attacks 278 00:09:19,740 --> 00:09:22,770 without having to reinvent the wheel every time. 279 00:09:22,770 --> 00:09:25,095 And so the major shortcoming of PACMAN I, 280 00:09:25,095 --> 00:09:26,400 was that we assumed we could do this 281 00:09:26,400 --> 00:09:28,800 instruction TLB eviction with system calls, 282 00:09:28,800 --> 00:09:30,930 and that's a relatively realistic assumption, 283 00:09:30,930 --> 00:09:33,300 but the noise that this creates is actually a lot. 284 00:09:33,300 --> 00:09:35,490 And so doing this in practice is quite hard. 285 00:09:35,490 --> 00:09:37,440 With PACMAN II, we've removed that restriction, 286 00:09:37,440 --> 00:09:38,730 we do a different way of timing. 287 00:09:38,730 --> 00:09:40,680 So PACMAN II doesn't have that problem. 288 00:09:41,610 --> 00:09:42,724 All right. 289 00:09:42,724 --> 00:09:44,363 So with that outta the way, let's talk about software. 290 00:09:45,390 --> 00:09:48,270 So we're gonna look at this as CPU architects, 291 00:09:48,270 --> 00:09:51,000 together we're all going to design a processor. 292 00:09:51,000 --> 00:09:54,060 And so our processor is gonna have 64 bit addresses. 293 00:09:54,060 --> 00:09:56,370 That's the best way to do it, at least today, 294 00:09:56,370 --> 00:09:58,110 maybe in a couple years that'll be different. 295 00:09:58,110 --> 00:10:00,540 And so our design doesn't have 16 exabytes of Ram. 296 00:10:00,540 --> 00:10:01,656 We don't, 297 00:10:01,656 --> 00:10:03,270 we're not using that much Ram in our computers right now. 298 00:10:03,270 --> 00:10:05,730 And so what it turns out is that these pointers actually 299 00:10:05,730 --> 00:10:07,620 just have a bunch of bits that we're just not using. 300 00:10:07,620 --> 00:10:09,270 They're just completely unused. 301 00:10:09,270 --> 00:10:12,090 And so let's use these bits for something useful, 302 00:10:12,090 --> 00:10:13,440 let's put them to good use. 303 00:10:14,349 --> 00:10:15,750 And so what we're gonna do is take, 304 00:10:15,750 --> 00:10:18,060 set aside 16 bits in every address 305 00:10:18,060 --> 00:10:21,030 as a signature that verifies the rest of the pointer 306 00:10:21,030 --> 00:10:22,680 has not been tampered with. 307 00:10:22,680 --> 00:10:24,270 And so we're gonna compute the PAC 308 00:10:24,270 --> 00:10:27,180 by taking together a hash of the pointer itself, 309 00:10:27,180 --> 00:10:29,490 a per object salt and some secret key, 310 00:10:29,490 --> 00:10:31,170 but for the purposes of today's talk, 311 00:10:31,170 --> 00:10:33,450 we actually don't even care how this hash works. 312 00:10:33,450 --> 00:10:35,400 We're gonna assume it is as strong as possible 313 00:10:35,400 --> 00:10:36,930 and cannot be forged. 314 00:10:36,930 --> 00:10:38,230 We have to Brute force it. 315 00:10:39,300 --> 00:10:40,440 And so there's two instructions 316 00:10:40,440 --> 00:10:42,390 that you can use to operate on PAC's. 317 00:10:42,390 --> 00:10:44,820 You have the PAC instructions that can insert a PAC 318 00:10:44,820 --> 00:10:47,730 and the AUT instructions will verify a PAC. 319 00:10:47,730 --> 00:10:49,890 And the important thing to note is that we do not crash, 320 00:10:49,890 --> 00:10:51,000 crash on the AUT, 321 00:10:51,000 --> 00:10:52,740 we actually crash on the use. 322 00:10:52,740 --> 00:10:55,050 And so let's walk through a really quick example here. 323 00:10:55,050 --> 00:10:56,850 So here, we've got an object hanging out in memory. 324 00:10:56,850 --> 00:10:57,870 That's a signed pointer 325 00:10:57,870 --> 00:11:00,180 and we'll see this exact object come back later. 326 00:11:00,180 --> 00:11:01,440 And so we're gonna do a load 327 00:11:01,440 --> 00:11:04,980 to load that signer pointer outta memory into X 16, 328 00:11:04,980 --> 00:11:06,780 we're gonna pull the object's address 329 00:11:06,780 --> 00:11:08,250 and a per object salt, 330 00:11:08,250 --> 00:11:11,580 put that together and that's gonna be our object's salt. 331 00:11:11,580 --> 00:11:13,530 And do the authentication with that in mind. 332 00:11:13,530 --> 00:11:17,043 So take the pointer and it's salt and verify the signature. 333 00:11:17,910 --> 00:11:20,640 And so what happens is if the verification was wrong, 334 00:11:20,640 --> 00:11:22,800 that pointer that's been put into X 16, 335 00:11:22,800 --> 00:11:24,480 is now just some corrupted pointer. 336 00:11:24,480 --> 00:11:25,620 And when we try to load it, 337 00:11:25,620 --> 00:11:27,270 this is where the crash comes in. 338 00:11:29,070 --> 00:11:30,204 All right. 339 00:11:30,204 --> 00:11:31,037 So let's talk about Buffer Overflows. 340 00:11:31,037 --> 00:11:32,670 So maybe you've got some, 341 00:11:32,670 --> 00:11:34,350 in this example you've got a buffer hanging out 342 00:11:34,350 --> 00:11:36,150 and then some function pointer afterwards, 343 00:11:36,150 --> 00:11:38,160 and maybe you forgot to use the right version 344 00:11:38,160 --> 00:11:39,660 of string copy or whatever. 345 00:11:39,660 --> 00:11:42,390 And the Buffer Overflow overwrites this function pointer. 346 00:11:42,390 --> 00:11:44,400 Now, traditionally, this is game over, right. 347 00:11:44,400 --> 00:11:46,080 The attacker has got complete control 348 00:11:46,080 --> 00:11:47,370 of the function pointer. 349 00:11:47,370 --> 00:11:50,490 So let's fix this with pointer authentication. 350 00:11:50,490 --> 00:11:51,600 And so the key thing to assume, 351 00:11:51,600 --> 00:11:54,060 is we're gonna assume that same software bugs still exists, 352 00:11:54,060 --> 00:11:55,980 cause remember these are hard to find. 353 00:11:55,980 --> 00:11:57,540 And so we're gonna do that overflow 354 00:11:57,540 --> 00:11:59,130 and corrupt the function pointer 355 00:11:59,130 --> 00:12:00,780 but since the PAC has been changed, 356 00:12:00,780 --> 00:12:02,820 we can detect that and actually crash. 357 00:12:02,820 --> 00:12:05,620 So pointer authentication can keep us safe in this case. 358 00:12:06,750 --> 00:12:08,550 So today's goal is to reveal 359 00:12:08,550 --> 00:12:10,440 the PAC for an arbitrary pointer 360 00:12:10,440 --> 00:12:12,090 without any of those crashes. 361 00:12:12,090 --> 00:12:14,640 And for that, we're gonna have to turn to hardware. 362 00:12:15,930 --> 00:12:18,180 And so we're gonna solve the software problem that we have, 363 00:12:18,180 --> 00:12:20,640 which is that using the wrong pointer crashes, 364 00:12:20,640 --> 00:12:22,890 and we're gonna solve it in hardware. 365 00:12:22,890 --> 00:12:25,470 So we're gonna start by guessing a PAC speculatively 366 00:12:25,470 --> 00:12:27,240 to prevent a crash, 367 00:12:27,240 --> 00:12:29,370 and then we're gonna leak the verification results 368 00:12:29,370 --> 00:12:31,740 of that test case through a side channel. 369 00:12:31,740 --> 00:12:34,560 And so we're gonna talk about what both of those things are. 370 00:12:34,560 --> 00:12:36,330 And so let's switch back to CPU design mode. 371 00:12:36,330 --> 00:12:37,920 So we're gonna build our processor 372 00:12:37,920 --> 00:12:40,270 with this feature called speculative execution. 373 00:12:41,202 --> 00:12:42,630 And the idea behind speculative execution 374 00:12:42,630 --> 00:12:44,790 is that we wanna just increase performance, 375 00:12:44,790 --> 00:12:47,040 we want our processor to be as fast as possible. 376 00:12:47,040 --> 00:12:49,230 And so in this example here, we've got if true, 377 00:12:49,230 --> 00:12:51,540 do A else do B. 378 00:12:51,540 --> 00:12:53,100 And so you're in order basic CPU 379 00:12:53,100 --> 00:12:56,310 is gonna have to spend some time thinking about that branch 380 00:12:56,310 --> 00:12:57,960 and then just do the right thing. 381 00:12:58,958 --> 00:12:59,791 So it's pretty straightforward, 382 00:12:59,791 --> 00:13:01,170 but we can actually do better. 383 00:13:01,170 --> 00:13:04,020 So if we speculate the direction of the branch, 384 00:13:04,020 --> 00:13:05,820 we can predicatively begin executing 385 00:13:05,820 --> 00:13:07,410 before we know we should execute. 386 00:13:07,410 --> 00:13:08,243 So in this case, 387 00:13:08,243 --> 00:13:09,076 we're gonna start speculating 388 00:13:09,076 --> 00:13:10,650 that A is the correct direction. 389 00:13:10,650 --> 00:13:12,570 And in this case we'd be right. 390 00:13:12,570 --> 00:13:15,780 And so we're actually faster than the in order case. 391 00:13:15,780 --> 00:13:19,140 But if we miss speculate, if we get the wrong prediction, 392 00:13:19,140 --> 00:13:21,600 now we gotta spend some extra time to undo 393 00:13:21,600 --> 00:13:24,270 the effects of that speculation and then do A, 394 00:13:24,270 --> 00:13:26,610 but you'll notice that this undo is only surface level. 395 00:13:26,610 --> 00:13:28,440 It doesn't undo every change that was made. 396 00:13:28,440 --> 00:13:31,320 It just undoes the ones that the programmer can see. 397 00:13:31,320 --> 00:13:33,840 And so the micro architectural side effects 398 00:13:33,840 --> 00:13:37,200 of running B speculatively are not undone. 399 00:13:37,200 --> 00:13:38,650 So let's see what that means. 400 00:13:39,570 --> 00:13:41,730 And so we have a design decision to make here. 401 00:13:41,730 --> 00:13:44,010 So how do we speculate on pointer authentication, 402 00:13:44,010 --> 00:13:45,210 protected pointers? 403 00:13:45,210 --> 00:13:46,590 So we wanna do this PAC thing. 404 00:13:46,590 --> 00:13:48,030 We wanna do the speculation thing. 405 00:13:48,030 --> 00:13:49,350 How do they come together? 406 00:13:49,350 --> 00:13:51,720 And so it seems to me that there are three basic cases. 407 00:13:51,720 --> 00:13:54,540 You can ignore them, just pretend they're not there. 408 00:13:54,540 --> 00:13:55,710 You can never load them. 409 00:13:55,710 --> 00:13:58,170 So if you hit a PAC, just stop speculating, 410 00:13:58,170 --> 00:14:00,240 or you could just treat them normally, right? 411 00:14:00,240 --> 00:14:02,490 Pretend like the program runs in order. 412 00:14:02,490 --> 00:14:04,770 And so these three cases have three very different outcomes, 413 00:14:04,770 --> 00:14:06,480 but the first one is actually quite surprising. 414 00:14:06,480 --> 00:14:09,750 If you ignore PAC's that also introduces a security problem. 415 00:14:09,750 --> 00:14:12,330 And so you can read our paper to find out more about that. 416 00:14:12,330 --> 00:14:13,920 If you never load, this is slow, 417 00:14:13,920 --> 00:14:16,110 we want our processor to be as fast as possible. 418 00:14:16,110 --> 00:14:18,390 And so treating them normally is what the M1 does 419 00:14:18,390 --> 00:14:20,240 and that's how we're gonna do it too. 420 00:14:21,180 --> 00:14:22,950 And so let's take another look at speculation, 421 00:14:22,950 --> 00:14:24,900 but with pointer authentication in mind. 422 00:14:24,900 --> 00:14:26,760 So for this example, we're gonna do if true, 423 00:14:26,760 --> 00:14:27,930 we're just gonna leave the function, 424 00:14:27,930 --> 00:14:29,430 we're just gonna return. 425 00:14:29,430 --> 00:14:31,530 Otherwise we're gonna do a check of a pointer 426 00:14:31,530 --> 00:14:32,760 and then try to load it. 427 00:14:32,760 --> 00:14:33,840 Okay. 428 00:14:33,840 --> 00:14:35,550 And so for the in order system, 429 00:14:35,550 --> 00:14:38,130 we're gonna do the if and then return, no leaks. 430 00:14:38,130 --> 00:14:38,963 We're all good. 431 00:14:39,870 --> 00:14:41,820 And the speculative system can be good too. 432 00:14:41,820 --> 00:14:43,140 So if we do correct, 433 00:14:43,140 --> 00:14:44,130 predict correctly, 434 00:14:44,130 --> 00:14:45,360 we still don't leak anything. 435 00:14:45,360 --> 00:14:47,880 We never run the code we're not supposed to, 436 00:14:47,880 --> 00:14:49,350 but if we miss predict, 437 00:14:49,350 --> 00:14:51,300 if we run that wrong branch, 438 00:14:51,300 --> 00:14:53,760 we're still gonna do the check and the load. 439 00:14:53,760 --> 00:14:55,830 And if that load is incorrect, 440 00:14:55,830 --> 00:14:57,780 we're not gonna actually load anything into the cache, 441 00:14:57,780 --> 00:14:59,430 but we're gonna start a speculative exception. 442 00:14:59,430 --> 00:15:01,410 So there's two possible outcomes here. 443 00:15:01,410 --> 00:15:02,760 When we do the undo, 444 00:15:02,760 --> 00:15:05,430 all we do is undo the change to the X variable. 445 00:15:05,430 --> 00:15:06,930 We don't actually undo any of the loads 446 00:15:06,930 --> 00:15:08,100 that we just performed. 447 00:15:08,100 --> 00:15:10,230 And so that is gonna cause a leak. 448 00:15:10,230 --> 00:15:11,940 So the value still being in the cache, 449 00:15:11,940 --> 00:15:13,740 this is gonna leak some information. 450 00:15:14,940 --> 00:15:18,150 And so operating on pointer authentication speculatively 451 00:15:18,150 --> 00:15:20,400 can leak correctness without causing a crash. 452 00:15:21,420 --> 00:15:22,500 So let's take a step back here 453 00:15:22,500 --> 00:15:23,970 and look at this from a bird's eye view. 454 00:15:23,970 --> 00:15:25,560 So we've got our first, is a bug. 455 00:15:25,560 --> 00:15:26,460 Remember, bring your own bug. 456 00:15:26,460 --> 00:15:28,470 We're gonna assume we can read and write into memory. 457 00:15:28,470 --> 00:15:30,450 We're gonna write a guess into memory 458 00:15:30,450 --> 00:15:32,670 and then trigger the miss speculation 459 00:15:32,670 --> 00:15:35,640 to run the PACMAN gadget speculatively. 460 00:15:35,640 --> 00:15:37,920 And so if we're correct, if our guess is right, 461 00:15:37,920 --> 00:15:39,990 we're going to do a speculative load. 462 00:15:39,990 --> 00:15:42,150 If we're incorrect, we're not gonna load. 463 00:15:42,150 --> 00:15:44,400 And so those are the two cases we wanna tell apart. 464 00:15:44,400 --> 00:15:46,450 So how can we tell these two cases apart? 465 00:15:47,490 --> 00:15:49,622 Well, let's actually take a step back 466 00:15:49,622 --> 00:15:50,455 and go back to our CPU design mode. 467 00:15:50,455 --> 00:15:53,490 So memory is really, really slow and we wanna speed it up. 468 00:15:53,490 --> 00:15:56,430 So what we're gonna do is put a cache in between memory 469 00:15:56,430 --> 00:15:58,350 and the CPU. 470 00:15:58,350 --> 00:16:00,510 And so this difference in the memory hierarchy, 471 00:16:00,510 --> 00:16:02,370 having addresses that can be cached 472 00:16:02,370 --> 00:16:05,190 or in DRAM is where that difference comes into play. 473 00:16:05,190 --> 00:16:07,410 That's how we're gonna tell them of apart. 474 00:16:07,410 --> 00:16:09,600 And so let's just revisit how caching works really quick. 475 00:16:09,600 --> 00:16:11,987 So this is how we're gonna represent cache's today. 476 00:16:11,987 --> 00:16:14,670 You divide your cache into sets in ways. 477 00:16:14,670 --> 00:16:17,940 So in this case, we've got eight sets in four ways. 478 00:16:17,940 --> 00:16:19,470 And the way we put an object 479 00:16:19,470 --> 00:16:21,240 or an address rather into the cache, 480 00:16:21,240 --> 00:16:22,860 is we take the address, 481 00:16:22,860 --> 00:16:25,410 pull out a tag, a set, and an offset. 482 00:16:25,410 --> 00:16:26,580 And we just look at the set. 483 00:16:26,580 --> 00:16:29,400 So we say which sets of the cache we map to. 484 00:16:29,400 --> 00:16:30,570 So an address with, 485 00:16:30,570 --> 00:16:32,190 two addresses that map in the same set 486 00:16:32,190 --> 00:16:34,440 will go to the same row in the cache. 487 00:16:34,440 --> 00:16:35,550 They can go into any column. 488 00:16:35,550 --> 00:16:36,660 We can't predict that, 489 00:16:36,660 --> 00:16:39,570 but we can predict which set they're gonna go into. 490 00:16:39,570 --> 00:16:41,910 And so let's switch gears and think about this 491 00:16:41,910 --> 00:16:43,050 like an attacker, 492 00:16:43,050 --> 00:16:46,293 what can we do with the cache to do some type of attack? 493 00:16:47,400 --> 00:16:49,650 And so again, revisit the fact that these addresses, 494 00:16:49,650 --> 00:16:51,090 we predict which set they go into. 495 00:16:51,090 --> 00:16:52,050 We can look at the address 496 00:16:52,050 --> 00:16:53,820 and say which side it's gonna be in. 497 00:16:53,820 --> 00:16:56,280 And so what we can do is develop the following. 498 00:16:56,280 --> 00:16:58,260 So let's fill up an entire set. 499 00:16:58,260 --> 00:16:59,400 We'll figure out how big the set is 500 00:16:59,400 --> 00:17:02,220 and just fill every line in the setup with our data. 501 00:17:02,220 --> 00:17:04,110 Then we're gonna let someone else run. 502 00:17:04,110 --> 00:17:06,420 So this could be the kernel or just some victim, 503 00:17:06,420 --> 00:17:07,980 and it's gonna do its own load pattern. 504 00:17:07,980 --> 00:17:08,813 So in this case, 505 00:17:08,813 --> 00:17:09,930 it has kicked out a couple lines 506 00:17:09,930 --> 00:17:11,520 and you can see one of them hit the set 507 00:17:11,520 --> 00:17:12,750 that we're looking at, 508 00:17:12,750 --> 00:17:14,790 and we can reload our data 509 00:17:14,790 --> 00:17:16,980 and see if any lines got kicked out. 510 00:17:16,980 --> 00:17:18,660 And in this case, one of them did. 511 00:17:18,660 --> 00:17:20,370 And so we can tell what the victim is doing. 512 00:17:20,370 --> 00:17:22,020 We can infer victim behavior 513 00:17:22,020 --> 00:17:24,660 just by watching addresses that we control in the cache. 514 00:17:24,660 --> 00:17:26,280 And so this technique is called Prime Probe, 515 00:17:26,280 --> 00:17:29,220 and we're gonna see it again in just a few minutes. 516 00:17:29,220 --> 00:17:31,590 And so let's switch back to our design perspective. 517 00:17:31,590 --> 00:17:33,480 So there's actually been a lot of confusion 518 00:17:33,480 --> 00:17:34,410 that we've seen on the internet 519 00:17:34,410 --> 00:17:36,900 about what is the cache hierarchy of M1. 520 00:17:36,900 --> 00:17:38,430 And so these are the numbers we pulled 521 00:17:38,430 --> 00:17:40,590 right from the Silicon through the cache ID register. 522 00:17:40,590 --> 00:17:43,410 So Apple's cache hierarchy is split up into 523 00:17:43,410 --> 00:17:44,580 a level one in data, 524 00:17:44,580 --> 00:17:45,480 level one instruction, 525 00:17:45,480 --> 00:17:47,100 and then a unified level two cache. 526 00:17:47,100 --> 00:17:49,350 So there's actually hierarchies within the cache 527 00:17:49,350 --> 00:17:50,910 and you'll notice that data and instruction 528 00:17:50,910 --> 00:17:52,173 are cached differently. 529 00:17:53,670 --> 00:17:54,503 Okay. 530 00:17:54,503 --> 00:17:55,590 So we've seen this actually before, already, 531 00:17:55,590 --> 00:17:58,800 but let's formally define what we mean by a PACMAN gadget. 532 00:17:58,800 --> 00:18:01,170 So a PACMAN gadget is the speculative use 533 00:18:01,170 --> 00:18:03,450 and check of a signed pointer. 534 00:18:03,450 --> 00:18:05,400 And so in this example, here's just any, 535 00:18:05,400 --> 00:18:07,110 if some condition we're gonna do a check 536 00:18:07,110 --> 00:18:08,580 and then we're gonna try to do a load. 537 00:18:08,580 --> 00:18:10,980 Anytime you've got that, that's a PACMAN gadget. 538 00:18:11,940 --> 00:18:13,680 And so now let's walk through in detail 539 00:18:13,680 --> 00:18:15,660 how the data PACMAN attack works. 540 00:18:15,660 --> 00:18:17,730 And so we're gonna begin by training the branch predictor 541 00:18:17,730 --> 00:18:19,320 to use a known signed pointer. 542 00:18:19,320 --> 00:18:21,210 So we're gonna enter this PACMAN gadget, 543 00:18:21,210 --> 00:18:23,730 say if true, we'll pass in the condition, true. 544 00:18:23,730 --> 00:18:25,410 We'll do this check on a good pointer 545 00:18:25,410 --> 00:18:27,810 that we know is gonna be fine and then do the load. 546 00:18:27,810 --> 00:18:29,190 And that's all good. 547 00:18:29,190 --> 00:18:31,140 And so we do that enough to tell the branch predictor, 548 00:18:31,140 --> 00:18:32,880 Hey, we're gonna take this branch all the time. 549 00:18:32,880 --> 00:18:33,960 So now it's gonna start predicting 550 00:18:33,960 --> 00:18:35,850 that that branch will be taken. 551 00:18:35,850 --> 00:18:37,050 Now we're gonna reset the cache. 552 00:18:37,050 --> 00:18:39,930 So just flush it out with addresses we control, 553 00:18:39,930 --> 00:18:42,240 and we're gonna prime it by loading an eviction set. 554 00:18:42,240 --> 00:18:45,660 So let's go ahead and throw our eviction set in there. 555 00:18:45,660 --> 00:18:47,430 And now we're gonna call this gadget again, 556 00:18:47,430 --> 00:18:49,590 but this time we're gonna make the condition false 557 00:18:49,590 --> 00:18:51,780 and we're gonna load instead of a correct pointer, 558 00:18:51,780 --> 00:18:53,820 we're gonna load the pointer we'd like to guess. 559 00:18:53,820 --> 00:18:55,470 And so we're gonna hit this condition 560 00:18:55,470 --> 00:18:56,970 and enter the speculative regime. 561 00:18:56,970 --> 00:18:58,830 So again, this should not be being run, 562 00:18:58,830 --> 00:19:00,870 but since the branch predictor believes it should be, 563 00:19:00,870 --> 00:19:02,730 we're gonna start speculating on this. 564 00:19:02,730 --> 00:19:05,370 And so we're gonna do the verification of our guest pointer 565 00:19:05,370 --> 00:19:06,480 and then try to load it. 566 00:19:06,480 --> 00:19:08,520 And now one of two things is gonna happen. 567 00:19:08,520 --> 00:19:10,260 So if the guest was correct, 568 00:19:10,260 --> 00:19:12,570 the load will succeed and kick something that we own 569 00:19:12,570 --> 00:19:14,310 completely out of the cache. 570 00:19:14,310 --> 00:19:16,350 Otherwise nothing's gonna happen 571 00:19:16,350 --> 00:19:18,330 and the cache is gonna stay as it is. 572 00:19:18,330 --> 00:19:19,620 And so all we gotta do now 573 00:19:19,620 --> 00:19:22,170 is go back to our addresses we just put there and ask, 574 00:19:22,170 --> 00:19:24,090 did any of these get kicked out? 575 00:19:24,090 --> 00:19:27,393 If it was, we had the right PAC, that's the attack. 576 00:19:28,260 --> 00:19:29,490 And so now that we've done the attack 577 00:19:29,490 --> 00:19:32,400 on an abstract machine, let's actually do it for real. 578 00:19:32,400 --> 00:19:34,050 And so one of the things I wanna focus on 579 00:19:34,050 --> 00:19:34,950 in this next section, 580 00:19:34,950 --> 00:19:37,230 is not just what do you need to do to do PACMAN, 581 00:19:37,230 --> 00:19:39,270 but I wanna really encourage a discussion of 582 00:19:39,270 --> 00:19:41,070 what are the techniques that researchers use 583 00:19:41,070 --> 00:19:42,390 to do these kinds of attacks. 584 00:19:42,390 --> 00:19:44,490 So you all can go off and do your own research 585 00:19:44,490 --> 00:19:45,640 using these techniques. 586 00:19:48,690 --> 00:19:52,470 So two terminologies here for the rest of our attack, 587 00:19:52,470 --> 00:19:53,760 we have two operations we wanna do. 588 00:19:53,760 --> 00:19:55,410 So differentiation, 589 00:19:55,410 --> 00:19:57,960 you give me a correct and an incorrect pointer. 590 00:19:57,960 --> 00:19:59,220 Can I tell them apart? 591 00:19:59,220 --> 00:20:01,050 And so we're gonna look at graphs that look like this, 592 00:20:01,050 --> 00:20:05,012 where we've got on the X axis, a number of cache misses. 593 00:20:05,012 --> 00:20:05,845 So zero misses being, 594 00:20:05,845 --> 00:20:06,840 we didn't lose anything, 595 00:20:06,840 --> 00:20:09,480 seven or eight being like we lost a lot of addresses 596 00:20:09,480 --> 00:20:10,830 and we should see two different patterns. 597 00:20:10,830 --> 00:20:13,200 So if the PAC is incorrect, we shouldn't see any misses. 598 00:20:13,200 --> 00:20:15,660 If it's correct, we should see a lot. 599 00:20:15,660 --> 00:20:17,490 And the other thing we wanna do is Brute Force. 600 00:20:17,490 --> 00:20:19,680 So try every single possible PAC 601 00:20:19,680 --> 00:20:21,330 and figure out which one's right. 602 00:20:22,320 --> 00:20:23,700 And so we know we wanna get here. 603 00:20:23,700 --> 00:20:24,690 We know that we in the end, 604 00:20:24,690 --> 00:20:27,360 we wanna be able to say a correct PAC leads to a load 605 00:20:27,360 --> 00:20:29,220 and incorrect leads to an incorrect load. 606 00:20:29,220 --> 00:20:31,650 And so what do we need to do to make this happen? 607 00:20:31,650 --> 00:20:33,870 Well, first we need to know when a load occurs 608 00:20:33,870 --> 00:20:35,340 and since we're attacking the kernel, 609 00:20:35,340 --> 00:20:37,590 we need to be able to tell when the kernel loads an address, 610 00:20:37,590 --> 00:20:38,423 and we can't look at these 611 00:20:38,423 --> 00:20:39,750 cause we don't own these addresses. 612 00:20:39,750 --> 00:20:41,343 So guys do Prime Probe here. 613 00:20:42,570 --> 00:20:44,850 Next we gotta contend with the kernel in the cache. 614 00:20:44,850 --> 00:20:46,650 So before we can tell if a load occurs, 615 00:20:46,650 --> 00:20:47,970 we have to be able to measure 616 00:20:47,970 --> 00:20:49,200 whether or not the kernel is loading. 617 00:20:49,200 --> 00:20:51,270 So we have to form what's called an eviction set 618 00:20:51,270 --> 00:20:52,620 for this contention. 619 00:20:52,620 --> 00:20:53,850 And before we can even do that, 620 00:20:53,850 --> 00:20:55,560 we gotta know if something's in the cache or not. 621 00:20:55,560 --> 00:20:57,630 So doing this very basic, is the cache, 622 00:20:57,630 --> 00:20:59,850 is it a cache hit or a cache miss? 623 00:20:59,850 --> 00:21:00,683 And so to start, 624 00:21:00,683 --> 00:21:03,003 we're gonna begin by reverse engineering the M1. 625 00:21:04,350 --> 00:21:06,690 And so we looked at four different possible timer sources, 626 00:21:06,690 --> 00:21:09,330 cause again, we want very high performance timing data. 627 00:21:09,330 --> 00:21:10,163 And these first two, 628 00:21:10,163 --> 00:21:10,996 you can just rule out, 629 00:21:10,996 --> 00:21:12,300 the first one's way too slow. 630 00:21:12,300 --> 00:21:14,220 And the second one isn't even present. 631 00:21:14,220 --> 00:21:15,630 And so we looked at these last two, 632 00:21:15,630 --> 00:21:17,250 the Apple custom cycle counter 633 00:21:17,250 --> 00:21:19,140 and our own multi threaded counter. 634 00:21:19,140 --> 00:21:20,640 And we did some analysis on them 635 00:21:20,640 --> 00:21:22,500 and we found the they're both pretty good. 636 00:21:22,500 --> 00:21:24,780 And so what we can do is use the multi threaded counter, 637 00:21:24,780 --> 00:21:26,250 we'll talk about that in just a second. 638 00:21:26,250 --> 00:21:28,650 We can use that in the attack because it's not privileged, 639 00:21:28,650 --> 00:21:30,480 but the Apple custom cycle counter, 640 00:21:30,480 --> 00:21:33,180 the one that we want for our high performance reversing data 641 00:21:33,180 --> 00:21:34,013 is privileged. 642 00:21:34,013 --> 00:21:35,400 So we can't use that in our attack, 643 00:21:35,400 --> 00:21:38,130 but we can use it for reverse engineering. 644 00:21:38,130 --> 00:21:40,230 And so what you can do is go into Ghidra 645 00:21:40,230 --> 00:21:42,570 and search for any reads of this privileged timer. 646 00:21:42,570 --> 00:21:44,305 And what you'll find is that 647 00:21:44,305 --> 00:21:45,138 there's a couple places that do that. 648 00:21:45,138 --> 00:21:47,070 So we have PMC zero is our cycle counter, 649 00:21:47,070 --> 00:21:48,480 that's the one we wanna read. 650 00:21:48,480 --> 00:21:51,060 And if you look at how it's set up in the kernel, 651 00:21:51,060 --> 00:21:51,893 PMC R0, 652 00:21:51,893 --> 00:21:54,270 which controls whether or not you can use this register, 653 00:21:54,270 --> 00:21:55,530 doesn't set the user bit. 654 00:21:55,530 --> 00:21:57,030 So this bit is not set, 655 00:21:57,030 --> 00:22:00,210 which means that user space cannot read this pointer. 656 00:22:00,210 --> 00:22:01,830 And so if you look for places in the kernel 657 00:22:01,830 --> 00:22:03,600 that do the read, that might leak its user space, 658 00:22:03,600 --> 00:22:04,830 there actually are a couple. 659 00:22:04,830 --> 00:22:07,830 And so there's these KPC sysctls that are masks, 660 00:22:07,830 --> 00:22:08,663 so you won't, 661 00:22:08,663 --> 00:22:09,540 if you do like sysctl list, 662 00:22:09,540 --> 00:22:11,520 you're not gonna see 'em, but these are there. 663 00:22:11,520 --> 00:22:15,000 And this is actually what the private framework kperf uses. 664 00:22:15,000 --> 00:22:15,990 But these sadly, 665 00:22:15,990 --> 00:22:17,460 they require route 666 00:22:17,460 --> 00:22:19,020 and they also take a trip to the kernel. 667 00:22:19,020 --> 00:22:20,550 So when you wanna know what time it is, 668 00:22:20,550 --> 00:22:22,740 you actually make a system call, go through all this stuff. 669 00:22:22,740 --> 00:22:24,060 And then by the time you get back, 670 00:22:24,060 --> 00:22:25,410 you've wasted so many cycles 671 00:22:25,410 --> 00:22:27,840 that it's not really worth it for what we're trying to do. 672 00:22:27,840 --> 00:22:29,910 So that's not really an option. 673 00:22:29,910 --> 00:22:31,260 Something else that's pretty interesting 674 00:22:31,260 --> 00:22:33,570 is this special dev perfmon file. 675 00:22:33,570 --> 00:22:35,310 So if you look at these, there's two of them, 676 00:22:35,310 --> 00:22:37,410 there's perfmon uncore and perfmon core. 677 00:22:37,410 --> 00:22:39,090 They're defined in this file here. 678 00:22:39,090 --> 00:22:41,070 These actually do give you access to the timers 679 00:22:41,070 --> 00:22:42,000 without route. 680 00:22:42,000 --> 00:22:45,060 So you can read all sorts of really interesting MSRS 681 00:22:45,060 --> 00:22:46,620 without any, ever going to the route, 682 00:22:46,620 --> 00:22:48,090 but it still takes a trip to the kernel, 683 00:22:48,090 --> 00:22:49,650 so we can't use it, 684 00:22:49,650 --> 00:22:50,550 but here's all the timers 685 00:22:50,550 --> 00:22:52,560 that I was able to dump for my machine. 686 00:22:52,560 --> 00:22:54,390 We're not really sure what all of them do, 687 00:22:54,390 --> 00:22:55,440 but they are pretty cool. 688 00:22:55,440 --> 00:22:56,520 So if you wanna play with that, 689 00:22:56,520 --> 00:22:58,530 we have some code that can let you do that in our release 690 00:22:58,530 --> 00:23:00,360 and X and U will actually ship it too. 691 00:23:00,360 --> 00:23:03,693 So test/perfmon_test.c has some sample code in the kernel. 692 00:23:06,660 --> 00:23:09,330 So if we just need timing, why not just use a kext, 693 00:23:09,330 --> 00:23:11,850 just install a kernel extension and set the timers up. 694 00:23:11,850 --> 00:23:12,750 And so we tried this 695 00:23:12,750 --> 00:23:14,280 and actually a lot of groups have done this, 696 00:23:14,280 --> 00:23:16,890 I believe it was Douglas Johnson who pioneered this. 697 00:23:16,890 --> 00:23:17,730 But when you do this, 698 00:23:17,730 --> 00:23:19,680 the problem is when you switch course, 699 00:23:19,680 --> 00:23:22,110 X and U will reset those timer values. 700 00:23:22,110 --> 00:23:23,370 And now that test case that you're running 701 00:23:23,370 --> 00:23:24,720 is gonna segfault. 702 00:23:24,720 --> 00:23:25,553 And so you can get around this, 703 00:23:25,553 --> 00:23:27,840 what we used to do is install a signal handler. 704 00:23:27,840 --> 00:23:29,790 Every time we segfault, we just restart, 705 00:23:29,790 --> 00:23:31,230 but that's a pain and it's really, 706 00:23:31,230 --> 00:23:32,580 really not a great solution. 707 00:23:32,580 --> 00:23:35,040 And so what we did is we came up with PACMAN Patcher. 708 00:23:35,040 --> 00:23:36,120 And so the way this works 709 00:23:36,120 --> 00:23:38,070 is it actually patches your kernel cache 710 00:23:38,070 --> 00:23:39,900 to enable timers universally. 711 00:23:39,900 --> 00:23:41,820 And so all you need to do to run PACMAN Patcher 712 00:23:41,820 --> 00:23:43,620 is download the kernel from Apple, 713 00:23:43,620 --> 00:23:45,750 run Patch on the kernel image 714 00:23:45,750 --> 00:23:48,090 and then just restart with the new kernel installed. 715 00:23:48,090 --> 00:23:50,310 And now you've got timers permanently. 716 00:23:50,310 --> 00:23:51,600 And so this is patching your kernel, 717 00:23:51,600 --> 00:23:54,660 we don't recommend running this on a machine you use daily, 718 00:23:54,660 --> 00:23:57,060 but actually as a matter of fact, 719 00:23:57,060 --> 00:23:59,010 I am running it on this machine right here. 720 00:23:59,010 --> 00:24:01,353 So it works relatively well. 721 00:24:02,970 --> 00:24:04,650 Okay, so let's talk about the multi threaded counter. 722 00:24:04,650 --> 00:24:07,020 So the idea behind this is we just wanna know 723 00:24:07,020 --> 00:24:08,430 how long something's taking. 724 00:24:08,430 --> 00:24:11,820 And so what we can do is just while true increment, right? 725 00:24:11,820 --> 00:24:13,380 And this works surprisingly well. 726 00:24:13,380 --> 00:24:15,180 So this is our real implementation of it, 727 00:24:15,180 --> 00:24:18,510 for the counter we just inline assembly store, add, 728 00:24:18,510 --> 00:24:19,650 increment, run. 729 00:24:19,650 --> 00:24:21,810 And that way we're moving things very fast. 730 00:24:21,810 --> 00:24:22,830 And for the timing access, 731 00:24:22,830 --> 00:24:24,120 this is where you gotta be careful, 732 00:24:24,120 --> 00:24:25,710 it works best in our experience. 733 00:24:25,710 --> 00:24:27,570 If you do a data synchronization, 734 00:24:27,570 --> 00:24:29,550 then a nested instruction synchronization 735 00:24:29,550 --> 00:24:30,810 between the reads, 736 00:24:30,810 --> 00:24:32,340 load and then same thing in reverse. 737 00:24:32,340 --> 00:24:33,630 So this is how we do it. 738 00:24:33,630 --> 00:24:35,610 This works really, really well. 739 00:24:35,610 --> 00:24:36,443 And in fact, 740 00:24:36,443 --> 00:24:37,320 we did an analysis of it 741 00:24:37,320 --> 00:24:39,780 and you can see that everything that timers can register 742 00:24:39,780 --> 00:24:41,250 from the Apple performance counter, 743 00:24:41,250 --> 00:24:43,530 you can still differentiate with the multi threaded approach 744 00:24:43,530 --> 00:24:44,363 as well. 745 00:24:44,363 --> 00:24:46,470 So our conclusion is that the multi threaded timer 746 00:24:46,470 --> 00:24:48,570 can do whatever the performance counters do, 747 00:24:48,570 --> 00:24:50,070 but you still want the performance counters 748 00:24:50,070 --> 00:24:51,480 for those high performance numbers 749 00:24:51,480 --> 00:24:53,010 when you're really just reversing stuff. 750 00:24:53,010 --> 00:24:54,300 Right? 751 00:24:54,300 --> 00:24:56,580 Okay. So we can tell cache hits from cache misses. 752 00:24:56,580 --> 00:24:57,413 That's great. 753 00:24:57,413 --> 00:25:00,030 Now how do we contend in the kernel? 754 00:25:00,030 --> 00:25:02,130 So this is where PACMAN Kit comes into play. 755 00:25:02,130 --> 00:25:04,290 And so we're gonna do a technique called a victory load. 756 00:25:04,290 --> 00:25:05,820 So we're gonna start by loading the address 757 00:25:05,820 --> 00:25:07,680 we wanna measure in the kernel, 758 00:25:07,680 --> 00:25:09,030 load a bunch of things from user space 759 00:25:09,030 --> 00:25:10,290 that might contend with it 760 00:25:10,290 --> 00:25:12,000 and then reload the thing in the kernel 761 00:25:12,000 --> 00:25:13,680 to see if we were successful. 762 00:25:13,680 --> 00:25:15,870 And so we're gonna slowly build up this eviction set 763 00:25:15,870 --> 00:25:18,540 to see how far apart the addresses need to be 764 00:25:18,540 --> 00:25:19,860 and how many of them we need 765 00:25:19,860 --> 00:25:21,900 in order to evict kernel addresses. 766 00:25:21,900 --> 00:25:24,420 And so what we're gonna do is look at the memory like this. 767 00:25:24,420 --> 00:25:26,730 So we've got different pages and different cache lines, 768 00:25:26,730 --> 00:25:27,660 and we're gonna have a stride 769 00:25:27,660 --> 00:25:29,250 that hits the beginning of every page 770 00:25:29,250 --> 00:25:30,480 and the beginning of every cache line. 771 00:25:30,480 --> 00:25:32,550 So the cache lines and the pages interfere. 772 00:25:32,550 --> 00:25:34,230 So you're getting contention in the cache 773 00:25:34,230 --> 00:25:36,690 as well as the TLB, which is another cache. 774 00:25:36,690 --> 00:25:38,610 And so this is how you compute those addresses. 775 00:25:38,610 --> 00:25:39,660 And if you do that, 776 00:25:39,660 --> 00:25:42,540 you get a beautiful graph that looks like this. 777 00:25:42,540 --> 00:25:44,100 And so you can see for three different strides, 778 00:25:44,100 --> 00:25:46,890 we've plotted three different eviction patterns. 779 00:25:46,890 --> 00:25:48,240 And at 12 addresses, 780 00:25:48,240 --> 00:25:49,560 when you've got strides that are big enough, 781 00:25:49,560 --> 00:25:52,320 you see a jump and at 23, you see another jump. 782 00:25:52,320 --> 00:25:54,480 If again, you have a large enough stride. 783 00:25:54,480 --> 00:25:56,640 And so we're gonna use this 12 address eviction set 784 00:25:56,640 --> 00:25:59,520 as our eviction set for the rest of the talk. 785 00:25:59,520 --> 00:26:00,353 And so great, 786 00:26:00,353 --> 00:26:01,560 we can actually kick kernel addresses out. 787 00:26:01,560 --> 00:26:02,820 If we do loads in a certain way, 788 00:26:02,820 --> 00:26:05,430 we can knock kernel things into a DRAM. 789 00:26:05,430 --> 00:26:08,370 So now how can we tell when a kernel load occurs? 790 00:26:08,370 --> 00:26:09,203 Well, to start, 791 00:26:09,203 --> 00:26:10,260 we're gonna talk about what happens 792 00:26:10,260 --> 00:26:11,430 when the cache gets full. 793 00:26:11,430 --> 00:26:13,800 So this is something called the replacement policy 794 00:26:13,800 --> 00:26:15,480 and now most cache's aren't gonna use 795 00:26:15,480 --> 00:26:16,860 a least recently used policy, 796 00:26:16,860 --> 00:26:19,350 cause that's actually very hard to put into real Silicon, 797 00:26:19,350 --> 00:26:21,712 but you can estimate the approximate this right? 798 00:26:21,712 --> 00:26:23,160 And so if we do four loads, 799 00:26:23,160 --> 00:26:25,350 we load A, B, C and D in that order. 800 00:26:25,350 --> 00:26:27,030 When we wanna load address E, 801 00:26:27,030 --> 00:26:28,380 it makes sense just to kick out the thing 802 00:26:28,380 --> 00:26:29,880 we just least recently used, right? 803 00:26:29,880 --> 00:26:31,770 Cause it's probably not gonna get used again. 804 00:26:31,770 --> 00:26:33,540 And so let's try to load E 805 00:26:33,540 --> 00:26:34,860 and we're gonna swap A for E, 806 00:26:34,860 --> 00:26:37,053 cause again A is the least recently used. 807 00:26:38,130 --> 00:26:39,180 So now if we scale this up 808 00:26:39,180 --> 00:26:41,070 to see how this affects Prime Probe, 809 00:26:41,070 --> 00:26:42,270 if we do an attack, 810 00:26:42,270 --> 00:26:45,510 attacker load of A one, A two, A three, A four, 811 00:26:45,510 --> 00:26:47,130 and then try to load a kernel address 812 00:26:47,130 --> 00:26:48,780 that can contend with these addresses, 813 00:26:48,780 --> 00:26:50,610 here's what's gonna happen. 814 00:26:50,610 --> 00:26:52,110 So A one is gonna get kicked out, 815 00:26:52,110 --> 00:26:54,840 cause that was the least recently used. 816 00:26:54,840 --> 00:26:56,400 Now we're gonna go back 817 00:26:56,400 --> 00:26:58,440 and ask for those same four addresses 818 00:26:58,440 --> 00:27:00,060 in the same exact order. 819 00:27:00,060 --> 00:27:02,940 And so what's gonna happen is A one is gonna replace A two 820 00:27:02,940 --> 00:27:05,190 and then A two is gonna come and replace A three, 821 00:27:05,190 --> 00:27:07,020 A three is gonna replace A four 822 00:27:07,020 --> 00:27:08,850 and A four is gonna replace K one. 823 00:27:08,850 --> 00:27:10,890 So you can see that what was supposed to be one miss, 824 00:27:10,890 --> 00:27:12,900 we only had the kernel kick one of our lines out, 825 00:27:12,900 --> 00:27:14,730 has turned into four misses. 826 00:27:14,730 --> 00:27:16,890 Every address we put in there is now missing. 827 00:27:16,890 --> 00:27:19,770 And so by priming and probing in the same direction, 828 00:27:19,770 --> 00:27:21,690 you can trigger this cascade of misses, 829 00:27:21,690 --> 00:27:23,130 that results in a huge difference. 830 00:27:23,130 --> 00:27:25,020 That can be graphed very, very well. 831 00:27:25,020 --> 00:27:26,370 And if you don't want that behavior, 832 00:27:26,370 --> 00:27:28,500 if you wanna just see it, only one missed difference, 833 00:27:28,500 --> 00:27:30,090 we actually have a version of that too. 834 00:27:30,090 --> 00:27:32,370 And all you have to do is reload in the opposite direction. 835 00:27:32,370 --> 00:27:33,810 So PACMAN II can do both. 836 00:27:33,810 --> 00:27:35,820 We set it to the cascading mode 837 00:27:35,820 --> 00:27:37,720 cause it's a lot easier to tell apart. 838 00:27:38,940 --> 00:27:39,773 Okay, cool. 839 00:27:39,773 --> 00:27:41,803 So we can do, tell when these kernel load, 840 00:27:41,803 --> 00:27:42,636 okay loads occur 841 00:27:42,636 --> 00:27:43,530 and you'll notice that all these techniques 842 00:27:43,530 --> 00:27:44,520 are very generic. 843 00:27:44,520 --> 00:27:47,610 They can be used for many things besides just PACMAN. 844 00:27:47,610 --> 00:27:49,920 And so now we wanna get to this last step here, 845 00:27:49,920 --> 00:27:51,210 do the correct PAC means a load, 846 00:27:51,210 --> 00:27:52,610 incorrect PAC means no load. 847 00:27:54,960 --> 00:27:57,150 And so we're gonna have three target programs. 848 00:27:57,150 --> 00:27:58,260 We're gonna start with just the basic one 849 00:27:58,260 --> 00:27:59,400 to prove this works. 850 00:27:59,400 --> 00:28:00,540 We're gonna have an advanced program, 851 00:28:00,540 --> 00:28:02,340 which is a C++ object lookup. 852 00:28:02,340 --> 00:28:04,350 We'll talk about some restrictions on that. 853 00:28:04,350 --> 00:28:05,850 And then we're gonna have what we call Ultra, 854 00:28:05,850 --> 00:28:08,220 which is a legitimate system call in the real kernel, 855 00:28:08,220 --> 00:28:09,303 completely unpatched. 856 00:28:10,530 --> 00:28:13,140 And so our basic victim here is an if statement 857 00:28:13,140 --> 00:28:14,550 with lots and lots and lots of instructions 858 00:28:14,550 --> 00:28:15,780 that take a long time to run, 859 00:28:15,780 --> 00:28:17,580 gives us as much time as possible 860 00:28:17,580 --> 00:28:19,080 for our instructions to run. 861 00:28:19,080 --> 00:28:22,290 And then we're just gonna do a simple authenticate and load. 862 00:28:22,290 --> 00:28:23,580 And this is what it looks like. 863 00:28:23,580 --> 00:28:24,630 So when you run this, 864 00:28:24,630 --> 00:28:27,930 the data on the left and the instructions on the right 865 00:28:27,930 --> 00:28:28,980 both look really great, 866 00:28:28,980 --> 00:28:31,350 you can actually tell with 99% accuracy, 867 00:28:31,350 --> 00:28:32,310 which one is wedge, 868 00:28:32,310 --> 00:28:33,573 it's quite good. 869 00:28:34,710 --> 00:28:36,510 But when you try it on this other instruction, 870 00:28:36,510 --> 00:28:37,920 so there's this third type of instruction, 871 00:28:37,920 --> 00:28:39,240 this BLRAA, 872 00:28:39,240 --> 00:28:42,300 which is a built in branch and off at the same time, 873 00:28:42,300 --> 00:28:45,060 what you're gonna see is actually this disjoint pattern 874 00:28:45,060 --> 00:28:47,460 where yeah, your correct PAC's look really, really good, 875 00:28:47,460 --> 00:28:48,690 but half of the time, 876 00:28:48,690 --> 00:28:51,660 your incorrect PAC's also look like they're doing loads. 877 00:28:51,660 --> 00:28:52,980 So what's going on here? 878 00:28:52,980 --> 00:28:55,620 Well, if you look at it exactly 50% of the time, 879 00:28:55,620 --> 00:28:56,730 we're gonna do a load. 880 00:28:56,730 --> 00:28:57,960 And so what we think is happening 881 00:28:57,960 --> 00:28:59,400 is for this type of instruction, 882 00:28:59,400 --> 00:29:01,853 there's actually a race condition in the pipeline 883 00:29:01,853 --> 00:29:05,160 where the authenticate and the load kind of run parallel. 884 00:29:05,160 --> 00:29:08,190 And one of them might finish sooner than the other one. 885 00:29:08,190 --> 00:29:09,840 And so half the time the authenticate wins 886 00:29:09,840 --> 00:29:10,800 and you don't get a load, 887 00:29:10,800 --> 00:29:12,540 half the time the authenticate loses 888 00:29:12,540 --> 00:29:13,830 and you do get a load. 889 00:29:13,830 --> 00:29:18,270 And so we classify this as BLRAA is actually vulnerable, 890 00:29:18,270 --> 00:29:19,860 but it's just a little harder to look at. 891 00:29:19,860 --> 00:29:21,360 So for the sake of our demonstration 892 00:29:21,360 --> 00:29:22,260 for the rest of the day, 893 00:29:22,260 --> 00:29:25,043 we're going to remove BLRAA's and just look at BLR's. 894 00:29:26,730 --> 00:29:28,170 All right. So the advanced victim. 895 00:29:28,170 --> 00:29:30,030 So in this case, we have a different if statement, 896 00:29:30,030 --> 00:29:32,550 this is a more realistic kind of branch condition. 897 00:29:32,550 --> 00:29:35,250 And so we say, if the user argument is less than some limit, 898 00:29:35,250 --> 00:29:38,220 we're gonna do a C++ method call, right? 899 00:29:38,220 --> 00:29:39,450 So a couple challenges with this, 900 00:29:39,450 --> 00:29:42,330 but let's start by revisiting the C++ method dispatch. 901 00:29:42,330 --> 00:29:45,480 So every C++ object is gonna have this vtable pointer, 902 00:29:45,480 --> 00:29:47,310 which points to its table of functions. 903 00:29:47,310 --> 00:29:49,470 So we're gonna have to do a data load from this table 904 00:29:49,470 --> 00:29:52,200 and then an instruction call from the table entry. 905 00:29:52,200 --> 00:29:53,700 And so there's two attacks that need to be done 906 00:29:53,700 --> 00:29:54,570 serially here, 907 00:29:54,570 --> 00:29:55,470 serially here, 908 00:29:55,470 --> 00:29:58,370 there's the data attack as well as the instruction attack. 909 00:29:59,340 --> 00:30:00,540 And so if you look at the assembly, 910 00:30:00,540 --> 00:30:02,160 this is actually the same object we looked at 911 00:30:02,160 --> 00:30:03,300 at the beginning. 912 00:30:03,300 --> 00:30:06,330 You'll see that we do the verify data pointer right here. 913 00:30:06,330 --> 00:30:09,210 And then we load the contents of that data pointer 914 00:30:09,210 --> 00:30:10,860 and then verify them as well. 915 00:30:10,860 --> 00:30:12,993 So it's two verify is right in a row. 916 00:30:13,890 --> 00:30:16,920 And so what we'd like to do is set up the memory scenario, 917 00:30:16,920 --> 00:30:19,050 such as that we have a forged vtable 918 00:30:19,050 --> 00:30:20,340 hanging out somewhere else 919 00:30:20,340 --> 00:30:23,010 that is signed correctly with a vtable pointer to that, 920 00:30:23,010 --> 00:30:24,360 to a signed pointer, 921 00:30:24,360 --> 00:30:26,040 to our code that we'd like to use. 922 00:30:26,040 --> 00:30:27,600 That's the end game here. 923 00:30:27,600 --> 00:30:30,120 And so forging the vtable pointer is straightforward. 924 00:30:30,120 --> 00:30:31,380 We've just showed that with a, 925 00:30:31,380 --> 00:30:32,213 directly replaced it. 926 00:30:32,213 --> 00:30:33,420 And the reason that's straightforward 927 00:30:33,420 --> 00:30:34,890 is because we know a good pointer. 928 00:30:34,890 --> 00:30:38,250 We know that the original vtable is located where it is, 929 00:30:38,250 --> 00:30:40,290 but we cannot forge this instruction pointer. 930 00:30:40,290 --> 00:30:41,123 And we can't do that 931 00:30:41,123 --> 00:30:43,230 because we don't know how to train the branch predictor 932 00:30:43,230 --> 00:30:44,460 on pointers in this location. 933 00:30:44,460 --> 00:30:46,830 Remember moving a pointer breaks the seal. 934 00:30:46,830 --> 00:30:48,840 So we don't have a good pointer to put here. 935 00:30:48,840 --> 00:30:51,510 And so there's a little trick we can use instead 936 00:30:51,510 --> 00:30:53,220 is to actually train the branch predictor 937 00:30:53,220 --> 00:30:54,510 on the old vtable. 938 00:30:54,510 --> 00:30:56,370 So have the old training running 939 00:30:56,370 --> 00:30:57,930 with the old external method. 940 00:30:57,930 --> 00:30:59,220 And then when we wanna do a test, 941 00:30:59,220 --> 00:31:01,020 we actually swap both the vtable 942 00:31:01,020 --> 00:31:02,680 and the vtable entry at the same time 943 00:31:02,680 --> 00:31:04,770 to do the trials in this forage table like this. 944 00:31:04,770 --> 00:31:07,380 And if you do that, it actually works. 945 00:31:07,380 --> 00:31:09,270 And so the other problem we have 946 00:31:09,270 --> 00:31:12,510 is that the speculation window is very, very short. 947 00:31:12,510 --> 00:31:13,650 And the reason for that is because 948 00:31:13,650 --> 00:31:14,700 when we're doing our test, 949 00:31:14,700 --> 00:31:16,230 we have five things we wanna do. 950 00:31:16,230 --> 00:31:19,680 We need to do a load, a check, another load, another check, 951 00:31:19,680 --> 00:31:20,670 and then a call. 952 00:31:20,670 --> 00:31:21,503 And we have to do that, 953 00:31:21,503 --> 00:31:24,120 all of that faster before the CPU realizes 954 00:31:24,120 --> 00:31:25,377 it's not supposed to be running that. 955 00:31:25,377 --> 00:31:26,940 And all the CPU has to do 956 00:31:26,940 --> 00:31:28,920 is do two loads in a comparison, 957 00:31:28,920 --> 00:31:30,120 really, really simple. 958 00:31:30,120 --> 00:31:32,310 And so we wanna make the limit variable, 959 00:31:32,310 --> 00:31:33,450 take a lot longer to load. 960 00:31:33,450 --> 00:31:34,770 So we have more time. 961 00:31:34,770 --> 00:31:35,940 So how do we do that? 962 00:31:35,940 --> 00:31:37,830 Well, we just solved that problem earlier on 963 00:31:37,830 --> 00:31:40,230 with kernel eviction sets. 964 00:31:40,230 --> 00:31:41,610 And so if you imagine the cache, 965 00:31:41,610 --> 00:31:43,500 this is kind your mental model of the cache. 966 00:31:43,500 --> 00:31:45,120 We've got the limit variable in the cache, 967 00:31:45,120 --> 00:31:46,470 and that that's loading way too quickly. 968 00:31:46,470 --> 00:31:47,520 We don't like that. 969 00:31:47,520 --> 00:31:50,070 And we also have an eviction set for that target address, 970 00:31:50,070 --> 00:31:50,903 cause again, 971 00:31:50,903 --> 00:31:51,736 we need to do the Prime Probe 972 00:31:51,736 --> 00:31:53,160 to know where the load is successful. 973 00:31:53,160 --> 00:31:55,320 And so if we're in the condition where the limit 974 00:31:55,320 --> 00:31:57,930 and the eviction set are not in the same set, 975 00:31:57,930 --> 00:32:00,510 we can just kick limit out with the second eviction set. 976 00:32:00,510 --> 00:32:02,400 So make the limit go all the way back to memory 977 00:32:02,400 --> 00:32:04,350 and then it'll take forever to load. 978 00:32:04,350 --> 00:32:07,680 And again, we need to be in different sets for that to work. 979 00:32:07,680 --> 00:32:10,140 And when you do that, the load now takes a lot longer, 980 00:32:10,140 --> 00:32:12,540 gives you plenty of time in that window to do those tests 981 00:32:12,540 --> 00:32:14,460 and do the forage without further ado, 982 00:32:14,460 --> 00:32:16,260 let's actually do it for real. 983 00:32:16,260 --> 00:32:17,760 And so in this example here, 984 00:32:17,760 --> 00:32:19,170 we're gonna have a destination, 985 00:32:19,170 --> 00:32:21,240 which is, you can think of it like a rat to win, 986 00:32:21,240 --> 00:32:22,560 it's just a giant nop sled. 987 00:32:22,560 --> 00:32:23,700 So lots and lots of nop's 988 00:32:23,700 --> 00:32:26,400 that ends in a branch to a log function. 989 00:32:26,400 --> 00:32:27,330 And so here on the left, 990 00:32:27,330 --> 00:32:29,130 we've got a log viewer trying to see 991 00:32:29,130 --> 00:32:30,570 if the kernel's doing any logs 992 00:32:30,570 --> 00:32:32,430 and on the right, we're gonna do the PACMAN attack. 993 00:32:32,430 --> 00:32:33,360 And so I said earlier, 994 00:32:33,360 --> 00:32:35,790 PACMAN II is an improvement on PACMAN I. 995 00:32:35,790 --> 00:32:37,920 And so one of the things that PACMAN II does 996 00:32:37,920 --> 00:32:40,140 is instead of looking at every pointer in detail, 997 00:32:40,140 --> 00:32:41,490 it actually does two passes 998 00:32:41,490 --> 00:32:43,860 over the entire space of possible packs. 999 00:32:43,860 --> 00:32:45,480 And so the first thing that it does is it says, 1000 00:32:45,480 --> 00:32:47,580 is this pointer potentially the right one? 1001 00:32:47,580 --> 00:32:48,690 I don't care if it is the right one, 1002 00:32:48,690 --> 00:32:50,580 but could it be the correct pointer? 1003 00:32:50,580 --> 00:32:53,160 And if that is not possible at all, we don't see any misses, 1004 00:32:53,160 --> 00:32:54,180 we throw it out. 1005 00:32:54,180 --> 00:32:55,860 And so that way we can look at all the pointers really, 1006 00:32:55,860 --> 00:32:58,260 really quickly by doing a cursory glance at all of them, 1007 00:32:58,260 --> 00:32:59,850 comparing the ones that look promising 1008 00:32:59,850 --> 00:33:00,840 and then figuring out, 1009 00:33:00,840 --> 00:33:02,430 figuring them out from there. 1010 00:33:02,430 --> 00:33:03,360 And so let's go ahead and launch it. 1011 00:33:03,360 --> 00:33:05,160 We're gonna start by forging that data pointer. 1012 00:33:05,160 --> 00:33:06,307 You'll see, 1013 00:33:06,307 --> 00:33:07,140 we're picking up some hits 1014 00:33:07,140 --> 00:33:08,070 and we're gonna keep track of those hits 1015 00:33:08,070 --> 00:33:09,780 and how many misses they've got 1016 00:33:09,780 --> 00:33:12,510 and you see we're going through this space really fast here 1017 00:33:12,510 --> 00:33:13,563 and it's almost done. 1018 00:33:16,350 --> 00:33:17,183 And there we go. 1019 00:33:17,183 --> 00:33:19,710 So we're gonna start looking at them and we've got it. 1020 00:33:19,710 --> 00:33:21,060 So we got the data pointer signed 1021 00:33:21,060 --> 00:33:22,800 and now we're moving on to that instruction pointer. 1022 00:33:22,800 --> 00:33:23,910 So each of these iterations, 1023 00:33:23,910 --> 00:33:25,620 we're gonna train with the old vtable 1024 00:33:25,620 --> 00:33:26,790 and then swap it for the new one, 1025 00:33:26,790 --> 00:33:28,440 right when we need to do the test. 1026 00:33:28,440 --> 00:33:30,420 And we're trying to forge to jump to that nop sled 1027 00:33:30,420 --> 00:33:31,533 with our wind method. 1028 00:33:34,950 --> 00:33:36,300 And you'll see we got it right. 1029 00:33:36,300 --> 00:33:38,010 And the kernel can actually print that it won. 1030 00:33:38,010 --> 00:33:39,600 So we were able to forage both a data 1031 00:33:39,600 --> 00:33:41,450 and instruction pointer successfully. 1032 00:33:42,926 --> 00:33:45,843 (crowd applauding) 1033 00:33:49,110 --> 00:33:49,943 Thank you. 1034 00:33:51,300 --> 00:33:54,690 And so now let's use PACMAN Finder to do one last attack 1035 00:33:54,690 --> 00:33:56,160 and we're gonna use this as a case study 1036 00:33:56,160 --> 00:33:57,810 of doing this in the real kernel. 1037 00:33:59,070 --> 00:34:00,840 So what we're gonna do is tell PACMAN Finder, 1038 00:34:00,840 --> 00:34:04,170 I want all the gadgets for just the BSD system calls. 1039 00:34:04,170 --> 00:34:05,003 And the reason for that is 1040 00:34:05,003 --> 00:34:06,810 because those are really each easy to reach. 1041 00:34:06,810 --> 00:34:09,090 So I can spend less time looking at the gadgets 1042 00:34:09,090 --> 00:34:11,280 to see which ones are fitting my constraints. 1043 00:34:11,280 --> 00:34:12,990 Now, if you were doing this as a real attacker, 1044 00:34:12,990 --> 00:34:14,460 you might wanna target more specifically 1045 00:34:14,460 --> 00:34:16,530 to maybe the text you're looking at or whatever. 1046 00:34:16,530 --> 00:34:17,363 But in this case, 1047 00:34:17,363 --> 00:34:18,630 let's just look at the BSD system calls. 1048 00:34:18,630 --> 00:34:19,950 And so these ones look good. 1049 00:34:19,950 --> 00:34:20,783 And of these, 1050 00:34:20,783 --> 00:34:22,170 we pulled out this one right here. 1051 00:34:22,170 --> 00:34:23,040 So memory status, 1052 00:34:23,040 --> 00:34:24,180 available memory, 1053 00:34:24,180 --> 00:34:26,010 and let's look at what this is doing. 1054 00:34:26,010 --> 00:34:29,370 And so what the PACMAN Finder found 1055 00:34:29,370 --> 00:34:32,820 was a very simple load, comparison, branch 1056 00:34:32,820 --> 00:34:34,380 and then authenticated load. 1057 00:34:34,380 --> 00:34:36,540 So it is your quintessential PACMAN gadget. 1058 00:34:36,540 --> 00:34:38,553 It's very, very obvious. 1059 00:34:39,450 --> 00:34:42,600 And so the branch condition is this proc plus 560. 1060 00:34:42,600 --> 00:34:45,060 And the thing that's being forged is proc plus 10, 1061 00:34:45,060 --> 00:34:45,990 which is kind of a bummer. 1062 00:34:45,990 --> 00:34:47,160 We'll see why in just a second, 1063 00:34:47,160 --> 00:34:51,090 but it is forging things in the process structure. 1064 00:34:51,090 --> 00:34:52,800 And so if you look through the kernel, 1065 00:34:52,800 --> 00:34:53,760 the pointer in question here 1066 00:34:53,760 --> 00:34:55,440 is actually the proc dot task structure. 1067 00:34:55,440 --> 00:34:59,160 So this is the core task that belongs to that process. 1068 00:34:59,160 --> 00:35:00,610 And that's what we can forge. 1069 00:35:01,470 --> 00:35:04,050 And so the branch condition is the memstat limit field 1070 00:35:04,050 --> 00:35:05,100 of the process. 1071 00:35:05,100 --> 00:35:05,933 And again, 1072 00:35:05,933 --> 00:35:07,590 what we're forging is the task field of the process. 1073 00:35:07,590 --> 00:35:09,330 But the problem is that these are in the same page, 1074 00:35:09,330 --> 00:35:10,740 so our limit trick doesn't work. 1075 00:35:10,740 --> 00:35:12,210 If we try to evict that limit, 1076 00:35:12,210 --> 00:35:14,160 we're gonna make both loads take longer 1077 00:35:14,160 --> 00:35:17,220 and we've had a net zero change in the speculative behavior. 1078 00:35:17,220 --> 00:35:19,260 So that's not a great choice of gadget. 1079 00:35:19,260 --> 00:35:21,270 Another reason this is not a great choice of a gadget 1080 00:35:21,270 --> 00:35:23,280 is because this is in a commonly used field 1081 00:35:23,280 --> 00:35:24,780 and a frequently access page. 1082 00:35:24,780 --> 00:35:26,400 So since this is hot kernel code, 1083 00:35:26,400 --> 00:35:28,740 there's gonna be a lot of loads and rights to it. 1084 00:35:28,740 --> 00:35:31,320 So it's gonna be probably very high up in the TLB, 1085 00:35:31,320 --> 00:35:32,340 which means that you're not gonna get 1086 00:35:32,340 --> 00:35:35,460 super great eviction patterns and a lot of noise. 1087 00:35:35,460 --> 00:35:36,300 The other thing is that 1088 00:35:36,300 --> 00:35:39,120 since this is a very commonly used field across the kernel, 1089 00:35:39,120 --> 00:35:41,700 many, many asynchronous threads might try to read from it. 1090 00:35:41,700 --> 00:35:43,260 So you could have problems where 1091 00:35:43,260 --> 00:35:45,210 your test case has an invalid pointer 1092 00:35:45,210 --> 00:35:47,730 that gets read, dereference and causes a crash 1093 00:35:47,730 --> 00:35:50,460 independent of the PACMAN attack. 1094 00:35:50,460 --> 00:35:53,010 And so we did this 12 times, here's the first six results. 1095 00:35:53,010 --> 00:35:54,540 You can see the first two look really good. 1096 00:35:54,540 --> 00:35:56,490 We have that great differentiation pattern. 1097 00:35:56,490 --> 00:35:57,600 Third one, we got a kernel panic. 1098 00:35:57,600 --> 00:35:58,500 And then the other three, 1099 00:35:58,500 --> 00:36:00,270 we just kind of didn't see anything. 1100 00:36:00,270 --> 00:36:01,410 And it's kinda the same story 1101 00:36:01,410 --> 00:36:02,820 for some of the other tests we did. 1102 00:36:02,820 --> 00:36:05,054 So this one, there is a signal there, 1103 00:36:05,054 --> 00:36:06,390 there's some signal there, 1104 00:36:06,390 --> 00:36:08,670 but the problem is that it's not super reliable, 1105 00:36:08,670 --> 00:36:09,900 again for the reasons we discussed. 1106 00:36:09,900 --> 00:36:11,970 It's not a super great choice of gadget, 1107 00:36:11,970 --> 00:36:14,460 but the important takeaway is that for a gadget like this, 1108 00:36:14,460 --> 00:36:15,870 when we win, we win big. 1109 00:36:15,870 --> 00:36:18,270 It's very easy to tell that this is the correct pointer 1110 00:36:18,270 --> 00:36:19,320 in this case. 1111 00:36:19,320 --> 00:36:21,420 And when we fail, we fail safely. 1112 00:36:21,420 --> 00:36:22,980 We don't report an incorrect pointer. 1113 00:36:22,980 --> 00:36:24,810 We just report, we didn't find anything. 1114 00:36:24,810 --> 00:36:25,920 And so those are two great points 1115 00:36:25,920 --> 00:36:28,500 that make this a compelling attack, 1116 00:36:28,500 --> 00:36:30,690 but you do gotta be afraid of these asynchronous accesses. 1117 00:36:30,690 --> 00:36:32,850 So if you are running something asynchronously, 1118 00:36:32,850 --> 00:36:34,590 you could actually result in a kernel panic, 1119 00:36:34,590 --> 00:36:35,853 which is not super great. 1120 00:36:36,900 --> 00:36:38,400 And so I wanna return to this question 1121 00:36:38,400 --> 00:36:39,690 we asked at the beginning. 1122 00:36:39,690 --> 00:36:40,830 So at the beginning we said, 1123 00:36:40,830 --> 00:36:44,160 PACMAN is a vulnerability in PAC protected systems. 1124 00:36:44,160 --> 00:36:46,650 And we asked the question, is this a flaw? 1125 00:36:46,650 --> 00:36:47,970 Is this represent a real flaw 1126 00:36:47,970 --> 00:36:49,720 in the CPU architect's perspective? 1127 00:36:50,737 --> 00:36:52,350 Or is this a consequence of us being greedy 1128 00:36:52,350 --> 00:36:53,850 for more speculative behavior, 1129 00:36:53,850 --> 00:36:55,020 as well as trying to combine that 1130 00:36:55,020 --> 00:36:57,270 with a fundamentally incompatible feature. 1131 00:36:57,270 --> 00:36:59,430 So is PAC fundamentally incompatible with specter 1132 00:36:59,430 --> 00:37:00,263 or speculation 1133 00:37:00,263 --> 00:37:02,600 or is there something we can do about this? 1134 00:37:02,600 --> 00:37:04,830 So I leave that to you to come up with your answers. 1135 00:37:04,830 --> 00:37:06,390 And I'd love to discuss this further with you, 1136 00:37:06,390 --> 00:37:08,640 if you have any thoughts on this. 1137 00:37:08,640 --> 00:37:10,770 And so with that, all of our code is available on GitHub. 1138 00:37:10,770 --> 00:37:12,840 If you go to this repo, we've got everything posted there, 1139 00:37:12,840 --> 00:37:14,280 all the tools and the proof of concepts, 1140 00:37:14,280 --> 00:37:16,980 both the ISCA code and the code from today, 1141 00:37:16,980 --> 00:37:18,720 you can go ahead and go play with that. 1142 00:37:18,720 --> 00:37:20,733 And without further ado, that's PACMAN. 1143 00:37:22,227 --> 00:37:25,144 (crowd applauding)