On restrictive firewalls and SSH+X

So I had to set up a firewall for a box at work. The firewall should only allow inbound SSH connections from specific IPs within the LAN, and outbound connections to the LAN. Ok.

Well easy peasy, I get my nice iptables script courtesy of Dan Robbins, alter the default policy for the OUTPUT chain to DROP, add in the rules to allow traffic towards the LAN, and off we go!

All is well, except… X11 forwarding doesn’t work. I double-check: firewall off = OK, firewall on = KO. Meh.

And so after a frustrating hour of trial-and-error-and-google later, I finally learn that X forwarding needs to be allowed outbound connections on the loopback interface. Obviously.

And by the way: no, it’s not spelled iptables -A OUTPUT -i lo -j ACCEPT. It’s spelled iptables -A OUTPUT -o lo -j ACCEPT. -i stands for --in-interface, not --interface. Duh.

Leveraging Intel Ivy Bridge’s hardware RNG

Intel Ivy Bridge CPUs such as the i7-3770K that I own ship with a hardware random number generator that can be polled through the RdRand instruction.
This feature is advertised in /proc/cpuinfo with the rdrand flag.

This hardware RNG can be leveraged to increase the entropy bits available to Linux’s random character devices /dev/random and /dev/urandom.

First, some configuration items may (or may not) need to be enabled in the kernel: namely, CONFIG_HW_RANDOM and CONFIG_HW_RANDOM_INTEL. I enabled the latter only because it has “Intel” in the name, but I’m not sure it’s actually required (the docs mention Intel i8xx motherboards) and I’m too lazy to test.
You may also take a look at the Documentation/hw_random.txt file in the kernel sources for some more background info on HWRNGs and the kernel.
Note this file mentions sysfs‘s /sys/class/misc/hw_random/rng_{available,current} which on my machine are empty, for reasons unknown – well, rng_available is empty, rng_current contains none.

A userspace daemon is also required to poll the hardware RNG: rngd (available in the sys-apps/rng-tools package on Gentoo).
Note to Gentoo users: the init script installed for rngd tries to autodetect the actual name of the hardware RNG device in /dev, but fails in my case since I have two nodes for the device (both /dev/hw_random and /dev/hwrng). I had to manually set the hardware RNG device in /etc/conf.d/rngd (both nodes are the same device, so pick either one).

First a test without rngd running:

$ cat /dev/random           # don't use /dev/urandom, it's non-blocking
a few lines of garbage
Ctrl-C

Then with rngd:

$ rc-service rngd start
 * Starting rngd ...                                                  [ ok ]
read error

read error
                                                                      [ ok ]
# I don't know what these "read errors" are.
# They don't seem to hinder anything afterwards.
$ cat /dev/random
a solid stream of garbage
Ctrl-C            # this may not work, I usually need to kill the terminal

Voilà. :)

Burning CDs from the command line

I needed to burn some files to a CD recently and had to go through some searching and trial-and-error before finding the right tools and options, so here goes what I turned out to use, for future reference:

  • to build the ISO:
    mkisofs -o <image.iso> -V <volume-label> -l -J -joliet-long -R <directory>
    

    This enables the Joliet and Rocky Ridge extensions, which make the filenames look good on the disk (otherwise with plain ISO9660 they’re nastily altered).

  • to burn the ISO:
    cdrecord -v -raw dev=<device> <image.iso>
    
  • This burns in raw mode (preferred mode according to the cdrecord man page) on the specified device (usually /dev/cdrom will do).

Note I’m using cdrtools but it should work the same with cdrkit‘s genisoimage and wodim.

pkg-config chaining

Quick note: chaining pkg-config .pc files using the Requires: statement works. As in, flags from the required packages are indeed added to the flags for the requiring package, including -L flags (which I was wondering about in particular, w.r.t. PR Itseez/opencv#3792).
This might seem obvious as that’s quite the purpose of this statement, but I wasn’t sure what it did exactly.

Here is a quick example.

requirer.pc :


# requirer pkg-config file

Name: requirer
Description: I require some other package.
Version: 1.0
Requires: requiree
Conflicts:
Libs: -lrequirer

requiree.pc :


# requiree pkg-config file

Name: requiree
Description: I am required by some other package.
Version: 1.0
Requires:
Conflicts:
Libs: -L/some/libdir/path -lrequiree

pkg-config output:


$ PKG_CONFIG_PATH=. pkg-config --libs requirer
-L/some/libdir/path -lrequirer -lrequiree

So not only are the entries from the required packages added to the entries for the requiring package, but they are also added intelligently in that -L entries are prepended and -l entries appended.

Good to know.

Sweatless –help text

I just stumbled upon a nice way to generate the --help text from the comments at the top of the file.

Here’s how it’s done in hub‘s build script:

#!/usr/bin/env bash
# Usage: script/build [-o output] [test]
#
# Sets up GOPATH and compiles hub. With `test`, runs tests instead.

#[blah]

case "$1" in
 #[blah]
 -h | --help )
  sed -ne '/^#/!q;s/.\{1,2\}//;1d;p' < "$0"
  exit
  ;;
 #[blah]
