diff mbox series

Always build for LFS mode on 32-bit archs.

Message ID 20241128165436.93649-1-cgoettsche@seltendoof.de (mailing list archive)
State New
Headers show
Series Always build for LFS mode on 32-bit archs. | expand

Commit Message

Christian Göttsche Nov. 28, 2024, 4:54 p.m. UTC
From: Steve Langasek <steve.langasek@canonical.com>

Maintains the type signature of the existing matchpathcon_filespec_add()
entry point on 32-bit archs but maps the API to a new
matchpathcon_filespec_add64() entry point that takes a 64-bit ino_t argument
instead.

Software on 32-bit Linux ports which historically use a 32-bit time_t (thus
affected by the y2038 problem) have, as a precondition of migrating to
64-bit time_t, that they also migrate to large filesystem support because
glibc does not provide entry points for the cross-product of
(LFS: yes, LFS: no) x (time_t: 32, time_t: 64).

In order to support smooth migration of such operating systems from 32-bit
time_t to 64-bit time_t, it is useful for libselinux to:

- provide entry points on 32-bit systems for both LFS and non-LFS variants
  of the API (as glibc itself does)
- use LFS internally for all filesystem calls (just in case)
- map the API call to the correct implementation based on the build
  environment of the caller.

Signed-off-by: Steve Langasek <steve.langasek@canonical.com>
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
Originally posted https://lore.kernel.org/selinux/ZeQuOBwQ2eSbkUAS@homer.dodds.net/1.2-0001-Always-build-for-LFS-mode-on-32-bit-archs.patch

v2:
 - Adjusted version in libselinux.map
 - check for __BITS_PER_LONG availability in matchpathcon.c similar to
   selinux.h
 - add static asserts, it's better to fail hard at compile time instead
   of having a silent ABI break
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libselinux/Makefile                  |  6 ++++++
 libselinux/include/selinux/selinux.h |  5 +++++
 libselinux/src/Makefile              |  2 ++
 libselinux/src/libselinux.map        |  5 +++++
 libselinux/src/matchpathcon.c        | 26 ++++++++++++++++++++++++++
 libselinux/utils/Makefile            |  2 ++
 6 files changed, 46 insertions(+)
diff mbox series

Patch

diff --git a/libselinux/Makefile b/libselinux/Makefile
index 6d9e2736..a50b6491 100644
--- a/libselinux/Makefile
+++ b/libselinux/Makefile
@@ -34,6 +34,12 @@  PCRE_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(PCRE_MODULE))
 PCRE_LDLIBS := $(shell $(PKG_CONFIG) --libs $(PCRE_MODULE))
 export PCRE_MODULE PCRE_CFLAGS PCRE_LDLIBS
 
+USE_LFS ?= y
+ifeq ($(USE_LFS),y)
+	LFS_CFLAGS := -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+export LFS_CFLAGS
+
 OS := $(shell uname)
 export OS
 
diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h
index 50419a7c..f3cf5a20 100644
--- a/libselinux/include/selinux/selinux.h
+++ b/libselinux/include/selinux/selinux.h
@@ -1,8 +1,10 @@ 
 #ifndef _SELINUX_H_
 #define _SELINUX_H_
 
+#include <stdint.h>
 #include <sys/types.h>
 #include <stdarg.h>
+#include <asm/bitsperlong.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -535,6 +537,9 @@  extern int matchpathcon_index(const char *path,
    with the same inode (e.g. due to multiple hard links).  If so, then
    use the latter of the two specifications based on their order in the 
    file contexts configuration.  Return the used specification index. */
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && __BITS_PER_LONG < 64
+#define matchpathcon_filespec_add matchpathcon_filespec_add64
+#endif
 extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file);
 
 /* Destroy any inode associations that have been added, e.g. to restart
diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile
index 41cfbdca..9909eb40 100644
--- a/libselinux/src/Makefile
+++ b/libselinux/src/Makefile
@@ -89,6 +89,8 @@  CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissi
           -Werror -Wno-aggregate-return \
           $(EXTRA_CFLAGS)
 
+override CFLAGS += $(LFS_CFLAGS)
+
 LD_SONAME_FLAGS=-soname,$(LIBSO),--version-script=libselinux.map,-z,defs,-z,relro
 
 ifeq ($(OS), Darwin)
diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map
index 5e00f45b..02f5b761 100644
--- a/libselinux/src/libselinux.map
+++ b/libselinux/src/libselinux.map
@@ -252,3 +252,8 @@  LIBSELINUX_3.5 {
     getpidprevcon;
     getpidprevcon_raw;
 } LIBSELINUX_3.4;
+
+LIBSELINUX_3.8 {
+  global:
+    matchpathcon_filespec_add64;
+} LIBSELINUX_3.5;
diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c
index 967520e4..15f9353d 100644
--- a/libselinux/src/matchpathcon.c
+++ b/libselinux/src/matchpathcon.c
@@ -1,3 +1,4 @@ 
+#include <assert.h>
 #include <sys/stat.h>
 #include <string.h>
 #include <errno.h>
@@ -261,6 +262,31 @@  int matchpathcon_filespec_add(ino_t ino, int specind, const char *file)
 	return -1;
 }
 
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && __BITS_PER_LONG < 64
+/* alias defined in the public header but we undefine it here */
+#undef matchpathcon_filespec_add
+
+/* ABI backwards-compatible shim for non-LFS 32-bit systems */
+
+static_assert(sizeof(unsigned long) == sizeof(__ino_t), "inode size mismatch");
+static_assert(sizeof(unsigned long) == sizeof(uint32_t), "inode size mismatch");
+static_assert(sizeof(ino_t) == sizeof(ino64_t), "inode size mismatch");
+static_assert(sizeof(ino64_t) == sizeof(uint64_t), "inode size mismatch");
+
+extern int matchpathcon_filespec_add(unsigned long ino, int specind,
+                                     const char *file);
+
+int matchpathcon_filespec_add(unsigned long ino, int specind,
+                              const char *file)
+{
+	return matchpathcon_filespec_add64(ino, specind, file);
+}
+#else
+
+static_assert(sizeof(unsigned long) == sizeof(ino_t), "inode size mismatch");
+
+#endif
+
 /*
  * Evaluate the association hash table distribution.
  */
diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile
index f3cedc11..0d7095b1 100644
--- a/libselinux/utils/Makefile
+++ b/libselinux/utils/Makefile
@@ -36,6 +36,8 @@  CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissi
           -Werror -Wno-aggregate-return -Wno-redundant-decls -Wstrict-overflow=5 \
           $(EXTRA_CFLAGS)
 
+override CFLAGS += $(LFS_CFLAGS)
+
 ifeq ($(OS), Darwin)
 override CFLAGS += -I/opt/local/include -I../../libsepol/include
 override LDFLAGS += -L../../libsepol/src -undefined dynamic_lookup