diff options
author | Simon Gomizelj <simongmzlj@gmail.com> | 2013-05-22 00:43:11 -0400 |
---|---|---|
committer | Allan McRae <allan@archlinux.org> | 2013-06-04 13:45:12 +1000 |
commit | dd62fde53ec00f1b08d312951b919e15050efe86 (patch) | |
tree | f0e2376a933734276a74b7445687bfba724aef08 /lib | |
parent | fe794ccb25d3ab1f7c07331b437b61c30c08a018 (diff) |
validate %FILEPATH% when parsing repo dbs
Currently we make no effort to validate the %FILENAME% field in the
repo db. This allows for relative paths to be considered valid.
A carefully crafted db entry with a malicious relative path,
(e.g. `../../../../etc/passwd`) will cause pacman to to
overwrite _any_ file on the target's machine.
Add the following validation:
- doesn't start with '.'
- doesn't contain a '/'
- won't overflow PATH_MAX
Signed-off-by: Simon Gomizelj <simongmzlj@gmail.com>
Signed-off-by: Allan McRae <allan@archlinux.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libalpm/be_sync.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 1cbe055e..f9fd5d1f 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -479,6 +479,33 @@ cleanup: return count; } +/* This function validates %FILENAME%. filename must be between 3 and + * PATH_MAX characters and cannot be contain a path */ +static int _alpm_validate_filename(alpm_db_t *db, const char *pkgname, + const char *filename) +{ + size_t len = strlen(filename); + + if(filename[0] == '.') { + errno = EINVAL; + _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename " + "of package %s is illegal\n"), db->treename, pkgname); + return -1; + } else if(memchr(filename, '/', len) != NULL) { + errno = EINVAL; + _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename " + "of package %s is illegal\n"), db->treename, pkgname); + return -1; + } else if(len > PATH_MAX) { + errno = EINVAL; + _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename " + "of package %s is too long\n"), db->treename, pkgname); + return -1; + } + + return 0; +} + #define READ_NEXT() do { \ if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ line = buf.line; \ @@ -558,6 +585,9 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, } } else if(strcmp(line, "%FILENAME%") == 0) { READ_AND_STORE(pkg->filename); + if(_alpm_validate_filename(db, pkg->name, pkg->filename) < 0) { + return -1; + } } else if(strcmp(line, "%DESC%") == 0) { READ_AND_STORE(pkg->desc); } else if(strcmp(line, "%GROUPS%") == 0) { |