Fix package files removal with only read bit set.

The previous code was checking incorrectly if the file had the write
bit set, and this is wrong because a package could have files with
only the read bit set (0444).
This commit is contained in:
Juan RP 2014-09-28 13:33:15 +02:00
parent 2a89552375
commit 2711b07b77
2 changed files with 37 additions and 15 deletions

9
NEWS
View File

@ -1,5 +1,11 @@
xbps-0.41 (???):
* libxbps: rather than checking if user has write permission on
package files for removal, check if the files are owned by the
same user ID. This fixes a new issue where files with only the read
bit set cannot be removed. Added a new test case to verify its
correctness.
* xbps-create(8): xz compressed packages now use default compression
level (-6) rather than max level (-9); max compression level uses
too much memory and it's much slower; by Christian Neukirchen.
@ -15,7 +21,8 @@ xbps-0.41 (???):
the next update xbps-install will automatically replace the broken release by
the new downgraded release.
* replace xbps-package directory by the new void-packages, by Enno Boland.
* Replace xbps-packages directory by void-packages in xbps-checkvers(8),
xbps-uchroot(8) and others, by Enno Boland.
xbps-0.40 (2014-09-18):

View File

@ -37,8 +37,9 @@
static bool
check_remove_pkg_files(struct xbps_handle *xhp,
xbps_dictionary_t pkgd, const char *pkgver)
xbps_dictionary_t pkgd, const char *pkgver, uid_t euid)
{
struct stat st;
xbps_array_t array;
xbps_object_iterator_t iter;
xbps_object_t obj;
@ -46,7 +47,6 @@ check_remove_pkg_files(struct xbps_handle *xhp,
const char *file;
char path[PATH_MAX];
bool fail = false;
int fd = 0;
for (uint8_t i = 0; i < __arraycount(objs); i++) {
array = xbps_dictionary_get(pkgd, objs[i]);
@ -60,18 +60,30 @@ check_remove_pkg_files(struct xbps_handle *xhp,
while ((obj = xbps_object_iterator_next(iter))) {
xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file);
if (faccessat(fd, path, W_OK, AT_SYMLINK_NOFOLLOW) == -1) {
if (errno != ENOENT) {
/*
* only bail out if something else than ENOENT
* is returned.
*/
fail = true;
xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL,
errno, pkgver,
"%s: cannot remove `%s': %s",
pkgver, file, strerror(errno));
/*
* Check if effective user ID owns the file; this is
* enough to ensure the user has write permissions
* on the directory.
*/
if (!lstat(path, &st) && euid == st.st_uid) {
/* success */
continue;
}
if (errno != ENOENT) {
/*
* only bail out if something else than ENOENT
* is returned.
*/
int rv = errno;
if (rv == 0) {
/* lstat succeeds but euid != uid */
rv = EPERM;
}
fail = true;
xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL,
errno, pkgver,
"%s: cannot remove `%s': %s",
pkgver, file, strerror(rv));
}
}
xbps_object_iterator_release(iter);
@ -219,6 +231,7 @@ xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update)
char *pkgname, metafile[PATH_MAX];
int rv = 0;
pkg_state_t state = 0;
uid_t euid;
assert(xhp);
assert(pkgver);
@ -226,6 +239,8 @@ xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update)
pkgname = xbps_pkg_name(pkgver);
assert(pkgname);
euid = geteuid();
if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
rv = errno;
xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n",
@ -293,7 +308,7 @@ xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update)
* 1- check if user has enough perms to remove all entries
* 2- perform removal
*/
if (check_remove_pkg_files(xhp, pkgfilesd, pkgver)) {
if (check_remove_pkg_files(xhp, pkgfilesd, pkgver, euid)) {
rv = EPERM;
goto out;
}