Adventuring with a.out

The first step in the Glendix project was to write a binary loader for the Plan 9 a.out format. Linux has a clean interface for registering new binary format handlers from a module. Basically, you define a structure of type linux_binfmt and call register_binfmt during initialization of the module. Now all that’s left to do is implement the three functions that you pointed to in your structure: load_binary, load_shlib and core_dump.

Luckily for me, all Plan 9 executables are statically linked so I can just leave load_shlib as NULL. core_dump is also not that important during the development stages, although the final product must definitely implement it. To get a feel of what I needed to do in load_binary, I decided to take a peek into some of the other binary format handlers. I tried to comprehend the code for ELF with not much luck. I then turned to UTLK, which helped me understand what was going on. I highly recommend the book for anyone interested in kernel programming.

Anyway, here is when I found out that all ELF executables have sections that are actually page aligned! That means every ELF executable contains a bunch of zeroes after the TEXT section, so that the DATA section starts at the next page address. That’s how the executable is supposed to be laid out in memory, but I had no idea someone would actually think of doing it in the file. I guess they have their reasons, all the binary format loader does is mmap the file. Maybe for ELF2 they could put in zeros for the BSS section in the file too :p

Plan 9 executables on the other hand, are just normal files with no padding. This gives me a headache because I can no longer use mmap. Recall that all addressees passed to mmap have to be page-aligned. But the DATA section in Plan 9′s a.out will start at a non-page-aligned address most of the time.

One of the first things I tried to do was to mmap the file into a high address, copy portions into the appropriate locations and then free the mapping. That didn’t work so well because:

  • memcpy works only on physical addresses. Logical addresses from the virtual process address space can’t be easily translated to physical ones because Linux delays physical memory allocation for as long as possible. Now we know why all the loaders use mmap, it is fundamental to the “Linux way” of memory management.
  • There is no generic copy_in_user implementation. There are specific ones that use assembly code for PPC, SPARC and even x86_64, but none for x86. The alternative was to use copy_from_user to move data into kernel addresses and then bring them back using copy_to_user. That didn’t work out well either – copy_to_user kept failing for some reason.

I ended up writing a userspace program called ‘pad’ that page-aligns a Plan 9 a.out executable. The loader just mmap‘s the file, like all other loaders. The solution is suboptimal, if someone knows a clean way of doing all of this in kernel-space, I’ll be grateful for the help. The ultimate goal is to run Plan 9 executables on Linux, unmodified.

The code for the loader and the pad program can be found on git here.

My new virtual private server: Gandi

I’ve been contemplating switching to a virtual private server for quite some time. The cheapest one I could find was SliceHost. While their services seem to be great, $20 a month was too steep a price. A few weeks ago, I stumbled upon Gandi.

Gandi is a known name in the domain registrar space, but they recently launched a “beta” version of their Xen-based hosting service. Because the service is beta, they offer a rock-bottom price of $7 per month for 256 MB RAM, 1/64th the processing power of a Quad Dual-Core AMD, and ~500GB of monthly traffic! Talk about tempting, I wasted no time in signing up :)

