On 09/22/18 at 09:16pm, morganamilo wrote:
in the function query_fileowner, if the user enters a string longer than PATH_MAX then rpath will buffer overflow when lrealpath tries to strcat everything together.
Even if we made sure filename was never longer than PATH_MAX this would not help because lrealpath may concatenate filename with the current directory among other things.
So simply let lrealpath calculate the size needed and allocate it for us.
This also fixes the compiler warning; query.c: In function ‘query_fileowner’: query.c:192:4: warning: ‘strncpy’ specified bound 4096 equals destination size [-Wstringop-truncation] strncpy(rpath, filename, PATH_MAX);
The warning could have also been Fixed by using PATH_MAX -1 and explicitly terminating the string. However this would not fix the buffer overflow.
Signed-off-by: morganamilo <morganamilo@gmail.com>
diff --git a/src/pacman/query.c b/src/pacman/query.c index 00c39638..a1197cea 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -155,10 +155,10 @@ static int query_fileowner(alpm_list_t *targets)
for(t = targets; t; t = alpm_list_next(t)) { char *filename = NULL; - char rpath[PATH_MAX], *rel_path; + char *rpath = NULL, *rpathsave, *rel_path; struct stat buf; alpm_list_t *i; - size_t len; + size_t len, rlen; unsigned int found = 0; int is_dir = 0, is_missing = 0;
@@ -187,9 +187,15 @@ static int query_fileowner(alpm_list_t *targets) } }
- if(!lrealpath(filename, rpath)) { + if(!(rpath = lrealpath(filename, NULL))) { /* Can't canonicalize path, try to proceed anyway */ - strncpy(rpath, filename, PATH_MAX); + rpath = strdup(filename); + } + + rlen = strlen(rpath); + if(rlen + 1 >= PATH_MAX) { + pm_printf(ALPM_LOG_ERROR, _("path too long: %s/\n"), rpath); + goto targcleanup; }
if(strncmp(rpath, root, rootlen) != 0) { @@ -201,11 +207,14 @@ static int query_fileowner(alpm_list_t *targets) rel_path = rpath + rootlen;
if((is_missing && is_dir) || (!is_missing && (is_dir = S_ISDIR(buf.st_mode)))) { - size_t rlen = strlen(rpath); if(rlen + 2 >= PATH_MAX) { pm_printf(ALPM_LOG_ERROR, _("path too long: %s/\n"), rpath); goto targcleanup; } + if ((rpathsave = realloc(rpath, rlen + 2)) == NULL) { + goto targcleanup; + } + rpath = rpathsave; strcat(rpath + rlen, "/"); }
-- 2.19.0
Good catch, but this approach allows lrealpath to allocate a buffer larger than PATH_MAX only to error if it actually does. lrealpath is intended to be the same as realpath (aside from not resolving symlinks obviously), so it should be fixed so that it doesn't write more than PATH_MAX into a provided buffer. We could switch to dynamic allocation in addition to fixing lrealpath, but then the PATH_MAX checks would be pointless and should be removed. You also never free the malloc'd path. You can run the entire test suite under valgrind with `make PY_TEST_FLAGS=--valgrind check` to catch most memory leaks. apg