[personal profile] mjg59
I dug out a computer running Fedora 28, which was released 2018-04-01 - over 5 years ago. Backing up the data and re-installing seemed tedious, but the current version of Fedora is 38, and while Fedora supports updates from N to N+2 that was still going to be 5 separate upgrades. That seemed tedious, so I figured I'd just try to do an update from 28 directly to 38. This is, obviously, extremely unsupported, but what could possibly go wrong?

Running sudo dnf system-upgrade download --releasever=38 didn't successfully resolve dependencies, but sudo dnf system-upgrade download --releasever=38 --allowerasing passed and dnf started downloading 6GB of packages. And then promptly failed, since I didn't have any of the relevant signing keys. So I downloaded the fedora-gpg-keys package from F38 by hand and tried to install it, and got a signature hdr data: BAD, no. of bytes(88084) out of range error. It turns out that rpm doesn't handle cases where the signature header is larger than a few K, and RPMs from modern versions of Fedora. The obvious fix would be to install a newer version of rpm, but that wouldn't be easy without upgrading the rest of the system as well - or, alternatively, downloading a bunch of build depends and building it. Given that I'm already doing all of this in the worst way possible, let's do something different.

The relevant code in the hdrblobRead function of rpm's lib/header.c is:

int32_t il_max = HEADER_TAGS_MAX;
int32_t dl_max = HEADER_DATA_MAX;

if (regionTag == RPMTAG_HEADERSIGNATURES) {
il_max = 32;
dl_max = 8192;
}

