validate package metadata after loading
alpm has certain requirements for package metadata necessary for proper functioning, name and version in particular. These requirements are already enforced in makepkg, but nowhere in alpm. Exceptions are treated as errors for non-local packages because they cannot be installed without potentially resulting in undefined behavior. Exceptions for local packages are treated as warnings because they are already installed, so any damage has already been done, and the user would otherwise have no way to uninstall them. Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
This commit is contained in:
parent
fde59b99e8
commit
0a394144b2
9 changed files with 101 additions and 0 deletions
|
@ -630,6 +630,10 @@ static int local_db_populate(alpm_db_t *db)
|
||||||
continue;
|
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 */
|
/* add to the collection */
|
||||||
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
|
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
|
||||||
pkg->name, db->treename);
|
pkg->name, db->treename);
|
||||||
|
|
|
@ -673,6 +673,10 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
|
||||||
newpkg->infolevel |= INFRQ_FILES;
|
newpkg->infolevel |= INFRQ_FILES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_alpm_pkg_check_meta(newpkg) != 0) {
|
||||||
|
goto pkg_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
_alpm_archive_read_free(archive);
|
_alpm_archive_read_free(archive);
|
||||||
close(fd);
|
close(fd);
|
||||||
return newpkg;
|
return newpkg;
|
||||||
|
|
|
@ -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->ops = get_sync_pkg_ops();
|
||||||
pkg->handle = db->handle;
|
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 */
|
/* add to the collection */
|
||||||
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
|
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
|
||||||
pkg->name, db->treename);
|
pkg->name, db->treename);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -844,3 +845,58 @@ int SYMEXPORT alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg)
|
||||||
|
|
||||||
return 0;
|
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 <pkgname>-<pkgver> */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string);
|
||||||
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd);
|
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd);
|
||||||
|
|
||||||
|
int _alpm_pkg_check_meta(alpm_pkg_t *pkg);
|
||||||
|
|
||||||
#endif /* ALPM_PACKAGE_H */
|
#endif /* ALPM_PACKAGE_H */
|
||||||
|
|
|
@ -97,6 +97,9 @@ pacman_tests = [
|
||||||
'tests/pacman003.py',
|
'tests/pacman003.py',
|
||||||
'tests/pacman004.py',
|
'tests/pacman004.py',
|
||||||
'tests/pacman005.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/provision001.py',
|
||||||
'tests/provision002.py',
|
'tests/provision002.py',
|
||||||
'tests/provision003.py',
|
'tests/provision003.py',
|
||||||
|
|
9
test/pacman/tests/pkg-meta-invalid-name-file.py
Normal file
9
test/pacman/tests/pkg-meta-invalid-name-file.py
Normal file
|
@ -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")
|
9
test/pacman/tests/pkg-meta-invalid-name-local.py
Normal file
9
test/pacman/tests/pkg-meta-invalid-name-local.py
Normal file
|
@ -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")
|
9
test/pacman/tests/pkg-meta-invalid-name-sync.py
Normal file
9
test/pacman/tests/pkg-meta-invalid-name-sync.py
Normal file
|
@ -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")
|
Loading…
Add table
Reference in a new issue