aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-efi.c
diff options
context:
space:
mode:
authorJan Beulich <JBeulich@suse.com>2014-08-08 17:20:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 18:57:19 -0400
commit6e85bab6bc1019f9b87c53b32da3ad7791e7ddf9 (patch)
tree7f83156bdd6fa857286d224a3443dc5f481cbd74 /drivers/rtc/rtc-efi.c
parent3710f597aca5af4f605cda9793a8b2f0a42bc29a (diff)
drivers/rtc/rtc-efi.c: check for invalid data coming back from UEFI
In particular seeing zero in eft->month is problematic, as it results in -1 (converted to unsigned int, i.e. yielding 0xffffffff) getting passed to rtc_year_days(), where the value gets used as an array index (normally resulting in a crash). This was observed with the driver enabled on x86 on some Fujitsu system (with possibly not up to date firmware, but anyway). Perhaps efi_read_alarm() should not fail if neither enabled nor pending are set, but the returned time is invalid? Signed-off-by: Jan Beulich <jbeulich@suse.com> Reported-by: Raymund Will <rw@suse.de> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Jingoo Han <jg1.han@samsung.com> Acked-by: Lee, Chun-Yi <jlee@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-efi.c')
-rw-r--r--drivers/rtc/rtc-efi.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index c4c38431012e..8225b89de810 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -17,6 +17,7 @@
17 17
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/stringify.h>
20#include <linux/time.h> 21#include <linux/time.h>
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
22#include <linux/rtc.h> 23#include <linux/rtc.h>
@@ -48,8 +49,8 @@ compute_wday(efi_time_t *eft)
48 int y; 49 int y;
49 int ndays = 0; 50 int ndays = 0;
50 51
51 if (eft->year < 1998) { 52 if (eft->year < EFI_RTC_EPOCH) {
52 pr_err("EFI year < 1998, invalid date\n"); 53 pr_err("EFI year < " __stringify(EFI_RTC_EPOCH) ", invalid date\n");
53 return -1; 54 return -1;
54 } 55 }
55 56
@@ -78,19 +79,36 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
78 eft->timezone = EFI_UNSPECIFIED_TIMEZONE; 79 eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
79} 80}
80 81
81static void 82static bool
82convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) 83convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
83{ 84{
84 memset(wtime, 0, sizeof(*wtime)); 85 memset(wtime, 0, sizeof(*wtime));
86
87 if (eft->second >= 60)
88 return false;
85 wtime->tm_sec = eft->second; 89 wtime->tm_sec = eft->second;
90
91 if (eft->minute >= 60)
92 return false;
86 wtime->tm_min = eft->minute; 93 wtime->tm_min = eft->minute;
94
95 if (eft->hour >= 24)
96 return false;
87 wtime->tm_hour = eft->hour; 97 wtime->tm_hour = eft->hour;
98
99 if (!eft->day || eft->day > 31)
100 return false;
88 wtime->tm_mday = eft->day; 101 wtime->tm_mday = eft->day;
102
103 if (!eft->month || eft->month > 12)
104 return false;
89 wtime->tm_mon = eft->month - 1; 105 wtime->tm_mon = eft->month - 1;
90 wtime->tm_year = eft->year - 1900; 106 wtime->tm_year = eft->year - 1900;
91 107
92 /* day of the week [0-6], Sunday=0 */ 108 /* day of the week [0-6], Sunday=0 */
93 wtime->tm_wday = compute_wday(eft); 109 wtime->tm_wday = compute_wday(eft);
110 if (wtime->tm_wday < 0)
111 return false;
94 112
95 /* day in the year [1-365]*/ 113 /* day in the year [1-365]*/
96 wtime->tm_yday = compute_yday(eft); 114 wtime->tm_yday = compute_yday(eft);
@@ -106,6 +124,8 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
106 default: 124 default:
107 wtime->tm_isdst = -1; 125 wtime->tm_isdst = -1;
108 } 126 }
127
128 return true;
109} 129}
110 130
111static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) 131static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
@@ -122,7 +142,8 @@ static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
122 if (status != EFI_SUCCESS) 142 if (status != EFI_SUCCESS)
123 return -EINVAL; 143 return -EINVAL;
124 144
125 convert_from_efi_time(&eft, &wkalrm->time); 145 if (!convert_from_efi_time(&eft, &wkalrm->time))
146 return -EIO;
126 147
127 return rtc_valid_tm(&wkalrm->time); 148 return rtc_valid_tm(&wkalrm->time);
128} 149}
@@ -163,7 +184,8 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
163 return -EINVAL; 184 return -EINVAL;
164 } 185 }
165 186
166 convert_from_efi_time(&eft, tm); 187 if (!convert_from_efi_time(&eft, tm))
188 return -EIO;
167 189
168 return rtc_valid_tm(tm); 190 return rtc_valid_tm(tm);
169} 191}