nfs: Permit null requests (aka server pings) from non-reserved ports
authorratchov <ratchov@openbsd.org>
Fri, 19 Apr 2024 06:50:37 +0000 (06:50 +0000)
committerratchov <ratchov@openbsd.org>
Fri, 19 Apr 2024 06:50:37 +0000 (06:50 +0000)
Unfortunately, this is recommended by rfc 2623 and used by Linux
nfs-utils to mount NFS exports. So until nfs-utils switches into
using reserved ports, this is needed to mount OpenBSD file-systems
on most (all?) Linux distros.

Bits from claudio, ok millert

sys/nfs/nfs_socket.c
sys/nfs/nfs_syscalls.c

index 9760db8..1f8635e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nfs_socket.c,v 1.147 2024/03/31 13:50:00 mvs Exp $    */
+/*     $OpenBSD: nfs_socket.c,v 1.148 2024/04/19 06:50:37 ratchov Exp $        */
 /*     $NetBSD: nfs_socket.c,v 1.27 1996/04/15 20:20:00 thorpej Exp $  */
 
 /*
@@ -1588,7 +1588,7 @@ nfsrv_rcv(struct socket *so, caddr_t arg, int waitflag)
                 */
                auio.uio_resid = 1000000000;
                flags = MSG_DONTWAIT;
-               error = soreceive(so, &nam, &auio, &mp, NULL,
+               error = soreceive(so, NULL, &auio, &mp, NULL,
                    &flags, 0);
                if (error || mp == NULL) {
                        if (error == EWOULDBLOCK)
@@ -1626,20 +1626,6 @@ nfsrv_rcv(struct socket *so, caddr_t arg, int waitflag)
                        error = soreceive(so, &nam, &auio, &mp,
                            NULL, &flags, 0);
                        if (mp) {
-                               struct sockaddr_in *sin;
-
-                               if (nam == NULL) {
-                                       nfsstats.srv_errs++;
-                                       m_freem(mp);
-                                       continue;
-                               }
-                               if (in_nam2sin(nam, &sin) != 0 ||
-                                   ntohs(sin->sin_port) >= IPPORT_RESERVED) {
-                                       nfsstats.srv_errs++;
-                                       m_freem(nam);
-                                       m_freem(mp);
-                                       continue;
-                               }
                                m = nam;
                                m->m_next = mp;
                                if (slp->ns_recend)
index 32f28f0..13bbd64 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nfs_syscalls.c,v 1.123 2024/03/31 13:50:00 mvs Exp $  */
+/*     $OpenBSD: nfs_syscalls.c,v 1.124 2024/04/19 06:50:37 ratchov Exp $      */
 /*     $NetBSD: nfs_syscalls.c,v 1.19 1996/02/18 11:53:52 fvdl Exp $   */
 
 /*
@@ -251,18 +251,6 @@ nfssvc_addsock(struct file *fp, struct mbuf *mynam)
                m_freem(mynam);
                return (EINVAL);
        }
-       if (mynam != NULL) {
-               struct sockaddr_in *sin;
-               error = in_nam2sin(mynam, &sin);
-               if (error) {
-                       m_freem(mynam);
-                       return (error);
-               }
-               if (ntohs(sin->sin_port) >= IPPORT_RESERVED) {
-                       m_freem(mynam);
-                       return (ECONNREFUSED);
-               }
-       }
 
        if (so->so_type == SOCK_STREAM)
                siz = NFS_MAXPACKET + sizeof (u_long);
@@ -323,6 +311,18 @@ nfssvc_addsock(struct file *fp, struct mbuf *mynam)
        return (0);
 }
 
+static inline int nfssvc_checknam(struct mbuf *nam)
+{
+       struct sockaddr_in *sin;
+
+       if (nam == NULL ||
+           in_nam2sin(nam, &sin) != 0 ||
+           ntohs(sin->sin_port) >= IPPORT_RESERVED) {
+               return -1;
+       }
+       return 0;
+}
+
 /*
  * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
  * until it is killed by a signal.
@@ -402,6 +402,16 @@ loop:
        cacherep = nfsrv_getcache(nd, slp, &mreq);
        switch (cacherep) {
        case RC_DOIT:
+               /*
+                * Unless this is a null request (server ping), make
+                * sure that the client is using a reserved source port.
+                */
+               if (nd->nd_procnum != 0 && nfssvc_checknam(nd->nd_nam) == -1) {
+                       /* drop it */
+                       m_freem(nd->nd_mrep);
+                       m_freem(nd->nd_nam2);
+                       break;
+               }
                error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, slp, nfsd->nfsd_procp, &mreq);
                if (mreq == NULL) {
                        if (nd != NULL) {