It’s been 3 weeks now, and I must say that their service is absolutely fantastic. My server was up in no more than 10 minutes (that includes the time taken for payment). I chose a Debian-based machine (Gentoo isn’t on their list yet :( ). As soon as I logged in, I got to work – I needed to setup my web and mail server. Here’s what I did first:

$ apt-get update
$ apt-get upgrade

Now to setup the web server with PHP 5:

$ apt-get install php5 php5-cli
The following NEW packages will be installed:
apache2-mpm-prefork apache2-utils apache2.2-common libapache2-mod-php5
libapr1 libaprutil1 libexpat1 libpcre3 libpq4 libsqlite3-0 php5 php5-cli php5-common ucf

Edit the default configuration files to your liking and get the default web site running:

$ vi /etc/apache2/sites-available/default
$ /etc/init.d/apache2 restart

Now, onto the mail server. I chose the postfix, procmail, saslauthd, spamassassin and dovecot combo:

$ apt-get install postfix procmail sasl2-bin libsasl2-modules
The following NEW packages will be installed:
postfix procmail sasl2-bin ssl-cert

You’ll be asked a few questions, but we’re going to be reconfiguring anyway so it doesn’t matter what you say:

$ dpkg-reconfigure postfix
General type of configuration?
Internet Site
Where should mail for root go
someuser
Mail name?
mail.example.com
Other destinations to accept mail for? (blank for none)
server.example.com, mail.example.com, example.com, localhost
Force synchronous updates on mail queue?
No
Local networks?
127.0.0.0/8
Use procmail for local delivery?
Yes
Mailbox size limit
0
Local address extension character?
+
Internet protocols to use?
ipv4

To get postfix to play along with saslauthd, we need to make some changes to the postfix configuration. You can edit /etc/postfix/main.cf directly, or use postconf:

$ postconf -e 'smtpd_sasl_local_domain ='
$ postconf -e 'smtpd_sasl_auth_enable = yes'
$ postconf -e 'smtpd_sasl_security_options = noanonymous'
$ postconf -e 'broken_sasl_auth_clients = yes'
$ postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination'
$ postconf -e 'inet_interfaces = all'
$ echo 'pwcheck_method: saslauthd' >> /etc/postfix/sasl/smtpd.conf
$ echo 'mech_list: plain login' >> /etc/postfix/sasl/smtpd.conf

Since postfix on Debian runs in a chroot, you need to make sure it can access saslauthd:

$ mkdir -p /var/spool/postfix/var/run/saslauthd
$ vi /etc/default/saslauthd #Edit to your liking, I use /etc/passwd as my auth source
$ /etc/init.d/postfix restart
$ /etc/init.d/saslauthd start

The most important thing while setting up a mail server is to test at every interval so you can know where a problem came from, if one comes at all. I tested whether postfix + saslauthd were working file using telnet. For the PLAIN authentication type, you can find your auth string by determining the Base64 encoding of the string “usernamepassword”. Here’s a transcript of the telnet session (‘<’ is data sent from you to the server – meaning you have to type it and press the return key, ‘>’ is data sent to your computer from the server):

$ telnet mail.example.com 25
> Trying 10.10.10.10
> Connected to mail.example.com.
> Escape character is '^]'.
> 220 mail.example.com ESMTP Postfix (Debian/GNU)
< auth plain AHVzZXJuYW1lAHBhc3N3b3Jk
> 235 2.0.0 Authentication successful
< quit
> 221 2.0.0 Bye
> Connection closed by foreign host.

When you see “Authentication successful”, you can be sure that saslauthd is working fine with postfix. Now, edit the .procmailrc file in your home directory as required. I love procmail because it lets me do all sorts of preprocessing on my mail (liking moving spam to /dev/null and arranging mails into the proper IMAP folders).

I also use greylisting, a technique used to block 99% of incoming spam (while spamassassin catches the rest 1%). This comes at a price though, whenever someone genuine sends you mail for the first time, it may take upto 20 minutes for it to reach your inbox. I’m not going to discuss greylisting in detail here, but I think 20 minutes is a fair compromise to keep my inbox spam-free:

$ apt-get install postgrey
The following NEW packages will be installed:
libberkeleydb-perl libdigest-hmac-perl libdigest-sha1-perl libio-multiplex-perl
libnet-cidr-perl libnet-dns-perl libnet-ip-perl libnet-server-perl postgrey
$ vi /etc/postfix/main.cf
# Add the line
smtpd_recipient_restrictions=check_policy_service inet:127.0.0.1:60000
# to the file

Time for another test to see if postgrey is doing its work. You also might want to send yourself a test mail to see if your system is working.

$ tail /var/log/mail.log

Now, for spamassassin:

$ apt-get install spamassassin spamc
The following NEW packages will be installed:
libarchive-tar-perl libcompress-zlib-perl libhtml-parser-perl libhtml-tagset-perl
libhtml-tree-perl libio-zlib-perl libsocket6-perl liburi-perl libwww-perl spamassassin spamc

You need to create a user so you can run spamassassin securely:

$ groupadd spamd
$ useradd -g spamd -s /sbin/nologin -d /var/lib/spamassassin spamd
$ mkdir /var/lib/spamassassin
$ chown spamd:spamd /var/lib/spamassassin

Now edit the spamassassin configuration:

$ vi /etc/default/spamassassin
ENABLED=1
OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir /var/lib/spamassassin -s /var/log/spamd.log"
$ vi /etc/spamassassin/local.cf
$ /etc/init.d/spamassassin start
# usual check
$ tail /var/log/spamd.log

Get postfix to start using spamassassin:

$ vi /etc/postfix/master.cf
# Append this to the first line:
-o content_filter=spamassassin
# and then add this at the end:
spamd   unix -     n       n       -       -       pipe
user=spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f
${sender} ${recipient}
$ /etc/init.d/postfix restart

Time for a final test!

telnet mail.example.com 25
> Trying 10.10.10.10...
> Connected to mail.example.com.
> Escape character is '^]'.
> 220 mail.example.com ESMTP Postfix (Debian/GNU)
< ehlo example.net
> 250-mail.example.com
> 250-PIPELINING
> 250-SIZE 10240000
> 250-VRFY
> 250-ETRN
> 250-STARTTLS
> 250-AUTH LOGIN PLAIN
> 250-AUTH=LOGIN PLAIN
> 250-ENHANCEDSTATUSCODES
> 250-8BITMIME
> 250 DSN
< auth plain AHVzZXJuYW1lAHBhc3N3b3Jk
> 235 2.0.0 Authentication successful
< mail from: test@example.net
> 250 2.1.0 Ok
< rcpt to: test@example.com
> 250 2.1.5 Ok
< data
> 354 End data with .
< Subject: Test Mail
< Let's see if you get this test mail!
< .
> 250 2.0.0 Ok: queued as 944E12E3EB
< quit
> 221 2.0.0 Bye
> Connection closed by foreign host.

Now how do you check if you actually got the mail? You can ssh into the server and use something like mutt, but a long term solution would be to setup an IMAP server so you can connect with your favorite mail client:

$ apt-get install dovecot-imapd
The following NEW packages will be installed:
dovecot-common dovecot-imapd libmysqlclient15off mysql-common
$ vi /etc/dovecot/dovecot.conf

The most important portions in the configuration file are the protocols, mail_location and auth sections. Once again, I chose to authenticate against /etc/passwd. Start the server and check for any warnings or errors:

$ /etc/init.d/dovecot start
$ tail /var/log/dovecot.log

Now, I also wanted to transfer all my mail from an old server to the new one. I came across a nifty utility called imapsync to do that for me:

$ apt-get install imapsync
The following NEW packages will be installed:
imapsync libio-socket-ssl-perl libmail-imapclient-perl libnet-ssleay-perl
libparse-recdescent-perl libterm-readkey-perl
$ imapsync --help

Phew!

FOSS.IN 07: Day 3

Day 3: The first day of the main conference. We thought we were running late (left home only at 09:50 after getting our Gentoo T-Shirts on) but the inauguration ceremony started half-hour late (as usual!) so we were able to catch the whole action. After FOSS.IN/2007 was kicked off by Atul & Kishore, Naba Kumar came up to give the keynote on Anjuta DevStudio. I didn’t know the origin of the name Anjuta earlier, but it was certainly fascinating :)

