]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ksmbd: normalize ungrantable lease states
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 21 Jun 2026 10:50:12 +0000 (19:50 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 01:15:06 +0000 (20:15 -0500)
smb2.lease.request verifies which SMB2 lease state combinations are granted
by the server.  Requests for H-only, W-only, and HW leases are valid lease
state bitmasks, but they are not grantable combinations and should be
returned as lease state none.

ksmbd only checked that the requested bits were inside the SMB2 lease state
mask.  As a result it could grant H-only, W-only, or HW requests and return
non-zero lease states where the client expects no lease.

Keep the bitmask validation, but normalize ungrantable combinations to zero
before allocating or looking up the lease.  The grantable combinations
remain unchanged: R, RH, RW, and RHW.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/oplock.c

index 5abeb90ebebb3bc76e69dd389351feca9f5fa9cf..331ce10dbb669a9bdfe957b7a13b782dbaa18f00 100644 (file)
@@ -29,6 +29,17 @@ static bool lease_state_valid(__le32 state)
        return !(state & ~SMB2_LEASE_STATE_MASK_LE);
 }
 
+static __le32 lease_state_grantable(__le32 state)
+{
+       if (state == SMB2_LEASE_READ_CACHING_LE ||
+           state == (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE) ||
+           state == (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_WRITE_CACHING_LE) ||
+           state == SMB2_LEASE_STATE_MASK_LE)
+               return state;
+
+       return 0;
+}
+
 static bool lease_v2_flags_valid(__le32 flags)
 {
        return !(flags & ~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE);
@@ -1760,6 +1771,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
                if (!lease_state_valid(lreq->req_state) ||
                    !lease_v2_flags_valid(lreq->flags))
                        goto err_out;
+               lreq->req_state = lease_state_grantable(lreq->req_state);
                if (lreq->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
                        memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
                               SMB2_LEASE_KEY_SIZE);
@@ -1777,6 +1789,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
                lreq->duration = lc->lcontext.LeaseDuration;
                if (!lease_state_valid(lreq->req_state))
                        goto err_out;
+               lreq->req_state = lease_state_grantable(lreq->req_state);
                lreq->version = 1;
        } else
                goto err_out;