Cover photo
Ryan Gordon
Works at
Attended Queens University
Lives in Charlotte, NC
1,706 followers|114,945 views


Ryan Gordon

Shared publicly  - 
Here's a comedy of errors for you.

Heartbleed hit OpenSSL 1.0.1 (through 1.0.1f), and since was vulnerable, I go to apt-get upgrade...and there's no libssl update. Wtf?

I find out the server is Ubuntu 13.04, and oh look, they aren't updating that version because it isn't LTS ("Long Term Support").

And sure enough, today, 13.04's OpenSSL is still vulnerable:

I get that it's free software, and one can upgrade for free, but come on, I wanted to patch 5 lines of C code to stop the worst security hole of modern times, not upgrade everything on a production server as fast as possible. Someone out there is making a conscious decision to leave his server vulnerable because it's too risky (or too annoying) to update everything.

So, fine, I updated.

And this is what happened next:

Apache refused to start because things needed updating in the config file for changes between 2.2 and 2.4. For example this...

    Order allow, deny
    Allow from all looks like this...

    Require all granted

Repeat for several virtual hosts, grumble grumble, probably prone to human repetition errors, grumble grumble.

When you are patching the worst thing that's happened to the Internet as fast as possible, you don't read the goddamn release notes for Apache. Whatever, it's just 2.2 to 2.4. I skimmed long enough to find out that syntax change and we were off and running again for the most part and I could focus on getting the SSL certs revoked and replaced (a comedy of errors in itself, let me tell you).

Then David Ludwig, who is kicking serious ass with the WinRT port of SDL, lets me know that he can't push changes to our Mercurial server. Authorization denied. Huh, broken for me too. I go to check. Many hours later, this is what I discover in our config for

    <Directory "/webspace/">
        AddHandler cgi-script .cgi
        DirectoryIndex hgwebdir.cgi
        Options +Indexes +FollowSymLinks +ExecCGI
        AllowOverride None
        Require all granted

        AuthUserFile hgweb.passwd
        AuthGroupFile /dev/null
        AuthName " Mercurial Repositories"
        AuthType Basic
        <Limit POST PUT>
            Require valid-user

That "Require all granted"? It's new, replacing the old "Order allow,deny" nonsense. But "Require" isn't a new command, as you can see we use it for saying that POSTing (how you push commits to a Mercurial server) requires a valid, known login.

Unfortunately, a poor reading of the docs misses this:

By default all Require directives are handled as though contained within a <RequireAny> container directive. In other words, if any of the specified authorization methods succeed, then authorization is granted.

So what was happening was Apache was refusing to check the user/password database to see if you're allowed to push changes, since we already told it to let everyone in, and instead sent the user right on to Mercurial as if they were authorized.

THANK GOD that Mercurial also checks its own list of allowed committers, so we had no problem here. It rejected commits properly in this case of trying to go on without authorization...the problem is that the people that should be authorized weren't either, but that's the only reason we noticed at all.

I don't know if that "Require all granted" line is necessary, or even why it was there. Apache config files are frankly awful, and this crap has been cut-and-paste between so many virtual hosts at this point, I can't say why it's there in the first place, or if it even needs to be, or if it just landed there at some point when I was throwing everything I could find at the config to get it working when something non-obvious went wrong one day in 2002.

But I do know this: it seems like an innocent config, and it did the right thing (for me, at least) all the way back to Apache 1.3. But this simple idiom, "Allow everyone read access, but require a valid login for write access," followed by a panicked rush to upgrade and rote conversion of syntax changes, to a new format that chose a different and insanely dangerous default, basically left the server wide open to intruders, in an effort to close a different security hole.

tl;dr: everyone is fired.
Tony Sidaway's profile photoRyan Gordon's profile photoPhil Schaf's profile photoScott Duensing's profile photo
Wishing doesn't make for a decent release mechanism. Seriously, don't put yourself in the position where you're reduced to advocating that others deviate from their own release cycles, announced long in advance. If your customers rely on you safeguarding their confidential information, you must take your responsibility seriously. 
Add a comment...

Ryan Gordon

Shared publicly  - 
Videos for my Steam Dev Days talks are posted!

SDL2 talk: Game Development with SDL 2.0
Linux talk: Getting Started with Linux Game Development
Kimmo Merikivi's profile photoErick Powers's profile photoErik Yuzwa's profile photoSusan Stabley's profile photo
And just after you debunked the distribution fragmentation myth in Steam dev days, CD Projekt made this uninformed statement:

Hopefully correct information reaches their ears. The video has been linked in The Witcher forums, at least.
Add a comment...

Ryan Gordon

Shared publicly  - 
My minor Christmas gift:

I love 1Password ( ), but it's a Mac and iOS app, mostly. There's a web interface for Linux users that want to run it off their Dropbox account, but it turns out doing 150,000+ iterations of pkcs5-pbkdf2 is really expensive in JavaScript, and I really really miss the hotkey popup you get on the Mac.

So I wrote a Linux version.

This just reads your existing 1Password keychain and lets you hit the hotkey combo the Mac version expects (alt-meta-\, at least on my keyboard), to get your encrypted keychain at your fingertips at any time. Much faster to find the password you want and get it on the clipboard.

Lots of work to do still. It's a janky thing I wrote quickly, but it's already really useful to me personally, so have a peek if you like it.

Enjoy! Merry Christmas!
J. Pablo Pérez Trabucco's profile photoPaulo A Ferreira's profile photoRyan Gordon's profile photoEric O'Brien's profile photo
+Eric O'Brien "./1pass & exit" is what I do. Leaves it running, kills the shell immediately.
Add a comment...
So I've got two kinds of logins on various websites: those with incredibly shitty passwords, and those with passwords I can't remember. Okay, three: those that force you to change it all the damned time, which results in incredibly shitty passwords that I can't remember.

I decided enough is enough, so I installed 1Password, which is pretty good. Now I've got a pile of massive random strings for passwords everywhere. I don't even know them and don't have to. I paid through the damned nose, but it's nice on Mac OS X and iOS, and if you're syncing it to Dropbox, the thing does some javascript magic so you can open the key file in your web browser on Linux to get a UI, which is pretty cool.

But here's what I learned:

- Some websites make it really hard to change your password. More than one had me Googling for "[website name] change password" to figure out how to do it. That's pretty fucked up. Steam makes you use their desktop client to do it, and you can't change it through the website at all, as far as I could tell, which is also fucked up.

- Many websites would complain if you failed all sorts of stupid requirements. Must have at least one number, must not have more than 9 numbers, must have at least one capital letter, must have at least one non-alphanumeric character, must not have any repeating characters, etc. Must have 8 to 16 characters, which brings me to my next point...

- If a site says you can't have more than X characters, they're probably storing your original password. I imagine that site's database has a "varchar(16)" field for your password. If they are hashing them--like they damned well should--they will always end up being the same size in their database and they shouldn't care if you entered five or fifty characters...which brings me to the next point...

- More than one site, if you gave it a 50-character password, or a password with an uncommon (but low-ASCII) character, would report that your password was successfully changed, but then fail to log in with that password. I had to get a password reset emailed to me and pick a smaller (or saner) password. Buffer overflow? String handling fail? Don't know.

Thankfully 1Password had sliders for tweaking the random string it generates, to cooperate.

And finally:
- It's an interesting exercise to think of all the places you have an account. I bet you've forgotten lots of them. Trying to go back and add a crazy random password to every thing I could think of took a lot longer than I expected, and I'm sure I've only started.
Fred Richards's profile photoJake Magee's profile photoLeon Nardella's profile photoMark Felder's profile photo
 ·  Translate
Add a comment...

Ryan Gordon

Shared publicly  - 
"9. Hacker News. In fact, all of the overeager startup hangers-on and fedora-wearing 'bitch, make me a sandwich' tools convinced code will save the world, whose willful blindness just helps perpetuate a sexist, racist, classist environment where white guys with computer science degrees can continue jerking off other white guys with computer science degrees until millions of dollars fall in their laps and they can shout, 'MERITOCRACY.'"

meg ford's profile photoDiego Elio Pettenò's profile photoMike Melanson's profile photoPaul Cutler's profile photo
+Diego Elio Pettenò Just kidding. I've got nothing against fedoras (the hat or the Linux distro). Try not to pay too much attention to people like the article's author. Especially on the internet, it's not hard to find people who are determined to hate you personally for any of a variety of reasons. Learn not to let it bother you.
Add a comment...
Have him in circles
1,706 people

Ryan Gordon

Shared publicly  - 
Just pushed a change to SDL to make it cooperate with Spaces on Mac OS X.

If you have a resizable SDL window, it'll now give you the "go fullscreen" button on the titlebar, and it works how you'd expect. To the SDL app, it just looks like the window changed sizes, no different than if the user clicked Maximize or whatever, but the user has more power now.

Also: FULLSCREEN_DESKTOP windows now get their own Space. This is really great; you can play your game, swipe over to your desktop for a moment, see an animated thumbnail in Mission Control, etc. Previously it just took over your desktop and minimized the window when you switched applications.