I had my talk on contributing to Gentoo right after the keynote, and we started at 11:30 on the dot (the schedules in other rooms were on-time). Gora gave an excellent introduction, and I began speaking to a somewhat-filled room about the different entry points to Gentoo development. The audience were really interactive and the questions were brilliant – this is something that I really liked about this years edition of FOSS.IN. There was a lot more interest in Gentoo than I had originally anticipated and it was nice to see our stall really crowded immediately after the talk. Hopefully, we’ve brain-washed atleast two-dozen people into using Gentoo :)

The remainder of the day was spent talking to people who approached our stall – it got a bit monotonous though, answering the same question “Why is Gentoo different?” over and over again. We’ve decided to print out an FAQ poster and put it up to make things a little more easier for us ;)

I had my third talk on Plan 9 from Bell Labs scheduled in the evening, right beside some really interesting stuff including the talk on PulseAudio and the lightning talk session. Again, I really didn’t expect much of a crowd for my talk, but I was happily mistaken. The room was not only full, but there were also people seated on the stairs and near the door! The talk went off really well, and I think it was *the* best talk I’ve delivered so far. The crowd was really smart and it was fun to interact with such an audience.

We’ve planned to have a small Mozilla hack-a-thon today, let’s see how that goes. Besides that I’ve planned to attend a few other interesting talks. Looking forward to keeping the pace up, I’ll catch you all tomorrow!

Freed!

A long overdue update; Freed.IN this year was a bundle of joy. I caught up with a majority of the #linux-india regulars, and met some of them for the first time (ilug-bom-ers mostly).

The event started a bit late (nothing unexpected), but everyone quickly caught up with the schedule over the course of the day. I attended Gopal’s talk on 10 things I didn’t about Python – the concluding demo on getting the Wii remote to control beryl was especially wicked. Immediately after that was my talk on Plan 9, which had more attendees than I would have expected. Niyam’s talk on FOSS multimedia tools was a real crowd-puller, and the samples were very impressive. We had a key-signing party that afternoon, which was fun; if it weren’t for the embarrassment of showing ID cards with 10-year old pictures on them ;)

I missed lunch on the first day thanks to the talk on the Python Standard Library, but it was worth it. I made my way to the nearby JNU canteen and munched on a few snickers before returning to an extremely interesting panel discussion on whether LUG’s should provide commercial FOSS support. (Why did everyone have their hands above their shoulders?):

Prof. Andrew Lynn in deep thoughtValsa Williams in deep thoughtDr. Gora joins the club

Later that night, a bunch of speakers along with the ilugd crew found ourselves in the Golden Dragon for dinner; which can only be summarized by ramkrsna’s excellent photography:

