Browse Source

fix opendir, fpathconf and ttyname_r to use fstat64(), not fstat()

There is no opendir64(), thus even programs built for 64-bit off_t
use opendir(). Before this change, internally opendir() uses fstat(),
with the following breakage if some of struct stat fields are too narrow:

$ strace ls -l
execve("/busybox/ls", ["ls", "-l"], 0x7ffcdc43ede8 /* 16 vars */) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
getuid32()                              = 0
time([1551486393 /* 2019-03-02T00:26:33+0000 */]) = 1551486393 (2019-03-02T00:26:33+0000)
ioctl(0, TIOCGWINSZ, {ws_row=38, ws_col=120, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
brk(NULL)                               = 0x9768000
brk(0x9769000)                          = 0x9769000
lstat64(".", 0xffa6e374)                = 0
open(".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, 0xffa6e378)                    = -1 EOVERFLOW (Value too large for defined data type)

See https://bugs.busybox.net/show_bug.cgi?id=11651

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Denys Vlasenko 4 years ago
parent
commit
4f506bb95a
3 changed files with 19 additions and 11 deletions
  1. 8 5
      libc/misc/dirent/opendir.c
  2. 7 4
      libc/termios/ttyname.c
  3. 4 2
      libc/unistd/fpathconf.c

+ 8 - 5
libc/misc/dirent/opendir.c

@@ -16,6 +16,9 @@
 #include <dirent.h>
 #include "dirstream.h"
 
+#define STAT stat64
+#define FSTAT fstat64
+
 static DIR *fd_to_DIR(int fd, __blksize_t size)
 {
 	DIR *ptr;
@@ -43,9 +46,9 @@ static DIR *fd_to_DIR(int fd, __blksize_t size)
 DIR *fdopendir(int fd)
 {
 	int flags;
-	struct stat st;
+	struct STAT st;
 
-	if (fstat(fd, &st))
+	if (FSTAT(fd, &st))
 		return NULL;
 	if (!S_ISDIR(st.st_mode)) {
 		__set_errno(ENOTDIR);
@@ -69,12 +72,12 @@ DIR *fdopendir(int fd)
 DIR *opendir(const char *name)
 {
 	int fd;
-	struct stat statbuf;
+	struct STAT statbuf;
 	DIR *ptr;
 
 #ifndef O_DIRECTORY
 	/* O_DIRECTORY is linux specific and has been around since like 2.1.x */
-	if (stat(name, &statbuf))
+	if (STAT(name, &statbuf))
 		return NULL;
 	if (!S_ISDIR(statbuf.st_mode)) {
 		__set_errno(ENOTDIR);
@@ -90,7 +93,7 @@ DIR *opendir(const char *name)
 	 * defined and since Linux has supported it for like ever, i'm not going
 	 * to worry about it right now (if ever). */
 
-	if (fstat(fd, &statbuf) < 0) {
+	if (FSTAT(fd, &statbuf) < 0) {
 		/* this close() never fails
 		 *int saved_errno;
 		 *saved_errno = errno; */

+ 7 - 4
libc/termios/ttyname.c

@@ -31,6 +31,9 @@
 #include <dirent.h>
 #include <sys/stat.h>
 
+#define STAT stat64
+#define FSTAT fstat64
+#define LSTAT lstat64
 
 #define TTYNAME_BUFLEN		32
 
@@ -45,8 +48,8 @@ static const char dirlist[] =
 int ttyname_r(int fd, char *ubuf, size_t ubuflen)
 {
 	struct dirent *d;
-	struct stat st;
-	struct stat dst;
+	struct STAT st;
+	struct STAT dst;
 	const char *p;
 	char *s;
 	DIR *fp;
@@ -54,7 +57,7 @@ int ttyname_r(int fd, char *ubuf, size_t ubuflen)
 	size_t len;
 	char buf[TTYNAME_BUFLEN];
 
-	if (fstat(fd, &st) < 0) {
+	if (FSTAT(fd, &st) < 0) {
 		return errno;
 	}
 
@@ -86,7 +89,7 @@ int ttyname_r(int fd, char *ubuf, size_t ubuflen)
 
 			strcpy(s, d->d_name);
 
-			if ((lstat(buf, &dst) == 0)
+			if ((LSTAT(buf, &dst) == 0)
 #if 0
 				/* Stupid filesystems like cramfs fail to guarantee that
 				 * st_ino and st_dev uniquely identify a file, contrary to

+ 4 - 2
libc/unistd/fpathconf.c

@@ -24,6 +24,8 @@
 #include <sys/stat.h>
 #include <sys/statfs.h>
 
+#define STAT stat64
+#define FSTAT fstat64
 
 #ifndef __USE_FILE_OFFSET64
 extern int fstatfs (int __fildes, struct statfs *__buf)
@@ -205,9 +207,9 @@ long int fpathconf(int fd, int name)
 #if defined _POSIX_ASYNC_IO
 	    {
 		/* AIO is only allowed on regular files and block devices.  */
-		struct stat st;
+		struct STAT st;
 
-		if (fstat (fd, &st) < 0 || (! S_ISREG (st.st_mode) && ! S_ISBLK (st.st_mode)))
+		if (FSTAT (fd, &st) < 0 || (! S_ISREG (st.st_mode) && ! S_ISBLK (st.st_mode)))
 		    return -1;
 		else
 		    return 1;