The following commit has been merged in the sid branch: commit 357ab385750c1cb657ff95c0b34ad0a6bf6d2cdf Author: Guillem Jover <guil...@debian.org> Date: Wed Aug 11 15:16:04 2010 +0200
libdpkg: When parsing database files only warn on bogus versions Those versions, although bogus, were previously accepted, so to avoid breaking systems by making dpkg refuse to parse the status and available files, we just make it warn for now, and will make it error out on status file parsing later on. We keep producing errors on the rest of version parsing to avoid newly introduced bogosity and so that packages get fixed, while not making the system unusable anymore. Closes: #590885, #590896, #591692, #591885 diff --git a/debian/changelog b/debian/changelog index bff0a33..45b00ed 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,9 @@ dpkg (1.15.8.4) UNRELEASED; urgency=low * Fix use after free segfault on update-alternatives --remove-all. Closes: #591653, #591654 * Always print a massage on warning when parsing control files. + * On database parsing only warn on bogus versions previously accepted, + the other instances will keep producing errors, to avoid newly + introduced bogosity. Closes: #590885, #590896, #591692, #591885 [ Raphaƫl Hertzog ] * Fix make -C man install so that it actually finds the manual pages diff --git a/lib/dpkg/dbmodify.c b/lib/dpkg/dbmodify.c index bc39448..fb2aeb2 100644 --- a/lib/dpkg/dbmodify.c +++ b/lib/dpkg/dbmodify.c @@ -75,7 +75,8 @@ static void cleanupdates(void) { struct dirent **cdlist; int cdn, i; - parsedb(statusfile, pdb_weakclassification, NULL,NULL,NULL); + parsedb(statusfile, pdb_lax_parser | pdb_weakclassification, + NULL, NULL, NULL); *updatefnrest = '\0'; updateslength= -1; @@ -86,7 +87,8 @@ static void cleanupdates(void) { for (i=0; i<cdn; i++) { strcpy(updatefnrest, cdlist[i]->d_name); - parsedb(updatefnbuf, pdb_weakclassification, NULL,NULL,NULL); + parsedb(updatefnbuf, pdb_lax_parser | pdb_weakclassification, + NULL, NULL, NULL); if (cstatus < msdbrw_write) free(cdlist[i]); } @@ -254,7 +256,7 @@ modstatdb_init(const char *admindir, enum modstatdb_rw readwritereq) cleanupdates(); if(!(cflags & msdbrw_noavail)) parsedb(availablefile, - pdb_recordavailable|pdb_rejectstatus, + pdb_recordavailable | pdb_rejectstatus | pdb_lax_parser, NULL,NULL,NULL); } diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h index 3590d42..89f6da1 100644 --- a/lib/dpkg/dpkg-db.h +++ b/lib/dpkg/dpkg-db.h @@ -234,7 +234,10 @@ enum parsedbflags { pdb_rejectstatus =002, /* Throw up an error if `Status' encountered */ pdb_weakclassification=004, /* Ignore priority/section info if we already have any */ pdb_ignorefiles =010, /* Ignore files info if we already have them */ - pdb_ignoreolder =020 /* Ignore packages with older versions already read */ + /* Ignore packages with older versions already read. */ + pdb_ignoreolder =020, + /* Perform laxer parsing, used to transition to stricter parsing. */ + pdb_lax_parser =040, }; const char *illegal_packagename(const char *p, const char **ep); diff --git a/lib/dpkg/fields.c b/lib/dpkg/fields.c index c94b92d..223f28d 100644 --- a/lib/dpkg/fields.c +++ b/lib/dpkg/fields.c @@ -178,12 +178,8 @@ void f_status(struct pkginfo *pigp, struct pkginfoperfile *pifp, void f_version(struct pkginfo *pigp, struct pkginfoperfile *pifp, struct parsedb_state *ps, const char *value, const struct fieldinfo *fip) { - const char *emsg; - - emsg= parseversion(&pifp->version,value); - if (emsg) - parse_error(ps, pigp, - _("error in Version string `%.250s': %.250s"), value, emsg); + parse_db_version(ps, pigp, &pifp->version, value, + _("error in Version string '%.250s'"), value); } void f_revision(struct pkginfo *pigp, struct pkginfoperfile *pifp, @@ -205,19 +201,15 @@ void f_revision(struct pkginfo *pigp, struct pkginfoperfile *pifp, void f_configversion(struct pkginfo *pigp, struct pkginfoperfile *pifp, struct parsedb_state *ps, const char *value, const struct fieldinfo *fip) { - const char *emsg; - if (ps->flags & pdb_rejectstatus) parse_error(ps, pigp, _("value for `config-version' field not allowed in this context")); if (ps->flags & pdb_recordavailable) return; - emsg= parseversion(&pigp->configversion,value); - if (emsg) - parse_error(ps, pigp, - _("error in Config-Version string `%.250s': %.250s"), - value, emsg); + parse_db_version(ps, pigp, &pigp->configversion, value, + _("error in Config-Version string '%.250s'"), value); + } static void conffvalue_lastword(const char *value, const char *from, @@ -426,12 +418,9 @@ void f_dependency(struct pkginfo *pigp, struct pkginfoperfile *pifp, varbufreset(&version); varbufaddbuf(&version, versionstart, versionlength); varbufaddc(&version, '\0'); - emsg = parseversion(&dop->version, version.buf); - if (emsg) - parse_error(ps, pigp, - _("`%s' field, reference to `%.255s': " - "error in version: %.255s"), - fip->name, depname.buf, emsg); + parse_db_version(ps, pigp, &dop->version, version.buf, + _("'%s' field, reference to '%.255s': " + "error in version"), fip->name, depname.buf); p++; while (isspace(*p)) p++; } else { dop->verrel= dvr_none; diff --git a/lib/dpkg/parsedump.h b/lib/dpkg/parsedump.h index 275c149..55e03d0 100644 --- a/lib/dpkg/parsedump.h +++ b/lib/dpkg/parsedump.h @@ -65,6 +65,10 @@ struct fieldinfo { size_t integer; }; +void parse_db_version(struct parsedb_state *ps, const struct pkginfo *pkg, + struct versionrevision *version, const char *value, + const char *fmt, ...) DPKG_ATTR_PRINTF(5); + void parse_error(struct parsedb_state *ps, const struct pkginfo *pigp, const char *fmt, ...) DPKG_ATTR_NORET DPKG_ATTR_PRINTF(3); void parse_warn(struct parsedb_state *ps, const struct pkginfo *pigp, diff --git a/lib/dpkg/parsehelp.c b/lib/dpkg/parsehelp.c index 5d80213..b401ee4 100644 --- a/lib/dpkg/parsehelp.c +++ b/lib/dpkg/parsehelp.c @@ -209,7 +209,9 @@ const char *versiondescribe return vb->buf; } -const char *parseversion(struct versionrevision *rversion, const char *string) { +static const char * +parseversion_lax(struct versionrevision *rversion, const char *string) +{ char *hyphen, *colon, *eepochcolon; const char *end, *ptr; unsigned long epoch; @@ -246,7 +248,24 @@ const char *parseversion(struct versionrevision *rversion, const char *string) { *hyphen++ = '\0'; rversion->revision= hyphen ? hyphen : ""; - /* Check for invalid chars in version and revision. */ + return NULL; +} + +/** + * Check for invalid syntax in version structure. + * + * The rest of the syntax has been already checked in parseversion_lax(). So + * we only do the stricter checks here. + * + * @param rversion The version to verify. + * + * @return An error string, or NULL if eveyrthing was ok. + */ +static const char * +version_strict_check(struct versionrevision *rversion) +{ + const char *ptr; + /* XXX: Would be faster to use something like cisversion and cisrevision. */ for (ptr = rversion->version; *ptr; ptr++) { if (!cisdigit(*ptr) && !cisalpha(*ptr) && strchr(".-+~:", *ptr) == NULL) @@ -260,6 +279,61 @@ const char *parseversion(struct versionrevision *rversion, const char *string) { return NULL; } +const char * +parseversion(struct versionrevision *rversion, const char *string) +{ + const char *emsg; + + emsg = parseversion_lax(rversion, string); + if (emsg) + return emsg; + + return version_strict_check(rversion); +} + +/** + * Parse a version string coming from a database file. + * + * It parses a version string, and prints a warning or an error depending + * on the parse options. + * + * @param ps The parsedb state. + * @param pkg The package being parsed. + * @param version The version to parse into. + * @param value The version string to parse from. + * @param fmt The error format string. + */ +void +parse_db_version(struct parsedb_state *ps, const struct pkginfo *pkg, + struct versionrevision *version, const char *value, + const char *fmt, ...) +{ + const char *msg; + bool warn_msg = false; + + msg = parseversion_lax(version, value); + if (msg == NULL) { + msg = version_strict_check(version); + if (ps->flags & pdb_lax_parser) + warn_msg = true; + } + + if (msg) { + va_list args; + char buf[1000]; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + + if (warn_msg) + parse_warn(ps, pkg, "%s: %.250s", buf, msg); + else + parse_error(ps, pkg, "%s: %.250s", buf, msg); + + va_end(args); + } +} + void parse_must_have_field(struct parsedb_state *ps, const struct pkginfo *pigp, diff --git a/src/update.c b/src/update.c index 246a489..a5eec72 100644 --- a/src/update.c +++ b/src/update.c @@ -79,7 +79,8 @@ void updateavailable(const char *const *argv) { varbufaddc(&vb,0); if (cipaction->arg == act_avmerge) - parsedb(vb.buf, pdb_recordavailable | pdb_rejectstatus, NULL, NULL, NULL); + parsedb(vb.buf, pdb_recordavailable | pdb_rejectstatus | pdb_lax_parser, + NULL, NULL, NULL); if (cipaction->arg != act_avclear) count += parsedb(sourcefile, -- dpkg's main repository -- To UNSUBSCRIBE, email to debian-dpkg-cvs-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org