diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index a0e7108b..349e84b7 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -630,6 +630,10 @@ static int local_db_populate(alpm_db_t *db) continue; } + /* treat local metadata errors as warning-only, + * they are already installed and otherwise they can't be operated on */ + _alpm_pkg_check_meta(pkg); + /* add to the collection */ _alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", pkg->name, db->treename); diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index f8e51f3c..cddbc01e 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -673,6 +673,10 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, newpkg->infolevel |= INFRQ_FILES; } + if(_alpm_pkg_check_meta(newpkg) != 0) { + goto pkg_invalid; + } + _alpm_archive_read_free(archive); close(fd); return newpkg; diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 588895e5..8d6795bf 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -344,6 +344,11 @@ static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname, pkg->ops = get_sync_pkg_ops(); pkg->handle = db->handle; + if(_alpm_pkg_check_meta(pkg) != 0) { + _alpm_pkg_free(pkg); + RET_ERR(db->handle, ALPM_ERR_PKG_INVALID, NULL); + } + /* add to the collection */ _alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", pkg->name, db->treename); diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 8c95dab3..50bbe591 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -21,6 +21,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -844,3 +845,58 @@ int SYMEXPORT alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg) return 0; } + +/* check that package metadata meets our requirements */ +int _alpm_pkg_check_meta(alpm_pkg_t *pkg) +{ + char *c; + int error_found = 0; + +#define EPKGMETA(error) do { \ + error_found = -1; \ + _alpm_log(pkg->handle, ALPM_LOG_ERROR, error, pkg->name, pkg->version); \ +} while(0) + + /* sanity check */ + if(pkg->handle == NULL) { + return -1; + } + + /* immediate bail if package doesn't have name or version */ + if(pkg->name == NULL || pkg->name[0] == '\0' + || pkg->version == NULL || pkg->version[0] == '\0') { + _alpm_log(pkg->handle, ALPM_LOG_ERROR, + _("invalid package metadata (name or version missing)")); + return -1; + } + + if(pkg->name[0] == '-' || pkg->name[0] == '.') { + EPKGMETA(_("invalid metadata for package %s-%s " + "(package name cannot start with '.' or '-')\n")); + } + if(_alpm_fnmatch(pkg->name, "[![:alnum:]+_.@-]") == 0) { + EPKGMETA(_("invalid metadata for package %s-%s " + "(package name contains invalid characters)\n")); + } + + /* multiple '-' in pkgver can cause local db entries for different packages + * to overlap (e.g. foo-1=2-3 and foo=1-2-3 both give foo-1-2-3) */ + if((c = strchr(pkg->version, '-')) && (strchr(c + 1, '-'))) { + EPKGMETA(_("invalid metadata for package %s-%s " + "(package version contains invalid characters)\n")); + } + if(strchr(pkg->version, '/')) { + EPKGMETA(_("invalid metadata for package %s-%s " + "(package version contains invalid characters)\n")); + } + + /* local db entry is - */ + if(strlen(pkg->name) + strlen(pkg->version) + 1 > NAME_MAX) { + EPKGMETA(_("invalid metadata for package %s-%s " + "(package name and version too long)\n")); + } + +#undef EPKGMETA + + return error_found; +} diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index 5ebe6bd1..c2313d35 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -165,4 +165,6 @@ int _alpm_pkg_compare_versions(alpm_pkg_t *local_pkg, alpm_pkg_t *pkg); alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string); void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd); +int _alpm_pkg_check_meta(alpm_pkg_t *pkg); + #endif /* ALPM_PACKAGE_H */ diff --git a/test/pacman/meson.build b/test/pacman/meson.build index 655005a4..c26ce0fa 100644 --- a/test/pacman/meson.build +++ b/test/pacman/meson.build @@ -97,6 +97,9 @@ pacman_tests = [ 'tests/pacman003.py', 'tests/pacman004.py', 'tests/pacman005.py', + 'tests/pkg-meta-invalid-name-file.py', + 'tests/pkg-meta-invalid-name-local.py', + 'tests/pkg-meta-invalid-name-sync.py', 'tests/provision001.py', 'tests/provision002.py', 'tests/provision003.py', diff --git a/test/pacman/tests/pkg-meta-invalid-name-file.py b/test/pacman/tests/pkg-meta-invalid-name-file.py new file mode 100644 index 00000000..49060340 --- /dev/null +++ b/test/pacman/tests/pkg-meta-invalid-name-file.py @@ -0,0 +1,9 @@ +self.description = "package name with invalid characters cannot be installed (file)" + +p = pmpkg("-foo") +self.addpkg(p) + +self.args = "-U -- %s" % p.filename() + +self.addrule("!PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=-foo") diff --git a/test/pacman/tests/pkg-meta-invalid-name-local.py b/test/pacman/tests/pkg-meta-invalid-name-local.py new file mode 100644 index 00000000..2789abdd --- /dev/null +++ b/test/pacman/tests/pkg-meta-invalid-name-local.py @@ -0,0 +1,9 @@ +self.description = "local package name with invalid characters can be removed" + +sp = pmpkg("-foo") +self.addpkg2db("local", sp) + +self.args = "-R -- %s" % sp.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=-foo") diff --git a/test/pacman/tests/pkg-meta-invalid-name-sync.py b/test/pacman/tests/pkg-meta-invalid-name-sync.py new file mode 100644 index 00000000..895facbf --- /dev/null +++ b/test/pacman/tests/pkg-meta-invalid-name-sync.py @@ -0,0 +1,9 @@ +self.description = "package name with invalid characters cannot be installed" + +sp = pmpkg("-foo") +self.addpkg2db("sync", sp) + +self.args = "-S -- %s" % sp.name + +self.addrule("!PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=-foo")