diff mbox series

[-next,v3,1/2] posix-timers: Check timespec64 before call clock_set()

Message ID 20240909074124.964907-2-ruanjinjie@huawei.com (mailing list archive)
State Changes Requested
Headers show
Series posix-timers: Check timespec64 before call clock_set() | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 16 this patch: 16
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 5 of 5 maintainers
netdev/build_clang success Errors and warnings before: 16 this patch: 16
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 27 this patch: 27
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 9 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Jinjie Ruan Sept. 9, 2024, 7:41 a.m. UTC
As Andrew pointed out, it will make sense that the PTP core
checked timespec64 struct's tv_sec and tv_nsec range before calling
ptp->info->settime64(). Check it ahead in more higher layer
clock_settime() as Richard suggested.

There are some drivers that use tp->tv_sec and tp->tv_nsec directly to
write registers without validity checks and assume that the higher layer
has checked it, which is dangerous and will benefit from this, such as
hclge_ptp_settime(), igb_ptp_settime_i210(), _rcar_gen4_ptp_settime(),
and some drivers can remove the checks of itself.

Suggested-by: Richard Cochran <richardcochran@gmail.com>
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
v3:
- Adjust to check in more higher layer clock_settime().
- Remove the NULL check.
- Update the commit message and subject.
v2:
- Adjust to check in ptp_clock_settime().
---
 kernel/time/posix-timers.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Richard Cochran Sept. 9, 2024, 3:19 p.m. UTC | #1
On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
> index 1cc830ef93a7..34deec619e17 100644
> --- a/kernel/time/posix-timers.c
> +++ b/kernel/time/posix-timers.c
> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>  	if (get_timespec64(&new_tp, tp))
>  		return -EFAULT;
>  
> +	if (!timespec64_valid(&new_tp))
> +		return -ERANGE;

Why not use timespec64_valid_settod()?

Thanks,
Richard
Jinjie Ruan Sept. 10, 2024, 11:23 a.m. UTC | #2
On 2024/9/9 23:19, Richard Cochran wrote:
> On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>> index 1cc830ef93a7..34deec619e17 100644
>> --- a/kernel/time/posix-timers.c
>> +++ b/kernel/time/posix-timers.c
>> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>>  	if (get_timespec64(&new_tp, tp))
>>  		return -EFAULT;
>>  
>> +	if (!timespec64_valid(&new_tp))
>> +		return -ERANGE;
> 
> Why not use timespec64_valid_settod()?

It seems more limited and is only used in timekeeping or
do_sys_settimeofday64().

And the timespec64_valid() is looser and wider used, which I think is
more appropriate here.

> 
> Thanks,
> Richard
Thomas Gleixner Sept. 10, 2024, 12:05 p.m. UTC | #3
On Tue, Sep 10 2024 at 19:23, Jinjie Ruan wrote:
> On 2024/9/9 23:19, Richard Cochran wrote:
>> On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
>>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>>> index 1cc830ef93a7..34deec619e17 100644
>>> --- a/kernel/time/posix-timers.c
>>> +++ b/kernel/time/posix-timers.c
>>> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>>>  	if (get_timespec64(&new_tp, tp))
>>>  		return -EFAULT;
>>>  
>>> +	if (!timespec64_valid(&new_tp))
>>> +		return -ERANGE;
>> 
>> Why not use timespec64_valid_settod()?
>
> It seems more limited and is only used in timekeeping or
> do_sys_settimeofday64().

For a very good reason.

> And the timespec64_valid() is looser and wider used, which I think is
> more appropriate here.

Can you please stop this handwaving and provide proper technical
arguments?

Why would PTP have less strict requirements than settimeofday()?

Thanks,

        tglx
Jinjie Ruan Sept. 10, 2024, 12:30 p.m. UTC | #4
On 2024/9/10 20:05, Thomas Gleixner wrote:
> On Tue, Sep 10 2024 at 19:23, Jinjie Ruan wrote:
>> On 2024/9/9 23:19, Richard Cochran wrote:
>>> On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
>>>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>>>> index 1cc830ef93a7..34deec619e17 100644
>>>> --- a/kernel/time/posix-timers.c
>>>> +++ b/kernel/time/posix-timers.c
>>>> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>>>>  	if (get_timespec64(&new_tp, tp))
>>>>  		return -EFAULT;
>>>>  
>>>> +	if (!timespec64_valid(&new_tp))
>>>> +		return -ERANGE;
>>>
>>> Why not use timespec64_valid_settod()?
>>
>> It seems more limited and is only used in timekeeping or
>> do_sys_settimeofday64().
> 
> For a very good reason.
> 
>> And the timespec64_valid() is looser and wider used, which I think is
>> more appropriate here.
> 
> Can you please stop this handwaving and provide proper technical
> arguments?
> 
> Why would PTP have less strict requirements than settimeofday()?

