[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1063329: libselinux1t64: breaks system in upgrade from unstable



Package: libselinux1t64
Version: 3.5-2.1~exp1
Severity: grave
X-Debbugs-Cc: vorlon@debian.org, debian-devel@lists.debian.org

Hi,

I was looking into performing an upgrade test of libselinux1 with
piuparts and that didn't go well. I spare you the piuparts stuff and go
into crafting a minimal reproducer using mmdebstrap:

mmdebstrap --variant=apt unstable /dev/null "deb http://deb.debian.org/debian unstable main" "deb http://deb.debian.org/debian experimental main" --chrooted-customize-hook="apt-get -y install libselinux1t64"

This looks fairly innocuous. We create a minimal sid chroot and install
libselinux1t64 using apt. What could possibly go wrong? Well, apt thinks
that it would be a good idea to avoid coinstalling breaking packages and
first removes libselinux1 before proceeding to install libselinux1t64.
Unfortunately, libselinux1 is transitively essential and dpkg links it,
so this is what you get:

| Reading package lists... Done
| Building dependency tree... Done
| The following packages will be REMOVED:
|   libselinux1
| The following NEW packages will be installed:
|   libselinux1t64
| 0 upgraded, 1 newly installed, 1 to remove and 0 not upgraded.
| Need to get 75.2 kB of archives.
| After this operation, 4096 B of additional disk space will be used.
| Get:1 http://deb.debian.org/debian experimental/main amd64 libselinux1t64 amd64 3.5-2.1~exp1 [75.2 kB]
| Fetched 75.2 kB in 0s (6067 kB/s)
| debconf: delaying package configuration, since apt-utils is not installed
| dpkg: libselinux1:amd64: dependency problems, but removing anyway as you requested:
|  util-linux depends on libselinux1 (>= 3.1~).
|  tar depends on libselinux1 (>= 3.1~).
|  sed depends on libselinux1 (>= 3.1~).
|  libpam-modules-bin depends on libselinux1 (>= 3.1~).
|  libpam-modules:amd64 depends on libselinux1 (>= 3.1~).
|  libmount1:amd64 depends on libselinux1 (>= 3.1~).
|  findutils depends on libselinux1 (>= 3.1~).
|  dpkg depends on libselinux1 (>= 3.1~).
|  coreutils depends on libselinux1 (>= 3.1~).
|  base-passwd depends on libselinux1 (>= 3.1~).
| 
| (Reading database ... 6230 files and directories currently installed.)
| Removing libselinux1:amd64 (3.5-2) ...
| /usr/bin/dpkg: error while loading shared libraries: libselinux.so.1: cannot open shared object file: No such file or directory
| E: Sub-process /usr/bin/dpkg returned an error code (127)

At that point stuff is fairly broken and we cannot easily recover as
both dpkg and tar are now broken. This is pretty bad. To make matters
worse, the situation arises from the combination of Breaks + Provides
and there is nothing libselinux1t64 could do in maintainer scripts to
prevent this from happening, because no libselinux1t64 maintainer script
has been run by the time damage has happened.

I also looked into whether I could reproduce a similar failure with
other packages such as libpam0t64 or libaudit1, but in no other case, I
was able to construct a comparable outcome.

I also looked into why libselinux was being time-bumped. Do I understand
correctly that libselinux is entirely unaffected by time64?
https://adrien.dcln.fr/misc/armhf-time_t/2024-02-01T09:53:00/compat_reports/libselinux1-dev/lfs_to_time_t/compat_report.html
It still is affected by LFS due to using ino_t in the public ABI of
matchpathcon_filespec_add:
https://adrien.dcln.fr/misc/armhf-time_t/2024-02-01T09:53:00/compat_reports/libselinux1-dev/base_to_lfs/compat_report.html
Since we also complete the LFS transition here, not bumping it would
result in an ABI break regarding this symbol. If we were to opt
libselinux out of the LFS transition (e.g. by removing the flags in
debian/rules), then other packages being rebuilt against libselinux-dev
with these flags enabled would be ABI-incompatible though.

An option I see here is to provide ABI-duality for libselinux:

-extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file);
+typedef unsigned long libselinux_ino_t;
+typedef uint64_t libselinux_ino64_t;
+extern int matchpathcon_filespec_add(libselinux_ino_t ino, int specind, const char *file);
+#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 && sizeof(unsigned long) < 8
+extern int matchpathcon_filespec_add64(libselinux_ino64_t ino, int specind, const char *file);
+#define matchpathcon_filespec_add matchpathcon_filespec_add64
+#endif

Looking at the implementation, it would be fairly possible to implement
this. Of course, doing this comes at its own cost: We are extending the
libselinux1 ABI in a Debian-specific way and thus programs built on
Debian will not run on non-Debian.

Another option of course is doing a proper soname bump of libselinux1 to
a Debian-specific soname.

I really hope, I am missing something.

Helmut


Reply to: