[libvirt] [PATCH v2 3/4] Validate the bios_date format for <sysinfo>
John Ferlan
jferlan at redhat.com
Tue May 14 10:22:42 UTC 2013
On 05/13/2013 03:51 PM, Eric Blake wrote:
> On 05/13/2013 11:01 AM, John Ferlan wrote:
>> Add incorrectly formatted bios_date validation test
>> ---
>> src/conf/domain_conf.c | 24 ++++++++++++++++++++++
>> .../qemuxml2argvdata/qemuxml2argv-smbios-date.xml | 23 +++++++++++++++++++++
>> tests/qemuxml2argvtest.c | 1 +
>> 3 files changed, 48 insertions(+)
>> create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smbios-date.xml
>>
>> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
>> index 862b997..d352055 100644
>> --- a/src/conf/domain_conf.c
>> +++ b/src/conf/domain_conf.c
>> @@ -8437,6 +8437,30 @@ virSysinfoParseXML(const xmlNodePtr node,
>> virXPathString("string(bios/entry[@name='version'])", ctxt);
>> def->bios_date =
>> virXPathString("string(bios/entry[@name='date'])", ctxt);
>> + if (def->bios_date != NULL) {
>> + char *ptr;
>> + struct tm tm;
>> + memset(&tm, 0, sizeof(tm));
>> +
>> + /* Validate just the format of the date
>> + * Expect mm/dd/yyyy or mm/dd/yy,
>> + * where yy must be 00->99 and would be assumed to be 19xx
>> + * a yyyy date should be 1900 and beyond
>> + */
>> + if (virStrToLong_i(def->bios_date, &ptr, 10, &tm.tm_mon) < 0 ||
>> + *ptr != '/' ||
>> + virStrToLong_i(ptr+1, &ptr, 10, &tm.tm_mday) < 0 ||
>
> Spaces around +
>
>> + *ptr != '/' ||
>> + virStrToLong_i(ptr+1, &ptr, 10, &tm.tm_year) < 0 ||
>
> and again
>
>> + *ptr != '\0' ||
>> + (tm.tm_mon < 0 || tm.tm_mon > 12) ||
>
> According to 'man gmtime', tm_mon should be in the range 0-11 (you're
> allowing an off-by-one on the high end). Worse, January is 0, not 1; so
> you need to take the number parsed by the user and subtract one before
> passing it to struct tm.
>
>> + (tm.tm_mday < 0 || tm.tm_mday > 31) ||
>
> tm_mday should be in the range 1-31 (you're allowing an off-by-one on
> the low end)
>
>> + (tm.tm_year < 0 || (tm.tm_year >= 100 && tm.tm_year < 1900))) {
>
> Oh, you aren't even using struct tm through a libc time-based function
> such as gmtime. In that case, my advice is to completely avoid 'struct
> tm'. It is such a non-intuitive struct (months start from 0, days from
> 1, years from 1900) that it should NOT be used for anything except the
> standardized functions that adhere to those conventions while converting
> between seconds since Epoch. Just declare 'int mon, day, year;' and
> parse into those variables, instead of trying to populate a struct tm
> that you then throw away.
>
>> + virReportError(VIR_ERR_XML_DETAIL, "%s",
>> + _("Invalid BIOS 'date' format"));
>> + goto error;
>> + }
>> + }
>
> I like the approach of the patch, and especially that you added a test
> case, but I think it's still worth a v3 that avoids 'struct tm' and any
> chance of confusion it provides.
>
Oh right - at one time I was doing the gmtime or strptime call to attempt
to validate the data; however, I found it was less than perfect allowing
things like 2/31/2000 to be accepted.
In any case, in lieu of a v3, here's a diff:
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index fbe4d9a..0516413 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -8442,23 +8442,22 @@ virSysinfoParseXML(const xmlNodePtr node,
virXPathString("string(bios/entry[@name='date'])", ctxt);
if (def->bios_date != NULL) {
char *ptr;
- struct tm tm;
- memset(&tm, 0, sizeof(tm));
+ int month, day, year;
/* Validate just the format of the date
* Expect mm/dd/yyyy or mm/dd/yy,
* where yy must be 00->99 and would be assumed to be 19xx
* a yyyy date should be 1900 and beyond
*/
- if (virStrToLong_i(def->bios_date, &ptr, 10, &tm.tm_mon) < 0 ||
+ if (virStrToLong_i(def->bios_date, &ptr, 10, &month) < 0 ||
*ptr != '/' ||
- virStrToLong_i(ptr+1, &ptr, 10, &tm.tm_mday) < 0 ||
+ virStrToLong_i(ptr + 1, &ptr, 10, &day) < 0 ||
*ptr != '/' ||
- virStrToLong_i(ptr+1, &ptr, 10, &tm.tm_year) < 0 ||
+ virStrToLong_i(ptr + 1, &ptr, 10, &year) < 0 ||
*ptr != '\0' ||
- (tm.tm_mon < 0 || tm.tm_mon > 12) ||
- (tm.tm_mday < 0 || tm.tm_mday > 31) ||
- (tm.tm_year < 0 || (tm.tm_year >= 100 && tm.tm_year < 1900))) {
+ (month < 1 || month > 12) ||
+ (day < 1 || day > 31) ||
+ (year < 0 || (year >= 100 && year < 1900))) {
virReportError(VIR_ERR_XML_DETAIL, "%s",
_("Invalid BIOS 'date' format"));
goto error;
or more visually appealing
if (def->bios_date != NULL) {
char *ptr;
int month, day, year;
/* Validate just the format of the date
* Expect mm/dd/yyyy or mm/dd/yy,
* where yy must be 00->99 and would be assumed to be 19xx
* a yyyy date should be 1900 and beyond
*/
if (virStrToLong_i(def->bios_date, &ptr, 10, &month) < 0 ||
*ptr != '/' ||
virStrToLong_i(ptr + 1, &ptr, 10, &day) < 0 ||
*ptr != '/' ||
virStrToLong_i(ptr + 1, &ptr, 10, &year) < 0 ||
*ptr != '\0' ||
(month < 1 || month > 12) ||
(day < 1 || day > 31) ||
(year < 0 || (year >= 100 && year < 1900))) {
virReportError(VIR_ERR_XML_DETAIL, "%s",
_("Invalid BIOS 'date' format"));
goto error;
}
}
John
More information about the libvir-list
mailing list