shadow-maint/shadow

Signed integer overflows in day processing

stoeckmann opened this issue · 0 comments

The day processing within shadow is prone to signed integer overflows, leading to undefined behavior with very large numbers.

See #876 for a possible solution.

Proof of Concept (for 64 bit systems):

  1. Compile and definitely use an sgetspent implementation which gets long parsing right (glibc does not)
ac_cv_func_getspnam=no \
ac_cv_func_sgetspent=no \
CFLAGS="-fsanitize=undefined" \
./configure --without-libpam
  1. Setup users with large shadow entries
# chage -m 10 user1
# chage -d 9223372036854775807 user1
# chage -M 10 user2
# chage -d 9223372036854775807 user2
# chage -M 10 user3
# chage -I 20 user3
# chage -d 9223372036854775807 user3
# chage -I 20 user4
# chage -W 1 user4
# chage -d 123 user4
# chage -M 9223372036854775807 user4
  1. Change password as user1
$ passwd
../../src/passwd.c:393:6: runtime error: signed integer overflow: 9223372036854775807 * 86400 cannot be represented in type 'long int'
  1. Run expiry as user2
$ expiry -c
../../lib/isexpired.c:97:28: runtime error: signed integer overflow: 9223372036854775807 + 10 cannot be represented in type 'long int'
  1. Run expiry as user3
$ expiry -c
../../lib/age.c:165:25: runtime error: signed integer overflow: 9223372036854775807 + 99999 cannot be represented in type 'long int'
../../lib/isexpired.c:75:32: runtime error: signed integer overflow: 9223372036854775807 + 99999 cannot be represented in type 'long int'
  1. Run expiry as user4
$ expiry -c
../../lib/age.c:165:25: runtime error: signed integer overflow: 123 + 9223372036854775807 cannot be represented in type 'long int'
../../lib/age.c:165:9: runtime error: signed integer overflow: -9223372036854775686 - 19709 cannot be represented in type 'long int'
../../lib/isexpired.c:75:32: runtime error: signed integer overflow: 123 + 9223372036854775807 cannot be represented in type 'long int'

The user1 password change should not be allowed because the minimum wait time since last change (in the future) is not reached yet.