esac

This lets you maintain your help text at the top of the file only, which is a convenient and straigthforward place to look for it when editing the file, and have the --help case short and simpleclever.

I like it. :)

Emerge blocker: =net-analyzer/openvas-7.0.6

After a Portage tree sync, OpenVAS was to be upgraded to version 7.0.6 (having ACCEPT_KEYWORDS ~amd64).

Unfortunately, this somehow triggered Portage into belching out a lot of blocker errors. Even after unmerging all OpenVAS packages to start over from a clean state, Portage still wanted me to install the following:

$ eix -e openvas
* net-analyzer/openvas
     Available versions:  (~)7.0.6 **8_beta3 **8_beta4 {+pdf}
     Homepage:            http://www.openvas.org/
     Description:         A remote security scanner

$ emerge -pv openvas

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild  N    ~] net-analyzer/openvas-tools-0_pre20512  46 KiB
[ebuild  N     ] dev-libs/hiredis-0.11.0-r1  USE="-static-libs" 42 KiB
[ebuild  N    *] net-analyzer/openvas-libraries-8.0_beta4  USE="-ldap" 576 KiB
[ebuild  N    *] net-analyzer/openvas-cli-1.4_beta4  78 KiB
[ebuild  N    *] net-analyzer/greenbone-security-assistant-6.0_beta4  1 146 KiB
[ebuild  N    *] net-analyzer/openvas-scanner-5.0_beta4  236 KiB
[ebuild  N    *] net-analyzer/openvas-manager-6.0_beta3  1 789 KiB
[ebuild  N    *] net-analyzer/openvas-8_beta4  USE="pdf" 0 KiB

Total: 8 packages (8 new), Size of downloads: 3 910 KiB

!!! The following update has been skipped due to unsatisfied dependencies:

net-analyzer/openvas-manager:0

emerge: there are no ebuilds to satisfy "~net-analyzer/openvas-libraries-8_beta4".
(dependency required by "net-analyzer/openvas-manager-6.0_beta4" [ebuild])


The following keyword changes are necessary to proceed:
 (see "package.accept_keywords" in the portage(5) man page for more details)
# required by openvas (argument)
=net-analyzer/openvas-8_beta4 **
# required by net-analyzer/openvas-8_beta4
# required by openvas (argument)
=net-analyzer/openvas-manager-6.0_beta3 **
# required by net-analyzer/openvas-8_beta4
# required by openvas (argument)
=net-analyzer/openvas-tools-0_pre20512 ~amd64
# required by net-analyzer/openvas-8_beta4
# required by openvas (argument)
=net-analyzer/openvas-cli-1.4_beta4 **
# required by net-analyzer/greenbone-security-assistant-6.0_beta4
# required by net-analyzer/openvas-8_beta4
# required by openvas (argument)
=net-analyzer/openvas-libraries-8.0_beta4 **
# required by net-analyzer/openvas-8_beta4
# required by openvas (argument)
=net-analyzer/greenbone-security-assistant-6.0_beta4 **
# required by net-analyzer/openvas-8_beta4
# required by openvas (argument)
=net-analyzer/openvas-scanner-5.0_beta4 **

NOTE: The --autounmask-keep-masks option will prevent emerge
      from creating package.unmask or ** keyword changes.

That’s a little too much beta for me, and since eix reports that OpenVAS 7.0.6 is indeed not keyword-masked, I should be able to install it, right?

Turns out there’s something fishy with the dependencies for OpenVAS:

