[Rpm-maint] [PATCH 14/18] Detect possible policy module conflicts

Steve Lawrence slawrence at tresys.com
Wed Dec 23 20:57:34 UTC 2009


Currently, it is possible for two different packages to install policy
modules with the same name. This patch adds detection for these conflicts
by iterating over all to-be-installed packages and all currently installed
packages and making sure no two packages own the same policies. This patch
also detects conflicts between two packages providing base modules for
the same type.

To accomplish this, this patch also stores the name of the package which
provided the policy module in the RPMTAG_SOURCERPM header tag of the pseudo
policy packages.
---
 lib/rpmpol.c      |  144 +++++++++++++++++++++++++++++++++++++++++++++++++---
 lib/rpmpol.h      |   26 ++++++++++
 lib/transaction.c |    5 ++
 3 files changed, 166 insertions(+), 9 deletions(-)

diff --git a/lib/rpmpol.c b/lib/rpmpol.c
index c69677f..e727ad3 100644
--- a/lib/rpmpol.c
+++ b/lib/rpmpol.c
@@ -31,6 +31,7 @@ struct rpmpol_s {
 	rpmpolAction * actions; /*!< install, upgrade, remove, ignore */
 	rpm_time_t time;       /*!< installation time of this policy, in seconds since the epoch */
 	rpmds requires;        /*!< PolicyRequires: dependencies */
+	char * source;         /*!< package policies came from */
 	int count;             /*!< number of policies */
 	int nrefs;             /*!< reference counting */
 	int index;             /*!< index for iterator */
@@ -101,6 +102,8 @@ rpmpol rpmpolFree(rpmpol pol)
 		pol->obsoletes = _free(pol->obsoletes);
 	}
 
+	pol->source = _free(pol->source);
+
 	rpmpolUnlink(pol);
 	pol = _free(pol);
 	return NULL;
@@ -213,6 +216,11 @@ rpmpol rpmpolNew(Header h)
 	if (pol->time == 0) { /* hasn't been installed yet */
 		pol->time = UINT_MAX; /* rpm_time_t is typedef to uint32_t */
 	}
+	if (rstreq(headerGetString(h, RPMTAG_NAME), RPMPOL_PKG_NAME)) {
+		pol->source = headerGetAsString(h, RPMTAG_SOURCERPM);
+	} else {
+		pol->source = headerGetAsString(h, RPMTAG_NAME);
+	}
 
 	pol = rpmpolLink(pol);
 
@@ -344,6 +352,11 @@ rpmds rpmpolGetRequires(const rpmpol pol)
     return pol ? pol->requires : NULL;
 }
 
+const char * rpmpolGetSource(const rpmpol pol)
+{
+    return pol ? pol->source : NULL;
+}
+
 rpm_time_t rpmpolGetTime(const rpmpol pol)
 {
 	return pol ? pol->time : 0;
@@ -436,6 +449,7 @@ Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid)
 	uint32_t zero = 0;
 	const char * data;
 	const char * name;
+	const char * source;
 	uint32_t flags;
 	ARGV_const_t types;
 	ARGV_const_t obs;
@@ -450,8 +464,9 @@ Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid)
 	flags = rpmpolGetFlags(pol);
 	types = rpmpolGetTypes(pol);
 	obs = rpmpolGetObsoletes(pol);
+	source = rpmpolGetSource(pol);
 
-	if (!data || !name || !types) {
+	if (!data || !name || !types || !source) {
 		goto exit;
 	}
 
@@ -461,6 +476,7 @@ Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid)
 	headerPutString(h, RPMTAG_NAME, RPMPOL_PKG_NAME);
 	headerPutString(h, RPMTAG_VERSION, type);
 	headerPutString(h, RPMTAG_RELEASE, name);
+	headerPutString(h, RPMTAG_SOURCERPM, source);
 
 	headerPutString(h, RPMTAG_POLICIES, data);
 	headerPutString(h, RPMTAG_POLICYNAMES, name);
@@ -481,12 +497,61 @@ Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid)
 	headerPutUint32(h, RPMTAG_INSTALLTIME, &tid, 1);
 	headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION);
 	headerPutString(h, RPMTAG_BUILDHOST, "localhost");
