summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Gomizelj <simongmzlj@gmail.com>2013-05-22 00:43:11 -0400
committerAllan McRae <allan@archlinux.org>2013-06-04 13:45:12 +1000
commitdd62fde53ec00f1b08d312951b919e15050efe86 (patch)
treef0e2376a933734276a74b7445687bfba724aef08
parentfe794ccb25d3ab1f7c07331b437b61c30c08a018 (diff)
downloadpacman-dd62fde53ec00f1b08d312951b919e15050efe86.tar.xz
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>
-rw-r--r--lib/libalpm/be_sync.c30
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) {