EliteBook 2560p Intel 82579LM Debian Squeeze Install

Started with a new employer (Citrix) today. Naturally my first task of setting up a development system was more work than I wanted it to be. Turns out the EliteBook 2560p has Intel 83579LM network hardware and the Debian Squeeze e1000 driver predates it. Using ‘testing’ is always an option but not a very stable / appealing one.

The 2.6.38 kernel and drivers have been backported to squeeze so all that’s really needed is an installer with this kernel / drivers. I didn’t know until I’d burned a good half hour searching around the web that there are unofficial Squeeze installers complete with backports: http://cdimage.debian.org/cdimage/unofficial/backports/squeeze/. One of those images is all you’ll need to get Squeeze running on a system with Intel 82579LM network hardware.

Validating IP Addresses

UPDATE: Added terminating ‘$’ in ipv4 regex as noted in comment from raorn.

I’ve been working on a fix to a system script that passes around and manipulates IP addresses. With IPv6 becoming more prevalent this script must work with IPv6 addresses not just v4. While working on this and digging around the web I ran across some stuff that I think is worth sharing.

The first thing I always do when I’m working with a new data format is writing a script / function that can be used to validate it. Here’s what I came up with for IPv4 and IPv6.

IPv4 Regex

With IPv4 this pretty boring and can be done with a one line regular expression (regex) that’s all over the web. I clean things up a bit by using shell variables but the regex should be clear:

#!/bin/sh
QUAD="25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9]"
is_ipv4 () {
    echo $1 | grep --silent "^(${QUAD})(.(${QUAD})){3}$"
    if [ $? -eq 0 ]; then
        return 1
    fi
    return 0
}

is_ipv4 $1
if [ $? -eq 1 ]; then
    exit 0
else
    echo "Invalid IPv4 address." >&2
    exit 1
fi

Nothing earth shattering.

IPv6 Regex

Working with IPv6 addresses is a bit more complex. To compensate for the larger addresses size when representing IPv6 addresses in text, the RFC recommends a canonical textual representation with rules that allow for compression (called “zero folding”). Addresses represented in this compressed format are more difficult to validate with just one regex and the regex is much longer:

#!/bin/sh
WORD="[0-9A-Fa-f]{1,4}"
# flat address, no compressed words
FLAT="^${WORD}(:${WORD}){7}$"
# ::'s compressions excluding beginning and end edge cases
COMP2="^(${WORD}:){1,1}(:${WORD}){1,6}$"
COMP3="^(${WORD}:){1,2}(:${WORD}){1,5}$"
COMP4="^(${WORD}:){1,3}(:${WORD}){1,4}$"
COMP5="^(${WORD}:){1,4}(:${WORD}){1,3}$"
COMP6="^(${WORD}:){1,5}(:${WORD}){1,2}$"
COMP7="^(${WORD}:){1,6}(:${WORD}){1,1}$"
# trailing :: edge case, includes case of only :: (all 0's)
EDGE_TAIL="^((${WORD}:){1,7}|:):$"
# leading :: edge case
EDGE_LEAD="^:(:${WORD}){1,7}$"
is_ipv6 () {
    echo $1 | grep --silent "(${FLAT})|(${COMP2})|(${COMP3})|(${COMP4})|(${COMP5})|(${COMP6})|(${COMP7})|(${EDGE_TAIL})|(${EDGE_LEAD})"
    if [ $? -eq 0 ]; then
        return 1
    fi
    return 0
}

is_ipv6 $1
if [ $? -eq 1 ]; then
    exit 0
else
    echo "Invalid IPv6 address: $1" >&2
    exit 1
fi

Folks on the web have got it right too and I definitely took a queue from Vernon Mauery. I got a bit caught up in the differences between addresses from RFC4291 and the recommendations in RFC5952. The prior allows for zero folding of single 16-bit 0 fields while the latter discourages this. As the “robustness principle” dictates this validation script will identify addresses with zero folded single 16-bit 0 fields as valid but tools producing addresses should not.