-	headerPutString(h, RPMTAG_SOURCERPM, "(none)");
 
 exit:
 	return h;
 }
 
+rpmRC rpmpolCheckConflicts(const rpmpol pola, const rpmpol polb)
+{
+	ARGV_const_t av;
+	const char * overlappingtype = NULL;
+	rpmRC rc = RPMRC_FAIL;
+
+	if (!rpmpolIsValidIndex(pola) || !rpmpolIsValidIndex(polb)) {
+		goto exit;
+	}
+
+	if (rstreq(rpmpolGetSource(pola), rpmpolGetSource(polb))) {
+		/* policies with the same source can't conflict */
+		rc = RPMRC_OK;
+		goto exit;
+	}
+
+	for (av = rpmpolGetTypes(pola); av && *av; av++) {
+		if (rstreq(*av, RPMPOL_TYPE_DEFAULT) || rpmpolHasType(polb, *av)) {
+			overlappingtype = *av;
+			break;
+		}
+	}
+
+	if (!overlappingtype) {
+		/* conflicts can only occur if types overlap */
+		rc = RPMRC_OK;
+		goto exit;
+	}
+
+	if ((rpmpolGetFlags(pola) & RPMPOL_FLAG_BASE) && (rpmpolGetFlags(polb) & RPMPOL_FLAG_BASE)) {
+		/* conflict, cannot have two base modules with overlapping types */
+		rpmlog(RPMLOG_ERR, _("base policy modules %s from %s and %s from %s have overlapping type %s\n"),
+			rpmpolGetName(pola), rpmpolGetSource(pola), rpmpolGetName(polb), rpmpolGetSource(polb),
+			overlappingtype);
+		goto exit;
+	}
+
+	if (rstreq(rpmpolGetName(pola), rpmpolGetName(polb))) {
+		/* conflict, cannot have two modules with the same name and overlapping types */
+		rpmlog(RPMLOG_ERR, _("policy module %s conflicts between %s and %s\n"),
+			rpmpolGetName(pola), rpmpolGetSource(pola), rpmpolGetSource(polb));
+		goto exit;
+	}
+
+	rc = RPMRC_OK;
+
+exit:
+	return rc;
+}
+
 rpmpoltrans rpmpoltransBegin(int chroot, const char * type)
 {
 	rpmpoltrans pt = xcalloc(1, sizeof(*pt));
@@ -837,6 +902,59 @@ const char * rpmpolsGetType(rpmpols ps)
 	return ps ? ps->type : NULL;
 }
 
