Neutronium update – Dec 12, 2011

I’ve continued working on Neutronium daily, but for the past week or so I’ve been focusing on refactoring some of the code I wrote earlier to facilitate actual new features. The biggest change has been putting most of the room-related logic in the STM monad, instead of having parts of it in STM and other parts using IO-based synchronization, particularly MVars. By putting all if it in STM, I avoid having the room directory MVar acting like a global mutual exclusion lock, and let room-related operations behave atomically, which could save some headaches down the time. I’ve also cleaned up various other bits of the code to simplify things and make things more easily testable, but nothing that warrants much discussion here.

Now I’m working on fixing how joining and leaving rooms work. Before, a member of a room was identified by the session identifier of the user’s session, but that’s very problematic. First, it means that opening the same room up in multiple tabs would result in confusing behavior, since the server wouldn’t have any way of distinguishing each tab. Second, it makes distinguishing one member from another difficult on the client side, since session IDs are sensitive information and can’t be shared, lest session hijacking result.

My solution is to assign yet another unique identifier to represent each member joining a room. Since member IDs aren’t sensitive, they can be freely communicated to everyone else in the room. Since it’s decoupled from the session cookie, each tab can be given its own member ID, should someone open the same room up multiple times for some reason. On the server side, each member ID is still bound to a particular session ID, preventing one member from trying to impersonate someone else; if the member ID sent in the request doesn’t match the session ID the request is made under, the request is ignored.

At least, that’s how it will work when I’m finished making those changes.

Comments Off

Reading is dangerous (if you’re writing Haskell)

In Haskell, the read function is the usual, simple way to parse a String into a value of some other type:

ghci> :t read
read :: Read a => String -> a

read can parse anything that implements the aptly-named Read class. All the standard numeric types implement Read:

ghci> read "42" :: Int

Actually, it turns out the Read instance for integral types like Int is a bit too clever for its own good. Did you know (in GHC, at least) it can handle floating-point-style scientific notation, as long as the mantissa significand is an integer and the exponent is nonnegative?

ghci> read "42e2" :: Int

This is nifty, but if the exponent is large, you can easily eat up all of GHC’s memory and crash the program:

ghci> read "1e1000000000" :: Int
<interactive>: out of memory (requested 45088768 bytes)

This is bad if the argument to read comes from an untrusted source. This was the subject of a recent security fix to happstack-server, where the entire server application could be brought down by sending it a request that used something like 1e1000000000 as a request parameter that would be parsed as an integral type. Of course, the vulnerability isn’t specific to happstack-server, but anything that tries to read an integer from untrusted input.

I don’t think Neutronium is currently vulnerable to this (other than being built against a vulnerable version of happstack-server at the moment), but that’s mostly because there isn’t yet anything that’s using read in this manner. One of the next changes I was planning to make was in how room membership is tracked, and part of that would be assigning each member of the room an integral identifier that is sent as a parameter to each room-related Ajax request. (This will support identifying who is who in the room, and solve the problem of having the same room open in multiple tabs without getting things all confused.) So, even if Neutronium isn’t vulnerable to this denial of service attack yet, it would be soon, and without having seen that posting, I don’t know if I would have even thought to worry about a seemingly simple built-in function like read for Int causing problems like that.

I can’t help but wonder if there are static source code analysis tools out there for Haskell that could find security-relevant flaws like this, like there are for more mainstream languages like C, C++, or Java. My gut tells me it’d be easier to write an analyzer for Haskell than for a language like C, but I don’t know if anyone has ever actually sat down to do it yet.

Neutronium Demo Video

With Renee’s help, I recorded a six-minute-or-so demo of Neutronium, the game I’ve been working on since the beginning of November. You’ll probably want to play it at 720p (HD) and full-screen in order to be able to read the text.

Neutronium is a web-based game inspired by a game inspired by the light-cycle game from the movie Tron. Currently, only the fundamental gameplay and a rudimentary chat function are implemented. Each player controls a constantly-growing line. They can’t speed up; they can’t slow down. All they can do (currently) is change direction. Once a player’s line collides with something, it stops and the player loses. The last player left alive wins.

(Note that the game doesn’t actually detect “winning” yet, so a game lasts until everyone has run into something.)

The video above was recorded from my machine. I am the blue line, and Renee is the red line. The chat window doesn’t yet have a way to identify who says what, but in this case you can tell my messages apart from Renee’s because you can watch me type them.

Working on a video

By popular request, I’m working out a way to record a quick video of my game in action. Before I do that, though, I want add an option to select the size of the game area. Right now it’s a hardcoded size, and it’s large enough to be awkward for an embeddable video. Something smaller would probably look better.

Comments Off