[Freeipa-devel] [PATCH 0026] Prevent integer overflow when setting krbPasswordExpiration

Tomas Babej tbabej at redhat.com
Tue Jan 22 14:50:50 UTC 2013


On 01/17/2013 05:18 PM, Simo Sorce wrote:
> On Thu, 2013-01-17 at 15:29 +0100, Tomas Babej wrote:
>> On 01/17/2013 01:56 AM, Dmitri Pal wrote:
>>
>>> On 01/16/2013 12:32 PM, Tomas Babej wrote:
>>>> On 01/16/2013 06:01 PM, Simo Sorce wrote:
>>>>> On Wed, 2013-01-16 at 17:57 +0100, Tomas Babej wrote:
>>>>>> On 01/16/2013 02:47 PM, Simo Sorce wrote:
>>>>>>> On Wed, 2013-01-16 at 12:52 +0100, Tomas Babej wrote:
>>>>>>>> On 01/15/2013 11:55 PM, Simo Sorce wrote:
>>>>>>>>> On Tue, 2013-01-15 at 17:36 -0500, Dmitri Pal wrote:
>>>>>>>>>> On 01/15/2013 03:59 PM, Simo Sorce wrote:
>>>>>>>>>>> On Tue, 2013-01-15 at 15:53 -0500, Rob Crittenden
>>>>>>>>>>> wrote:
>>>>>>>>>>>> Dmitri Pal wrote:
>>>>>>>>>>>>> On 01/15/2013 08:48 AM, Simo Sorce wrote:
>>>>>>>>>>>>>> On Mon, 2013-01-14 at 16:46 +0100, Tomas Babej
>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Since in Kerberos V5 are used 32-bit unix
>>>>>>>>>>>>>>> timestamps, setting
>>>>>>>>>>>>>>> maxlife in pwpolicy to values such as 9999
>>>>>>>>>>>>>>> days would cause
>>>>>>>>>>>>>>> integer overflow in krbPasswordExpiration
>>>>>>>>>>>>>>> attribute.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> This would result into unpredictable
>>>>>>>>>>>>>>> behaviour such as users
>>>>>>>>>>>>>>> not being able to log in after password
>>>>>>>>>>>>>>> expiration if password
>>>>>>>>>>>>>>> policy was changed (#3114) or new users not
>>>>>>>>>>>>>>> being able to log
>>>>>>>>>>>>>>> in at all (#3312).
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> https://fedorahosted.org/freeipa/ticket/3312
>>>>>>>>>>>>>>> https://fedorahosted.org/freeipa/ticket/3114
>>>>>>>>>>>>>> Given that we control the KDC LDAP driver I
>>>>>>>>>>>>>> think we should not limit
>>>>>>>>>>>>>> the time in LDAP but rather 'fix-it-up' for
>>>>>>>>>>>>>> the KDC in the DAL driver.
>>>>>>>>>>>>> Fix how? Truncate to max in the driver itself if
>>>>>>>>>>>>> it was entered beyond max?
>>>>>>>>>>>>> Shouldn't we also prevent entering the invalid
>>>>>>>>>>>>> value into the attribute?
>>>>>>>>>>>>>
>>>>>>>>>>>> I've been mulling the same question for a while.
>>>>>>>>>>>> Why would we want to
>>>>>>>>>>>> let bad data get into the directory?
>>>>>>>>>>> It is not bad data and the attribute holds a
>>>>>>>>>>> Generalize time date.
>>>>>>>>>>>
>>>>>>>>>>> The data is valid it's the MIT code that has a
>>>>>>>>>>> limitation in parsing it.
>>>>>>>>>>>
>>>>>>>>>>> Greg tells me he plans supporting additional time by
>>>>>>>>>>> using the
>>>>>>>>>>> 'negative' part of the integer to represent the
>>>>>>>>>>> years beyond 2038.
>>>>>>>>>>>
>>>>>>>>>>> So we should represent data in the directory
>>>>>>>>>>> correctly, which means
>>>>>>>>>>> whtever date in the future and only chop it when
>>>>>>>>>>> feeding MIT libraries
>>>>>>>>>>> until they support the additional range at which
>>>>>>>>>>> time we will change and
>>>>>>>>>>> chop further in the future (around 2067 or so).
>>>>>>>>>>>
>>>>>>>>>>> If we chopped early in the directory we'd not be
>>>>>>>>>>> able to properly
>>>>>>>>>>> represent/change rapresentation later when MIT libs
>>>>>>>>>>> gain additional
>>>>>>>>>>> range capabilities.
>>>>>>>>>>>
>>>>>>>>>>> Simo.
>>>>>>>>>>>
>>>>>>>>>> We would have to change our code either way and the
>>>>>>>>>> amount of change
>>>>>>>>>> will be similar so does it really matter?
>>>>>>>>> Yes it really matters IMO.
>>>>>>>>>
>>>>>>>>> Simo.
>>>>>>>>>
>>>>>>>> Updated patch attached.
>>>>>>> This part looks ok but I think you also need to properly
>>>>>>> set
>>>>>>> krb5_db_entry-> {expiration, pw_expiration, last_success,
>>>>>>> last_failed}
>>>>>>> in ipadb_parse_ldap_entry()
>>>>>>>
>>>>>>> Perhaps the best way is to introduce a new function
>>>>>>> ipadb_ldap_attr_to_krb5_timestamp() in ipa_kdb_common.c so
>>>>>>> that you do
>>>>>>> all the overflow checkings once.
>>>>>>>
>>>>>>> Simo.
>>>>>>>
>>>>>> They all use ipadb_ldap_attr_to_time_t() to get their values,
>>>>>> so the following addition to the patch should be sufficient.
>>>>> It will break dates for other users of the function that do not
>>>>> need to
>>>>> artificially limit the results. Please add a new function.
>>>>>
>>>>> Simo.
>>>>>
>>>> Done.
>>>>
>>>> Tomas
>>>>
>>>>
>>>> _______________________________________________
>>>> Freeipa-devel mailing list
>>>> Freeipa-devel at redhat.com
>>>> https://www.redhat.com/mailman/listinfo/freeipa-devel
>>> Nack from me, sorry.
>>>
>>> +int ipadb_ldap_attr_to_krb5_timestamp(LDAP *lcontext, LDAPMessage *le,
>>> +                                      char *attrname, time_t *result)
>>> +{
>>> +    int ret = ipadb_ldab_attr_to_time_t(lcontext, le,
>>> +                                        attrname, result);
>>>
>>> This function converts the time from the LDAP time by reading the string into the struct elements and then constructing time by using timegm() which is really a wrapper around mktime().
>>> According to mktime() man page:
>>>
>>>         If  the  specified broken-down time cannot be represented as calendar time (seconds since
>>>         the Epoch), mktime() returns a value of (time_t) -1 and does not alter the members of the
>>>         broken-down time structure.
>>>
>>> However it might not be the case so it would be nice to check if this function actually returns some negative value other than -1 if the time is overflown.
>>> Regardles of that part if it always returns -1 or can return other negative values like -2 or -3 the check below would produce positive result thus causing the function to return whatever is currently in the *result.
>> I double checked the behaviour. It holds that mktime() and timegm()
>> behave the same way, up to time-zone difference. I don't know whether
>> the man page is not correct,
>> or the implementation in the standard library is not compliant,
>> however, mktime() never returns -1 as return value (if it was not
>> given tm struct which refers to 31 Dec 1969 29:59:59).
>>
>> I guess the implementation was changed as there would be no way how to
>> distinguish between correct output of 31 Dec 1969 29:59:59 and
>> incorrect output.
>>
>> I tested both incorrect calendar days (like 14th month) and dates
>> behind year 2038. As expected, dates after the end of unix epoch
>> overflow big time (values such as -2143152000).
>> Incorrect dates just get converted into correct ones - 14th month was
>> interpreted as +1 year +3 months.
>>
>>> IMO the whole fix should be implemented inside the function above when the conversion to time_t happens so that it would never produce a negative result.
>> Simo had objections to this approach since this would limit the other
>> uses of ipadb_ldap_attr_to_time_t() function.
>>> My suggestion would be before calling timegm() to test if the year, month, and day returned by the break-down structure contain the day after the last day of epoch and then just use use last day of epoc without even calling timegm().
>> Indeed it would be simpler approach. However, for the current solution
>> to malfunction (overflow back to the positive values), the date would
>> have to be set to something beyond year ~2100.
>> That would correspond to maxlife of ~32 000 days with present dates.
>>
>> I guess there might be admins setting crazy values like that, I'll
>> send updated patch.
>>
>>> +
>>> +    /* in the case of integer owerflow, set result to IPAPWD_END_OF_TIME */
>>> +    if ((*result+86400) < 0) {
>>>
>>>
>>>   +        *result = IPAPWD_END_OF_TIME; // 1 Jan 2038, 00:00 GMT
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> +
> Ok this mail made me look again in the issue.
>
> I see 2 problems here.
>
> 1) platform dependent issues.
>
> On i686 time_t is a signed 32bit integer (int)
> On x86_64 time_t is a signed 64bit integer (long long)
>
> So when you test you need to be aware on what platform you are testing
> in order to know what to expect.
>
> 2) The current patch returns time_t *result for the new wrapper function
> which is wrong, it shoul return krb5_timestamp as the type.
>
>
> The actual test done in the code looks ok but only if you think time_t
> is a 32bit signed integer.
> In that case it will overflow. But on x86_64 it will not.
> Sorry for not catching it earlier.
>
> So the way to handle this is to actually check this is to change the
> wrapper function to look like this:
>
> int ipadb_ldap_attr_to_krb5_timestamp(LDAP *lcontext, LDAPMessage *le,
>                                        char *attrname, krb5_timestamp *result)
> {
>      time_t restime;
>      long long reslong;
>
>      int ret = ipadb_ldab_attr_to_time_t(lcontext, le,
>                                          attrname, restime);
>      if (ret) return ret;
>
>      reslong = restime; // <- this will cast correctly maintaing sign to a 64bit variable
>      if (reslong < 0 || reslong > IPAPWD_END_OF_TIME) {
>          *result = IPAPWD_END_OF_TIME;
>      } else {
>          *result = (krb5_timestamp)reslong;
>      }
>      return 0;
> }
>
> All calls in ipadb_parse_ldap_entry() that expects a singed 32 bit time
> as output should be hanged to use ipadb_ldap_attr_to_krb5_timestamp()
>
> This includes 2 additional calls Tomas pointed to me on a IRC
> conversation.
>
> So Nack again :-/
>
> Simo.
>

Here I bring the updated version of the patch. Please note, that I *added*
a flag attribute to ipadb_ldap_attr_to_krb5_timestamp function, that 
controls
whether the timestamp will be checked for overflow or not. The reasoning
behind this is that some attributes will not be set to future dates, due to
their inherent nature - such as krbLastSuccessfulAuth or krbLastAdminUnlock.

These are all related to past dates, and it would make no sense to set them
to future dates, even manually. Therefore I'd rather represent negative 
values
in these attributes as past dates. They would have to be set manually 
anyway,
because they would represent timestamps before the beginning of the unix 
epoch,
however, I find this approach better than pushing them up to year 2038 
in case
such things happens.

Any objections to this approach?

Tomas

-------------- next part --------------
A non-text attachment was scrubbed...
Name: freeipa-tbabej-0026-6-Prevent-integer-overflow-when-setting-krbPasswordExp.patch
Type: text/x-patch
Size: 8675 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20130122/9e75041e/attachment.bin>


More information about the Freeipa-devel mailing list