Fix catastrophic bug in NQNFS related to UDP mounts. The 'nqhost'
struct contains a major union for which lph_slp was being initialized only for TCP connections, but accessed for all types of connections leading to a crash. Also, a conditional controlling an nfs_slplock() call contained an improper paren grouping, causing a second crash in the UDP case. The nqhost structure has been reorganized and lph_slp has been made a normal structural field rather then a union field, and properly initialized for all connection types. Approved by: jkh
This commit is contained in:
parent
45248baa3c
commit
c9ef26814c
@ -387,6 +387,7 @@ nqsrv_addhost(lph, slp, nam)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nsso = slp->ns_so;
|
nsso = slp->ns_so;
|
||||||
|
lph->lph_slp = slp;
|
||||||
if (nsso && nsso->so_proto->pr_protocol == IPPROTO_UDP) {
|
if (nsso && nsso->so_proto->pr_protocol == IPPROTO_UDP) {
|
||||||
saddr = (struct sockaddr_in *)nam;
|
saddr = (struct sockaddr_in *)nam;
|
||||||
lph->lph_flag |= (LC_VALID | LC_UDP);
|
lph->lph_flag |= (LC_VALID | LC_UDP);
|
||||||
@ -399,7 +400,6 @@ nqsrv_addhost(lph, slp, nam)
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
lph->lph_flag |= (LC_VALID | LC_SREF);
|
lph->lph_flag |= (LC_VALID | LC_SREF);
|
||||||
lph->lph_slp = slp;
|
|
||||||
slp->ns_sref++;
|
slp->ns_sref++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,7 +506,6 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred)
|
|||||||
register int siz;
|
register int siz;
|
||||||
struct nqm *lphnext = lp->lc_morehosts;
|
struct nqm *lphnext = lp->lc_morehosts;
|
||||||
struct mbuf *m, *mreq, *mb, *mb2, *mheadend;
|
struct mbuf *m, *mreq, *mb, *mb2, *mheadend;
|
||||||
struct socket *so;
|
|
||||||
struct sockaddr *nam2;
|
struct sockaddr *nam2;
|
||||||
struct sockaddr_in *saddr;
|
struct sockaddr_in *saddr;
|
||||||
nfsfh_t nfh;
|
nfsfh_t nfh;
|
||||||
@ -514,12 +513,16 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred)
|
|||||||
caddr_t bpos, cp;
|
caddr_t bpos, cp;
|
||||||
u_int32_t xid, *tl;
|
u_int32_t xid, *tl;
|
||||||
int len = 1, ok = 1, i = 0;
|
int len = 1, ok = 1, i = 0;
|
||||||
int sotype, *solockp;
|
|
||||||
|
|
||||||
while (ok && (lph->lph_flag & LC_VALID)) {
|
while (ok && (lph->lph_flag & LC_VALID)) {
|
||||||
if (nqsrv_cmpnam(slp, nam, lph))
|
if (nqsrv_cmpnam(slp, nam, lph)) {
|
||||||
lph->lph_flag |= LC_VACATED;
|
lph->lph_flag |= LC_VACATED;
|
||||||
else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
|
} else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
|
||||||
|
struct socket *so;
|
||||||
|
int sotype;
|
||||||
|
int *solockp = NULL;
|
||||||
|
|
||||||
|
so = lph->lph_slp->ns_so;
|
||||||
if (lph->lph_flag & LC_UDP) {
|
if (lph->lph_flag & LC_UDP) {
|
||||||
MALLOC(nam2, struct sockaddr *,
|
MALLOC(nam2, struct sockaddr *,
|
||||||
sizeof *nam2, M_SONAME, M_WAITOK);
|
sizeof *nam2, M_SONAME, M_WAITOK);
|
||||||
@ -528,20 +531,16 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred)
|
|||||||
saddr->sin_family = AF_INET;
|
saddr->sin_family = AF_INET;
|
||||||
saddr->sin_addr.s_addr = lph->lph_inetaddr;
|
saddr->sin_addr.s_addr = lph->lph_inetaddr;
|
||||||
saddr->sin_port = lph->lph_port;
|
saddr->sin_port = lph->lph_port;
|
||||||
so = lph->lph_slp->ns_so;
|
|
||||||
} else if (lph->lph_flag & LC_CLTP) {
|
} else if (lph->lph_flag & LC_CLTP) {
|
||||||
nam2 = lph->lph_nam;
|
nam2 = lph->lph_nam;
|
||||||
so = lph->lph_slp->ns_so;
|
|
||||||
} else if (lph->lph_slp->ns_flag & SLP_VALID) {
|
} else if (lph->lph_slp->ns_flag & SLP_VALID) {
|
||||||
nam2 = (struct sockaddr *)0;
|
nam2 = (struct sockaddr *)0;
|
||||||
so = lph->lph_slp->ns_so;
|
} else {
|
||||||
} else
|
|
||||||
goto nextone;
|
goto nextone;
|
||||||
|
}
|
||||||
sotype = so->so_type;
|
sotype = so->so_type;
|
||||||
if (so->so_proto->pr_flags & PR_CONNREQUIRED)
|
if (so->so_proto->pr_flags & PR_CONNREQUIRED)
|
||||||
solockp = &lph->lph_slp->ns_solock;
|
solockp = &lph->lph_slp->ns_solock;
|
||||||
else
|
|
||||||
solockp = (int *)0;
|
|
||||||
nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
|
nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
|
||||||
NFSX_V3FH + NFSX_UNSIGNED);
|
NFSX_V3FH + NFSX_UNSIGNED);
|
||||||
fhp = &nfh.fh_generic;
|
fhp = &nfh.fh_generic;
|
||||||
@ -576,11 +575,11 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred)
|
|||||||
* nfs_sndlock if PR_CONNREQUIRED XXX
|
* nfs_sndlock if PR_CONNREQUIRED XXX
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 &&
|
if ((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 &&
|
||||||
(lph->lph_slp->ns_flag & SLP_VALID) == 0) ||
|
((lph->lph_slp->ns_flag & SLP_VALID) == 0 ||
|
||||||
(nfs_slplock(lph->lph_slp, 0) == 0))
|
nfs_slplock(lph->lph_slp, 0) == 0)) {
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
else {
|
} else {
|
||||||
(void) nfs_send(so, nam2, m,
|
(void) nfs_send(so, nam2, m,
|
||||||
(struct nfsreq *)0);
|
(struct nfsreq *)0);
|
||||||
if (solockp)
|
if (solockp)
|
||||||
|
@ -87,31 +87,26 @@
|
|||||||
#define LC_MOREHOSTSIZ 10
|
#define LC_MOREHOSTSIZ 10
|
||||||
|
|
||||||
struct nqhost {
|
struct nqhost {
|
||||||
|
u_int16_t lph_flag;
|
||||||
|
u_int16_t lph_port;
|
||||||
|
struct nfssvc_sock *lph_slp;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
u_int16_t udp_flag;
|
|
||||||
u_int16_t udp_port;
|
|
||||||
union nethostaddr udp_haddr;
|
union nethostaddr udp_haddr;
|
||||||
} un_udp;
|
} un_udp;
|
||||||
struct {
|
struct {
|
||||||
u_int16_t connless_flag;
|
|
||||||
u_int16_t connless_spare;
|
|
||||||
union nethostaddr connless_haddr;
|
union nethostaddr connless_haddr;
|
||||||
} un_connless;
|
} un_connless;
|
||||||
struct {
|
struct {
|
||||||
u_int16_t conn_flag;
|
int dummy;
|
||||||
u_int16_t conn_spare;
|
|
||||||
struct nfssvc_sock *conn_slp;
|
|
||||||
} un_conn;
|
} un_conn;
|
||||||
} lph_un;
|
} lph_un;
|
||||||
};
|
};
|
||||||
#define lph_flag lph_un.un_udp.udp_flag
|
|
||||||
#define lph_port lph_un.un_udp.udp_port
|
|
||||||
#define lph_haddr lph_un.un_udp.udp_haddr
|
#define lph_haddr lph_un.un_udp.udp_haddr
|
||||||
#define lph_inetaddr lph_un.un_udp.udp_haddr.had_inetaddr
|
#define lph_inetaddr lph_un.un_udp.udp_haddr.had_inetaddr
|
||||||
#define lph_claddr lph_un.un_connless.connless_haddr
|
#define lph_claddr lph_un.un_connless.connless_haddr
|
||||||
#define lph_nam lph_un.un_connless.connless_haddr.had_nam
|
#define lph_nam lph_un.un_connless.connless_haddr.had_nam
|
||||||
#define lph_slp lph_un.un_conn.conn_slp
|
|
||||||
|
|
||||||
struct nqlease {
|
struct nqlease {
|
||||||
LIST_ENTRY(nqlease) lc_hash; /* Fhandle hash list */
|
LIST_ENTRY(nqlease) lc_hash; /* Fhandle hash list */
|
||||||
@ -123,7 +118,7 @@ struct nqlease {
|
|||||||
char lc_fiddata[MAXFIDSZ];
|
char lc_fiddata[MAXFIDSZ];
|
||||||
struct vnode *lc_vp; /* Soft reference to associated vnode */
|
struct vnode *lc_vp; /* Soft reference to associated vnode */
|
||||||
};
|
};
|
||||||
#define lc_flag lc_host.lph_un.un_udp.udp_flag
|
#define lc_flag lc_host.lph_flag
|
||||||
|
|
||||||
/* lc_flag bits */
|
/* lc_flag bits */
|
||||||
#define LC_VALID 0x0001 /* Host address valid */
|
#define LC_VALID 0x0001 /* Host address valid */
|
||||||
|
Loading…
Reference in New Issue
Block a user