+rpmRC rpmpolsCheckConflicts(rpmpols ps, rpmdb db)
+{
+	int i, j;
+	int conflictCount = 0;
+	rpmpol pol;
+	rpmpol polcmp;
+	Header h;
+	rpmRC rc = RPMRC_FAIL;
+
+	for (i = 0; i < ps->count; i++) {
+		pol = ps->pols[i];
+
+		rpmpolInitIterator(pol);
+		while (rpmpolNext(pol) >= 0) {
+
+			/* check this rpmpol against all currently installed policies */
+			rpmdbMatchIterator mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
+			while ((h = rpmdbNextIterator(mi)) != NULL) {
+				if (!headerIsEntry(h, RPMTAG_POLICIES)) {
+					continue;
+				}
+
+				polcmp = rpmpolNew(h);
+				rpmpolInitIterator(polcmp);
+				while(rpmpolNext(polcmp) >= 0) {
+					if (rpmpolCheckConflicts(pol, polcmp) != RPMRC_OK) {
+						conflictCount++;
+					}
+				}
+				rpmpolFree(polcmp);
+			}
+			mi = rpmdbFreeIterator(mi);
+
+			/* check this rpmpol against all to be installed policies */
+			for (j = i + 1; j < ps->count; j++) {
+				polcmp = ps->pols[j];
+				rpmpolInitIterator(polcmp);
+				while(rpmpolNext(polcmp) >= 0) {
+					if (rpmpolCheckConflicts(pol, polcmp) != RPMRC_OK) {
+						conflictCount++;
+					}
+				}
+			}
+		}
+	}
+
+	if (conflictCount == 0) {
+		rc = RPMRC_OK;
+	}
+
+	return rc;
+}
+
 /*
  * Determine whether to install/udpate/remove/etc each rpmpol element
  *
@@ -917,21 +1035,29 @@ rpmRC rpmpolsPrepare(rpmpols ps, rpmdb db)
 			while (rpmpolNext(pola) >= 0) {
 				rpmpolInitIterator(polb);
 				while (rpmpolNext(polb) >= 0) {
+					int overlappingTypes = 0;
+					ARGV_const_t av;
+
 					if (!rstreq(rpmpolGetName(pola), rpmpolGetName(polb))) {
 						continue;
 					}
 
+					for (av = rpmpolGetTypes(pola); av && *av; av++) {
+						if (rstreq(*av, RPMPOL_TYPE_DEFAULT) || rpmpolHasType(polb, *av)) {
+							overlappingTypes = 1;
+							break;
+						}
+					}
+					if (!overlappingTypes) {
+						continue;
+					}
+
 					timea = rpmpolGetTime(pola);
 					timeb = rpmpolGetTime(polb);
 
 					if (timea == timeb) {
-						ARGV_const_t av;
-						for (av = rpmpolGetTypes(pola); av && *av; av++) {
-							if (rstreq(*av, RPMPOL_TYPE_DEFAULT) || rpmpolHasType(polb, *av)) {
-								rpmlog(RPMLOG_ERR, _("Duplicate policy modules with overlapping types found: %s\n"), rpmpolGetName(pola));
-								goto exit;
-							}
-						}
+						rpmlog(RPMLOG_ERR, _("Duplicate policy modules with overlapping types found: %s\n"), rpmpolGetName(pola));
+						goto exit;
 					} else if (timea > timeb) {
 						rpmpolRemove(polb);
 					} else {
diff --git a/lib/rpmpol.h b/lib/rpmpol.h
index a06ac74..747f324 100644
--- a/lib/rpmpol.h
+++ b/lib/rpmpol.h
@@ -147,6 +147,14 @@ void rpmpolSetAction(rpmpol pol, rpmpolAction action);
 RPM_GNUC_INTERNAL
 rpmds rpmpolGetRequires(const rpmpol pol);
 
+/*
+ * Get the source package dependency for this policy
+ * @param pol	policy set
+ * @return		source package
+ */
+RPM_GNUC_INTERNAL
+const char * rpmpolGetSource(const rpmpol pol);
+
 /** \ingroup rpmpol
  * Get the time the policy was installed
  * @param pol	policy set
@@ -203,6 +211,15 @@ RPM_GNUC_INTERNAL
 Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid);
 
 /** \ingroup rpmpol
+ * Check for conflicts between to policy elements
+ * @param pola	rpm policy element
+ * @param polb	rpm policy element
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolCheckConflicts(const rpmpol pola, const rpmpol polb);
+
+/** \ingroup rpmpol
  * Begin an rpm policy transaction
  * @param chroot	boolean, is the policy being installed in a chroot? 0 for no, non-zero for yes
  * @param type	type to install to during the transaction, or NULL to use the default
@@ -315,6 +332,15 @@ RPM_GNUC_INTERNAL
 const char * rpmpolsGetType(rpmpols ps);
 
 /** \ingroup rpmpol
+ * Check for conflicts in a policy set
+ * @param ps	rpm policy set
+ * @param db	rpm database
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolsCheckConflicts(rpmpols ps, rpmdb db);
+
+/** \ingroup rpmpol
  * Set the actions on the policies
  * @param ps	rpm policy set
  * @param db	rpm database
diff --git a/lib/transaction.c b/lib/transaction.c
index 91182c3..5a893c9 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -1233,6 +1233,11 @@ static rpmRC rpmtsLoadPolicy(rpmts ts)
 	rpmpolsSetType(ps, type);
 	type = _free(type);
 
+	rc = rpmpolsCheckConflicts(ps, rpmtsGetRdb(ts));
+	if (rc != RPMRC_OK) {
+		goto err;
+	}
+
 	rc = rpmpolsPrepare(ps, rpmtsGetRdb(ts));
 	if (rc != RPMRC_OK) {
 		if (rc == RPMRC_NOTFOUND) {
-- 
1.6.0.6



More information about the Rpm-maint mailing list