[PATCH v3 05/24] linux: Add fallback for 64-bit time_t SO_TIMESTAMP{NS}

Florian Weimer fweimer@redhat.com
Fri Jun 25 15:20:02 GMT 2021


* Adhemerval Zanella via Libc-alpha:

> +/* It converts the first SO_TIMESTAMP or SO_TIMESTAMPNS with 32-bit time and
> +   appends it to the control buffer.  The 32-bit time field is kept as-is.
> +
> +   Calls with __TIMESIZE=32 will see the converted 64-bit time control
> +   messages as spurious control message of unknown type.
> +
> +   Calls with __TIMESIZE=64 running on pre-time64 kernels will see the
> +   original message as a spurious control ones of unknown typ while running
> +   on kernel with native 64-bit time support will only see the time64 version
> +   of the control message.  */
> +void
> +__convert_scm_timestamps (struct msghdr *msg, socklen_t msgsize)
> +{
> +  if (msg->msg_control == NULL || msg->msg_controllen == 0)
> +    return;
> +
> +  /* The returned control message format for SO_TIMESTAMP_NEW is a
> +     'struct __kernel_sock_timeval' while for SO_TIMESTAMPNS_NEW is a
> +     'struct __kernel_timespec'.  In either case it is two uint64_t
> +     members.  */
> +  uint64_t tvts[2];
> +
> +  struct cmsghdr *cmsg, *last = NULL;
> +  int type = 0;
> +
> +  for (cmsg = CMSG_FIRSTHDR (msg);
> +       cmsg != NULL;
> +       cmsg = CMSG_NXTHDR (msg, cmsg))
> +    {
> +      if (cmsg->cmsg_level != SOL_SOCKET)
> +	continue;
> +
> +      switch (cmsg->cmsg_type)
> +	{
> +	case COMPAT_SO_TIMESTAMP_OLD:
> +	  if (type != 0)
> +	    break;
> +	  type = COMPAT_SO_TIMESTAMP_NEW;
> +	  goto common;
> +
> +	case COMPAT_SO_TIMESTAMPNS_OLD:
> +	  type = COMPAT_SO_TIMESTAMPNS_NEW;
> +
> +	/* fallthrough  */
> +	common:
> +	  memcpy (tvts, CMSG_DATA (cmsg), sizeof (tvts));
> +	  break;
> +	}
> +
> +      last = cmsg;
> +    }
> +
> +  if (last == NULL || type == 0)
> +    return;
> +
> +  if (CMSG_SPACE (sizeof tvts) > msgsize - msg->msg_controllen)
> +    {
> +      msg->msg_flags |= MSG_CTRUNC;
> +      return;
> +    }
> +
> +  msg->msg_controllen += CMSG_SPACE (sizeof tvts);
> +  cmsg = CMSG_NXTHDR(msg, last);
> +  cmsg->cmsg_level = SOL_SOCKET;
> +  cmsg->cmsg_type = type;
> +  cmsg->cmsg_len = CMSG_LEN (sizeof tvts);
> +  memcpy (CMSG_DATA (cmsg), tvts, sizeof tvts);
> +}
> +libc_hidden_def (__convert_scm_timestamps)
> +#endif

The Ruby test suite crashes on this line:

  cmsg->cmsg_level = SOL_SOCKET;

See:

  ruby: FTBFS with test suite failure (glibc 2.34 related)
  <https://bugzilla.redhat.com/show_bug.cgi?id=1975144>

The disassembly suggests that GCC has detected some undefined behavior.

This looks like a related bug:

  __cmsg_nxthdr in cmsg_nxthdr.c (CMSG_NXTHDR) has undefined behavior when setting up ancillary data
  <https://sourceware.org/bugzilla/show_bug.cgi?id=13500>

I believe you cannot use CMSG_NXTHDR to append data in this way.

The other question is why this code is running at all.  Doing this
complex conversion for a 32-bit applications doing a 32-bit function
call on a kernel which supports 32-bit system calls does not make much
sense to me.

Thanks,
Florian



More information about the Libc-alpha mailing list