Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20190725200107.GM1506@brightrain.aerifal.cx>
Date: Thu, 25 Jul 2019 16:01:07 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: Final (?) time64 proposal

On Thu, Jul 25, 2019 at 01:18:32AM -0400, Rich Felker wrote:
> On Wed, Jul 24, 2019 at 01:31:42AM -0400, Rich Felker wrote:
> > With that said, the following are the functions I've identified as
> > still interfacing with the kernel in ways that involve time_t:
> > 
> > - clock_gettime **
> > [...]
> 
> I think a good next-step here would be modifying all of the above to
> go through an intermediate kernel-type struct when using the existing
> syscalls. This should not change behavior anywhere except for a slight
> increase in size/time-spent, but will set things up so that, when the
> time_t definition is switched over, everything should just start
> working automatically with 64-bit time. It will also let us drop the
> __fixup hacks in arch/x32/syscall_arch.h and
> src/thread/x32/syscall_cp_fixup.c, analogous to how commit
> 01ae3fc6d48f4a45535189b7a6db286535af08ca let us drop the corresponding
> mips hacks.

I'm not so sure about this approach now. Conversions will never be
needed for 64-bit archs, nor for new code paths using the time64
syscalls on 32-bit archs. Aside from x32 awfulness, the condition for
the new version of the code to be needed is SYS_*time64 being defined
and time_t being 64-bit. This suggests we might let x32/syscall_arch.h
define the SYS_*time64 macros, and undef the legacy names, so that it
gets treated like a 32-bit arch with no legacy time32 syscalls (i.e.
like riscv32 will be). The logic will roughly be:

#ifdef SYS_foo_time64
	if (sizeof(time_t)>4) {
		[if there's an input timespec, copy it and zero padding]
		SYS_foo_time64
		[if success, return]
	}
#ifdef SYS_foo [legacy time32]
	[if there's input, explicitly convert to legacy time32 form]
	SYS_foo
	[if success and there's output, convert back to libc time form]
#endif
#else
	SYS_foo [native 64-bit]
#endif

The "if (sizeof(time_t)>4)" condition will become always-false once
32-bit archs are converted over, and can be removed after that. But
for now, it would allow the code to be compile-tested on all archs and
to take effect on x32, with the above-described renaming of syscalls
made in x32/syscall_arch.h.

Granted this is somewhat ugly, but I don't see any other better way;
it seems minimal to meet the (hard) requirements of running on pre-5.1
kernels and using correct time representations.



Now, on to errors. Below is analysis of valid error handling for
conversions that can't be represented.


The easiest are timeouts. Whether the overflowing timeout is absolute
or relative, it can't happen before the non-Y2038-safe system dies in
2038, so the syscall can just be made with no timeout. That covers:

- clock_nanosleep
- mq_timedsend
- mq_timedreceive
- select
- pselect
- ppoll
- recvmmsg
- sigtimedwait
- semtimedop
- __timedwait

In the case of clock_nanosleep (and select, if we want to continue
providing the updated remaining time for select), we can't just use an
unlimited timeout, but instead need to do something like INT32_MAX so
that we can add back the remaining time if the syscall does return.



The following take as input time values that need conversion and that
may not be representable in the legacy type. Thus changing time to
64-bit introduces error cases for them when new syscalls are not
available.

In general, EOVERFLOW is probably not appropriate for any of these.
Its meaning is that the actual value of something is too great to be
represented in the C type used for conveying back the result, not that
the C type used for input can represent values outside the range of
what's supported by the implementation. ENOTSUP is probably the
closest to the latter - "Not supported. The implementation does not
support the requested feature or value."
                              ^^^^^^^^

- clock_settime - obviously this one can't work for times past Y2038.
  there's no standard error (note that EOVERFLOW is specified for
  clock_gettime and matches the above reasoning), so ENOTSUP.

- clock_adjtime - same.

- timer_settime - no related errors defined. setting max possible
  value is tempting but would read back inconsistent results via
  timer_gettime. probably should use ENOTSUP.

- timerfd_settime - not governed by standard but should be the same
  as timer_settime for consistency.

- utimensat - possibly EINVAL (defined by POSIX) or ENOTSUP. for this
  function, EINVAL is defined as:

  [EINVAL]
    A new file timestamp would be a value whose tv_sec component is
    not a value supported by the file system.

  arguably "the file system" includes the kernel's implementation of
  it via syscalls like SYS_utimensat.

- setitimer - no related errors defined. probably need ENOTSUP for
  same reasons as timer_settime.

- setsockopt (SO_RCVTIMEO and SO_SNDTIMEO, using "_NEW" values) - the
  timeouts set need to be readable back through getsockopt, so we need
  an error if falling back to the _OLD versions and the time
  overflows. ENOTSUP again.


The next group is easy. They only produce times as output, and any
legacy 32-bit output necessarily fits in the 64-bit type. Thus, these
have no error cases:

- clock_gettime
- timer_gettime
- timerfd_gettime
- getitimer
- clock_getres
- sched_rr_get_interval
- getrusage
- wait4
- wait3
- getsockopt (SO_RCVTIMEO and SO_SNDTIMEO, using "_NEW" values)
- shmctl
- semctl
- msgctl


There are a few ugly things I didn't cover yet:

setsockopt with SO_TIMESTAMP* either needs to hard-fail if the kernel
doesn't support the "_NEW" values, or some slightly-heavy emulation in
recvmsg is needed (translating cmsgs to 64-bit).

ioctl probably has a number of places where we need to do translations
for fallback ioctl numbers. Hopefully the kernel time64 commits show
us what these are.


That should cover all the interfaces I had on this list so far. I'll
probably try some conversions using the above #ifdef idiom and see how
it goes.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.