$ equery depgraph --depth=1 openvas-7.0.6
 * Searching for openvas7.0.6 ...

 * dependency graph for net-analyzer/openvas-7.0.6
 `--  net-analyzer/openvas-7.0.6  ~amd64
   `--  net-analyzer/openvas-libraries-7.0.6  (~net-analyzer/openvas-libraries-7.0.6) [~amd64 keyword]
   `--  net-analyzer/openvas-scanner-4.0.5  (~net-analyzer/openvas-scanner-4.0.5) [~amd64 keyword]
   `--  net-analyzer/openvas-manager-5.0.7  (~net-analyzer/openvas-manager-5.0.7) [~amd64 keyword]
   `--  net-analyzer/openvas-cli-1.3.1  (~net-analyzer/openvas-cli-1.3.1) [~amd64 keyword]
   `--  net-analyzer/openvas-tools-0_pre20512  (net-analyzer/openvas-tools) [~amd64 keyword]
   `--  net-analyzer/greenbone-security-assistant-5.0.4  (~net-analyzer/greenbone-security-assistant-5.0.4) [~amd64 keyword]
   `--  app-text/htmldoc-1.8.27-r3  (app-text/htmldoc) amd64
   `--  dev-texlive/texlive-latexextra-2012  (dev-texlive/texlive-latexextra) amd64
   `--  virtual/latex-base-1.0  (virtual/latex-base) amd64
[ net-analyzer/openvas-7.0.6 stats: packages (10), max depth (1) ]

$ equery depgraph --depth=1 openvas-cli-1.3.1
 * Searching for openvas-cli1.3.1 ...

 * dependency graph for net-analyzer/openvas-cli-1.3.1
 `--  net-analyzer/openvas-cli-1.3.1  [~amd64 keyword]
   `--  net-analyzer/openvas-libraries-7.0.5  (~net-analyzer/openvas-libraries-7.0.5) [~amd64 keyword]
   `--  virtual/pkgconfig-0-r1  (virtual/pkgconfig) ~amd64
   `--  sys-devel/make-4.1-r1  (sys-devel/make) ~amd64
   `--  dev-util/cmake-2.8.12.2-r1  (>=dev-util/cmake-2.8.12) amd64
   `--  sys-apps/findutils-4.4.2-r1  (>=sys-apps/findutils-4.4.0) amd64
[ net-analyzer/openvas-cli-1.3.1 stats: packages (6), max depth (1) ]

So openvas-7.0.6 depends on openvas-libraries-7.0.6 and openvas-cli-1.3.1 which itself depends on openvas-libraries-7.0.5? Not good.

Time for some ebuild(1) plumbing:

$ ebuild /use/portage/net-analyzer/openvas-libraries/openvas-libraries-7.0.6.ebuild merge clean
# lots of output
$ ebuild /use/portage/net-analyzer/openvas-cli/openvas-cli-1.3.1.ebuild merge clean
# lots of output, but no failure!

Now emerge works out the dependencies fine:

$ emerge -av openvas

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild  N    ~] net-analyzer/openvas-tools-0_pre20512  46 KiB
[ebuild  N    ~] net-analyzer/openvas-manager-5.0.7  1 698 KiB
[ebuild  N    ~] net-analyzer/openvas-scanner-4.0.5  211 KiB
[ebuild  N    ~] net-analyzer/greenbone-security-assistant-5.0.4  1 024 KiB
[ebuild  N    ~] net-analyzer/openvas-7.0.6  USE="pdf" 0 KiB

Total: 5 packages (5 new), Size of downloads: 2 977 KiB

Re-parenting widgets with Tk’s [pack]

Just a short post about re-parenting widgets in Tcl/Tk, using the [pack] geometry manager.
Short because the solution is simple (and documented), but I couldn’t find it easily since I did not correctly understand the problem I was having.

So, I wanted to move a widget .frame.widget packed in a frame .frame into a sub-frame .frame.subframe. Note that .frame.widget and .frame.subframe are created in this order (the problem doesn’t arise otherwise).
Doing the simple

pack .frame.widget -in .frame.subframe

somehow didn’t work: the widget indeed disappeared from its previous master .frame but did not show up in its new master .frame.subframe (though it was listed by [pack slaves .frame.subframe]).

The reason for this is stacking order: .frame.widget was correctly re-packed in .frame.subframe, but was obscured by it (since .frame.subframe is created after .frame.widget and thus highest in stacking order).

The solution for this is to [raise] the widget above its new master in the stacking order:

raise .frame.widget .frame.subframe

This is all explained in the “Packing Order” section of the [pack] documentation, and the [raise] documentation even provides a nice example that specifically addresses the exact same case I was in.

 

