| .. SPDX-License-Identifier: GPL-2.0 | |
| ======================= | |
| NFSv4 client identifier | |
| ======================= | |
| This document explains how the NFSv4 protocol identifies client | |
| instances in order to maintain file open and lock state during | |
| system restarts. A special identifier and principal are maintained | |
| on each client. These can be set by administrators, scripts | |
| provided by site administrators, or tools provided by Linux | |
| distributors. | |
| There are risks if a client's NFSv4 identifier and its principal | |
| are not chosen carefully. | |
| Introduction | |
| ------------ | |
| The NFSv4 protocol uses "lease-based file locking". Leases help | |
| NFSv4 servers provide file lock guarantees and manage their | |
| resources. | |
| Simply put, an NFSv4 server creates a lease for each NFSv4 client. | |
| The server collects each client's file open and lock state under | |
| the lease for that client. | |
| The client is responsible for periodically renewing its leases. | |
| While a lease remains valid, the server holding that lease | |
| guarantees the file locks the client has created remain in place. | |
| If a client stops renewing its lease (for example, if it crashes), | |
| the NFSv4 protocol allows the server to remove the client's open | |
| and lock state after a certain period of time. When a client | |
| restarts, it indicates to servers that open and lock state | |
| associated with its previous leases is no longer valid and can be | |
| destroyed immediately. | |
| In addition, each NFSv4 server manages a persistent list of client | |
| leases. When the server restarts and clients attempt to recover | |
| their state, the server uses this list to distinguish amongst | |
| clients that held state before the server restarted and clients | |
| sending fresh OPEN and LOCK requests. This enables file locks to | |
| persist safely across server restarts. | |
| NFSv4 client identifiers | |
| ------------------------ | |
| Each NFSv4 client presents an identifier to NFSv4 servers so that | |
| they can associate the client with its lease. Each client's | |
| identifier consists of two elements: | |
| - co_ownerid: An arbitrary but fixed string. | |
| - boot verifier: A 64-bit incarnation verifier that enables a | |
| server to distinguish successive boot epochs of the same client. | |
| The NFSv4.0 specification refers to these two items as an | |
| "nfs_client_id4". The NFSv4.1 specification refers to these two | |
| items as a "client_owner4". | |
| NFSv4 servers tie this identifier to the principal and security | |
| flavor that the client used when presenting it. Servers use this | |
| principal to authorize subsequent lease modification operations | |
| sent by the client. Effectively this principal is a third element of | |
| the identifier. | |
| As part of the identity presented to servers, a good | |
| "co_ownerid" string has several important properties: | |
| - The "co_ownerid" string identifies the client during reboot | |
| recovery, therefore the string is persistent across client | |
| reboots. | |
| - The "co_ownerid" string helps servers distinguish the client | |
| from others, therefore the string is globally unique. Note | |
| that there is no central authority that assigns "co_ownerid" | |
| strings. | |
| - Because it often appears on the network in the clear, the | |
| "co_ownerid" string does not reveal private information about | |
| the client itself. | |
| - The content of the "co_ownerid" string is set and unchanging | |
| before the client attempts NFSv4 mounts after a restart. | |
| - The NFSv4 protocol places a 1024-byte limit on the size of the | |
| "co_ownerid" string. | |
| Protecting NFSv4 lease state | |
| ---------------------------- | |
| NFSv4 servers utilize the "client_owner4" as described above to | |
| assign a unique lease to each client. Under this scheme, there are | |
| circumstances where clients can interfere with each other. This is | |
| referred to as "lease stealing". | |
| If distinct clients present the same "co_ownerid" string and use | |
| the same principal (for example, AUTH_SYS and UID 0), a server is | |
| unable to tell that the clients are not the same. Each distinct | |
| client presents a different boot verifier, so it appears to the | |
| server as if there is one client that is rebooting frequently. | |
| Neither client can maintain open or lock state in this scenario. | |
| If distinct clients present the same "co_ownerid" string and use | |
| distinct principals, the server is likely to allow the first client | |
| to operate normally but reject subsequent clients with the same | |
| "co_ownerid" string. | |
| If a client's "co_ownerid" string or principal are not stable, | |
| state recovery after a server or client reboot is not guaranteed. | |
| If a client unexpectedly restarts but presents a different | |
| "co_ownerid" string or principal to the server, the server orphans | |
| the client's previous open and lock state. This blocks access to | |
| locked files until the server removes the orphaned state. | |
| If the server restarts and a client presents a changed "co_ownerid" | |
| string or principal to the server, the server will not allow the | |
| client to reclaim its open and lock state, and may give those locks | |
| to other clients in the meantime. This is referred to as "lock | |
| stealing". | |
| Lease stealing and lock stealing increase the potential for denial | |
| of service and in rare cases even data corruption. | |
| Selecting an appropriate client identifier | |
| ------------------------------------------ | |
| By default, the Linux NFSv4 client implementation constructs its | |
| "co_ownerid" string starting with the words "Linux NFS" followed by | |
| the client's UTS node name (the same node name, incidentally, that | |
| is used as the "machine name" in an AUTH_SYS credential). In small | |
| deployments, this construction is usually adequate. Often, however, | |
| the node name by itself is not adequately unique, and can change | |
| unexpectedly. Problematic situations include: | |
| - NFS-root (diskless) clients, where the local DHCP server (or | |
| equivalent) does not provide a unique host name. | |
| - "Containers" within a single Linux host. If each container has | |
| a separate network namespace, but does not use the UTS namespace | |
| to provide a unique host name, then there can be multiple NFS | |
| client instances with the same host name. | |
| - Clients across multiple administrative domains that access a | |
| common NFS server. If hostnames are not assigned centrally | |
| then uniqueness cannot be guaranteed unless a domain name is | |
| included in the hostname. | |
| Linux provides two mechanisms to add uniqueness to its "co_ownerid" | |
| string: | |
| nfs.nfs4_unique_id | |
| This module parameter can set an arbitrary uniquifier string | |
| via the kernel command line, or when the "nfs" module is | |
| loaded. | |
| /sys/fs/nfs/net/nfs_client/identifier | |
| This virtual file, available since Linux 5.3, is local to the | |
| network namespace in which it is accessed and so can provide | |
| distinction between network namespaces (containers) when the | |
| hostname remains uniform. | |
| Note that this file is empty on name-space creation. If the | |
| container system has access to some sort of per-container identity | |
| then that uniquifier can be used. For example, a uniquifier might | |
| be formed at boot using the container's internal identifier: | |
| sha256sum /etc/machine-id | awk '{print $1}' \\ | |
| > /sys/fs/nfs/net/nfs_client/identifier | |
| Security considerations | |
| ----------------------- | |
| The use of cryptographic security for lease management operations | |
| is strongly encouraged. | |
| If NFS with Kerberos is not configured, a Linux NFSv4 client uses | |
| AUTH_SYS and UID 0 as the principal part of its client identity. | |
| This configuration is not only insecure, it increases the risk of | |
| lease and lock stealing. However, it might be the only choice for | |
| client configurations that have no local persistent storage. | |
| "co_ownerid" string uniqueness and persistence is critical in this | |
| case. | |
| When a Kerberos keytab is present on a Linux NFS client, the client | |
| attempts to use one of the principals in that keytab when | |
| identifying itself to servers. The "sec=" mount option does not | |
| control this behavior. Alternately, a single-user client with a | |
| Kerberos principal can use that principal in place of the client's | |
| host principal. | |
| Using Kerberos for this purpose enables the client and server to | |
| use the same lease for operations covered by all "sec=" settings. | |
| Additionally, the Linux NFS client uses the RPCSEC_GSS security | |
| flavor with Kerberos and the integrity QOS to prevent in-transit | |
| modification of lease modification requests. | |
| Additional notes | |
| ---------------- | |
| The Linux NFSv4 client establishes a single lease on each NFSv4 | |
| server it accesses. NFSv4 mounts from a Linux NFSv4 client of a | |
| particular server then share that lease. | |
| Once a client establishes open and lock state, the NFSv4 protocol | |
| enables lease state to transition to other servers, following data | |
| that has been migrated. This hides data migration completely from | |
| running applications. The Linux NFSv4 client facilitates state | |
| migration by presenting the same "client_owner4" to all servers it | |
| encounters. | |
| ======== | |
| See Also | |
| ======== | |
| - nfs(5) | |
| - kerberos(7) | |
| - RFC 7530 for the NFSv4.0 specification | |
| - RFC 8881 for the NFSv4.1 specification. |