ldconfig: support hints files of either byte-order

Make the ldconfig program accept hints files in little-endian and
big-endian format on all architectures.

The default format is the native byte-order of the respective host.
This is expected to change when a version of the pkg command is
available that implements support for either byte-order in its
internal ldconfig function. (Already committed in the development
tree of the pkg utility, a release is expected at the end of Q1/2024).

This update adds the -B option to the ldconfig program. It enforces
the creation of a big-endian hints file on a little-endian host.
The main purpose to is support of tests with non-native byte-order
files on little-endian hosts. It will be removed when all supported
FreeBSD releases use little-endian hints files by default.

When little-endian hints files are generally used, support of
either byte-order in libexec/rtld can also be removed.

When support for big-endian hints files is no longer required,
the COND_SWAP macro in ldconfig and rtld shall be replaced by
le32toh(), which just return their argument on little-endian
architectures.

Approved by:	kib
MFC after:	1 month
Relnotes:	yes
Differential Revision:	https://reviews.freebsd.org/D44093
This commit is contained in:
Stefan Eßer 2024-02-28 18:49:29 +01:00
parent cf4d9bf8b3
commit e0dfecadf5
4 changed files with 49 additions and 23 deletions

View file

@ -27,6 +27,7 @@
*/
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/mman.h>
#include <sys/stat.h>
@ -48,11 +49,12 @@
static void add_dir(const char *, const char *, bool);
static void read_dirs_from_file(const char *, const char *);
static void read_elf_hints(const char *, bool);
static void read_elf_hints(const char *, bool, bool);
static void write_elf_hints(const char *);
static const char *dirs[MAXDIRS];
static int ndirs;
static bool is_be;
bool insecure;
static void
@ -95,7 +97,7 @@ list_elf_hints(const char *hintsfile)
int i;
int nlibs;
read_elf_hints(hintsfile, 1);
read_elf_hints(hintsfile, true, false);
printf("%s:\n", hintsfile);
printf("\tsearch directories:");
for (i = 0; i < ndirs; i++)
@ -183,8 +185,11 @@ read_dirs_from_file(const char *hintsfile, const char *listfile)
fclose(fp);
}
/* Convert between native byte order and forced little resp. big endian. */
#define COND_SWAP(n) (is_be ? be32toh(n) : le32toh(n))
static void
read_elf_hints(const char *hintsfile, bool must_exist)
read_elf_hints(const char *hintsfile, bool must_exist, bool force_be)
{
int fd;
struct stat s;
@ -193,6 +198,7 @@ read_elf_hints(const char *hintsfile, bool must_exist)
char *strtab;
char *dirlist;
char *p;
int hdr_version;
if ((fd = open(hintsfile, O_RDONLY)) == -1) {
if (errno == ENOENT && !must_exist)
@ -214,14 +220,18 @@ read_elf_hints(const char *hintsfile, bool must_exist)
close(fd);
hdr = (struct elfhints_hdr *)mapbase;
if (hdr->magic != ELFHINTS_MAGIC)
is_be = be32toh(hdr->magic) == ELFHINTS_MAGIC;
if (COND_SWAP(hdr->magic) != ELFHINTS_MAGIC)
errx(1, "\"%s\": invalid file format", hintsfile);
if (hdr->version != 1)
if (force_be && !is_be)
errx(1, "\"%s\": incompatible endianness requested", hintsfile);
hdr_version = COND_SWAP(hdr->version);
if (hdr_version != 1)
errx(1, "\"%s\": unrecognized file version (%d)", hintsfile,
hdr->version);
hdr_version);
strtab = (char *)mapbase + hdr->strtab;
dirlist = strtab + hdr->dirlist;
strtab = (char *)mapbase + COND_SWAP(hdr->strtab);
dirlist = strtab + COND_SWAP(hdr->dirlist);
if (*dirlist != '\0')
while ((p = strsep(&dirlist, ":")) != NULL)
@ -229,13 +239,19 @@ read_elf_hints(const char *hintsfile, bool must_exist)
}
void
update_elf_hints(const char *hintsfile, int argc, char **argv, bool merge)
update_elf_hints(const char *hintsfile, int argc, char **argv, bool merge,
bool force_be)
{
struct stat s;
int i;
/*
* Remove "be32toh(1) == 1" from this condition to create
* little-endian hints files on all architectures by default.
*/
is_be = be32toh(1) == 1 || force_be;
if (merge)
read_elf_hints(hintsfile, false);
read_elf_hints(hintsfile, false, force_be);
for (i = 0; i < argc; i++) {
if (stat(argv[i], &s) == -1)
warn("warning: %s", argv[i]);
@ -265,9 +281,9 @@ write_elf_hints(const char *hintsfile)
if ((fp = fdopen(fd, "wb")) == NULL)
err(1, "fdopen(%s)", tempname);
hdr.magic = ELFHINTS_MAGIC;
hdr.version = 1;
hdr.strtab = sizeof hdr;
hdr.magic = COND_SWAP(ELFHINTS_MAGIC);
hdr.version = COND_SWAP(1);
hdr.strtab = COND_SWAP(sizeof hdr);
hdr.strsize = 0;
hdr.dirlist = 0;
memset(hdr.spare, 0, sizeof hdr.spare);
@ -278,8 +294,10 @@ write_elf_hints(const char *hintsfile)
for (i = 1; i < ndirs; i++)
hdr.strsize += 1 + strlen(dirs[i]);
}
hdr.dirlistlen = hdr.strsize;
hdr.dirlistlen = COND_SWAP(hdr.strsize);
hdr.strsize++; /* For the null terminator */
/* convert in-place from native to target endianness */
hdr.strsize = COND_SWAP(hdr.strsize);
/* Write the header. */
if (fwrite(&hdr, 1, sizeof hdr, fp) != sizeof hdr)

View file

@ -32,7 +32,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 15, 2021
.Dd February 28, 2024
.Dt LDCONFIG 8
.Os
.Sh NAME
@ -41,7 +41,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl 32
.Op Fl Rimrv
.Op Fl BRimrv
.Op Fl f Ar hints_file
.Op Ar directory | Ar
.Sh DESCRIPTION
@ -105,6 +105,11 @@ Generate the hints for 32-bit ABI shared libraries
on 64-bit systems that support running 32-bit binaries.
.It Fl elf
Ignored for backwards compatibility.
.It Fl B
Force writing big-endian binary data´to the hints file.
The default is to create little-endian hints files on all architectures.
Reading of and merging into hints files preserves the endianness of the
existing hints file.
.It Fl R
Appends pathnames on the command line to the directory list from
the hints file.
@ -159,7 +164,7 @@ invocations with
.El
.Sh SEE ALSO
.Xr ld 1 ,
.Xr ld-elf.so.1 ,
.Xr ld-elf.so.1 1 ,
.Xr link 5
.Sh HISTORY
A

View file

@ -57,9 +57,9 @@ main(int argc, char **argv)
{
const char *hints_file;
int c;
bool is_32, justread, merge, rescan, verbose;
bool is_32, justread, merge, rescan, force_be, verbose;
is_32 = justread = merge = rescan = verbose = false;
force_be = is_32 = justread = merge = rescan = verbose = false;
while (argc > 1) {
if (strcmp(argv[1], "-aout") == 0) {
@ -80,8 +80,11 @@ main(int argc, char **argv)
hints_file = __PATH_ELF_HINTS("32");
else
hints_file = _PATH_ELF_HINTS;
while((c = getopt(argc, argv, "Rf:imrsv")) != -1) {
while((c = getopt(argc, argv, "BRf:imrsv")) != -1) {
switch (c) {
case 'B':
force_be = true;
break;
case 'R':
rescan = true;
break;
@ -115,7 +118,7 @@ main(int argc, char **argv)
if (argc == optind)
rescan = true;
update_elf_hints(hints_file, argc - optind,
argv + optind, merge || rescan);
argv + optind, merge || rescan, force_be);
}
exit(0);
}
@ -124,7 +127,7 @@ static void
usage(void)
{
fprintf(stderr,
"usage: ldconfig [-32] [-elf] [-Rimrv] [-f hints_file] "
"usage: ldconfig [-32] [-elf] [-BRimrv] [-f hints_file]"
"[directory | file ...]\n");
exit(1);
}

View file

@ -36,7 +36,7 @@ extern bool insecure; /* -i flag, needed here for elfhints.c */
__BEGIN_DECLS
void list_elf_hints(const char *);
void update_elf_hints(const char *, int, char **, bool);
void update_elf_hints(const char *, int, char **, bool, bool);
__END_DECLS
#endif