Bonus: the re-packing command can be made to preserve all attributes of the previous packing using [pack info] like so:

pack .frame.widget -in .frame.subframe {*}[lrange [pack info .frame.widget] 2 end]

Warning: a widget cannot be re-packed (or packed, for that matter) inside a widget that’s not either its parent, sibling or a descendant of one of its siblings.

Note: the term re-parenting used throughout this post is abusive: the widget isn’t strictly re-parented (its parent remains .frame as its name remains .frame.widget), it is rather re-mastered, but that sounded a bit weird and less understandable.

WiFi on Gentoo using a RTL8192CU wireless adapter

I’m trying to set up a wifi network interface on my Gentoo box, using a Realtek RTL8192CU wireless adapter.

After poking in the kernel configuration menu, I activated the following items:

  • Networking support > Wireless (CONFIG_WIRELESS)
  • Networking support > Wireless > cfg80211 – wireless configuration API (CONFIG_CFG80211)
  • Networking support > Wireless > enable powersave by default (CONFIG_CFG80211_DEFAULT_PS)
  • Networking support > Wireless > cfg80211 wireless extensions compatibility (CONFIG_CFG80211_WEXT)
  • Networking support > Wireless > Generic IEEE 802.11 Networking Stack (mac80211) (CONFIG_MAC80211)
  • Networking support > Wireless > Enable LED triggers (CONFIG_MAC80211_LEDS)
  • Networking support > RF switch subsystem support (CONFIG_RFKILL)
  • Device Drivers > Network device support > Wireless LAN (CONFIG_WLAN)
  • Device Drivers > Network device support > Wireless LAN > Realtek rtlwifi family of devices (CONFIG_RTL_CARDS, as a module)
  • Device Drivers > Network device support > Wireless LAN > Realtek rtlwifi family of devices > Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter (CONFIG_RTL8192CU, as a module)

I then eagerly rebooted, and was met with the following entries in dmesg:

rtl8192cu: Chip version 0x11
rtl8192cu: MAC address: 08:86:3b:ac:c6:88
rtl8192cu: Board Type 0
rtl_usb: rx_max_size 15360, rx_urb_num 8, in_ep 1
rtl8192cu: Loading firmware rtlwifi/rtl8192cufw_TMSC.bin
rtlwifi: Loading alternative firmware rtlwifi/rtl8192cufw.bin
rtlwifi: Firmware rtlwifi/rtl8192cufw_TMSC.bin not available

Apparently some firware was required but missing. Indeed, the new network interface did not show up with ifconfig -a or in /sys/class/net.

After some googling, I emerged the sys-kernel/linux-firmware package (with the savedconfig USE flag) and tweaked the configuration file to only install the rtl8192cufw_TMSC.bin firmware.
After rmmod-ing and insmod-ing back the rtl* modules, the log read:

rtl8192cu: Chip version 0x11
rtl8192cu: MAC address: 08:86:3b:ac:c6:88
rtl8192cu: Board Type 0
rtl_usb: rx_max_size 15360, rx_urb_num 8, in_ep 1
rtl8192cu: Loading firmware rtlwifi/rtl8192cufw_TMSC.bin
ieee80211 phy0: Selected rate control algorithm 'rtl_rc'
rtlwifi: wireless switch is on
systemd-udevd[1710]: renamed network interface wlan0 to wlp0s29u1u8

Looks good. Let’s see what ifconfig -a says:

wlp0s29u1u8: flags=4098  mtu 1500
        ether 08:86:3b:ac:c6:88  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Great!

Now on to activating the network interface:

$ ln -s /etc/init.d/net.lo /etc/init.d/net.wlp0s29u1u8
$ rc-service net.wlp0s29u1u8 start
 * Caching service dependencies ...                                   [ ok ]
 * Bringing up interface wlp0s29u1u8
 *   Starting wpa_supplicant on wlp0s29u1u8 ...
 *   /etc/wpa_supplicant/wpa_supplicant.conf not found                [ !! ]
 * ERROR: net.wlp0s29u1u8 failed to start

Snap. Well let’s just emerge -av net-wireless/wpa_supplicant, configure it according to the Gentoo wiki page on wpa_supplicant, and try again:

 * Caching service dependencies ...                                   [ ok ]
 * Bringing up interface wlp0s29u1u8
 *   Starting wpa_supplicant on wlp0s29u1u8 ...
