From: Ken Brown <kbrown@cornell.edu>
To: cygwin-developers@cygwin.com
Subject: Re: fstat and similar methods in fhandler_socket_local and fhandler_socket_unix
Date: Sun, 21 Feb 2021 13:04:53 -0500 [thread overview]
Message-ID: <508b12a5-9797-9236-a5b5-d8ff5968ad5d@cornell.edu> (raw)
In-Reply-To: <ebd6c660-6190-847f-0a8d-fa9827fddd91@cornell.edu>
On 2/20/2021 6:51 PM, Ken Brown via Cygwin-developers wrote:
> On 2/20/2021 6:32 PM, Ken Brown via Cygwin-developers wrote:
>> fhandler_socket_local::fstat and many similar methods seem to assume that the
>> fhandler is based on a socket *file*. When this is not the case, they end up
>> using handles inappropriately. Consider the following test case, for example.
>>
>> $ cat socket_stat.c
>> #include <time.h>
>> #include <sys/socket.h>
>> #include <sys/un.h>
>> #include <sys/stat.h>
>> #include <errno.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <unistd.h>
>>
>> void print_stat (struct stat);
>>
>> int
>> main ()
>> {
>> struct stat st;
>> int fd;
>>
>> fd = socket (AF_UNIX, SOCK_STREAM, 0);
>> if (fd == -1)
>> {
>> perror ("socket");
>> exit (1);
>> }
>> if (fstat (fd, &st) < 0)
>> {
>> perror ("fstat");
>> exit (1);
>> }
>> print_stat (st);
>> }
>>
>> /* https://man7.org/linux/man-pages/man2/lstat.2.html */
>> void
>> print_stat (struct stat st)
>> {
>> printf("File type: ");
>>
>> switch (st.st_mode & S_IFMT) {
>> case S_IFBLK: printf("block device\n"); break;
>> case S_IFCHR: printf("character device\n"); break;
>> case S_IFDIR: printf("directory\n"); break;
>> case S_IFIFO: printf("FIFO/pipe\n"); break;
>> case S_IFLNK: printf("symlink\n"); break;
>> case S_IFREG: printf("regular file\n"); break;
>> case S_IFSOCK: printf("socket\n"); break;
>> default: printf("unknown?\n"); break;
>> }
>>
>> printf("I-node number: %ld\n", (long) st.st_ino);
>> printf("dev: %lu\n", st.st_dev);
>> printf("rdev: %lu\n", st.st_rdev);
>> printf("Mode: %lo (octal)\n",
>> (unsigned long) st.st_mode);
>>
>> printf("Link count: %ld\n", (long) st.st_nlink);
>> printf("Ownership: UID=%ld GID=%ld\n",
>> (long) st.st_uid, (long) st.st_gid);
>>
>> printf("Preferred I/O block size: %ld bytes\n",
>> (long) st.st_blksize);
>> printf("File size: %lld bytes\n",
>> (long long) st.st_size);
>> printf("Blocks allocated: %lld\n",
>> (long long) st.st_blocks);
>>
>> printf("Last status change: %s", ctime(&st.st_ctime));
>> printf("Last file access: %s", ctime(&st.st_atime));
>> printf("Last file modification: %s", ctime(&st.st_mtime));
>> printf("\n");
>> }
>>
>> $ gcc -g -O0 -o socket_stat socket_stat.c
>>
>> $ ./socket_stat.exe
>> File type: socket
>> I-node number: 4
>> dev: 1966200
>> rdev: 1966200
>> Mode: 140644 (octal)
>> Link count: 0
>> Ownership: UID=197609 GID=197121
>> Preferred I/O block size: 65536 bytes
>> File size: 0 bytes
>> Blocks allocated: 0
>> Last status change: Wed Dec 31 19:00:00 1969
>> Last file access: Wed Dec 31 19:00:00 1969
>> Last file modification: Wed Dec 31 19:00:00 1969
>>
>> On Linux the output is:
>>
>> File type: socket
>> I-node number: 117
>> dev: 0
>> rdev: 0
>> Mode: 140777 (octal)
>> Link count: 1
>> Ownership: UID=1000 GID=1000
>> Preferred I/O block size: 512 bytes
>> File size: 0 bytes
>> Blocks allocated: 0
>> Last status change: Sat Feb 20 18:13:50 2021
>> Last file access: Sat Feb 20 18:13:50 2021
>> Last file modification: Sat Feb 20 18:13:50 2021
>>
>> I haven't been able to find any documentation about what fstat(2) should do on
>> a socket descriptor, so maybe the difference between Cygwin and Linux is
>> unimportant. But the code path followed on Cygwin definitely seems wrong.
>> fhandler_socket_local::fstat calls fstat_fs which ends up using the io_handle
>> as though it were a file handle. It seems to me that fstat_fs should only be
>> called if we have a path_conv handle (which is the case if the fstat call
>> resulted from a stat call) or if the socket descriptor came from open with
>> O_PATH set.
>>
>> Similar remarks apply to fstatfvs, fchmod,.... In some of these cases, like
>> fchmod, POSIX explicitly states that the behavior is undefined, so maybe we
>> should just fail when there's no underlying socket file.
>
> Maybe the answer in all these cases is just to revert to the fhandler_socket
> methods when our fhandler_socket_local is not based on a socket file.
I think the following should do the job for fstat:
--- a/winsup/cygwin/fhandler_socket_local.cc
+++ b/winsup/cygwin/fhandler_socket_local.cc
@@ -673,11 +673,11 @@ fhandler_socket_local::fcntl (int cmd, intptr_t arg)
int __reg2
fhandler_socket_local::fstat (struct stat *buf)
{
- int res;
+ if (!pc.handle () && !(get_flags () & O_PATH))
+ /* fstat is not being called on a socket file. */
+ return fhandler_socket::fstat (buf);
- if (get_sun_path () && get_sun_path ()[0] == '\0')
- return fhandler_socket_wsock::fstat (buf);
- res = fhandler_base::fstat_fs (buf);
+ int res = fhandler_base::fstat_fs (buf);
if (!res)
{
buf->st_mode = (buf->st_mode & ~S_IFMT) | S_IFSOCK;
With this patch, the output of my testcase looks like this:
File type: socket
I-node number: 6
dev: 1966080
rdev: 1966200
Mode: 140777 (octal)
Link count: 1
Ownership: UID=197609 GID=197121
Preferred I/O block size: 65536 bytes
File size: 0 bytes
Blocks allocated: 0
Last status change: Thu Nov 30 19:00:00 2006
Last file access: Sun Feb 21 13:03:03 2021
Last file modification: Sun Feb 21 13:03:03 2021
If this patch looks right, I'll look at the other system calls too.
Ken
next prev parent reply other threads:[~2021-02-21 18:04 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-20 23:32 Ken Brown
2021-02-20 23:51 ` Ken Brown
2021-02-21 18:04 ` Ken Brown [this message]
2021-02-22 9:44 ` Corinna Vinschen
2021-02-22 20:01 ` Ken Brown
2021-02-24 9:06 ` Corinna Vinschen
2021-02-24 15:32 ` Ken Brown
2021-02-24 17:06 ` Corinna Vinschen
2021-02-24 17:27 ` Ken Brown
2021-02-25 13:18 ` Ken Brown
2021-02-25 17:03 ` Corinna Vinschen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=508b12a5-9797-9236-a5b5-d8ff5968ad5d@cornell.edu \
--to=kbrown@cornell.edu \
--cc=cygwin-developers@cygwin.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).