[pacman-dev] [PATCH 1/2] pacman: fix possible buffer overflow

Andrew Gregory andrew.gregory.8 at gmail.com
Sat Sep 22 21:20:04 UTC 2018


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 at 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


More information about the pacman-dev mailing list