I haven’t taken on any of the weirdness that are mixed hexadecimal and dot decimal notations … those will remain for the interested reader.

Ethernet Bonding on Debian Squeeze

Spent a few minutes searching for a howto for setting up ethernet interface bonding on a new file server I’m building today. Nothing special but I found a bunch that aren’t that great … I know, welcome to the internet right? But I did find one that’s awesome from tuxhelp.org.

My final config went like this:

echo -e "bondingnmii" | sudo tee -a /etc/modules

With an /etc/network/interfaces file that looks like this:

auto lo bond0
iface lo inet loopback

iface bond0 inet dhcp
    bond_mode balance-rr
    bond_miimon 100
    bond_downdelay 200
    bond_updelay 200
    slaves eth0 eth1

What was lacking in all other (even Debian specific) howto’s is that they always use direct invocation of ifenslave and pass options to the bonding driver manually. IMHO it’s so much nicer to use the facilities built in to ifup like the slaves option instead of using something like:

up /sbin/ifenslave bond0 eth0 eth1

That said I haven’t had much luck finding documentation for options like this specific to a driver and how to use them in the interfaces file. Given the above example I can guess but I’m looking for a definitive source … Anyone out there know?

Laptop Docking Script and SELinux

I’ve continued to make progress in my efforts to get SELinux working on my laptop. My day job has been pretty demanding these days but I ran into a few interesting AVCs and had to come up with a fix that is worth mentioning. Let’s start with the AVCs:

avc:  denied  { read } for  pid=530 comm="dock.sh" name=".X11-unix" dev=dm-1 ino=1179649 scontext=system_u:system_r:udev_t:s0-s0:c0.c1023 tcontext=system_u:object_r:xdm_tmp_t:s0 tclass=dir
avc:  denied  { open } for  pid=530 comm="dock.sh" name=".X11-unix" dev=dm-1 ino=1179649 scontext=system_u:system_r:udev_t:s0-s0:c0.c1023 tcontext=system_u:object_r:xdm_tmp_t:s0 tclass=dir

There’s only two AVCs so it’s a pretty easy fix right? Just allow udev access to xdm’s tmp files … yeah I’m not convinced. What the heck is udev doing reading tmp files belonging to X? Yeah and what’s the command “dock.sh” all about (from the comm section in the AVC log).

A little digging in the udev rules files shows that this script is run when my laptop gets docked and undocked. So it makes sense that this script would manipulate my X configuration but it shouldn’t be digging around in private files belonging to X. Whoever wrote this script messed up so just granting udev additional permissions isn’t the right approach.

This time we have to get in touch with the author and fix the script. Interestingly enough this is one of my scripts! I wrote about this script some time ago and it looks like it’s time to update it.

Rewriting dock.sh with SELinux in mind

This is one of those situations where questioning these accesses is the right thing to do. But it’s not that the script shouldn’t be reconfiguring X, it’s that it shouldn’t be messing with X’s private tmp files. Really this has less to do with security than it does with good program design. These are temporary files and X may change their location and contents at any time. No other program should depend on them.

There’s a surprisingly easy fix to this problem and it’s a pretty cool one. ConsoleKit is a daemon that keeps track of desktop “sessions” which are effectively X logins. This is a gross over simplification and the interested reader should dig into the ConsoleKit docs for a more accurate description. What’s important is that the information that my dock.sh script needs is exposed by ConsoleKit through a few DBus calls.

All of the direct access to tmp in this script can be replaced by 3 calls to ConsoleKit through DBus. I’ve updated the script in my previous post where you can check it out if you’re interested.

Conclusion

This post ended up having less to do with SELinux and more to do with good programing practices. Write your programs / scripts to use the published interfaces available to accomplish their goals. Mucking around in another programs temporary files is a bad idea (shame on me!). Where SELinux comes into play is that it formalizes these accesses in policy forcing some bad programming practices out into the open.

