xbps-pkgdb: rework symlinks checks to avoid false positives with -r.
This commit is contained in:
		| @@ -45,30 +45,52 @@ | ||||
|  * | ||||
|  * returns 0 if test ran successfully, 1 otherwise and -1 on error. | ||||
|  */ | ||||
|  | ||||
| static char * | ||||
| symlink_target(const char *pkgname, const char *path) | ||||
| symlink_target(struct xbps_handle *xhp, const char *path) | ||||
| { | ||||
| 	struct stat sb; | ||||
| 	char *lnk; | ||||
| 	char *lnk, *res; | ||||
| 	ssize_t r; | ||||
|  | ||||
| 	if (lstat(path, &sb) == -1) { | ||||
| 		xbps_error_printf("%s: lstat failed for %s\n", pkgname, path); | ||||
| 	if (lstat(path, &sb) == -1) | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	lnk = malloc(sb.st_size + 1); | ||||
| 	assert(lnk); | ||||
|  | ||||
| 	r = readlink(path, lnk, sb.st_size + 1); | ||||
| 	if (r < 0 || r > sb.st_size) { | ||||
| 		xbps_error_printf("%s: readlink failed for %s\n", pkgname, path); | ||||
| 		free(lnk); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	lnk[sb.st_size] = '\0'; | ||||
| 	if (lnk[0] != '/') { | ||||
| 		char tpath[PATH_MAX], *p, *dname; | ||||
|  | ||||
| 	return lnk; | ||||
| 		/* relative */ | ||||
| 		p = strdup(path); | ||||
| 		assert(p); | ||||
| 		dname = dirname(p); | ||||
| 		assert(dname); | ||||
| 		snprintf(tpath, sizeof(tpath), "%s/%s", dname, lnk); | ||||
| 		free(p); | ||||
| 		if ((res = realpath(tpath, NULL)) == NULL) { | ||||
| 			free(lnk); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		if (strcmp(xhp->rootdir, "/") == 0) | ||||
| 			p = strdup(res); | ||||
| 		else | ||||
| 			p = strdup(res + strlen(xhp->rootdir)); | ||||
| 		free(res); | ||||
| 		res = p; | ||||
| 		free(lnk); | ||||
| 	} else { | ||||
| 		/* absolute */ | ||||
| 		res = lnk; | ||||
| 	} | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| int | ||||
| @@ -77,9 +99,6 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) | ||||
| 	xbps_array_t array; | ||||
| 	xbps_object_t obj; | ||||
| 	xbps_dictionary_t filesd = arg; | ||||
| 	const char *file, *tgt = NULL; | ||||
| 	char path[PATH_MAX], tgt_path[PATH_MAX], *p, *buf, *buf2, *lnk, *dname; | ||||
| 	int rv; | ||||
| 	bool broken = false; | ||||
|  | ||||
| 	array = xbps_dictionary_get(filesd, "links"); | ||||
| @@ -87,6 +106,9 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) | ||||
| 		return false; | ||||
|  | ||||
| 	for (unsigned int i = 0; i < xbps_array_count(array); i++) { | ||||
| 		const char *file = NULL, *tgt = NULL; | ||||
| 		char path[PATH_MAX], *lnk = NULL, *tlnk = NULL; | ||||
|  | ||||
| 		obj = xbps_array_get(array, i); | ||||
| 		if (!xbps_dictionary_get_cstring_nocopy(obj, "file", &file)) | ||||
| 			continue; | ||||
| @@ -96,62 +118,61 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) | ||||
| 			    "empty target object!\n", pkgname, file); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (strcmp(tgt, "") == 0) { | ||||
| 		if (tgt[0] == '\0') { | ||||
| 			xbps_warn_printf("%s: `%s' symlink with " | ||||
| 			    "empty target object!\n", pkgname, file); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(xhp->rootdir, "/")) { | ||||
| 			snprintf(path, sizeof(path), "%s%s", xhp->rootdir, file); | ||||
| 			snprintf(tgt_path, sizeof(tgt_path), "%s%s", xhp->rootdir, tgt); | ||||
|  | ||||
| 			strncpy(tgt_path, tgt, sizeof(tgt_path)-1); | ||||
| 		} else  { | ||||
| 			strncpy(path, file, sizeof(path)-1); | ||||
| 			strncpy(tgt_path, tgt, sizeof(tgt_path)-1); | ||||
| 		} | ||||
|  | ||||
| 		if ((lnk = symlink_target(pkgname, path)) == NULL) | ||||
| 			continue; | ||||
|  | ||||
| 		p = strdup(path); | ||||
| 		assert(p); | ||||
| 		dname = dirname(p); | ||||
| 		buf = xbps_xasprintf("%s/%s", dname, lnk); | ||||
| 		free(p); | ||||
|  | ||||
| 		buf2 = realpath(path, NULL); | ||||
| 		if (buf2 == NULL) { | ||||
| 			xbps_warn_printf("%s: broken symlink %s (target: %s)\n", | ||||
| 			     pkgname, file, tgt); | ||||
| 			free(buf); | ||||
| 			free(lnk); | ||||
| 		snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file); | ||||
| 		if ((lnk = symlink_target(xhp, path)) == NULL) { | ||||
| 			xbps_error_printf("%s: broken symlink %s (target: %s)\n", pkgname, file, tgt); | ||||
| 			broken = true; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (tgt[0] != '/') { | ||||
| 			char *p, *p1, *dname; | ||||
|  | ||||
| 		rv = 1; | ||||
| 		if (lnk[0] != '/') { | ||||
| 			/* relative symlink */ | ||||
| 			if ((strcmp(lnk, tgt) == 0) || | ||||
| 			    (strcmp(buf, tgt_path) == 0) || | ||||
| 			    (strcmp(buf2, tgt_path) == 0)) | ||||
| 				rv = 0; | ||||
| 			p = strdup(file); | ||||
| 			assert(p); | ||||
| 			dname = dirname(p); | ||||
| 			assert(dname); | ||||
| 			snprintf(path, sizeof(path), "%s/%s", dname, tgt); | ||||
| 			p1 = realpath(path, NULL); | ||||
| 			free(p); | ||||
| 			if (p1 == NULL) { | ||||
| 				xbps_error_printf("%s: failed to realpath %s: %s\n", | ||||
| 				    pkgname, file, strerror(errno)); | ||||
| 				free(lnk); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (strcmp(xhp->rootdir, "/") == 0) | ||||
| 				tlnk = strdup(p1); | ||||
| 			else | ||||
| 				tlnk = strdup(p1 + strlen(xhp->rootdir)); | ||||
| 			free(p1); | ||||
| 		} else { | ||||
| 			/* absolute symlink */ | ||||
| 			if (strcmp(lnk, tgt) == 0) | ||||
| 				rv = 0; | ||||
| 		} | ||||
| 			char *p; | ||||
|  | ||||
| 		if (rv) { | ||||
| 			snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, tgt); | ||||
| 			if ((p = realpath(path, NULL))) { | ||||
| 				if (strcmp(xhp->rootdir, "/") == 0) | ||||
| 					tlnk = strdup(p); | ||||
| 				else | ||||
| 					tlnk = strdup(p + strlen(xhp->rootdir)); | ||||
| 				free(p); | ||||
| 			} else { | ||||
| 				tlnk = strdup(tgt); | ||||
| 			} | ||||
| 		} | ||||
| 		/* absolute */ | ||||
| 		if (strcmp(lnk, tlnk)) { | ||||
| 			xbps_warn_printf("%s: modified symlink %s " | ||||
| 			    "points to %s (shall be %s)\n", | ||||
| 			    pkgname, file, lnk, tgt); | ||||
| 			    pkgname, file, lnk, tlnk); | ||||
| 			broken = true; | ||||
| 		} | ||||
| 		free(buf); | ||||
| 		free(buf2); | ||||
| 		free(lnk); | ||||
| 		free(tlnk); | ||||
| 	} | ||||
| 	return broken; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user