which indicates that if the header in question is RPMTAG_HEADERSIGNATURES, it sets more restrictive limits on the size (no, I don't know why). So I installed rpm-libs-debuginfo, ran gdb against librpm.so.8, loaded the symbol file, and then did disassemble hdrblobRead. The relevant chunk ends up being:

0x000000000001bc81 <+81>: cmp $0x3e,%ebx
0x000000000001bc84 <+84>: mov $0xfffffff,%ecx
0x000000000001bc89 <+89>: mov $0x2000,%eax
0x000000000001bc8e <+94>: mov %r12,%rdi
0x000000000001bc91 <+97>: cmovne %ecx,%eax

which is basically "If ebx is not 0x3e, set eax to 0xffffffff - otherwise, set it to 0x2000". RPMTAG_HEADERSIGNATURES is 62, which is 0x3e, so I just opened librpm.so.8 in hexedit, went to byte 0x1bc81, and replaced 0x3e with 0xfe (an arbitrary invalid value). This has the effect of skipping the if (regionTag == RPMTAG_HEADERSIGNATURES) code and so using the default limits even if the header section in question is the signatures. And with that one byte modification, rpm from F28 would suddenly install the fedora-gpg-keys package from F38. Success!

But short-lived. dnf now believed packages had valid signatures, but sadly there were still issues. A bunch of packages in F38 had files that conflicted with packages in F28. These were largely Python 3 packages that conflicted with Python 2 packages from F28 - jumping this many releases meant that a bunch of explicit replaces and the like no longer existed. The easiest way to solve this was simply to uninstall python 2 before upgrading, and avoiding the entire transition. Another issue was that some data files had moved from libxcrypt-common to libxcrypt, and removing libxcrypt-common would remove libxcrypt and a bunch of important things that depended on it (like, for instance, systemd). So I built a fake empty package that provided libxcrypt-common and removed the actual package. Surely everything would work now?

Ha no. The final obstacle was that several packages depended on rpmlib(CaretInVersions), and building another fake package that provided that didn't work. I shouted into the void and Bill Nottingham answered - rpmlib dependencies are synthesised by rpm itself, indicating that it has the ability to handle extensions that specific packages are making use of. This made things harder, since the list is hard-coded in the binary. But since I'm already committing crimes against humanity with a hex editor, why not go further? Back to editing librpm.so.8 and finding the list of rpmlib() dependencies it provides. There were a bunch, but I couldn't really extend the list. What I could do is overwrite existing entries. I tried this a few times but (unsurprisingly) broke other things since packages depended on the feature I'd overwritten. Finally, I rewrote rpmlib(ExplicitPackageProvide) to rpmlib(CaretInVersions) (adding an extra '\0' at the end of it to deal with it being shorter than the original string) and apparently nothing I wanted to install depended on rpmlib(ExplicitPackageProvide) because dnf finished its transaction checks and prompted me to reboot to perform the update. So, I did.

And about an hour later, it rebooted and gave me a whole bunch of errors due to the fact that dbus never got started. A bit of digging revealed that I had no /etc/systemd/system/dbus.service, a symlink that was presumably introduced at some point between F28 and F38 but which didn't get automatically added in my case because well who knows. That was literally the only thing I needed to fix up after the upgrade, and on the next reboot I was presented with a gdm prompt and had a fully functional F38 machine.

You should not do this. I should not do this. This was a terrible idea. Any situation where you're binary patching your package manager to get it to let you do something is obviously a bad situation. And with hindsight performing 5 independent upgrades might have been faster. But that would have just involved me typing the same thing 5 times, while this way I learned something. And what I learned is "Terrible ideas sometimes work and so you should definitely act upon them rather than doing the sensible thing", so like I said, you should not do this in case you learn the same lesson.

Date: 2023-08-08 03:18 pm (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker
At what point does it make most sense to just install a whole new version of the OS and then copy your files over to it?

Date: 2023-08-09 10:12 pm (UTC)
From: (Anonymous)
At a *much* earlier point than this.

Date: 2023-08-23 02:29 am (UTC)
From: (Anonymous)
He said that it doesn't make sense but he did it anyways.

I personally would have opted for reinstall 38.

Anyways, It's really cool of him that he did do it! Now we know what to expect in these sort of situations. :)

Date: 2023-08-29 09:55 pm (UTC)
From: (Anonymous)
I optimized for this about 20 years ago. My ~/archive/ directory is already my long-term replicated backup. All the other home dirs are temporary WIP dirs, including ~/git, all which I can go through in a short term to either copy to ~/archive or wipe. Usually I'm getting a new workstation so I just restore ~/archive on it and the next few days migrate any configs over I forgot to capture.

I capture all my local config settings either in ~/archive/dot-bashrc or ~/archive/new-desktop.txt. I walk through new-desktop.txt on my new system (which includes the appropriate dnf install, repos, and key management), then hold on to my old system for a few days for anything forgotten.

Date: 2023-08-08 08:20 pm (UTC)
From: (Anonymous)
I upgraded my Debian installation from being 32-bit to being 64-bit in a similar manner, following a hardware upgrade. First you install the -amd64 kernel, which is available for 32-bit builds too, and reboot into it. Then you force-install dpkg-amd64 and it looks like everything is broken. Finally, you gather the list of all 32-bit non-multiarch packages in your system and install -amd64 packages instead. I don't remember the details (presumably, there's an order that has to be followed in order to avoid a chicken-and-egg problem), but the system still runs after upgrading a few major versions.

Date: 2023-08-10 10:05 am (UTC)
From: (Anonymous)
I don't know why but i suspect you didn't have anything better to do at the time... eheheheh

Date: 2023-08-13 12:24 am (UTC)
From: (Anonymous)
I had openSUSE Tumbleweed on a VM which wasn't updated for 6 months. It was completely borked.

I did switch to Fedora, since openSUSE froze a lot on my laptop while Fedora is rock-solid, that on a HP Spectre not a Lenovo ThinkPad. Not to hate on openSUSE, while Tumbleweed is a neat idea, Fedora is more polished IMO and a better daily driver for me.

Date: 2023-08-15 12:44 am (UTC)
selki: (Default)
From: [personal profile] selki
And what I learned is "Terrible ideas sometimes work and so you should definitely act upon them rather than doing the sensible thing", so like I said, you should not do this in case you learn the same lesson.

Lol.

This is fantastic

Date: 2023-08-16 06:46 am (UTC)
From: (Anonymous)
It's a bit like watching Heston Blumenthal diligently, brilliantly, and successfully boil a pint of water using only three lettuce leaves, dry ice, sugar glass, and a marine flare, because he has no saucepans to hand, plus, well, reasons. It works, but you wouldn't attempt it in a million years.

Heads Up!

Date: 2023-08-23 01:52 am (UTC)
ext_1793530: (Default)
From: [identity profile] unixbhaskar.wordpress.com
Thanks for the insight.

Profile

Matthew Garrett

About Matthew

Power management, mobile and firmware developer on Linux. Security developer at Aurora. Ex-biologist. [personal profile] mjg59 on Twitter. Content here should not be interpreted as the opinion of my employer. Also on Mastodon.

Expand Cut Tags

No cut tags