Successfully initialized wpa_supplicant
 *   Starting wpa_cli on wlp0s29u1u8 ...                              [ ok ]
 *   Backgrounding ... ...
 * WARNING: net.wlp0s29u1u8 has started, but is inactive

Now let’s try to scan nearby networks:

$ wpa_cli scan
Selected interface 'wlp0s29u1u8'
OK
$ wpa_cli scan_results
Selected interface 'wlp0s29u1u8'
bssid / frequency / signal level / flags / ssid
f4:ca:e5:fe:6d:26       2452    -34     [WPA2-EAP-CCMP+TKIP][ESS]       FreeWifi_secure
f4:ca:e5:fe:6d:24       2452    -34     [WPA2-PSK-CCMP+TKIP][ESS]       Moria
c4:04:15:43:d3:9c       2452    -68     [WPA2-PSK-CCMP][WPS][ESS]       Moria_EXT
f4:ca:e5:fe:6d:25       2452    -34     [ESS]   FreeWifi

Success! :-)

Connecting to a network can then be done thanks to wpa_supplicant, either through configuration or helper programs such as wpa_cli or wpa_gui.
Another option is to use fully-fledged network management tools such as NetworkManager or Wicd (not useful on my desktop box, but that’s what I use on my netbook).

Precision audio ripping with abcde

I was recently offered a pair of AKG K702 cans, and decided to make sure my audio sources were up to par.
This prompted me to re-encode parts of my audio library using the lossless FLAC encoding, as opposed to WMA/MP3 192kbps earlier.

I thus needed a ripper/encoder, and decided to go for abcde:

$ echo "media-sound/abcde ~amd64" >> /etc/portage/package.accept_keywords
$ echo "media-sound/abcde aac cdparanoia flac id3tag lame musicbrainz replaygain vorbis" >> /etc/portage/package.use
$ emerge -av media-sound/abcde

Then following the advice found here, I went ahead and checked the required read offset for my drive:

$ emerge -av sys-fs/lsscsi
$ lsscsi | grep -F 'cd/dvd'
# look up the read offset for the drive in the list at:
# http://www.accuraterip.com/driveoffsets.htm

I then tweaked the configuration in ~/.abcde.conf:

# ~/.abcde.conf: abcde configuration file

# Actions to take: do the replaygain step (disabled by default)
ACTIONS=cddb,read,encode,replaygain,tag,move,clean

# Default to FLAC encoding
OUTPUTTYPE=flac

# Customize the filename format
OUTPUTFORMAT='${ARTISTFILE}/${ALBUMFILE}/${TRACKNUM} - ${TRACKFILE}'
VAOUTPUTFORMAT='Compilations/${ALBUMFILE}/${TRACKNUM} - ${ARTISTFILE} - ${TRACKFILE}'

# Don't translate spaces to underscores in filenames
mungefilename ()
{
	echo "$@" | sed s,:,\ -,g | tr / _ | tr -d \'\"\?\[:cntrl:\]
}

# Prepend a leading 0 to track # even with < 10 tracks
PADTRACKS=y

# Preserve relative volume differences between the tracks of an album
BATCHNORM=y

# Run on at most 5 cores
MAXPROCS=5

# Set read offset according to http://www.accuraterip.com/driveoffsets.htm
# Use `lsscsi` to identify the drive
CDPARANOIAOPTS="-O 667"

# Put the temporary .wav files on /tmp (SSD-backed)
WAVOUTPUTDIR="${TMPDIR:-/tmp}"

# Open the tray after ripping
EJECTCD=y
# Close the tray before ripping
pre_read ()
{
	eject -t
}

Note that most (all?) configuration options can be found in /etc/abcde/abcde.conf along with a brief description.

And then the magic:

$ abcde

The drive read offset may cause cdparanoia to spew out quite a lot of SCSI errors at the end of the last track, but the output file still seems to be fine.
However, let’s double-check against the AccurateRip database for safety. There is an ARFlac.pl script found at Hydrogen Audio which checks a FLAC-encoded album against the AccurateRip database.
First let’s comment the CDPARANOIAOPTS entry in the abcde configuration, rip a CD and check it using ARFlac.pl:

$ ./ARFlac.pl Pink_Floyd-The_Dark_Side_of_the_Moon.INACCURATE/
Pink_Floyd-The_Dark_Side_of_the_Moon.INACCURATE/:2962344:7476420:9939552:18230352:12527340:16899120:20692896:9103416:9996000:5847660:
Checking AccurateRip database