If you’re following along at home you’ll notice that this script went from causing 2 AVCs to causing about 10 🙂 I’m OK with that because the script is that much better than it was. Looks like this script needs to have it’s own policy module. I’ll save that for later this week. Stay tuned.

Debian Squeeze power management and SELinux

Most of the work that’s gone into the Debian SELinux policy seems to have has been done on servers. After taking a serious look at the AVCs on my laptop it seems that most of the power management stuff isn’t quite working. It was close though so the patch I had to whip up wasn’t too serious. It basically came down to:

  • get policykit started properly by dbus (I guess it used to be started by init)
  • differences between file paths on Fedora and Debian
  • allow upowerd to execute anacron properly(pm-utils script executing the anacron init scrip)
  • allow upowerd to talk to the unconfined users dbus session (started by X login scripts)

The Debian SELinux mailing list is pretty much defunct so I’ve been sending these patches directly to the package maintainer. We’ll see if he picks it up. The patch (against the current unstable package) is here if anyone is interested. Just copy the patch file to the root of the current policy from unstable (get it via apt-get source) and then apply it:

patch -p2 < 2011-01-26_devicekit.patch

Adding an Online Spare to p400i RAID Controller

I’ve had a HP DL360 hosting my blog, MySQL, SMTP and IMAP servers for a while now. The server’s been great and I’ve always intended to add an online spare (a.k.a. hot spare) for a little piece of mind. I’ve finally got around to it and it turns out that the syntax for using the CLI configuration tool from HP is a bit cryptic so this is a few notes on how I got the job done.

Tools & Documentation

Tracking down the tools for the job was a bit of a pain. To save you some time the documentation you want is here: Controller Reference Guide

HP actually supports the configuration tool (hpacucli) for Debian and they provide a package through the Proliant Support Pack apt repository. You can add the repository to your sources.list file with the following line:

deb http://downloads.linux.hp.com/SDR/downloads/ProLiantSupportPack/ lenny/current non-free

A Few Basic Commands

The general syntax for the hpacucli command is something like [parameter=value]. But to do something useful like dump out all of the disks on the controller (I’ve only got one on my server) you’ll do something like this:

flihp@server:~$ sudo hpacucli controller slot=0 physicaldrive all show

Smart Array P400i in Slot 0 (Embedded)

   array A

      physicaldrive 2I:1:5 (port 2I:box 1:bay 5, SATA, 32.0 GB, OK)

   array B

      physicaldrive 1I:1:1 (port 1I:box 1:bay 1, SAS, 72 GB, OK)
      physicaldrive 1I:1:2 (port 1I:box 1:bay 2, SAS, 72 GB, OK)
      physicaldrive 1I:1:3 (port 1I:box 1:bay 3, SAS, 72 GB, OK)
      physicaldrive 1I:1:4 (port 1I:box 1:bay 4, SAS, 72 GB, OK)

   unassigned

      physicaldrive 2I:1:6 (port 2I:box 1:bay 6, SAS, 72 GB, OK)

So there are 6 disks attached to the controller. For this task I’m concerned with those that make up array B and the unassigned disk. This disk is the one that I wish to add as an online spare to array B. But first lets dump so info about array B:

flihp@server:~$ sudo hpacucli controller slot=0 array B show

Smart Array P400i in Slot 0 (Embedded)

   Array: B
      Interface Type: SAS
      Unused Space: 0 MB
      Status: OK

That’s not very hlepful … Let’s try something else. The documentation says something about logical drives so lets try that:

flihp@www:~$ sudo hpacucli controller slot=0 array B logicaldrive all show

Smart Array P400i in Slot 0 (Embedded)

   array B

      logicaldrive 2 (136.7 GB, RAID 1+0, OK)