At the Golden DragonDessertMe! No, that’s not a ciggarette :-p

The second day began with Raj’s thought-provoking talk on the issue of software patents, immediately followed by a talk on how FOSS can cut costs and keep customers happy at the same time, by Robin Miller (of Slashdot/Sourceforge/ThinkGeek fame). Niyam had another talk on digital creativity with FOSS. The day wound up with a vote of thanks, and a panel discussion on getting FOSS communities to work together. I had to reach Jaipur the next day, so I bid goodbye to all the wonderful folks; but they had an amazing dinner party later from what I hear.

An extremely fun event, executed in typical ilugd style, and definitely improved since freedel. In retrospect, some things may have been better; like keeping the talk halls a bit closer to each other, choosing a more tighter set of talks (there were too many to attend!) and not make lunch clash with any talk! I would suggest Freed start charging for attendance next year to ensure that an interested audience turn up (you can make the lunch and a T-Shirt complimentary), and schedule talks with atleast a 10 minute gap between each other. The ilugd is all geared up for the next edition of the event, tentatively to be held in February 08. See you then!

Mapping 9P to REST

Now that the PHP bindings to libixp are somewhat usable, I’ve moved on to the JavaScript portion of my project. The first (and easier!) part of it is to map 9P to a RESTful scheme, so traditional web developers can use 9P without having to learn anything new.

The PHP bindings to libixp was an important pre-requisite to achieve this: presenting a REST interface to an existing 9P serve would require a “bridge” at the middle, to convert REST requests to 9P requests and vice-versa with responses. This “bridge” may be present at any location that is mutually accessible by the client wanting RESTful access and the server providing the 9P service. This bridge can be easily coded in PHP using the new libixp bindings.

To those not very familiar with REST, it is simply a way of accessing resources using plain-old HTTP. It’s become quite popular with web developers these days, as a much simpler alternative to SOAP. A lot of web services these days are RESTful, including those offered by Amazon and Yahoo.

From the client’s perspective, accessing a 9P resource boils down to 4 things: reading, creating, modifying and deleting. These operations map neatly onto the GET, PUT, POST and DELETE HTTP requests, respectively. And thus, we have our REST URI scheme. This scheme would be enough if my bridge exposes only a single 9P serve as a REST service. As an example, suppose I start a bridge at http://plan9.kix.in/rest/ that exposes only the tcp!sources.cs.bell-labs.com!564 9P serve, to read the file named ‘lsr’ I would perform a GET request at http://plan9.kix.in/rest/lsr.

However, the plot thickens when I want to design a bridge that allows access to any 9P service (which is definitely better). Now we need to encode the information represented in Plan 9 as: tcp!sources.cs.bell-labs.com!564 into a HTTP URI. The intuitive thing to do would be something like: [ROOT]/[PROTOCOL]/[9P-URI]/[PORT]/[FILE-PATH].

Hmm. That leads to really long URI’s like http://plan9.kix.in/rest/tcp/sources.cs.bell-labs.com/564/lsr. Besides that, there are several things that need to be worked out. What happens when you do a GET on a file that is actually a directory? What about parameters to GET that you usually pass to a read() function: Suppose you want to read the first 1024 bytes of a file only?

Comments and Suggestions welcome :)

P.S.: Thanks to some pointers by Kris, the PHP9P client example shown in the previous post now handles binary files correctly.

Herald the PHP 9P Client

I’ve given a few final touches to the 9P client for PHP. All the basic stuff should work (if they don’t please let me know!), and I’ve written a script that shows some of the basic functionality that the client offers. Two actually, this one for the CLI SAPI and this one for the Apache2 SAPI. All they do is read files and show directory listings, but the scripts are a good place to see what the API is like, since there’s no official documentation yet. I couldn’t locate a proper PHP 5 server to actually host the second example, which would have been cool… but now we’ll just have to make do with these screenshots I took off my browser (with the script running on my local Apache):



Startup Screen


Once you’ve put in the address, you’ll get a directory listing of the root:



Viewer


While the CLI SAPI demo script also handles binary files quite well, this one will just send gibberish to your screen if you click on a binary file (text files work fine though). I’m still trying to figure out what’s the best way of determining the MIME type of a file so I can send the appropriate HTTP header before transmitting the data itself,  so your browser would know how to interpret it. As for the server-side of things, the code is still in a state of flux and I’m not decided on what kind of API to offer. I’ll probably take a break from this part of the project and move on the JS bindings, and then come back to tie this up in the end. That’s not to say that the server-side code is not usable, just that it’s not very developer-friendly; feel free to play around with it if you’re feeling adventurous :)

Follow

Get every new post delivered to your Inbox.