fstat and similar methods in fhandler_socket_local and fhandler_socket_unix

Ken Brown kbrown@cornell.edu
Mon Feb 22 20:01:44 GMT 2021


On 2/22/2021 4:44 AM, Corinna Vinschen via Cygwin-developers wrote:
> On Feb 21 13:04, Ken Brown via Cygwin-developers wrote:
>> 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
>>>> [...]
>>>> 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.
> 
> I see what you mean.  This was clearly fat-fingered, probably after
> trying to add abstract sockets.
> 
>> 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. */
> 
> The comment should probably read "fstat called on a socket"...
> 
>> +    return fhandler_socket::fstat (buf);
> 
> ...plus adding a comment right here:
> 
>       /* stat/lstat on a socket file or fstat on a socket opened w/ O_PATH */
> 
>> -  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
> 
> Might be a good idea to check the output twice in your testcase, adding
> a second fstat call after calling bind, to see if it's still the same
> after binding the socket to a file.

Done.

>> If this patch looks right, I'll look at the other system calls too.
> 
> Yeah, I think you're right.  Thanks!

OK, I've got patches ready to go for fstat, fstatvfs, fchmod, fchown, facl, and 
link.  I have to test them, and then I'll send them to cygwin-patches.  In the 
case of link, I think the only way an fhandler_socket's link method can be 
called is through link(2) being called on a socket file.  So the following 
should do the job:

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 21e1df172..f4aa12956 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -611,7 +611,6 @@ class fhandler_socket: public fhandler_base
    int __reg1 fchmod (mode_t newmode);
    int __reg2 fchown (uid_t newuid, gid_t newgid);
    int __reg3 facl (int, int, struct acl *);
-  int __reg2 link (const char *);
    off_t lseek (off_t, int)
    {
      set_errno (ESPIPE);
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index f22412650..08870cc6b 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -357,9 +357,3 @@ fhandler_socket::facl (int cmd, int nentries, aclent_t *aclbufp)
    set_errno (EOPNOTSUPP);
    return -1;
  }
-
-int
-fhandler_socket::link (const char *newpath)
-{
-  return fhandler_base::link (newpath);
-}
diff --git a/winsup/cygwin/fhandler_socket_local.cc 
b/winsup/cygwin/fhandler_socket_local.cc
index 2c66a7fd4..176d64b9b 100644
--- a/winsup/cygwin/fhandler_socket_local.cc
+++ b/winsup/cygwin/fhandler_socket_local.cc
@@ -747,8 +747,6 @@ fhandler_socket_local::facl (int cmd, int nentries, aclent_t 
*aclbufp)
  int
  fhandler_socket_local::link (const char *newpath)
  {
-  if (get_sun_path () && get_sun_path ()[0] == '\0')
-    return fhandler_socket_wsock::link (newpath);
    fhandler_disk_file fh (pc);
    return fh.link (newpath);
  }
diff --git a/winsup/cygwin/fhandler_socket_unix.cc 
b/winsup/cygwin/fhandler_socket_unix.cc
index bd5e1b854..3c713e025 100644
--- a/winsup/cygwin/fhandler_socket_unix.cc
+++ b/winsup/cygwin/fhandler_socket_unix.cc
@@ -2394,10 +2394,6 @@ fhandler_socket_unix::facl (int cmd, int nentries, 
aclent_t *aclbufp)
  int
  fhandler_socket_unix::link (const char *newpath)
  {
-  if (sun_path ()
-      && (sun_path ()->un_len <= (socklen_t) sizeof (sa_family_t)
-         || sun_path ()->un.sun_path[0] == '\0'))
-    return fhandler_socket::link (newpath);
    fhandler_disk_file fh (pc);
    return fh.link (newpath);
  }

Let me know if I've missed something and we really do need fhandler_socket::link.

Ken


More information about the Cygwin-developers mailing list