I checked all the PTP driver, most of them use timespec64_to_ns()
convert them to ns which already have a check, but the others not check
them, and lan743x_ptp check them differently and more, so i think this
is a minimum check.

Use timespec64_to_ns()
- drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c:
- drivers/net/ethernet/cavium/liquidio/lio_main.c:
- drivers/net/ethernet/engleder/tsnep_ptp.c
- drivers/net/ethernet/freescale/fec_ptp.c
- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c:
- drivers/net/ethernet/intel/i40e/i40e_ptp.c
- drivers/net/ethernet/intel/ice/ice_ptp.c
- drivers/net/ethernet/intel/igc/igc_ptp.c
- drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
- drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c
- drivers/net/ethernet/qlogic/qede/qede_ptp.c
- drivers/ptp/ptp_idt82p33.c

Not check:
- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
- drivers/net/ethernet/intel/igb/igb_ptp.c (only one igb_ptp_settime_i210())
- drivers/net/ethernet/marvell/mvpp2/mvpp2_tai.c
- drivers/net/ethernet/renesas/rcar_gen4_ptp.c
-
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
- drivers/net/phy/micrel.c
- drivers/ptp/ptp_dfl_tod.c

Self check and check more:
- drivers/net/ethernet/microchip/lan743x_ptp.c

> 
> Thanks,
> 
>         tglx
> 
>
Thomas Gleixner Sept. 10, 2024, 3:48 p.m. UTC | #5
On Tue, Sep 10 2024 at 20:30, Jinjie Ruan wrote:
> On 2024/9/10 20:05, Thomas Gleixner wrote:
>> Can you please stop this handwaving and provide proper technical
>> arguments?
>> 
>> Why would PTP have less strict requirements than settimeofday()?
>
> I checked all the PTP driver, most of them use timespec64_to_ns()
> convert them to ns which already have a check, but the others not check
> them, and lan743x_ptp check them differently and more, so i think this
> is a minimum check.

It does not matter at all what the PTP drivers do. What matters is what
is correct and what not.

What they do is actually wrong as they simply cut off an overly large
value instead of rejecting it in the first place. That's not a check at
all.

The cutoff in timespec64_to_ns() is there to saturate the result instead
of running into a multiplication overflow. That's correct for some use
cases, but not a replacement for an actual useful range check.

This is about correctness and correctness is not defined by what a bunch
of drivers implement which are all a big copy & pasta orgy.

Thanks,

        tglx
Jinjie Ruan Sept. 12, 2024, 2:53 a.m. UTC | #6
On 2024/9/9 23:19, Richard Cochran wrote:
> On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>> index 1cc830ef93a7..34deec619e17 100644
>> --- a/kernel/time/posix-timers.c
>> +++ b/kernel/time/posix-timers.c
>> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>>  	if (get_timespec64(&new_tp, tp))
>>  		return -EFAULT;
>>  
>> +	if (!timespec64_valid(&new_tp))
>> +		return -ERANGE;
> 
> Why not use timespec64_valid_settod()?

There was already checks in following code, so it is not necessary to
check NULL or timespec64_valid() in ptp core and its drivers, only the
second patch is needed.