That’s what I wanted to see: the logical drives that are on array B. As you can see this is 136.7 GB and configured as RAID 1+0. This makes sense since it is a RAID 1+0 made up of 4x72GB SAS drives. I’ve only allocated one logical drive on this array because I’m using LVM to create logical volumes in software. This is just how I like to do things. It may very well be faster and just as convenient to allocate more logical drives at the controller level but that’s another debate for another time. For now let’s stay focused on adding the unallocated disk as an online spare to array B.

Assigning an Online Spare

The specific syntax is spelled out in the manual I linked above. We’ve gathered all the necessary data for the command above and it looks like this:

flihp@server:~$ sudo hpacucli controller slot=0 array B add spares=2I:1:6

The target is controller slot=0 array B. This is the identifier for the array discussed above. The command is add spares which is pretty self explanatory. The last part is the identifier for the physical device we’re adding as a spare. If you scroll a bit up you’ll see that I got this identifier by asking the controller to dump info on all attached physical drives. If you want to see which drive this is on your system you can actually make the drive light on it flash which I thought was pretty cool (see the manual for details).

Executing the above command produced no output so you can either assume everything went as planned or you can check up on the array that we just modified:

flihp@www:~$ sudo hpacucli controller slot=0 array B physicaldrive all show

Smart Array P400i in Slot 0 (Embedded)

   array B

      physicaldrive 1I:1:1 (port 1I:box 1:bay 1, SAS, 72 GB, OK)
      physicaldrive 1I:1:2 (port 1I:box 1:bay 2, SAS, 72 GB, OK)
      physicaldrive 1I:1:3 (port 1I:box 1:bay 3, SAS, 72 GB, OK)
      physicaldrive 1I:1:4 (port 1I:box 1:bay 4, SAS, 72 GB, OK)
      physicaldrive 2I:1:6 (port 2I:box 1:bay 6, SAS, 72 GB, OK, spare)

Sweet! Now that extra drive is lined up to be a fail-over if one of the other drives in the array fails.

What does acpi_fakekeyd do?

In setting up SELinux on my Laptop running Squeeze I’m taking a pretty standard approach. First off I’m working off the packages provided in Sid maintained by Russell Coker so most of the hard work has been done. There are a few programs, mostly specific to a laptop that still aren’t in the right domains. We can see this by dumping out the running programs and their domains:

ps auxZ

Determining the “right domain” for a process is a bit harder but there’s a pretty obvious place to start. No daemons should be running in initrc_t!

initrc_t is the domain given to scripts run by the init daemon. That’s pretty much any script in /etc/init.d. If a daemon is running in this domain after startup it likely means that there was no transition rule in place to put it into a domain specific to the daemon. I figured I’d take these on alphabetically and started with acpi_fakekeyd 🙂

A policy for acpi_fakekeyd

All of the power management stuff like acpid runs in the apmd_t so the first thing I tried was running acpi_fakekeyd in this domain. You can go through the trouble of adding the path /usr/sbin/acpi_fakekeydto the apmd_t policy module, rebuilding it and reloading it (which really isn’t that hard these days) or you can take a shortcut like so:

echo "system_u:system_r:apmd_exec_t:s0" | sudo attr -S -s selinux /usr/sbin/acpi_setkeyd

This sets the label on the executable such that when init runs the start up script, the daemon will end up in the apmd_t domain.

Once the label is set you can restart the daemon using run_init, assuming your user is in a domain that can run init scripts (unconfined, admin etc). If all goes well the daemon will end up running in the right domain. I then did what I thought was exercising the domain to see if it would cause any AVCs. This required sending the daemon a few characters using the acpi_fakekey command directly as well as putting my laptop to sleep and into hibernation (see the /etc/acpi/sleep.sh script). There weren’t any AVCs so I concluded the apmd_t domain had all of the permissios that the fakekey daemon needed. I was wrong but we’ll get to that.

acpi_fakekeyd in it’s own domain

I was really expecting a few denial messages so I decided to put acpi_fakekeyd into its own domain with no privileges. The idea was to see some AVCs and to get a feeling for what exactly the daemon does.

