Skip to content

Commit ba82092

Browse files
committed
common: validate PLIST_DATE values before Time64_T conversion
Avoid undefined behavior when serializing malformed PLIST_DATE values containing NaN, infinity, or values outside the Time64_T range. Add a shared helper for checked date conversion and use it across writer paths.
1 parent 9711459 commit ba82092

9 files changed

Lines changed: 48 additions & 6 deletions

File tree

src/common.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,18 @@ int num_digits_u(uint64_t i)
9898
return n;
9999
}
100100
#undef PO10u_LIMIT
101+
102+
int plist_real_to_time64(double realval, Time64_T *timev)
103+
{
104+
if (!timev || !isfinite(realval)) {
105+
return -1;
106+
}
107+
108+
if (realval < (double)TIME64_MIN - (double)MAC_EPOCH ||
109+
realval > (double)TIME64_MAX - (double)MAC_EPOCH) {
110+
return -1;
111+
}
112+
113+
*timev = (Time64_T)realval + MAC_EPOCH;
114+
return 0;
115+
}

src/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
#define COMMON_H
2323

2424
#include <stddef.h>
25+
#include "time64.h"
2526

2627
#define MAC_EPOCH 978307200
2728

2829
size_t dtostr(char *buf, size_t bufsize, double realval);
2930
int num_digits_i(int64_t i);
3031
int num_digits_u(uint64_t i);
32+
int plist_real_to_time64(double realval, Time64_T *timev);
3133

3234
#endif

src/jplist.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,10 @@ static plist_err_t node_to_json(node_t node, bytearray_t **outbuf, uint32_t dept
257257
break;
258258
case PLIST_DATE:
259259
if (coerce) {
260-
Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
260+
Time64_T timev;
261+
if (plist_real_to_time64(node_data->realval, &timev) < 0) {
262+
return PLIST_ERR_INVALID_ARG;
263+
}
261264
struct TM _btime;
262265
struct TM *btime = gmtime64_r(&timev, &_btime);
263266
char datebuf[32];

src/oplist.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,10 @@ static plist_err_t node_to_openstep(node_t node, bytearray_t **outbuf, uint32_t
301301
break;
302302
case PLIST_DATE:
303303
if (coerce) {
304-
Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
304+
Time64_T timev;
305+
if (plist_real_to_time64(node_data->realval, &timev) < 0) {
306+
return PLIST_ERR_INVALID_ARG;
307+
}
305308
struct TM _btime;
306309
struct TM *btime = gmtime64_r(&timev, &_btime);
307310
char datebuf[32];

src/out-default.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,10 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
231231
break;
232232
case PLIST_DATE:
233233
{
234-
Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
234+
Time64_T timev;
235+
if (plist_real_to_time64(node_data->realval, &timev) < 0) {
236+
return PLIST_ERR_INVALID_ARG;
237+
}
235238
struct TM _btime;
236239
struct TM *btime = gmtime64_r(&timev, &_btime);
237240
if (btime) {

src/out-limd.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
220220
break;
221221
case PLIST_DATE:
222222
{
223-
Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
223+
Time64_T timev;
224+
if (plist_real_to_time64(node_data->realval, &timev) < 0) {
225+
return PLIST_ERR_INVALID_ARG;
226+
}
224227
struct TM _btime;
225228
struct TM *btime = gmtime64_r(&timev, &_btime);
226229
if (btime) {

src/out-plutil.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,10 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
237237
break;
238238
case PLIST_DATE:
239239
{
240-
Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
240+
Time64_T timev;
241+
if (plist_real_to_time64(node_data->realval, &timev) < 0) {
242+
return PLIST_ERR_INVALID_ARG;
243+
}
241244
struct TM _btime;
242245
struct TM *btime = gmtime64_r(&timev, &_btime);
243246
if (btime) {

src/time64.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ typedef long long Int64;
1111
typedef Int64 Time64_T;
1212
typedef Int64 Year;
1313

14+
#ifndef TIME64_MIN
15+
#define TIME64_MIN ((Time64_T)INT64_MIN)
16+
#endif
17+
18+
#ifndef TIME64_MAX
19+
#define TIME64_MAX ((Time64_T)INT64_MAX)
20+
#endif
1421

1522
/* A copy of the tm struct but with a 64 bit year */
1623
struct TM64 {

src/xplist.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth
192192
tag = XPLIST_DATE;
193193
tag_len = XPLIST_DATE_LEN;
194194
{
195-
Time64_T timev = (Time64_T)node_data->realval + MAC_EPOCH;
195+
Time64_T timev;
196+
if (plist_real_to_time64(node_data->realval, &timev) < 0) {
197+
return PLIST_ERR_INVALID_ARG;
198+
}
196199
struct TM _btime;
197200
struct TM *btime = gmtime64_r(&timev, &_btime);
198201
if (btime) {

0 commit comments

Comments
 (0)