Skip to content

Commit 0adc136

Browse files
Merge pull request #21 from NathanNeurotic/codex/replace-sprintf-with-snprintf-in-getmountinfo
Guard getMountInfo against buffer overflows
2 parents e256600 + 12b57a8 commit 0adc136

3 files changed

Lines changed: 95 additions & 40 deletions

File tree

include/util.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <stddef.h>
2+
13
/**
24
* @brief checks for file existence
35
* @param filepath path to the file to check
@@ -26,14 +28,17 @@ int get_CNF_string(char **CNF_p_p,
2628
char **value_p_p);
2729

2830
/**
29-
* @brief method returns true if it can extract needed info from path, otherwise false.
30-
* In case of true, it also updates mountString, mountPoint and newCWD parameters
31+
* @brief method returns 0 if it can extract needed info from path, otherwise a negative error code.
32+
* In case of success, it also updates mountString, mountPoint and newCWD parameters
3133
* It splits path by ":", and requires a minimum of 3 elements
3234
* @example if path = hdd0:__common:pfs:/retroarch/ then: mountString = "pfs:", mountPoint = "hdd0:__common", newCWD = pfs:/retroarch/
3335
* @param path input parameter with full hdd path (`hdd0:__common:pfs:/retroarch/`)
3436
* @param mountString pointer to char* wich will contain pfs mountpoint (`pfs:`)
37+
* @param mountStringSize total size of the mountString buffer
3538
* @param mountPoint returns the path of mounted partition (`hdd0:__common`)
39+
* @param mountPointSize total size of the mountPoint buffer
3640
* @param newCWD returns the path to the file as pfs mount point string
37-
* @return true on success
41+
* @param newCWDSize total size of the newCWD buffer
42+
* @return 0 on success, negative error code on failure or truncation
3843
*/
39-
int getMountInfo(char *path, char *mountString, char *mountPoint, char *newCWD);
44+
int getMountInfo(char *path, char *mountString, size_t mountStringSize, char *mountPoint, size_t mountPointSize, char *newCWD, size_t newCWDSize);

src/main.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <errno.h>
2+
13
#include "main.h"
24
// --------------- glob stuff --------------- //
35
#define RUNKELF_ARG_BUF_SIZE 64
@@ -1296,16 +1298,29 @@ int MountParty(const char *path)
12961298
DPRINTF("%s: %s\n", __func__, path);
12971299
char *BUF = NULL;
12981300
BUF = strdup(path); //use strdup, otherwise, path will become `hdd0:`
1299-
char MountPoint[40];
1300-
if (getMountInfo(BUF, NULL, MountPoint, NULL)) {
1301-
mnt(MountPoint);
1302-
if (BUF != NULL)
1303-
free(BUF);
1304-
strcpy(PART, MountPoint);
1305-
strcat(PART, ":");
1306-
return 0;
1301+
if (BUF == NULL) {
1302+
DPRINTF("ERROR: could not duplicate path '%s'\n", path);
1303+
return ret;
1304+
}
1305+
char MountPoint[sizeof(PART)];
1306+
int mountInfoRet = getMountInfo(BUF, NULL, 0, MountPoint, sizeof(MountPoint), NULL, 0);
1307+
if (mountInfoRet == 0) {
1308+
ret = mnt(MountPoint);
1309+
if (ret == 0) {
1310+
int part_written = snprintf(PART, sizeof(PART), "%s:", MountPoint);
1311+
if (part_written < 0 || (size_t)part_written >= sizeof(PART)) {
1312+
DPRINTF("ERROR: partition path too long for PART buffer\n");
1313+
PART[0] = '\0';
1314+
ret = -ENAMETOOLONG;
1315+
} else {
1316+
free(BUF);
1317+
return 0;
1318+
}
1319+
}
13071320
} else {
1308-
DPRINTF("ERROR: could not process path '%s'\n", path);
1321+
DPRINTF("ERROR: could not process path '%s' (err=%d)\n", path, mountInfoRet);
1322+
if (mountInfoRet == -ENAMETOOLONG)
1323+
DPRINTF("Path components exceed buffer limits and were rejected\n");
13091324
PART[0] = '\0';
13101325
}
13111326
if (BUF != NULL)

src/util.c

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <errno.h>
12
#include <stdio.h>
23
#include <string.h>
34
#include <fcntl.h>
@@ -138,52 +139,86 @@ char **str_split(char *a_str, const char a_delim)
138139
}
139140