169 int do_sys_settimeofday64(const struct timespec64 *tv, const struct
timezone *tz)
 170 {
 171 >-------static int firsttime = 1;
 172 >-------int error = 0;
 173
 174 >-------if (tv && !timespec64_valid_settod(tv))
 175 >------->-------return -EINVAL;



> 
> Thanks,
> Richard
Thomas Gleixner Sept. 12, 2024, 12:04 p.m. UTC | #7
On Thu, Sep 12 2024 at 10:53, Jinjie Ruan wrote:

> On 2024/9/9 23:19, Richard Cochran wrote:
>> On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
>>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>>> index 1cc830ef93a7..34deec619e17 100644
>>> --- a/kernel/time/posix-timers.c
>>> +++ b/kernel/time/posix-timers.c
>>> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>>>  	if (get_timespec64(&new_tp, tp))
>>>  		return -EFAULT;
>>>  
>>> +	if (!timespec64_valid(&new_tp))
>>> +		return -ERANGE;
>> 
>> Why not use timespec64_valid_settod()?
>
> There was already checks in following code, so it is not necessary to
> check NULL or timespec64_valid() in ptp core and its drivers, only the
> second patch is needed.
>
> 169 int do_sys_settimeofday64(const struct timespec64 *tv, const struct
> timezone *tz)
>  170 {
>  171 >-------static int firsttime = 1;
>  172 >-------int error = 0;
>  173
>  174 >-------if (tv && !timespec64_valid_settod(tv))
>  175 >------->-------return -EINVAL;

How does this code validate timespecs for clock_settime(clockid) where
clockid != CLOCK_REALTIME?

Thanks,

        tglx
Jinjie Ruan Sept. 12, 2024, 12:24 p.m. UTC | #8
On 2024/9/12 20:04, Thomas Gleixner wrote:
> On Thu, Sep 12 2024 at 10:53, Jinjie Ruan wrote:
> 
>> On 2024/9/9 23:19, Richard Cochran wrote:
>>> On Mon, Sep 09, 2024 at 03:41:23PM +0800, Jinjie Ruan wrote:
>>>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>>>> index 1cc830ef93a7..34deec619e17 100644
>>>> --- a/kernel/time/posix-timers.c
>>>> +++ b/kernel/time/posix-timers.c
>>>> @@ -1137,6 +1137,9 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
>>>>  	if (get_timespec64(&new_tp, tp))
>>>>  		return -EFAULT;
>>>>  
>>>> +	if (!timespec64_valid(&new_tp))
>>>> +		return -ERANGE;
>>>
>>> Why not use timespec64_valid_settod()?
>>
>> There was already checks in following code, so it is not necessary to
>> check NULL or timespec64_valid() in ptp core and its drivers, only the
>> second patch is needed.
>>
>> 169 int do_sys_settimeofday64(const struct timespec64 *tv, const struct
>> timezone *tz)
>>  170 {
>>  171 >-------static int firsttime = 1;
>>  172 >-------int error = 0;
>>  173
>>  174 >-------if (tv && !timespec64_valid_settod(tv))
>>  175 >------->-------return -EINVAL;
> 
> How does this code validate timespecs for clock_settime(clockid) where
> clockid != CLOCK_REALTIME?

According to the man manual of clock_settime(), the other clockids are
not settable.

And in Linux kernel code, except for CLOCK_REALTIME which is defined in
posix_clocks array, the clock_set() hooks are not defined and will
return -EINVAL in SYSCALL_DEFINE2(clock_settime), so the check is not
necessary.

> 
> Thanks,
> 
>         tglx
Thomas Gleixner Sept. 13, 2024, 10:46 a.m. UTC | #9
On Thu, Sep 12 2024 at 20:24, Jinjie Ruan wrote:
> On 2024/9/12 20:04, Thomas Gleixner wrote:
>> How does this code validate timespecs for clock_settime(clockid) where
>> clockid != CLOCK_REALTIME?
>
> According to the man manual of clock_settime(), the other clockids are
> not settable.
>
> And in Linux kernel code, except for CLOCK_REALTIME which is defined in
> posix_clocks array, the clock_set() hooks are not defined and will
> return -EINVAL in SYSCALL_DEFINE2(clock_settime), so the check is not
> necessary.

You clearly understand the code you are modifying:

const struct k_clock clock_posix_dynamic = {
	.clock_getres           = pc_clock_getres,
        .clock_set              = pc_clock_settime, 

which is what PTP clocks use and that's what this is about, no?

Thanks,

        tglx
Jinjie Ruan Sept. 14, 2024, 9 a.m. UTC | #10
On 2024/9/13 18:46, Thomas Gleixner wrote:
> On Thu, Sep 12 2024 at 20:24, Jinjie Ruan wrote:
>> On 2024/9/12 20:04, Thomas Gleixner wrote:
>>> How does this code validate timespecs for clock_settime(clockid) where
>>> clockid != CLOCK_REALTIME?
>>
>> According to the man manual of clock_settime(), the other clockids are
>> not settable.
>>
>> And in Linux kernel code, except for CLOCK_REALTIME which is defined in
>> posix_clocks array, the clock_set() hooks are not defined and will
>> return -EINVAL in SYSCALL_DEFINE2(clock_settime), so the check is not
>> necessary.
> 
> You clearly understand the code you are modifying:
> 
> const struct k_clock clock_posix_dynamic = {
> 	.clock_getres           = pc_clock_getres,
>         .clock_set              = pc_clock_settime, 
> 
> which is what PTP clocks use and that's what this is about, no?

Yes, it uses the dynamic one rather than the static ones.

> 
> Thanks,
> 
>         tglx
diff mbox series

Patch

diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 1cc830ef93a7..34deec619e17 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1137,6 +1137,9 @@  SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
 	if (get_timespec64(&new_tp, tp))
 		return -EFAULT;
 
+	if (!timespec64_valid(&new_tp))
+		return -ERANGE;
+
 	/*
 	 * Permission checks have to be done inside the clock specific
 	 * setter callback.