From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Wed, 14 Apr 2021 11:07:21 +0200 Subject: [PATCH] fs: Use 64bit type for filesystem timestamp Some filesystems nowadays uses 64bit types for timestamps, so, update grub_dirhook_info struct to use an int64 type to store mtime. This also updates grub_unixtime2datetime() to receive a 64-bit timestamp argument and do 64bit-safe divisions. All the remaining conversion from 32 to 64 should be safe, as 32 to 64 attributions will be implicitly casted. The most crictical part in the 32 to 64bits conversion is on grub_unixtime2datetime() where it needs to deal with the 64bit type, specially with division in x86_architectures, so, for that, the grub_divmod64() helper has been used. These changes enables grub to support dates beyond y2038. Reviewed-by: Javier Martinez Canillas Signed-off-by: Carlos Maiolino --- grub-core/fs/affs.c | 2 +- grub-core/fs/ext2.c | 2 +- grub-core/fs/fat.c | 4 ++-- grub-core/fs/hfs.c | 2 +- grub-core/fs/hfsplus.c | 2 +- grub-core/fs/iso9660.c | 6 +++--- grub-core/fs/nilfs2.c | 2 +- grub-core/fs/squash4.c | 2 +- grub-core/fs/ufs.c | 2 +- grub-core/fs/zfs/zfs.c | 2 +- grub-core/lib/datetime.c | 15 ++++++++++++--- grub-core/net/bootp.c | 2 +- grub-core/normal/misc.c | 2 +- grub-core/tests/sleep_test.c | 4 ++-- include/grub/datetime.h | 4 ++-- include/grub/fs.h | 4 ++-- 16 files changed, 33 insertions(+), 24 deletions(-) diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index 230e26af0f8..cafcd0fba91 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -641,7 +641,7 @@ grub_affs_label (grub_device_t device, char **label) } static grub_err_t -grub_affs_mtime (grub_device_t device, grub_int32_t *t) +grub_affs_mtime (grub_device_t device, grub_int64_t *t) { struct grub_affs_data *data; grub_disk_t disk = device->disk; diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c index 848bf939dba..e7dd78e6635 100644 --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@ -1055,7 +1055,7 @@ grub_ext2_uuid (grub_device_t device, char **uuid) /* Get mtime. */ static grub_err_t -grub_ext2_mtime (grub_device_t device, grub_int32_t *tm) +grub_ext2_mtime (grub_device_t device, grub_int64_t *tm) { struct grub_ext2_data *data; grub_disk_t disk = device->disk; diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c index 7f775a17038..dd82e4ee35d 100644 --- a/grub-core/fs/fat.c +++ b/grub-core/fs/fat.c @@ -737,7 +737,7 @@ grub_fat_iterate_dir_next (grub_fshelp_node_t node, * https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification */ static int -grub_exfat_timestamp (grub_uint32_t field, grub_uint8_t msec, grub_int32_t *nix) { +grub_exfat_timestamp (grub_uint32_t field, grub_uint8_t msec, grub_int64_t *nix) { struct grub_datetime datetime = { .year = (field >> 25) + 1980, .month = (field & 0x01E00000) >> 21, @@ -891,7 +891,7 @@ grub_fat_iterate_dir_next (grub_fshelp_node_t node, * https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-107.pdf */ static int -grub_fat_timestamp (grub_uint16_t time, grub_uint16_t date, grub_int32_t *nix) { +grub_fat_timestamp (grub_uint16_t time, grub_uint16_t date, grub_int64_t *nix) { struct grub_datetime datetime = { .year = (date >> 9) + 1980, .month = (date & 0x01E0) >> 5, diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c index 9a5b7bbe906..f419965d154 100644 --- a/grub-core/fs/hfs.c +++ b/grub-core/fs/hfs.c @@ -1374,7 +1374,7 @@ grub_hfs_label (grub_device_t device, char **label) } static grub_err_t -grub_hfs_mtime (grub_device_t device, grub_int32_t *tm) +grub_hfs_mtime (grub_device_t device, grub_int64_t *tm) { struct grub_hfs_data *data; diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c index 2a69055c7ec..19c7b336798 100644 --- a/grub-core/fs/hfsplus.c +++ b/grub-core/fs/hfsplus.c @@ -1083,7 +1083,7 @@ grub_hfsplus_label (grub_device_t device, char **label) /* Get mtime. */ static grub_err_t -grub_hfsplus_mtime (grub_device_t device, grub_int32_t *tm) +grub_hfsplus_mtime (grub_device_t device, grub_int64_t *tm) { struct grub_hfsplus_data *data; grub_disk_t disk = device->disk; diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c index 5ec4433b8f8..ac011950a64 100644 --- a/grub-core/fs/iso9660.c +++ b/grub-core/fs/iso9660.c @@ -178,7 +178,7 @@ static grub_dl_t my_mod; static grub_err_t -iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix) +iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int64_t *nix) { struct grub_datetime datetime; @@ -206,7 +206,7 @@ iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix) } static int -iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix) +iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int64_t *nix) { struct grub_datetime datetime; @@ -1107,7 +1107,7 @@ grub_iso9660_uuid (grub_device_t device, char **uuid) /* Get writing time of filesystem. */ static grub_err_t -grub_iso9660_mtime (grub_device_t device, grub_int32_t *timebuf) +grub_iso9660_mtime (grub_device_t device, grub_int64_t *timebuf) { struct grub_iso9660_data *data; grub_disk_t disk = device->disk; diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c index 9b76982b3b0..3c248a910b4 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -1186,7 +1186,7 @@ grub_nilfs2_uuid (grub_device_t device, char **uuid) /* Get mtime. */ static grub_err_t -grub_nilfs2_mtime (grub_device_t device, grub_int32_t * tm) +grub_nilfs2_mtime (grub_device_t device, grub_int64_t * tm) { struct grub_nilfs2_data *data; grub_disk_t disk = device->disk; diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c index a5f35c10e2f..6dd731e231e 100644 --- a/grub-core/fs/squash4.c +++ b/grub-core/fs/squash4.c @@ -1003,7 +1003,7 @@ grub_squash_close (grub_file_t file) } static grub_err_t -grub_squash_mtime (grub_device_t dev, grub_int32_t *tm) +grub_squash_mtime (grub_device_t dev, grub_int64_t *tm) { struct grub_squash_data *data = 0; diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c index fca46baa19d..34a698b71b8 100644 --- a/grub-core/fs/ufs.c +++ b/grub-core/fs/ufs.c @@ -837,7 +837,7 @@ grub_ufs_uuid (grub_device_t device, char **uuid) /* Get mtime. */ static grub_err_t -grub_ufs_mtime (grub_device_t device, grub_int32_t *tm) +grub_ufs_mtime (grub_device_t device, grub_int64_t *tm) { struct grub_ufs_data *data = 0; diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index f9e755197c5..cf4d2ab189a 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -3771,7 +3771,7 @@ zfs_uuid (grub_device_t device, char **uuid) } static grub_err_t -zfs_mtime (grub_device_t device, grub_int32_t *mt) +zfs_mtime (grub_device_t device, grub_int64_t *mt) { struct grub_zfs_data *data; grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c index 95b8c9ff5e3..3e84fa1dbc4 100644 --- a/grub-core/lib/datetime.c +++ b/grub-core/lib/datetime.c @@ -19,6 +19,7 @@ #include #include +#include static const char *const grub_weekday_names[] = { @@ -60,9 +61,10 @@ grub_get_weekday_name (struct grub_datetime *datetime) void -grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime) +grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime) { int i; + grub_uint64_t rem; grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* In the period of validity of unixtime all years divisible by 4 are bissextile*/ @@ -75,9 +77,16 @@ grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime) unsigned secs_in_day; /* Transform C divisions and modulos to mathematical ones */ if (nix < 0) - days_epoch = -(((unsigned) (SECPERDAY-nix-1)) / SECPERDAY); + /* + * the division here shouldn't be larger than INT_MAX, + * so, it's safe to store the result back in an int + */ + days_epoch = -(grub_divmod64(((grub_int64_t)(SECPERDAY) - nix - 1), + SECPERDAY, + &rem)); else - days_epoch = ((unsigned) nix) / SECPERDAY; + days_epoch = grub_divmod64(nix, SECPERDAY, &rem); + secs_in_day = nix - days_epoch * SECPERDAY; days = days_epoch + 69 * DAYSPERYEAR + 17; diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 8f2f55c0079..7baf3540c81 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -610,7 +610,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) grub_err_t err; struct grub_net_bootp_packet *pack; struct grub_datetime date; - grub_int32_t t = 0; + grub_int64_t t = 0; struct grub_net_buff *nb; struct udphdr *udph; grub_net_network_level_address_t target; diff --git a/grub-core/normal/misc.c b/grub-core/normal/misc.c index 8bb6da31fb3..f7e9e3ac4a1 100644 --- a/grub-core/normal/misc.c +++ b/grub-core/normal/misc.c @@ -136,7 +136,7 @@ grub_normal_print_device_info (const char *name) } if (fs->fs_mtime) { - grub_int32_t tm; + grub_int64_t tm; struct grub_datetime datetime; (fs->fs_mtime) (dev, &tm); if (grub_errno == GRUB_ERR_NONE) diff --git a/grub-core/tests/sleep_test.c b/grub-core/tests/sleep_test.c index 3d11c717cb7..63f6713165f 100644 --- a/grub-core/tests/sleep_test.c +++ b/grub-core/tests/sleep_test.c @@ -32,7 +32,7 @@ static void sleep_test (void) { struct grub_datetime st, en; - grub_int32_t stu = 0, enu = 0; + grub_int64_t stu = 0, enu = 0; int is_delayok; grub_test_assert (!grub_get_datetime (&st), "Couldn't retrieve start time"); grub_millisleep (10000); @@ -45,7 +45,7 @@ sleep_test (void) if (enu - stu >= 15 && enu - stu <= 17) is_delayok = 1; #endif - grub_test_assert (is_delayok, "Interval out of range: %d", enu-stu); + grub_test_assert (is_delayok, "Interval out of range: %lld", enu-stu); } diff --git a/include/grub/datetime.h b/include/grub/datetime.h index fef281404d7..23ae0791ced 100644 --- a/include/grub/datetime.h +++ b/include/grub/datetime.h @@ -48,11 +48,11 @@ grub_err_t grub_set_datetime (struct grub_datetime *datetime); int grub_get_weekday (struct grub_datetime *datetime); const char *grub_get_weekday_name (struct grub_datetime *datetime); -void grub_unixtime2datetime (grub_int32_t nix, +void grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime); static inline int -grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int32_t *nix) +grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int64_t *nix) { grub_int32_t ret; int y4, ay; diff --git a/include/grub/fs.h b/include/grub/fs.h index 302e48d4b50..026bc3bb861 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -39,7 +39,7 @@ struct grub_dirhook_info unsigned mtimeset:1; unsigned case_insensitive:1; unsigned inodeset:1; - grub_int32_t mtime; + grub_int64_t mtime; grub_uint64_t inode; }; @@ -81,7 +81,7 @@ struct grub_fs grub_err_t (*fs_uuid) (grub_device_t device, char **uuid); /* Get writing time of filesystem. */ - grub_err_t (*fs_mtime) (grub_device_t device, grub_int32_t *timebuf); + grub_err_t (*fs_mtime) (grub_device_t device, grub_int64_t *timebuf); #ifdef GRUB_UTIL /* Determine sectors available for embedding. */