Source: glibc
Version: 2.28-2
Severity: important
Tags: patch
User: debian-...@lists.debian.org
Usertags: m68k
Hi!
In 298d0e3129c0b5137f4989275b13fe30d0733c4d ("Consolidate Linux getdents{64}
implementation"), upstream made changes to the getdents{64} implementation
which breaks glibc on qemu-user.
The result of that is that applications like dash behave erratically, such that
for example pattern expansion no longer works. This means that "*" is not
expanded
to filenames:
$ ls -l old/
total 148
-rw-r--r-- 1 glaubitz fbedv 16188 Jun 21 2003 chardraw.c
-rw-r--r-- 1 glaubitz fbedv 7922 Jun 21 2003 fillpoly.c
-rw-r--r-- 1 glaubitz fbedv 948 Jun 21 2003 readme
-rw-r--r-- 1 glaubitz fbedv 31860 Jun 21 2003 to_atari.c
-rw-r--r-- 1 glaubitz fbedv 13093 Jun 21 2003 to_eps.c
-rw-r--r-- 1 glaubitz fbedv 6631 Jun 21 2003 to_mf.c
-rw-r--r-- 1 glaubitz fbedv 3261 Jun 21 2003 to_pbm.c
-rw-r--r-- 1 glaubitz fbedv 12854 Jun 21 2003 to_pcx.c
-rw-r--r-- 1 glaubitz fbedv 10657 Jun 21 2003 to_pdf.c
-rw-r--r-- 1 glaubitz fbedv 6697 Jun 21 2003 to_pm.c
-rw-r--r-- 1 glaubitz fbedv 9463 Jun 21 2003 to_x11a.c
-rw-r--r-- 1 glaubitz fbedv 10405 Jun 21 2003 to_x11.c
$ ls -l old/*
/bin/ls: cannot access 'old/*': No such file or directory
$
dash is just one example. Other affected applications are cmake or qmake.
The attached prelimenary patch by James Clarke fixes the problem for me.
Thanks,
Adrian
> [1] https://sourceware.org/bugzilla/show_bug.cgi?id=23960
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - glaub...@debian.org
`. `' Freie Universitaet Berlin - glaub...@physik.fu-berlin.de
`-GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
Description: Fix regression of glibc 2.28 on qemu-user
The new getdents{64} implementation in glibc 2.28 breaks
qemu-user making certain applications like dash fail to
work properly.
.
Author: James Clarke
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23960
Last-Update: 2018-12-11
Index: glibc-2.28/sysdeps/unix/sysv/linux/alpha/getdents.c
===
--- glibc-2.28.orig/sysdeps/unix/sysv/linux/alpha/getdents.c
+++ glibc-2.28/sysdeps/unix/sysv/linux/alpha/getdents.c
@@ -1,11 +1,13 @@
/* Although Alpha defines _DIRENT_MATCHES_DIRENT64, 'struct dirent' and
'struct dirent64' have slight different internal layout with d_ino
being a __ino_t on non-LFS version with an extra __pad field which should
- be zeroed. */
+ be zero. */
#include
#undef _DIRENT_MATCHES_DIRENT64
#define _DIRENT_MATCHES_DIRENT64 0
-#define DIRENT_SET_DP_INO(dp, value) \
- do { (dp)->d_ino = (value); (dp)->__pad = 0; } while (0)
+#define DIRENT_CHECK_DP_INO_SIZE(kdp, dp) \
+ (sizeof ((kdp)->d_ino) == sizeof ((dp)->d_ino) + sizeof ((dp)->__pad))
+#define DIRENT_CHECK_DP_INO(dp) \
+ (dp)->__pad == 0
#include
Index: glibc-2.28/sysdeps/unix/sysv/linux/getdents.c
===
--- glibc-2.28.orig/sysdeps/unix/sysv/linux/getdents.c
+++ glibc-2.28/sysdeps/unix/sysv/linux/getdents.c
@@ -24,92 +24,85 @@
# include
# include
-# ifndef DIRENT_SET_DP_INO
-# define DIRENT_SET_DP_INO(dp, value) (dp)->d_ino = (value)
+/* For Linux we need a special version of this file since the
+ definition of `struct dirent' is not the same for the kernel and
+ the libc; the kernel places d_type after the variable-length d_name,
+ but we place it at a fixed offset just before d_name. */
+
+struct kernel_dirent
+ {
+__syscall_ulong_t d_ino;
+__syscall_ulong_t d_off;
+unsigned short d_reclen;
+char d_name[256];
+ };
+
+# ifndef DIRENT_CHECK_DP_INO_SIZE
+# define DIRENT_CHECK_DP_INO_SIZE(kdp, dp) \
+(sizeof ((kdp)->d_ino) == sizeof ((dp)->d_ino))
# endif
-/* Pack the dirent64 struct down into 32-bit offset/inode fields, and
- ensure that no overflow occurs. */
ssize_t
__getdents (int fd, char *buf, size_t nbytes)
{
- union
- {
-/* For !_DIRENT_MATCHES_DIRENT64 kernel 'linux_dirent64' has the same
- layout of 'struct dirent64'. */
-struct dirent64 k;
-struct dirent u;
-char b[1];
- } *kbuf = (void *) buf, *outp, *inp;
- size_t kbytes = nbytes;
- off64_t last_offset = -1;
ssize_t retval;
+# ifdef DIRENT_CHECK_DP_INO
+ off64_t last_offset = -1;
+# endif
-# define size_diff (offsetof (struct dirent64, d_name) \
- - offsetof (struct dirent, d_name))
- char kbuftmp[sizeof (struct dirent) + size_diff];
- if (nbytes <= sizeof (struct dirent))
-kbuf = (void*) kbuftmp;
-
- retval = INLINE_SYSCALL_CALL (getdents64, fd, kbuf, kbytes);
- if (retval == -1)
-return -1;
-
- /* These two pointers might alias the same memory buffer.
- Standard C requires that we always use the same type for them,
- so we must use the union type. */
- inp = kbuf;
- outp = (void *) buf;
-
- while (&inp->b < &kbuf->b + retval)
+ /* The d_ino and d_off fields in kernel_dirent and dirent