140141
/**
141-
* @brief method returns true if it can extract needed info from path, otherwise false.
142-
* In case of true, it also updates mountString, mountPoint and newCWD parameters
142+
* @brief method returns 0 if it can extract needed info from path, otherwise a negative error code.
143+
* In case of success, it also updates mountString, mountPoint and newCWD parameters
143144
* It splits path by ":", and requires a minimum of 3 elements
144145
* Example: if path = hdd0:__common:pfs:/retroarch/ then
145146
* mountString = "pfs:"
146147
* mountPoint = "hdd0:__common"
147148
* newCWD = pfs:/retroarch/
148-
* return true
149+
* return 0 on success, negative error code on failure
149150
*/
150-
int getMountInfo(char *path, char *mountString, char *mountPoint, char *newCWD)
151+
int getMountInfo(char *path, char *mountString, size_t mountStringSize, char *mountPoint, size_t mountPointSize, char *newCWD, size_t newCWDSize)
151152
{
152-
int expected_items = 4;
153153
int i = 0;
154-
char *items[expected_items];
155154
char **tokens = str_split(path, ':');
155+
int ret = -EINVAL;
156156

157157
if (!tokens)
158-
return 0;
158+
return -ENOMEM;
159159

160-
for (i = 0; *(tokens + i); i++) {
161-
if (i < expected_items) {
162-
items[i] = *(tokens + i);
163-
} else {
164-
free(*(tokens + i));
165-
}
166-
}
160+
for (i = 0; *(tokens + i); i++)
161+
;
167162

168163
if (i < 3)
169-
return 0;
164+
goto cleanup;
170165

171-
if (mountPoint != NULL)
172-
sprintf(mountPoint, "%s:%s", items[0], items[1]);
166+
if (mountPoint != NULL) {
167+
if (mountPointSize == 0) {
168+
ret = -ENAMETOOLONG;
169+
goto cleanup;
170+
}
171+
int written = snprintf(mountPoint, mountPointSize, "%s:%s", tokens[0], tokens[1]);
172+
if (written < 0) {
173+
ret = -EIO;
174+
goto cleanup;
175+
}
176+
if ((size_t)written >= mountPointSize) {
177+
ret = -ENAMETOOLONG;
178+
goto cleanup;
179+
}
180+
}
173181

174-
if (mountString != NULL)
175-
sprintf(mountString, "%s:", items[2]);
182+
if (mountString != NULL) {
183+
if (mountStringSize == 0) {
184+
ret = -ENAMETOOLONG;
185+
goto cleanup;
186+
}
187+
int written = snprintf(mountString, mountStringSize, "%s:", tokens[2]);
188+
if (written < 0) {
189+
ret = -EIO;
190+
goto cleanup;
191+
}
192+
if ((size_t)written >= mountStringSize) {
193+
ret = -ENAMETOOLONG;
194+
goto cleanup;
195+
}
196+
}
176197

177-
if (newCWD != NULL)
178-
sprintf(newCWD, "%s:%s", items[2], i > 3 ? items[3] : "");
198+
if (newCWD != NULL) {
199+
if (newCWDSize == 0) {
200+
ret = -ENAMETOOLONG;
201+
goto cleanup;
202+
}
203+
int written = snprintf(newCWD, newCWDSize, "%s:%s", tokens[2], i > 3 ? tokens[3] : "");
204+
if (written < 0) {
205+
ret = -EIO;
206+
goto cleanup;
207+
}
208+
if ((size_t)written >= newCWDSize) {
209+
ret = -ENAMETOOLONG;
210+
goto cleanup;
211+
}
212+
}
179213

180-
free(items[0]);
181-
free(items[1]);
182-
free(items[2]);
214+
ret = 0;
183215

184-
if (i > 3)
185-
free(items[3]);
216+
cleanup:
217+
for (int idx = 0; *(tokens + idx); idx++) {
218+
free(*(tokens + idx));
219+
}
220+
free(tokens);
186221

187-
return 1;
222+
return ret;
188223
}
189224
#endif

0 commit comments

Comments
 (0)