Track   Ripping Status          [Disc ID: 000f8f74-760a110a]
 1      ** Rip not accurate **   (confidence -56)    [84dc4e66] [18823f25]
 2      ** Rip not accurate **   (confidence -56)    [61022134] [d55869e9]
 3      ** Rip not accurate **   (confidence -56)    [627e3310] [a7c577ce]
 4      ** Rip not accurate **   (confidence -56)    [177232d3] [7698149c]
 5      ** Rip not accurate **   (confidence -56)    [87b85a58] [a745c453]
 6      ** Rip not accurate **   (confidence -56)    [f0e8d520] [58073ba7]
 7      ** Rip not accurate **   (confidence -56)    [15e08776] [364c9aab]
 8      ** Rip not accurate **   (confidence -56)    [f12f4bf2] [5851c3b1]
 9      ** Rip not accurate **   (confidence -56)    [def0efff] [f759de20]
 10     ** Rip not accurate **   (confidence -56)    [24bbe552] [73924ffd]
Your CD disc is possibly a different pressing to the one(s) stored in AccurateRip.
Track(s) Accurately Ripped: 0
**** Track(s) Not Ripped Accurately: 10 ****
Track(s) Not in Database: 0

Ouch. Now with the read offset in CDPARANOIAOPTS:

$ ./ARFlac.pl "Pink Floyd/The Dark Side of the Moon/"
Pink Floyd/The Dark Side of the Moon/:2962344:7476420:9939552:18230352:12527340:16899120:20692896:9103416:9996000:5847660:
Checking AccurateRip database

Track   Ripping Status          [Disc ID: 000f8f74-760a110a]
 1      Accurately Ripped  (confidence 86)  [ca4ccf0a]
 2      Accurately Ripped  (confidence 85)  [c8891a92]
 3      Accurately Ripped  (confidence 86)  [3aee1393]
 4      Accurately Ripped  (confidence 85)  [4b37d200]
 5      Accurately Ripped  (confidence 85)  [e7be89df]
 6      Accurately Ripped  (confidence 85)  [6a5c6bb8]
 7      Accurately Ripped  (confidence 85)  [0fa68472]
 8      Accurately Ripped  (confidence 85)  [e22f112d]
 9      Accurately Ripped  (confidence 85)  [e6bfb1a9]
 10     Accurately Ripped  (confidence 85)  [598e31e2]
All Tracks Accurately Ripped.

Hooah!

Off to ripping my whole library now. :)

Un-bricking Debian: apt-get crash in non-critical packages

I’ve got an old Asus Eee netbook that I run Debian on, since as much as I love Gentoo, I wouldn’t want to compile anything on that Atom N280 – and I’m too lazy to setup distcc.
Unfortunately, the beast tends to fall victim to chronic MCEs, almost systematically in the course of apt-get operation. Reproducibility is always top-notch: trying to resume the upgrade will trigger another MCE at the exact same stage at which the previous occurred. Top-notch indeed, but quite brutal too.

This often leaves the system a bit wonky: it is halfway through an upgrade – i.e., in an inconsistent state – and keeps crashing if I try to complete the upgrade. Varying degrees of wonkiness can be reached according to the package upgrade that failed: from a minor, non-vital package to, say, an X server package. The system may even be left crippled if the crash occurred while upgrading the kernel image, but this will be the subject of another post (I’ll write about it the next time it happens – hopefully not too soon).

So this is the sorry state the system is in after a crash:

$ apt-get upgrade
# says the previous operation borked and I should run dpkg --configure -a
$ dpkg --configure -a
# sorts of resumes the upgrade but eventually panics in the process

The procedure that I’ve been using to work around this kind of breakage is the following:

$ dpkg -r <crashing package>
# remove the culprit
$ dpkg --configure -a
# configure all remaining packages (hopefully these won't trigger a crash)
$ apt-get download <crashing package>
$ dpkg -i <crashing package's .deb archive>
# download and reinstall the crashing package (it usually installs fine at this point)
# (the .deb archive must be downloaded anew as often the cached one is corrupted)
# (installing through dpkg prevents apt-get from marking the package as manually installed)

Took me some time (and quite a bunch of MCEs) to figure out the exact sequence, but thanks to this I’m now pretty effective at recovering from those apt-get MCEs.