struct timespec is not y2038 safe.
Audit timestamps are recorded in string format into
an audit buffer for a given context.
These mark the entry timestamps for the syscalls.
Use y2038 safe struct timespec64 to represent the times.
The log strings can handle this transition as strings can
hold upto 1024 characters.
Signed-off-by: Deepa Dinamani <deepa.kernel(a)gmail.com>
Reviewed-by: Arnd Bergmann <arnd(a)arndb.de>
Acked-by: Paul Moore <paul(a)paul-moore.com>
Acked-by: Richard Guy Briggs <rgb(a)redhat.com>
Cc: Eric Paris <eparis(a)redhat.com>
Cc: Paul Moore <paul(a)paul-moore.com>
Cc: Richard Guy Briggs <rgb(a)redhat.com>
Cc: linux-audit(a)redhat.com
---
include/linux/audit.h | 4 ++--
kernel/audit.c | 10 +++++-----
kernel/audit.h | 2 +-
kernel/auditsc.c | 6 +++---
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 9d4443f..e51782b 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -332,7 +332,7 @@ static inline void audit_ptrace(struct task_struct *t)
/* Private API (for audit.c only) */
extern unsigned int audit_serial(void);
extern int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec *t, unsigned int *serial);
+ struct timespec64 *t, unsigned int *serial);
extern int audit_set_loginuid(kuid_t loginuid);
static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
@@ -490,7 +490,7 @@ static inline void __audit_seccomp(unsigned long syscall, long signr, int code)
static inline void audit_seccomp(unsigned long syscall, long signr, int code)
{ }
static inline int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec *t, unsigned int *serial)
+ struct timespec64 *t, unsigned int *serial)
{
return 0;
}
diff --git a/kernel/audit.c b/kernel/audit.c
index a8a91bd..b03b6c7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1325,10 +1325,10 @@ unsigned int audit_serial(void)
}
static inline void audit_get_stamp(struct audit_context *ctx,
- struct timespec *t, unsigned int *serial)
+ struct timespec64 *t, unsigned int *serial)
{
if (!ctx || !auditsc_get_stamp(ctx, t, serial)) {
- *t = CURRENT_TIME;
+ ktime_get_real_ts64(t);
*serial = audit_serial();
}
}
@@ -1370,7 +1370,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
int type)
{
struct audit_buffer *ab = NULL;
- struct timespec t;
+ struct timespec64 t;
unsigned int uninitialized_var(serial);
int reserve = 5; /* Allow atomic callers to go up to five
entries over the normal backlog limit */
@@ -1422,8 +1422,8 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
audit_get_stamp(ab->ctx, &t, &serial);
- audit_log_format(ab, "audit(%lu.%03lu:%u): ",
- t.tv_sec, t.tv_nsec/1000000, serial);
+ audit_log_format(ab, "audit(%llu.%03lu:%u): ",
+ (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
return ab;
}
diff --git a/kernel/audit.h b/kernel/audit.h
index 431444c..55d1ca2 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -112,7 +112,7 @@ struct audit_context {
enum audit_state state, current_state;
unsigned int serial; /* serial number for record */
int major; /* syscall number */
- struct timespec ctime; /* time of syscall entry */
+ struct timespec64 ctime; /* time of syscall entry */
unsigned long argv[4]; /* syscall arguments */
long return_code;/* syscall return code */
u64 prio;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 5abf1dc..8dc7fe9 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1522,7 +1522,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
return;
context->serial = 0;
- context->ctime = CURRENT_TIME;
+ ktime_get_real_ts64(&context->ctime);
context->in_syscall = 1;
context->current_state = state;
context->ppid = 0;
@@ -1931,13 +1931,13 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
/**
* auditsc_get_stamp - get local copies of audit_context values
* @ctx: audit_context for the task
- * @t: timespec to store time recorded in the audit_context
+ * @t: timespec64 to store time recorded in the audit_context
* @serial: serial value that is recorded in the audit_context
*
* Also sets the context as auditable.
*/
int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec *t, unsigned int *serial)
+ struct timespec64 *t, unsigned int *serial)
{
if (!ctx->in_syscall)
return 0;
--
2.7.4
struct timespec is not y2038 safe.
Use time64_t which is y2038 safe to represent orphan
scan times.
time64_t is sufficient here as only the seconds delta
times are relevant.
Also use appropriate time functions that return time in
time64_t format. Time functions now return monotonic
time instead of real time as only delta scan times are
relevant and these values are not persistent across
reboots.
The format string for the debug print is still using long
as this is only the time elapsed since the last scan and
long is sufficient to represent this value.
Signed-off-by: Deepa Dinamani <deepa.kernel(a)gmail.com>
Reviewed-by: Arnd Bergmann <arnd(a)arndb.de>
Cc: Mark Fasheh <mfasheh(a)suse.com>
Cc: Joel Becker <jlbec(a)evilplan.org>
Cc: ocfs2-devel(a)oss.oracle.com
---
fs/ocfs2/journal.c | 4 ++--
fs/ocfs2/ocfs2.h | 2 +-
fs/ocfs2/super.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index a244f14..d5e5fa7 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -1947,7 +1947,7 @@ static void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
*/
seqno++;
os->os_count++;
- os->os_scantime = CURRENT_TIME;
+ os->os_scantime = ktime_get_seconds();
unlock:
ocfs2_orphan_scan_unlock(osb, seqno);
out:
@@ -2004,7 +2004,7 @@ void ocfs2_orphan_scan_start(struct ocfs2_super *osb)
struct ocfs2_orphan_scan *os;
os = &osb->osb_orphan_scan;
- os->os_scantime = CURRENT_TIME;
+ os->os_scantime = ktime_get_seconds();
if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb))
atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE);
else {
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index e63af7d..7e5958b 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -224,7 +224,7 @@ struct ocfs2_orphan_scan {
struct ocfs2_super *os_osb;
struct ocfs2_lock_res os_lockres; /* lock to synchronize scans */
struct delayed_work os_orphan_scan_work;
- struct timespec os_scantime; /* time this node ran the scan */
+ time64_t os_scantime; /* time this node ran the scan */
u32 os_count; /* tracks node specific scans */
u32 os_seqno; /* tracks cluster wide scans */
atomic_t os_state; /* ACTIVE or INACTIVE */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 603b28d..bf3ca30 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -337,7 +337,7 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
out += snprintf(buf + out, len - out, "Disabled\n");
else
out += snprintf(buf + out, len - out, "%lu seconds ago\n",
- (get_seconds() - os->os_scantime.tv_sec));
+ (unsigned long)(ktime_get_seconds() - os->os_scantime));
out += snprintf(buf + out, len - out, "%10s => %3s %10s\n",
"Slots", "Num", "RecoGen");
--
2.7.4
btrfs_root_item maintains the ctime for root updates.
This is not part of vfs_inode.
Since current_time() uses struct inode* as an argument
as Linus suggested, this cannot be used to update root
times unless, we modify the signature to use inode.
Since btrfs uses nanosecond time granularity, it can also
use ktime_get_real_ts directly to obtain timestamp for
the root. It is necessary to use the timespec time api
here because the same btrfs_set_stack_timespec_*() apis
are used for vfs inode times as well. These can be
transitioned to using timespec64 when btrfs internally
changes to use timespec64 as well.
Signed-off-by: Deepa Dinamani <deepa.kernel(a)gmail.com>
Cc: Chris Mason <clm(a)fb.com>
Cc: David Sterba <dsterba(a)suse.com>
Cc: Josef Bacik <jbacik(a)fb.com>
Cc: linux-btrfs(a)vger.kernel.org
---
Changes from previous version:
* Separated from the current_time() api series.
* Moved ktime_get_real_ts() outside of spin lock.
fs/btrfs/root-tree.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 0912960..17e5a5f 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -505,8 +505,9 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
struct btrfs_root_item *item = &root->root_item;
- struct timespec ct = current_fs_time(root->fs_info->sb);
+ struct timespec ct;
+ ktime_get_real_ts(&ct);
spin_lock(&root->root_item_lock);
btrfs_set_root_ctransid(item, trans->transid);
btrfs_set_stack_timespec_sec(&item->ctime, ct.tv_sec);
--
2.7.4
This is in preparation for the change that transitions
filesystem timestamps to use 64 bit time and hence make
them y2038 safe.
CURRENT_TIME macro will be deleted before merging the
aforementioned patch.
Filesystems will use current_time() instead of
CURRENT_TIME.
Use ktime_get_real_seconds() here as this is not filesystem
time.
Only the seconds portion of the timestamp is necessary for
timezone calculation using server time.
Assume that the difference between server and client times
lie in the range INT_MIN..INT_MAX. This is valid because
this is the difference between current times between server
and client, and the largest timezone difference is in the
range of one day.
All cifs timestamps currently use timespec internally.
This timestamp can also be transitioned into using
timespec64 when all other timestamps for cifs is transitioned
to use timespec64.
Signed-off-by: Deepa Dinamani <deepa.kernel(a)gmail.com>
Reviewed-by: Arnd Bergmann <arnd(a)arndb.de>
Cc: Steve French <sfrench(a)samba.org>
---
fs/cifs/cifssmb.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d47197e..6c666a3 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -478,14 +478,14 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
* this requirement.
*/
int val, seconds, remain, result;
- struct timespec ts, utc;
- utc = CURRENT_TIME;
+ struct timespec ts;
+ unsigned long utc = ktime_get_real_seconds();
ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
rsp->SrvTime.Time, 0);
cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
- (int)ts.tv_sec, (int)utc.tv_sec,
- (int)(utc.tv_sec - ts.tv_sec));
- val = (int)(utc.tv_sec - ts.tv_sec);
+ (int)ts.tv_sec, (int)utc,
+ (int)(utc - ts.tv_sec));
+ val = (int)(utc - ts.tv_sec);
seconds = abs(val);
result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
remain = seconds % MIN_TZ_ADJ;
--
2.7.4
This is in preparation for the patch that transitions
vfs timestamps to use 64 bit time and hence make them
y2038 safe.
CURRENT_TIME macro will be deleted before merging the
aforementioned patch.
Filesystem times will use current_fs_time() instead of
CURRENT_TIME.
Use ktime_get_real_ts() here as this is not filesystem time.
ktime_get_real_ts() returns the timestamp in ns which can
be used to calculate network time for NTLMv2 authentication
timestamp.
All cifs timestamps currently use timespec internally.
This timestamp can also be transitioned into using
timespec64 when all other timestamps for cifs is transitioned
to use timespec64.
Signed-off-by: Deepa Dinamani <deepa.kernel(a)gmail.com>
Reviewed-by: Arnd Bergmann <arnd(a)arndb.de>
Cc: Steve French <sfrench(a)samba.org>
---
fs/cifs/cifsencrypt.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 8347c90..fd01bf0 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -471,6 +471,7 @@ find_timestamp(struct cifs_ses *ses)
unsigned char *blobptr;
unsigned char *blobend;
struct ntlmssp2_name *attrptr;
+ struct timespec ts;
if (!ses->auth_key.len || !ses->auth_key.response)
return 0;
@@ -495,7 +496,8 @@ find_timestamp(struct cifs_ses *ses)
blobptr += attrsize; /* advance attr value */
}
- return cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+ ktime_get_real_ts(&ts);
+ return cpu_to_le64(cifs_UnixTimeToNT(ts));
}
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
--
2.7.4
On Wednesday, June 22, 2016 12:58:38 AM CEST Albert ARIBAUD wrote:
> Hi all,
>
> I have produced a fourth draft of what will eventually become the Y2038
> design document:
>
> https://sourceware.org/glibc/wiki/Y2038ProofnessDesign?rev=83
>
> Relative to the previous draft:
>
> * the scope clarifies that *only* Y2038 is considered, and no other
> doomsday such as Y2106 or Y9999;
>
> * all types directly or indirectly derived from time_t are now listed;
>
> * all APIs using these types are now listed;
>
> * all functions which use time_t internally are now listed;
>
> * also listed are types and APIs related to time but which are
> Y2038-safe (even though they might be unsafe for some other
> doomsday, e.g. struct rpc_timeval being Y2106-unsafe).
>
> As always, comments welcome.
I've cross-checked your list of data structures with the one I have
for the kernel at
https://docs.google.com/spreadsheets/d/1HCYwHXxs48TsTb6IGUduNjQnmfRvMPzCN6T…
I noticed 'struct sysinfo' as another interface that holds a time,
even though this is documented as 'long' and I concluded that we
won't need to change it, that should probably be documented.
'struct rusage' is also interesting, as there is no overflow in 2038,
but instead it could overflow on large machines (hundreds of CPUs)
with very long-running tasks (months), so I'm unsure how to treat that
from the kernel side. It's also one of very few kernel interfaces using
'timeval' rather than 'timespec' (we generally replaced the other ones).
My current kernel patch series changes rusage by using 64-bit fields for
everything, with the intention of having the same binary layout for
32-bit and 64-bit processes, and reusing the 64-bit syscall entry point
for compat mode (running 32-bit tasks on a 64-bit kernel). Does that work
for you?
I think we should expand the ioctl section a bit: I can do most of it
in the kernel, but need help from glibc for a few things in which we
need to agree on calling conventions. Here is what I'd suggest having in
the document, feel free to take that into your document or edit as you
wish:
== IOCTLs and Y2038 ==
Some Linux IOCTLs may be Y2038-unsafe, or use types defined by glibc
that do not match the kernel internal types. Known important cases are:
- An ioctl command number is defined using the _IOR/_IOW/_IORW macros
by the kernel with a structure whose size changes based on glibc's
time_t. The kernel can handle these transparently by implementing
handlers for both command numbers with the correct structure format.
- The binary ABI changes based on the glibc time_t type, but the
command number does not change. In this case, the kernel header files
defining the data structure will check the "__USE_TIME_BITS64"
macro [do we need a new macro for the kernel headers?] to provide
a different command number for the new data structure layout. glibc
will define this macro at an appropriate location [where?] to make
it visible before including kernel header files.
- An ioctl command passes time information in a structure that is not
based on time_t but another integer type that does not get changed.
The kernel header files will provide both a new structure layout
and command number when "__USE_TIME_BITS64" is set.
[I can find examples for ioctl commands in each of those
categories if needed.]
== Socket options ==
Like ioctl(), setsockopt()/getsockopt() has a few interfaces that are
passing time data:
SO_TIMESTAMP/SO_TIMESTAMPNS/SO_TIMESTAMPING: These enable the
timestamping infrastructure for a socket, which will consecutively
return data to user space using "cmsg" data on the socket. The kernel
does not know the layout of 'struct timespec' and 'struct timeval'
when filling the cmsg data, so we need to define new binary values
for the three flags, which then get used if __USE_TIME_BITS64
is set.
SO_RCVTIMEO/SO_SNTTIMEO: These pass a 'struct timeval' and a length.
Assuming that the 'optlen' argument of the setsockopt syscall always
matches the size of 'struct timeval', the kernel will be able to
access the data in the same format that was passed by glibc. [alternatively,
we could handle this the same way as SO_TIMESTAMP*, using new numbers
for the flags].
[end quote]
Regarding the "Support for non-Y2038-safe kernels" section, I'm not
sure if that can work at all: A kernel that does not have the appropriate
system calls will also not have the handlers for a lot of the ioctl
commands and possibly other interfaces that rely on a specific
structure layout. If we can instead enforce that __USE_TIME_BITS64
is only set with a minimal version of kernel headers and that it
implies binary compatibility with no older kernel version, we could
avoid those problems.
On your note "The implementation needs further thinking about, as
application code defining _TIME_BITS=64 and gets built against
new kernel headers and old GLIBC headers, then GLIBC will use 32-bit
time_t and kernel will expect 64-bit time_t, and there is no way
to ensure detection of this case.", I think that is covered by
having the kernel headers check __USE_TIME_BITS64 instead of
_TIME_BITS=64, as I described above.
Arnd