Last week, Apple released a security update for iOS, indicating that the vulnerability being fixed is one that allows SSL / TLS connections to continue even though the server should not be authenticated. This is how they described it:
Impact: An attacker with a privileged network position may capture or modify data in sessions protected by SSL/TLS
Description: Secure Transport failed to validate the authenticity of the connection. This issue was addressed by restoring missing validation steps.
Secure Transport is their library for handling SSL / TLS, meaning that the bulk of applications written for these platforms would not adequately validate the authenticity of servers to which they are connected.
Ignore “An attacker with a privileged network position” – this is the very definition of a Man-in-the-Middle (MITM) attacker, and whereas we used to be more blasé about this in the past, when networking was done with wires, now that much of our use is wireless (possibly ALL in the case of iOS), the MITM attacker can easily insert themselves in the privileged position on the network.
The other reason to ignore that terminology is that SSL / TLS takes as its core assumption that it is protecting against exactly such a MITM. By using SSL / TLS in your service, you are noting that there is a significant risk that an attacker has assumed just such a privileged network position.
Also note that “failed to validate the authenticity of the connection” means “allowed the attacker to attack you through an encrypted channel which you believed to be secure”. If the attacker can force your authentication to incorrectly succeed, you believe you are talking to the right server, and you open an encrypted channel to the attacker. That attacker can then open an encrypted channel to the server to which you meant to connect, and echo your information straight on to the server, so you get the same behaviour you expect, but the attacker can see everything that goes on between you and your server, and modify whatever parts of that communication they choose.
So this lack of authentication is essentially a complete failure of your secure connection.
As always happens when a patch is released, within hours (minutes?) of the release, the patch has been reverse engineered, and others are offering their description of the changes made, and how they might have come about.
In this case, the reverse engineering was made easier by the availability of open source copies of the source code in use. Note that this is not an intimation that open source is, in this case, any less secure than closed source, because the patches can be reverse engineered quickly – but it does give us a better insight into exactly the code as it’s seen by Apple’s developers.
if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;
Yes, that’s a second “goto fail”, which means that the last “if” never gets called, and the failure case is always executed. Because of the condition before it, however, the ‘fail’ label gets executed with ‘err’ set to 0.
So, of course, the Internet being what it is, the first reaction is to laugh at the clowns who made such a simple mistake, that looks so obvious.
T-shirts are printed with “goto fail; goto fail;” on them. Nearly 200 have been sold already (not for me – I don’t generally wear black t-shirts).
This is SSL code. You don’t get let loose on SSL code unless you’re pretty smart to begin with. You don’t get to work as a developer at Apple on SSL code unless you’re very smart.
Clearly “be smart” is already in evidence.
There is a possibility that this is too much in evidence – that the arrogance of those with experience and a track record may have led these guys to avoid some standard protective measures. The evidence certainly fits that view, but then many developers start with that perspective anyway, so in the spirit of working with the developers you have, rather than the ones you theorise might be possible, let’s see how to address this issue long term:
OK, so it’s considered macho to not rely on an IDE. I’ve never understood that. It’s rather like saying how much you prefer pounding nails in with your bare fists, because it demonstrates how much more of a man you are than the guy with a hammer. It doesn’t make sense when you compare how fast the job gets done, or the silly and obvious errors that turn up clearly when the IDE handles your indenting, colouring, and style for you.
Yes, colouring. I know, colour-blind people exist – and those people should adjust the colours in the IDE so that they make sense. Even a colour-blind person can get shade information to help them. I know syntax colouring often helps me spot when an XSS injection is just about ready to work, when I would otherwise have missed it in all the surrounding garbage of HTML code. The same is true when building code, you can spot when keywords are being interpreted as values, when string delimiters are accidentally unescaped, etc.
The same is true for indentation. Indentation, when it’s caused by your IDE based on parsing your code, rather than by yourself pounding the space bar, is a valuable indication of program flow. If your indentation doesn’t match control flow, it’s because you aren’t enforcing indentation with an automated tool.
Your IDE and your check-in process are a great place to enforce style standards to ensure that code is not confusing to the other developers on your team – or to yourself.
A little secret – one of the reasons I’m in this country in the first place is that I sent an eight-page fax to my bosses in the US, criticising their programming style and blaming (rightly) a number of bugs on the use of poor and inconsistent coding standards. This was true two decades ago using Fortran, and it’s true today in any number of different languages.
The style that was missed in this case – put braces around all your conditionally-executed statements.
I have other style recommendations that have worked for me in the past – meaningful variable names, enforced indenting, maximum level of indenting, comment guidelines, constant-on-the-left of comparisons, don’t include comparisons and assignments in the same line, one line does one thing, etc, etc.
Make sure you back the style requirements with statements as to what you are trying to do with the style recommendation. “Make the code look the same across the team” is a good enough reason, but “prevent incorrect flow” is better.
gcc has the option “-Wunreachable-code”.
gcc disabled the option in 2010.
gcc silently disabled the option, because they didn’t want anyone’s build to fail.
This is not (IMHO) a smart choice. If someone has a warning enabled, and has enabled the setting to produce a fatal error on warnings, they WANT their build to fail if that warning is triggered, and they WANT to know when that warning can no longer be relied upon.
So, without a warning on unreachable code, you’re basically screwed when it comes to control flow going where you don’t want it to.
And of course there’s the trouble that’s caused when you have dozens and dozens of warnings, so warnings are ignored. Don’t get into this state – every warning is a place where the compiler is confused enough by your code that it doesn’t know whether you intended to do that bad thing.
Let me stress – if you have a warning, you have confused the compiler.
This is a bad thing.
You can individually silence warnings (with much comments in your code, please!) if you are truly in need of a confusing operation, but for the most part, it’s a great saving on your code cleanliness and clarity if you address the warnings in a smart and simple fashion.
The compiler has an optimiser.
It’s really good at its job.
It’s better than you are at optimising code, unless you’re going to get more than a 10-20% improvement in speed.
Making code shorter in its source form does not make it run faster. It may make it harder to read. For instance, this is a perfectly workable form of strstr:
const char * strstr(const char *s1, const char *s2)
Can you tell me if it has any bugs in it?
What’s its memory usage? Processor usage? How would you change it to make it work on case-insensitive comparisons? Does it overflow buffers?
Better still: does it compile to smaller or more performant code, if you rewrite it so that an entry-level developer can understand how it works?
Now go and read the implementation from your CRT. It’s much clearer, isn’t it?
Releasing the patch on Friday for iOS and on Tuesday for OS X may have actually been the correct move – but it brings home the point that you should release patches when you maximise the payoff between having your customers patch the issue and having your attackers reverse engineer it and build attacks.
Where is the security announcement at Apple? I go to apple.com and search for “iOS 7.0.6 security update”, and I get nothing. It’d be really nice to find the bulletin right there. If it’s easier to find your documentation from outside your web site than from inside, you have a bad search engine.
People who know me may have the impression that I hate Apple. It’s a little more nuanced than that.
I accept that other people love their Apple devices. In many ways, I can understand why.
I have previously owned Apple devices – and I have tried desperately to love them, and to find why other people are so devoted to them. I have failed. My attempts at devotion are unrequited, and the device stubbornly avoids helping me do anything useful.
Instead of a MacBook Pro, I now use a ThinkPad. Instead of an iPad (remember, I won one for free!), I now use a Surface 2.
I feel like Steve Jobs turned to me and quoted Dr Frank N Furter: “I didn’t make him for you.”
So, no, I don’t like Apple products FOR ME. I’m fine if other people want to use them.
This article is simply about a really quick and easy example of how simple faults cause major errors, and what you can do, even as an experienced developer, to prevent them from happening to you.
I often thought I’d like to have a career in 3D animation, solely so I could send out invoices with the title of this blog post as their content.
It seems a little late for me to choose that career, so I’ll have to use that title for a blog posting about my Surface, now that I am three weeks in to using it.
There’s no secret (or if there is, it’s poorly hidden) to the fact that MVPs visiting Redmond for the MVP Summit this year received a pretty sweet deal on a 32GB Surface 2 and Touch Cover. Along with hundreds of my brethren, I lined up at the Microsoft Store in Bellevue yelling “shut up and take my money!”
As an actual purchase, rather than a complete giveaway, I did have to pass the purchasing decision through my boss. Fortunately, she agreed that it was a good buy, as long as I treated it as a purchase of a toy for me, and stopped trying to persuade her it was a bona fide business investment for the company. Canny woman, my wife, and skilled at reducing arguments to their simplest and most incisive points.
So, a toy it was pitched as, a replacement for my iPad, which I also got for very little money – I won it in a hacking competition. As a toy, I couldn’t expect to get the Surface Pro, which is convenient, because one wasn’t offered.
Does it have the Angry Birds,then? Space and Star Wars versions, yes – Rovio hasn’t been paid to get around to porting the others to Windows 8 yet.
It’s also got Minesweeper and Solitaire, with the added thrill of daily challenges, and an Adventure Mode for Minesweeper that looks a little ripped off from Repton. Mahjong, Jetpack Joyride, Cut the Rope, there’s enough games that while you might find a few individual names here and there that are missing, you’ll be able to replace them with something in the same genre.
The front and back camera make for good Skype use, whether you’re having a face-to-face chat, or showing someone the view out the window.
I can read comics, whether through the dozen or so manga readers, or through the Comics app from Comixology. Books come, of course, courtesy of the Kindle app, and of course there’s a native Amazon app as well, although as usual, it’s hard to get a better shopping experience in an app than Amazon has built into the web version.
That’s right, you actually have a version of Internet Explorer 11 built specially for the touch-screen “Modern UI”, which Microsoft used to call Metro, and which thoroughly needs a new name. This version of Internet Explorer is fairly basic, but fully functional for what most people are going to want it for. For most of what I do on the web, it’s certainly sufficient.
Social media makes its presence felt nicely in the People hub, like on my Windows Phone, where in one place I can keep up with my Twitter, Facebook and LinkedIn friends/followers/minions. I can also post there, although I miss my phone’s ability to post to multiple outlets at once.
If you’ve been paying attention to my gripes about podcast support on my Windows Phone, I have to say that, out of the box, I have the same – or worse –issues with the Surface 2. The native audio player does allow you to create playlists, but infallibly returns you to the start of an MP3 file almost every time you play it anew, apparently whether you played another MP3 file, skipped to a different app, or received a notification. I await the development of a good podcast / audiobook application with support for local MP3s.
On the video front, things are somewhat improved, with the Xbox Video app being the natively supported method to play my MP4s. Sadly, there’s still no subtitle support, as is the case across every single one of Microsoft’s video playing tools – if the file isn’t streaming across the web, with the closed captions in a separate stream, there’s no way to get captions to display. This is a shame, as there is good support for standard subtitles in MP4s on the Apple competition, whether it’s iPad, iPod or iPhone. Microsoft, this can’t be that hard – support accessibility on all your video players, please! [I’m not deaf, but the bus can get a little loud]
The Touch Cover is barely usable as a keyboard – but I’ve added a Bluetooth keyboard to my Christmas wishlist, for the serious typing moments, and the Touch Cover is certainly sufficient for those occasional bon mots on the bus or airplane.
Sadly, Live Writer isn’t available for Windows RT, so I’m not likely to use this for many blogs – although to keep myself honest, I am typing this on the Surface using the Touch Cover keyboard.
To write the blog entry, I’m actually using Word with its blogging template.
Why yes, yes I did – but since the presence of Office 2013 on the Surface was advertised (at least, Excel, PowerPoint, OneNote, Word and Outlook), this was hardly a surprise to me – but it seems like a surprise to many of my Apple-owning friends who are just starting to get excited that Apple have deigned to let them have iWorks on their iPads now.
But the inclusion of Office isn’t the only thing that makes this device veer further into the territory of a non-toy.
I wasn’t really expecting that Windows RT would have a desktop mode. I pretty much thought it would be Modern UI apps and nothing else. That seemed like it would suck, because I can’t then copy files across the network for playing MP3s and MP4s on the bus to and from work.
So a friend of mine set my fears at rest before I bought the Surface, and let me know that there was indeed a desktop, and a Windows Explorer. That was the tipping point to realizing I could get along with my Surface.
Then came the surprises.
There’s a Desktop version of Internet Explorer – and this one is fully functional! It even has “View Source” and the F12 Developer Tools, Microsoft’s best-kept secret in IE for some time now. [On your Touch Cover, you get F12 by holding down the “Fn” key as you press “PgDn”] This means I can carry on my Cross-Site Scripting endeavours on my Surface – which I couldn’t do from my iPad at all.
Also not on the iPad, but present on the Surface, a full version of the Command Prompt – I can run all my old batch scripts. Notepad, too (but no WordPad, sadly). Even, and I can’t imagine using the power of this too much, PowerShell!
Flash Player, as well, which isn’t available on the iPad. Remote Assistance and Remote Desktop, so I can connect to a real computer, something that wasn’t a good experience on the iPad.
Woah, BitLocker? Wow, my hard drive is already encrypted. So too could be the 64GB MicroSD card I’ve attached for extra video and audio storage, again something I can’t do on my iPad.
PerfMon, ResMon, Event Viewer, RegEdit, Windows Scripting Host, all sorts of serious tooling works in the desktop environment. Not Visual Studio, yet, but let’s remember… this is a toy, not a real laptop.
I use my Surface 2 far more than I ever used my iPad.
Despite a few niggling sharp corners that need to be addressed, it irritates me far less than any Apple device I’ve ever owned. This just cements in my mind that, while there are many people who love their Apples, I’m just not their target consumer. I’m not sure that I’m exactly the target consumer of the Surface, but it’s inspired me and continues to grow on me. I’m even starting to write code for it. We’ll see if that becomes anything in due course.
Java not yet available for Surface – one more advantage.
OK, so that’s a horrible stretching of a song to cover a point, but it’s kind of the way I feel right now – torn between a rock and a hard place.
Some time ago now, I let you readers know that I’d won an iPad at the Black Hat security conference, and that I’d be trying it out to let you know what I thought.
First, let’s consider my usage case, and what I am comparing it against.
The iPad is, to my mind, a potential killer device for a few things I like to do:
In common with many people, I have a lengthy commute – at least 40 minutes each way of which is on a bus, so I can happily watch videos. My comparison device in this use case is my Windows Phone – an HTC HD7 (I’d link to it, but apparently it’s not being sold any more).
The iPad is bulkier, for certain, and I can hold my phone in one hand comfortably for some time. However, making up for this is the fact that the iPad is a larger display and therefore easier to see at a comfortable distance. But watching on the phone isn’t bad either.
Syncing to the iPad is accomplished through Apple’s piss-poor iTunes software (of which, more later), which seems to require that my videos be already in a suitable format for the iPad. Syncing to the HD7 requires the Zune software, which is configured by default to convert video and audio in the background without any further assistance from me.
Note that – Zune converts the videos to the right format automatically when necessary, the iTunes software simply shrugs its shoulders like a Frenchman and refuses to cope.
Because of this, I can sync to the HD7 from more sources, and more easily and automatically than to the iPad.
However, the winning step that the iPad has for me comes from a combination of its viewing size, and the fact that it can play the audio from my videos to my Bluetooth headset, something that the HD7 currently does not. I have to use a Bluetooth dongle on the HD7 to hear my videos – and that’s not right, when I already paid for a phone with Bluetooth support.
It’s worth noting, however, that because the iPad seems to pretend to be a phone, I can’t have the appropriate level of Bluetooth support, allowing incoming phone calls to pause my video and let me answer the phone.
So, a narrow win for the iPad there. But keep reading. [Add Bluetooth support for video watching, and the Windows Phone will easily surpass the iPad]
Killer app, no doubt – the size and colours make the iPad superior for reading comics. For other books, you can’t really beat a Kindle, because it’s the size and shape of a book. The iPad does seem to suffer in daylight as well, not that we get much of that around Seattle – but we clearly get enough for this to be a noticeable problem for me.
The Kindle Fire is a more subtle device than the iPad in this use as well, since it doesn’t take up as much space. The battery life, as well as the use of standard charging cables (read: I already have dozens of the things, as opposed to having to look for the one wonky, too short cable that came with the iPad) makes the convenience factor that much greater.
However, I’ve even read my comics on the Windows Phone. It’s not that bad a format, because the display is so high a resolution.
Winner: Kindle Fire. Of course, I would say that. But since the Fire has no Bluetooth audio, I can’t use it on the bus as comfortably for my videos.
The iPad is certainly convenient for this, with free Twitter and Facebook apps, as well as a web browser to use the online versions. The iPad’s desire to keep pushing text further and further to the right of the screen, in ever-decreasing strips of window, make it incredibly difficult to read some items.
In comparison, while the Windows Phone does have a free Twitter and Facebook app, and access to the web, it doesn’t actually need any of these, because there are the “Me” and “People” tiles, through which you can read notices from all your social media sources (Twitter, Facebook, Linked-In, MSN Messenger in my case). This gives a more natural, integrated feel to the communication, and it feels more like I’m sharing with my friends than I’m using this or that app.
Winner: Windows Phone, hands down. [But it would be nice to have Bluetooth keyboard support]
OK, the iPad wins hands-down on this one. There’s a Skype app in beta for the Windows Phone, but my HD7 has only a rear-facing camera, and the Fire of course doesn’t have one.
Winner: iPad (but only because I have a 1st-gen Windows Phone)
The iPad has no Flash support – but then nor does the Windows Phone.
The iPad uses a webkit-based browser, which comes with a fresh batch of security flaws once a month (as does iTunes). The Windows Phone comes with Internet Explorer – but without the same set of flaws that get patched in your regular Windows update. I strongly believe that the Windows Phone gives me the most secure browsing of any device that I have. But it is a little hard to read.
I got the iPad for free, so I have to bear in mind that for most people, they pay $500 to have it. It’s not that much better than the Windows Phone. I got the Windows Phone for practically free – one cent on Amazon Wireless, with a two year commitment. But then I was going to get a phone anyway, and the two year commitment is common for phones.
As with every Apple product I have ever used, it seems like they skimped a little on the “fit and finish” of the software. This leads to small – but constant – irritations. There have been many times I’ve been tempted to throw it to the floor and stomp on it. So far, the iPad has survived largely because I know that if I want to get rid of it, there are numerous people who would happily take it from me. And then I settle down.
So, what are my irritations?
There are some areas where it’s clear that the Apple design philosophy hasn’t been communicated well – even to writers of the native apps.
A clear example – how do you delete an item? In iBooks, you swipe to the right, which causes a delete button to appear. You press this button, and the item goes away. In Videos, you hold your finger on an item until a little “x” appears. You press the “x”, and are asked if you really want to delete the video. I guess videos are more important than books, that you have to be prompted.
I should say that this is how videos are supposed to be deleted. What actually happens is that you hold your finger on a video for a while. The “x” fails to appear, because you wiggled your finger a little (really common on a bus). So you let your finger up, and the video opens up. So you close it down again, and hold your finger on the video again. Now the “x” appears – albeit sometimes in a different place than you expect. So you press it. Damn, missed, because the bus must have hit a bump, so the “x” goes away. Bring it back! Bring it back! Okay, here it is again, so I can press it finally. And then I get asked if I’m sure. Am I sure? Am I sure? I’ve only spent the last ten minutes trying to get the damn “x” up on screen and hit it – of course I’m sure! And I remind myself not to throw the iPad to the floor and stomp on it.
Yes, I know about the “Edit” button, and that shortcuts one part of the process, but makes it more likely that you’ll accidentally delete the wrong video, because it puts an “x” above each one.
[A short note – the “x” appears in one of two places – either immediately on the top left corner, or a good half-inch above that. I can see no logic in why it does this.]
In the Videos app, there are three kinds of video. “Movies”, “TV Shows”, and “iTunes U”. The “TV Shows” and “iTunes U” items all come from iTunes, so all the videos I put on my system end up in “Movies”, no matter what metadata I put on the file. Whereas I never metadata I didn’t like, iTunes clearly never metadata. For the iTunes U and TV Shows tabs, each item is listed with details – length, a title, and a description. This is great, although it would also be nice to see which ones I’m part-way through watching.
For the Movies tabs, however, there’s only two things showing – a thumbnail, which is the first frame of the movie (oh, and so often, that means it is plain black), and the curtailed title of the video. So, “Have I Got News for You: Series 42, Episode 5” is displayed as “Have I Got News for You:…” – as is every episode of every series of that show. Same thing for “The Sarah Jane Adventures…”, or “Who Do You Think You Are…” Yeah, the BBC could choose shorter titles, but the iPad could pay attention to the Subtitle field in the metadata for the episode information. Oh, yeah, that’s right, metadata is to be ignored.
And there’s no details on the video – no duration, no description, no indication of whether or not I’ve been watching this video file at all. I’d like to say “hey, this component of my bus ride is going to take another twenty-five minutes, so I’d like to watch something that length or shorter”.
When watching a video, you can ‘scrub’ through it by dragging a little slider at the top of the screen. Except when the slider is near the middle of the top of the screen, because then you’re going to actually be pulling down the notifications window. If anyone writing this software actually used an iPad, they’d be experiencing this frustration, and it would have been fixed by now.
To go backward in the user interface of an app, you click the button in the top left. Except that sometimes, the button in the top left takes you somewhere else, like the iTunes store.
You can delete videos all you like, bus joggling allowing, and when you’re done, your storage usage hasn’t gone down at all. There is no room for more videos. This one confused me for some time, until I remembered that you never actually close apps when you switch between them. The storage is released, not when you delete the movie, but when you close the app.
That would make sense, if you could actually undelete the movie while the videos app runs, but no. That doesn’t happen.
I could carry on, but I just get angrier and angrier. The difference between editing the list of apps you can run, versus editing the list of apps currently running, for instance. One is dismissed by a tap, the other requires that you hit the home button, and I can’t remember which one.
So, the first complaint I have about iTunes is the one I have made from the beginning – it includes way too much, and it screws up my system way too badly. What do you get when you install iTunes?
Well, first you get a file called “iTunes64Setup.exe”. This installs iTunes into “C:\Program Files (x86)” – uh, yeah, that means the “64 bit” version of iTunes is actually all 32-bit. Then it tells you:
What does iTunes have to do with Outlook? That’s crazy.
And then, what does it install? Only another four applications.
When syncing videos to the iPad with the Windows version of iTunes, they are synced with at least one default setting not correctly set.
That’d be fine if it was an unimportant setting, but no. The setting is “resume from where I left off”. That means that every time I switch videos, or close the video application (see previous discussion of why I need to do this to recover storage), the video I want to watch starts again from scratch.
There is a simple fix to this – for every video I upload to the iPad, I have to go into iTunes, select the video, right-click it, select “Get Info”, open the “Options” tab, uncheck the box that says “Remember Playback Position” (or if I selected multiple videos, set to “No” the drop-down arrow labeled “Remember Position”), hit “OK” (there is no “Apply”), wait for this action to sync to the iPad, then right-click the video(s) again, select “Get Info”, open the “Options” tab, and then recheck the box (or set the drop-down box to “Yes”), hit “OK” and sync once again.
For weeks I’ve been complaining that every USB device on my system has been unreliable – I have to plug and unplug simple USB flash drives a half dozen times before they finally get recognised in Explorer.
Then it finally dawned on me.
One device has been steadfastly reliable, always becoming active and ready to use within seconds of plugging it in. Yes, it’s the iPad.
Acting on this hunch, I removed iTunes, Apple Mobile Device Support, Apple Application Support, Apple Software Update, Bonjour, and even QuickTime (not sure how that got on there). Suddenly all my USB devices connect first time, every time. With the exception of the iPad, of course, which sulks if it doesn’t have iTunes (though the same charge can be leveled against my Windows Phone requiring Zune – although that hasn’t yet caused all my other USB devices to become unavailable).
Adding iTunes back in to the mix, strangely, has yet to reproduce the same unreliable behaviour. I strongly distrust software acting randomly.
If I could just drag my videos into a folder using Explorer without installing iTunes (since iTunes doesn’t actually properly do any of the other things that an intermediate program should do, such as converting video formats, extracting and using metadata, or setting the “resume from where you left off” option), I’d be happy without iTunes on my PC at all.
There are other reasons not to like the iPad – it’s too trendy, for one; and it’s not really a $500 product. There are, as I point out above, too many areas where it’s clear that the developers have not finished the job.
I use the iPad simply because it’s free, and has a large display.
I’d far rather use a tablet that works in a more predictable and controlled manner, where the applications on the device and to sync the device have the flavour of being finished.
But I didn’t get one of those for free.
I got an iPad.
And I’m grateful.
Even if, once in a while, I want to dash it to the floor and stomp it into pieces.