summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2026-05-22 16:37:57 +0200
committerGravatar Nikias Bassen2026-05-22 16:37:57 +0200
commit389fab9a07baf3913c4214425e86cca588d559a1 (patch)
tree79194d9bf12f11ac788c6ac7c8512c69ede90ed9 /src
parent5546a8746558d088d90ba8f6cb52a50f886c9572 (diff)
downloadlibplist-389fab9a07baf3913c4214425e86cca588d559a1.tar.gz
libplist-389fab9a07baf3913c4214425e86cca588d559a1.tar.bz2
out-default: harden node serialization paths
Improve robustness and memory safety in node_to_string() and dtostr(): - add missing NULL and allocation checks - fix snprintf() error handling and signed/unsigned conversions - replace sprintf() with snprintf() - fix base64 buffer sizing - switch string offset tracking to size_t - improve malformed data handling for strings and data blobs
Diffstat (limited to 'src')
-rw-r--r--src/out-default.c86
1 files changed, 63 insertions, 23 deletions
diff --git a/src/out-default.c b/src/out-default.c
index fb57bcf..676a677 100644
--- a/src/out-default.c
+++ b/src/out-default.c
@@ -44,17 +44,27 @@
44 44
45static size_t dtostr(char *buf, size_t bufsize, double realval) 45static size_t dtostr(char *buf, size_t bufsize, double realval)
46{ 46{
47 size_t len = 0; 47 int slen = 0;
48 if (isnan(realval)) { 48 if (isnan(realval)) {
49 len = snprintf(buf, bufsize, "nan"); 49 slen = snprintf(buf, bufsize, "nan");
50 } else if (isinf(realval)) { 50 } else if (isinf(realval)) {
51 len = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-'); 51 slen = snprintf(buf, bufsize, "%cinfinity", (realval > 0.0) ? '+' : '-');
52 } else if (realval == 0.0f) { 52 } else if (realval == 0.0f) {
53 len = snprintf(buf, bufsize, "0.0"); 53 slen = snprintf(buf, bufsize, "0.0");
54 } else { 54 } else {
55 slen = snprintf(buf, bufsize, "%.*g", 17, realval);
56 if (slen < 0) {
57 return 0;
58 }
59 if (!buf || bufsize == 0) {
60 return (size_t)slen;
61 }
62 size_t len = (size_t)slen;
63 if (len >= bufsize) {
64 len = bufsize - 1;
65 }
55 size_t i = 0; 66 size_t i = 0;
56 len = snprintf(buf, bufsize, "%.*g", 17, realval); 67 for (i = 0; i < len; i++) {
57 for (i = 0; buf && i < len; i++) {
58 if (buf[i] == ',') { 68 if (buf[i] == ',') {
59 buf[i] = '.'; 69 buf[i] = '.';
60 break; 70 break;
@@ -62,8 +72,12 @@ static size_t dtostr(char *buf, size_t bufsize, double realval)
62 break; 72 break;
63 } 73 }
64 } 74 }
75 return len;
76 }
77 if (slen < 0) {
78 return 0;
65 } 79 }
66 return len; 80 return (size_t)slen;
67} 81}
68 82
69static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent, int partial_data) 83static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t depth, uint32_t indent, int partial_data)
@@ -71,14 +85,19 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
71 plist_data_t node_data = NULL; 85 plist_data_t node_data = NULL;
72 86
73 char *val = NULL; 87 char *val = NULL;
88 int slen = 0;
74 size_t val_len = 0; 89 size_t val_len = 0;
75 90
76 uint32_t i = 0; 91 uint32_t i = 0;
77 92
78 if (!node) 93 if (!node || !outbuf || !*outbuf) {
79 return PLIST_ERR_INVALID_ARG; 94 return PLIST_ERR_INVALID_ARG;
95 }
80 96
81 node_data = plist_get_data(node); 97 node_data = plist_get_data(node);
98 if (!node_data) {
99 return PLIST_ERR_INVALID_ARG;
100 }
82 101
83 switch (node_data->type) 102 switch (node_data->type)
84 { 103 {
@@ -98,17 +117,24 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
98 117
99 case PLIST_INT: 118 case PLIST_INT:
100 val = (char*)malloc(64); 119 val = (char*)malloc(64);
120 if (!val) return PLIST_ERR_NO_MEM;
101 if (node_data->length == 16) { 121 if (node_data->length == 16) {
102 val_len = snprintf(val, 64, "%" PRIu64, node_data->intval); 122 slen = snprintf(val, 64, "%" PRIu64, node_data->intval);
103 } else { 123 } else {
104 val_len = snprintf(val, 64, "%" PRIi64, node_data->intval); 124 slen = snprintf(val, 64, "%" PRIi64, node_data->intval);
105 } 125 }
126 if (slen < 0) {
127 free(val);
128 return PLIST_ERR_UNKNOWN;
129 }
130 val_len = (size_t)slen;
106 str_buf_append(*outbuf, val, val_len); 131 str_buf_append(*outbuf, val, val_len);
107 free(val); 132 free(val);
108 break; 133 break;
109 134
110 case PLIST_REAL: 135 case PLIST_REAL:
111 val = (char*)malloc(64); 136 val = (char*)malloc(64);
137 if (!val) return PLIST_ERR_NO_MEM;
112 val_len = dtostr(val, 64, node_data->realval); 138 val_len = dtostr(val, 64, node_data->realval);
113 str_buf_append(*outbuf, val, val_len); 139 str_buf_append(*outbuf, val, val_len);
114 free(val); 140 free(val);
@@ -116,6 +142,9 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
116 142
117 case PLIST_STRING: 143 case PLIST_STRING:
118 case PLIST_KEY: { 144 case PLIST_KEY: {
145 if (!node_data->strval && node_data->length > 0) {
146 return PLIST_ERR_INVALID_ARG;
147 }
119 const char *charmap[32] = { 148 const char *charmap[32] = {
120 "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", 149 "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
121 "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", 150 "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f",
@@ -124,8 +153,8 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
124 }; 153 };
125 size_t j = 0; 154 size_t j = 0;
126 size_t len = 0; 155 size_t len = 0;
127 off_t start = 0; 156 size_t start = 0;
128 off_t cur = 0; 157 size_t cur = 0;
129 158
130 str_buf_append(*outbuf, "\"", 1); 159 str_buf_append(*outbuf, "\"", 1);
131 160
@@ -207,28 +236,32 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
207 } break; 236 } break;
208 case PLIST_DATA: 237 case PLIST_DATA:
209 { 238 {
239 if (!node_data->buff && node_data->length > 0) {
240 return PLIST_ERR_INVALID_ARG;
241 }
210 str_buf_append(*outbuf, "<", 1); 242 str_buf_append(*outbuf, "<", 1);
211 size_t len = node_data->length; 243 size_t len = node_data->length;
212 char charb[4]; 244 char charb[4];
245 size_t j;
213 if (!partial_data || len <= 24) { 246 if (!partial_data || len <= 24) {
214 for (i = 0; i < len; i++) { 247 for (j = 0; j < len; j++) {
215 if (i > 0 && (i % 4 == 0)) 248 if (j > 0 && (j % 4 == 0))
216 str_buf_append(*outbuf, " ", 1); 249 str_buf_append(*outbuf, " ", 1);
217 sprintf(charb, "%02x", (unsigned char)node_data->buff[i]); 250 snprintf(charb, sizeof(charb), "%02x", (unsigned char)node_data->buff[j]);
218 str_buf_append(*outbuf, charb, 2); 251 str_buf_append(*outbuf, charb, 2);
219 } 252 }
220 } else { 253 } else {
221 for (i = 0; i < 16; i++) { 254 for (j = 0; j < 16; j++) {
222 if (i > 0 && (i % 4 == 0)) 255 if (j > 0 && (j % 4 == 0))
223 str_buf_append(*outbuf, " ", 1); 256 str_buf_append(*outbuf, " ", 1);
224 sprintf(charb, "%02x", (unsigned char)node_data->buff[i]); 257 snprintf(charb, sizeof(charb), "%02x", (unsigned char)node_data->buff[j]);
225 str_buf_append(*outbuf, charb, 2); 258 str_buf_append(*outbuf, charb, 2);
226 } 259 }
227 str_buf_append(*outbuf, " ... ", 5); 260 str_buf_append(*outbuf, " ... ", 5);
228 for (i = len - 8; i < len; i++) { 261 for (j = len - 8; j < len; j++) {
229 sprintf(charb, "%02x", (unsigned char)node_data->buff[i]); 262 snprintf(charb, sizeof(charb), "%02x", (unsigned char)node_data->buff[j]);
230 str_buf_append(*outbuf, charb, 2); 263 str_buf_append(*outbuf, charb, 2);
231 if (i > 0 && i < len-1 && (i % 4 == 0)) 264 if (j > 0 && j < len-1 && (j % 4 == 0))
232 str_buf_append(*outbuf, " ", 1); 265 str_buf_append(*outbuf, " ", 1);
233 } 266 }
234 } 267 }
@@ -242,6 +275,7 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
242 struct TM *btime = gmtime64_r(&timev, &_btime); 275 struct TM *btime = gmtime64_r(&timev, &_btime);
243 if (btime) { 276 if (btime) {
244 val = (char*)calloc(1, 26); 277 val = (char*)calloc(1, 26);
278 if (!val) return PLIST_ERR_NO_MEM;
245 struct tm _tmcopy; 279 struct tm _tmcopy;
246 copy_TM64_to_tm(btime, &_tmcopy); 280 copy_TM64_to_tm(btime, &_tmcopy);
247 val_len = strftime(val, 26, "%Y-%m-%d %H:%M:%S +0000", &_tmcopy); 281 val_len = strftime(val, 26, "%Y-%m-%d %H:%M:%S +0000", &_tmcopy);
@@ -257,11 +291,17 @@ static plist_err_t node_to_string(node_t node, bytearray_t **outbuf, uint32_t de
257 { 291 {
258 str_buf_append(*outbuf, "CF$UID:", 7); 292 str_buf_append(*outbuf, "CF$UID:", 7);
259 val = (char*)malloc(64); 293 val = (char*)malloc(64);
294 if (!val) return PLIST_ERR_NO_MEM;
260 if (node_data->length == 16) { 295 if (node_data->length == 16) {
261 val_len = snprintf(val, 64, "%" PRIu64, node_data->intval); 296 slen = snprintf(val, 64, "%" PRIu64, node_data->intval);
262 } else { 297 } else {
263 val_len = snprintf(val, 64, "%" PRIi64, node_data->intval); 298 slen = snprintf(val, 64, "%" PRIi64, node_data->intval);
299 }
300 if (slen < 0) {
301 free(val);
302 return PLIST_ERR_UNKNOWN;
264 } 303 }
304 val_len = (size_t)slen;
265 str_buf_append(*outbuf, val, val_len); 305 str_buf_append(*outbuf, val, val_len);
266 free(val); 306 free(val);
267 } 307 }