diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 0cdecbd15..989afae19 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -21,6 +21,7 @@ import ( "github.com/lightninglabs/protobuf-hex-display/jsonpb" "github.com/lightninglabs/protobuf-hex-display/proto" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/signal" "github.com/urfave/cli" @@ -2029,7 +2030,7 @@ var updateChannelPolicyCommand = cli.Command{ "with a granularity of 0.000001 (millionths). Can not " + "be set at the same time as fee_rate.", }, - cli.Int64Flag{ + cli.Uint64Flag{ Name: "time_lock_delta", Usage: "the CLTV delta that will be applied to all " + "forwarded HTLCs", @@ -2080,6 +2081,25 @@ func parseChanPoint(s string) (*lnrpc.ChannelPoint, error) { }, nil } +// parseTimeLockDelta is expected to get a uint16 type of timeLockDelta, +// which maximum value is MaxTimeLockDelta. +func parseTimeLockDelta(timeLockDeltaStr string) (uint16, error) { + timeLockDeltaUnCheck, err := strconv.ParseUint( + timeLockDeltaStr, 10, 64, + ) + if err != nil { + return 0, fmt.Errorf("failed to parse time_lock_delta: %s "+ + "to uint64, err: %v", timeLockDeltaStr, err) + } + + if timeLockDeltaUnCheck > routing.MaxCLTVDelta { + return 0, fmt.Errorf("time_lock_delta is too big, "+ + "max value is %d", routing.MaxCLTVDelta) + } + + return uint16(timeLockDeltaUnCheck), nil +} + func updateChannelPolicy(ctx *cli.Context) error { ctxc := getContext() client, cleanUp := getClient(ctx) @@ -2089,7 +2109,7 @@ func updateChannelPolicy(ctx *cli.Context) error { baseFee int64 feeRate float64 feeRatePpm uint64 - timeLockDelta int64 + timeLockDelta uint16 err error ) args := ctx.Args() @@ -2127,12 +2147,15 @@ func updateChannelPolicy(ctx *cli.Context) error { switch { case ctx.IsSet("time_lock_delta"): - timeLockDelta = ctx.Int64("time_lock_delta") - case args.Present(): - timeLockDelta, err = strconv.ParseInt(args.First(), 10, 64) + timeLockDeltaStr := ctx.String("time_lock_delta") + timeLockDelta, err = parseTimeLockDelta(timeLockDeltaStr) if err != nil { - return fmt.Errorf("unable to decode time_lock_delta: %v", - err) + return err + } + case args.Present(): + timeLockDelta, err = parseTimeLockDelta(args.First()) + if err != nil { + return err } args = args.Tail() diff --git a/config.go b/config.go index e49bbc909..6130410e6 100644 --- a/config.go +++ b/config.go @@ -98,6 +98,10 @@ const ( // HTLCs on our channels. minTimeLockDelta = routing.MinCLTVDelta + // MaxTimeLockDelta is the maximum CLTV delta that can be applied to + // forwarded HTLCs. + MaxTimeLockDelta = routing.MaxCLTVDelta + // defaultAcceptorTimeout is the time after which an RPCAcceptor will time // out and return false if it hasn't yet received a response. defaultAcceptorTimeout = 15 * time.Second diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index b6e9a9f16..afb702380 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -4,6 +4,10 @@ * The `lncli wallet psbt fund` command now allows users to specify the [`--min_confs` flag](https://github.com/lightningnetwork/lnd/pull/7510). + +* [Add time_lock_delta overflow check for UpdateChannelPolicy](https://github.com/lightningnetwork/lnd/pull/7350) + that ensure `time_lock_delta` is greater or equal than `0` and less or equal than `65535` + ## Watchtowers diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 00e88ecc1..745952147 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -348,7 +348,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, // We'll use our current default CLTV value unless one was specified as // an option on the command line when creating an invoice. switch { - case invoice.CltvExpiry > math.MaxUint16: + case invoice.CltvExpiry > routing.MaxCLTVDelta: return nil, nil, fmt.Errorf("CLTV delta of %v is too large, "+ "max accepted is: %v", invoice.CltvExpiry, math.MaxUint16) diff --git a/routing/router.go b/routing/router.go index eea5189d9..f4de5a784 100644 --- a/routing/router.go +++ b/routing/router.go @@ -4,6 +4,7 @@ import ( "bytes" goErrors "errors" "fmt" + "math" "runtime" "strings" "sync" @@ -80,6 +81,10 @@ const ( // bitcoin (160 for litecoin), though we now clamp the lower end of this // range for user-chosen deltas to 18 blocks to be conservative. MinCLTVDelta = 18 + + // MaxCLTVDelta is the maximum CLTV value accepted by LND for all + // timelock deltas. + MaxCLTVDelta = math.MaxUint16 ) var ( diff --git a/rpcserver.go b/rpcserver.go index f531e8a5b..9dac0b977 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6827,6 +6827,10 @@ func (r *rpcServer) UpdateChannelPolicy(ctx context.Context, return nil, fmt.Errorf("time lock delta of %v is too small, "+ "minimum supported is %v", req.TimeLockDelta, minTimeLockDelta) + } else if req.TimeLockDelta > uint32(MaxTimeLockDelta) { + return nil, fmt.Errorf("time lock delta of %v is too big, "+ + "maximum supported is %v", req.TimeLockDelta, + MaxTimeLockDelta) } baseFeeMsat := lnwire.MilliSatoshi(req.BaseFeeMsat)