The policy module I whipped up is super simple:
acpi_fakekeyd.te

policy_module(acpi_fakekeyd, 0.1)

########################################
#
# Declarations
#
type acpi_fakekeyd_t;
type acpi_fakekeyd_exec_t;
init_daemon_domain(acpi_fakekeyd_t, acpi_fakekeyd_exec_t)

acpi_fakekey.fc

/usr/sbin/acpi_fakekeyd --      gen_context(system_u:object_r:acpi_fakekeyd_exec_t,s0)

No interfaces yet so the acpi_fakekeyd.if file was empty.

After restarting the daemon, checking it’s in the right domain and exercising my ACPI system … there still weren’t any AVCs! Obviously I’m missing something so a bit of research turned up this bug report which explains pretty much everything.

acpi_fakekeyd deprecated

To save you a bunch of reading it turns out that toward the end of the discussion thread (about 8 months after the initial post) it’s identified that the functionality of acpi_fakekeyd is deprecated in kernels after 2.6.24. It seems that the functionality should instead be provided by an in-kernel driver which my laptop (ThinkPad x61s) has.

So why is this daemon installed and running? If I disable it my laptop ACPI still works fine. But the acpi_support package which is required to put my laptop to sleep depends on the acpi_fakekey package. This is likely because the scripts provided by acpi_support call the acpi_fakekey application for backwards comparability on some systems. This doesn’t make much sense to me though since Squeeze ships with a 2.6.32 kernel.

The answer to the question I pose as the title of this post is: It doesn’t do anything on my system. I don’t even need to have it running so I just shut it off. Problem solved I guess, and from a security perspective this is an even better solution that running it in it’s own SELinux domain. If it’s not running, it can’t do any damage. I’d rather be able to remove the package completely though.

Does anyone out there have a laptop that requires this daemon? I’m tempted to file a bug against the package … Anyway on to the next daemon 🙂

SELinux on Squeeze Laptop

I’ve been meaning to play around with the SELinux packages in Squeeze for a while now. Over this past weekend I finally got started. Russell Coker maintains these packages and you can find them on his website under the SELinux tag.

The Debian package for the policy is quite nice. The post install script even enumerates the installed packages and attempts to load the necessary policy modules. This is, of course, limited by a mapping in the post-install script that manually maps SELinux policy packages to the packages installed through dpkg. This will likely be difficult to maintain over time and was the source of the first bug that I ran into.

I’ve written in the past about playing around with the racoon daemon so I’ve got the ipsec-tools and racoon packages on my laptop. The selinux-policy-default post install script however was missing the mapping between the ipsec policy package and the Debian packages. 10 minutes of reading the script was enough to whip up a one-line patch even though I’ve never written a line of perl in my life. Russell picked up the patch and … problem solved!

There’s probably lots of little bugs like this lurking in the policy package most of which won’t be discovered until it’s installed on lots of different systems and configurations (servers, desktops, laptops etc). The Debian community in general doesn’t seem very interested in SELinux so this is probably a very good place to make some contributions. More to come.

Comparison of Catalyst Logo

It’s been four months since I posted on the striking symilarity between the Debian logo and that currently being used by the Catalyst Career Group. At the recommendation of MJ Ray on the debian-legal mailing list I’m following up (a bit late) with a reasonably thorough comparison of the two logos. So here they are side by side:
Debian LogoCatalyst Career Group Logo

Hmmm well they’re not identical … so is this a case of mistaken identity? Well no. The Debian logo is still there, but it has been transformed a bit. Actually if we just reflect the standard Debian logo across the X axis we come pretty close:
Debian Logo transformedCatalyst Career Group Logo

Close is good but this is legal stuff so being exact is probably important or something. I’m a complete n00b with the GIMP but even I can take 20 minutes and figure out how to rotate an image another 45 degrees:
Catalyst Career Group Logo