(We still support the old behavior on older Mac OS X versions that didn't have Spaces.)

This is more reason to stop using SDL_WINDOW_FULLSCREEN. If you can, you should be using SDL_WINDOW_FULLSCREEN_DESKTOP and adjusting for whatever resolution you get. It makes for a better end-user experience for many reasons, and today there's one more reason.

We're going to shake bugs out of these changes as fast as possible and ship it in SDL 2.0.2.
David Poole's profile photoBastien Nocera's profile photoEthan Lee's profile photoRyan Gordon's profile photo
Thanks for merging it :)
Add a comment...

Ryan Gordon

Shared publicly  - 

I've just pushed an interesting change to SDL, but to explain what it is, it's useful to know the problem we were trying to solve.

- The Steam Runtime has (at least in theory) a really kick-ass build of SDL2, but developers are shipping their own SDL2 with individual Steam games--including me. These games might stop getting updates, but a newer SDL2 (with, say, Wayland support, which we'll be shipping in 2.0.2) might be needed later. Certainly we'll always be fixing bugs in SDL, even if a new video target isn't ever needed, and these fixes won't make it to a game shipping its own SDL.
- Even if we replace the SDL2 in those games with a compatible one, that is to say, edit a developer's Steam depot (yuck!), there are developers that are statically linking SDL2 that we can't do this for. We can't even force the dynamic loader to ignore their SDL2 in this case, of course.
- If you don't ship an SDL2 with the game in some form, people that disabled the Steam Runtime, or just tried to run the game from the command line instead of Steam might find themselves unable to run the game, due to a missing dependency.
- If you want to ship on non-Steam platforms like GOG or Humble Bundle, or target generic Linux boxes that may or may not have SDL2 installed, you have to ship the library or risk a total failure to launch. So now, you might have to have a non-Steam build plus a Steam build (that is, one with and one without SDL2 included), which is inconvenient if you could have had one universal build that works everywhere.
- We like the zlib license, but the biggest complaint from the open source community about the license change is the static linking. The LGPL forced this as a legal, not technical issue, but zlib doesn't care. Even those that aren't concerned about the GNU freedoms found themselves solving the same problems: swapping in a newer SDL to an older game often times can save the day. Static linking stops this dead.

So here's what we did:

SDL now has, internally, a table of function pointers. So, this is what SDL_Init now looks like:

    UInt32 SDL_Init(Uint32 flags)
        return jump_table.SDL_Init(flags);

Except that is all done with a bunch of macro magic so we don't have to maintain every one of these.

What is jump_table.SDL_init()? Eventually, that's a function pointer of the real SDL_Init() that you've been calling all this time. But at startup, it looks more like this:

    Uint32 SDL_Init_DEFAULT(Uint32 flags)
        return jump_table.SDL_Init(flags);

SDL_InitDynamicAPI() fills in jump_table with all the actual SDL function pointers, which means that this _DEFAULT function never gets called again. First call to any SDL function sets the whole thing up.

So you might be asking, what was the value in that? Isn't this what the operating system's dynamic loader was supposed to do for us? Yes, but now we've got this level of indirection, we can do things like this:

    export SDL_DYNAMIC_API=/my/actual/

And now, this game that is staticallly linked to SDL, can still be overridden with a newer, or better, SDL. The statically linked one will only be used as far as calling into the jump table in this case. But in cases where no override is desired, the statically linked version will provide its own jump table, and everyone is happy.

So now:
- Developers can statically link SDL, and users can still replace it. (We'd still rather you ship a shared library, though!)
- Developers can ship an SDL with their game, Valve can override it for, say, new features on SteamOS, or distros can override it for their own needs, but it'll also just work in the default case.
- Developers can ship the same package to everyone (Humble Bundle, GOG, etc), and it'll do the right thing.
- End users (and Valve) can update a game's SDL in almost any case, to keep abandoned games running on newer platforms.
- Everyone develops with SDL exactly as they have been doing all along. Same headers, same ABI. Just get the latest version to enable this magic.

A little more about SDL_InitDynamicAPI():

Internally, InitAPI does some locking to make sure everything waits until a single thread initializes everything (although even SDL_CreateThread() goes through here before spinning a thread, too), and then decides if it should use an external SDL library. If not, it sets up the jump table using the current SDL's function pointers (which might be statically linked into a program, or in a shared library of its own). If so, it loads that library and looks for and calls a single function:

    SInt32 SDL_DYNAPI_entry(Uint32 version, void *table, Uint32 tablesize);

That function takes a version number (more on that in a moment), the address of the jump table, and the size, in bytes, of the table. Now, we've got policy here: this table's layout never changes; new stuff gets added to the end. Therefore SDL_DYNAPI_entry() knows that it can provide all the needed functions if tablesize <= sizeof its own jump table. If tablesize is bigger (say, SDL 2.0.4 is trying to load SDL 2.0.3), then we know to abort, but if it's smaller, we know we can provide the entire API that the caller needs.

The version variable is a failsafe switch. Right now it's always 1. This number changes when there are major API changes (so we know if the tablesize might be smaller, or entries in it have changed). Right now SDL_DYNAPI_entry gives up if the version doesn't match, but it's not inconceivable to have a small dispatch library that only supplies this one function and loads different, otherwise-incompatible SDL libraries and has the right one initialize the jump table based on the version. For something that must generically catch lots of different versions of SDL over time, like the Steam Client, this isn't a bad option.

Finally, I'm sure some people are reading this and thinking "I don't want that overhead in my project!"  To which I would point out that the extra function call through the jump table probably wouldn't even show up in a profile, but lucky you: this can all be disabled. You can build SDL without this if you absolutely must, but we would encourage you not to do that. However, on heavily locked down platforms like iOS, or maybe when debugging,  it makes sense to disable it. The way this is designed in SDL, you just have to change one #define, and the entire system vaporizes out, and SDL functions exactly like it always did. Most of it is macro magic, so the system is contained to one C file and a few headers. However, this is on by default and you have to edit a header file to turn it off. Our hopes is that if we make it easy to disable, but not too easy, everyone will ultimately be able to get what they want, but we've gently nudged everyone towards what we think is the best solution.

Here are most of the changes for the Dynamic API:

C.W. Betts's profile photoJason Dagit's profile photoMatteo De Carlo's profile photoJames Lomax's profile photo
+Clément DAVID OS X does not use ELF: it uses Mach-0. To my knowledge, OS X is the only modern UNIX or UNIX-like that does not use ELF. Although you can mess with the dynamic linking names, there's always a possibility that SDL2.framework won't be installed in either /Library/Frameworks or ~/Library/Frameworks. And said version might be out-of-date itself. Yeah, OS X doesn't have a good native package management built-into it: developers have to work around it.

Not to mention Windows, which uses something quite archaic in comparison of the other two binary formats (I'm pretty sure it supports Pascal symbol linking. Not even OS X/Darwin has that). C.F. "DLL Hell."
Add a comment...
Jimmie Johnson wins the NASCAR race, climbs on top of his logo-covered car, next to a giant cardboard Sprint cellphone, sprays the crowd with Gatorade, and reminds everyone in his victory speech to shop at Lowes tomorrow.

And all my web-savvy friends are all like "who clicks on ads on the Internet?"

I suspect there's some overlap in viewership.
Jan Moren's profile photoTimothee Besset's profile photoRyan Gordon's profile photoMichael Monn's profile photo
+Timothee Besset Visiting in-laws watching the race. :)
Add a comment...

Ryan Gordon

Shared publicly  - 
So there's a massive Mac/Linux update for Super Meat Boy, just in time for it to be 80% off on Steam:

Here's the rundown of new stuff.

- Linux version now available on Steam. If you already own the game for Windows or Mac on Steam, you get the Linux version for free right now. Otherwise, your three dollars gets you three platforms of Super Meat Boy, plus SteamOS support some day.
- Now using SDL2, which means...
- controller support that actually works!
- Tons of bug fixes.
- Super Meat World now works on Linux.
- 64-bit support on Mac OS X.
- Steamworks support on Linux (32-bit only, not my fault!)
- Fullscreen support on Mac OS X.
- Better fullscreen support on Linux.
- Mac framerate should be dramatically better.

Updated Humble Bundle builds coming soon, but I'll probably wait a day or two for Steam feedback before packaging it up.

Please be gentle: a lot of code changed, as part of this work was smashing Tommy's Mac port and my Linux port together and fixing things up from there. If you find bugs, please report them at and I'll try to sort them out asap.
Ryan Gordon's profile photoAnıl Özbek's profile photoDima Braun's profile photoJanne Sinisalo's profile photo
Bah. :( Oh well. At least it won't be lost again in the future. Thanks Ryan!
Add a comment...

Ryan Gordon

Shared publicly  - 
Meanwhile, this very minute, old Jessie McVey the well digger--no one knows how old he is, lived in that county all his life--is sitting at the bar of the National Hotel this very minute, looking at the freaks out in the street and muttering under his breath: "No matter how New Age you get, old age gon' kick yo' ass."
Add a comment...
Have him in circles
1,706 people
    Ninja, present
Map of the places this user has livedMap of the places this user has livedMap of the places this user has lived
Charlotte, NC
Philadelphia, PA - Tustin, CA - Raleigh, NC
Stick it in the camel and go.
  • Queens University
Basic Information