So I’m no expert here but that’s pretty damn close. Change the color a little and I’ve transformed the Debian logo into that of the Catalyst Career Group in 3 or so moves. I’m convinced. Looks to me like the Debian logo is being misused. Let’s see what the debian-legal list says … to be continued.

thinkpad keys on awesome WM

The last bit of configuration that my laptop required before I’d call it “usable” with the new window manager was related to the function keys. This doesn’t have anything to do with configuring the awesome window manager directly but it does address a few small configurations necessary to provide some functionality that I was used to having gnome do by default.

Linux has great support for Thinkpads in general and my x61s specifically. With basic power management packages installed and the kernel thinkpad_acpi driver loaded not only did S3 work fine but my Thinkpad function key to put my laptop to sleep worked out of the box! The only keys that didn’t work right out of the box were an easy fix.

Screen Brightness

Traveling as much as I do I find that I use the manual controls for screen brightness quite a bit. If you’re on a plane often times it’s really nice to be able to dial down the screen brightness to absolutely minimal levels to preserve your battery and your eyes. The gnome-power-manager is the gnome component that takes care of this and it’s simple enough to install. Nothing interesting here except a new found appreciation for how much Gnome does out of the box and why it’s so big.

Volume and Mute

Lastly configuring the volume buttons was a must. If you’re just interested in getting them to work, install the gnome-settings-daemon and add a command to your rc.lua file to run it. I spent a little time getting to the bottom of it and learned a little bit.

Fire up a terminal and run the xev command to see the keyboard events from each key. A regular keyboard key will generate some output like:

KeyPress event, serial 29, synthetic NO, window 0x1600001,
    root 0x105, subw 0x0, time 316658902, (470,254), root:(472,689),
    state 0x0, keycode 24 (keysym 0x71, q), same_screen YES,
    XLookupString gives 1 bytes: (71) "q"
    XmbLookupString gives 1 bytes: (71) "q"
    XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x1600001,
    root 0x105, subw 0x0, time 316658990, (470,254), root:(472,689),
    state 0x0, keycode 24 (keysym 0x71, q), same_screen YES,
    XLookupString gives 1 bytes: (71) "q"
    XFilterEvent returns: False

Those are they key press and release events triggered by typing a ‘q’. Pressing one of the volume buttons looks a little different:

KeyPress event, serial 28, synthetic NO, window 0x1000001,
    root 0x105, subw 0x0, time 316864564, (132,42), root:(134,477),
    state 0x0, keycode 121 (keysym 0x1008ff12, XF86AudioMute), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x1000001,
    root 0x105, subw 0x0, time 316864684, (132,42), root:(134,477),
    state 0x0, keycode 121 (keysym 0x1008ff12, XF86AudioMute), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

You’ll notice that they keycode indicates the XF86AudioMute button was pressed this time instead of q but the XLookupString returns 0 bytes.

Basically the three volume buttons are is associated with virtual X keys: XF86AudioMute, XF86AudioRaiseVolume, XF86AudioLowerVolume. It’s pretty straight forward to use xbindkeys to map these to alsa commands to manually mute, raise or lower the volue. My .xbindkeys looked like this:

"amixer  set Master 2dB+"
  XF86AudioRaiseVolume

"amixer set Master 2dB-"
  XF86AudioLowerVolume

"amixer set Master toggle"
  XF86AudioMute

Some prefer to link these keys to the PCM volume control. I found that toggle (as well as mute/unmute) doesn’t work for the PCM channel. I’m honestly not sure what the PCM channel is even for so I reserve the right to change this in the future. There’s lots of howto’s out there with people implementing shell hacks to fake a mute / unmute for the PCM channel using xbindkeys if you’re interested enough to search.

So the above configuration and a quick entry in my rc.lua to kick off xbindkeys was enough to get this working. The one down side to using xbind keys: it doesn’t have a cool little volume indicator that pops up to show the volume level when you press your volume keys 🙂