When an underlying ioctl(2) handler returns an error, our ioctl(2)
interface considers that it hits a fatal error, and will not copyout the request structure back for _IOW and _IOWR ioctls, keeping them untouched. The previous implementation of the SIOCGIFDESCR ioctl intends to feed the buffer length back to userland. However, if we return an error, the feedback would be defeated and ifconfig(8) would trap into an infinite loop. This commit changes SIOCGIFDESCR to set buffer field to NULL to indicate the previous ENAMETOOLONG case. Reported by: bschmidt MFC after: 2 weeks
This commit is contained in:
parent
410c766274
commit
57d848483e
@ -922,19 +922,20 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
|
|||||||
ifr.ifr_buffer.buffer = descr;
|
ifr.ifr_buffer.buffer = descr;
|
||||||
ifr.ifr_buffer.length = descrlen;
|
ifr.ifr_buffer.length = descrlen;
|
||||||
if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) {
|
if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) {
|
||||||
if (strlen(descr) > 0)
|
if (ifr.ifr_buffer.buffer == descr) {
|
||||||
printf("\tdescription: %s\n", descr);
|
if (strlen(descr) > 0)
|
||||||
break;
|
printf("\tdescription: %s\n",
|
||||||
} else if (errno == ENAMETOOLONG)
|
descr);
|
||||||
descrlen = ifr.ifr_buffer.length;
|
} else if (ifr.ifr_buffer.length > descrlen) {
|
||||||
else
|
descrlen = ifr.ifr_buffer.length;
|
||||||
break;
|
continue;
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
warn("unable to allocate memory for interface"
|
warn("unable to allocate memory for interface"
|
||||||
"description");
|
"description");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
|
if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
|
||||||
if (ifr.ifr_curcap != 0) {
|
if (ifr.ifr_curcap != 0) {
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
.\" @(#)netintro.4 8.2 (Berkeley) 11/30/93
|
.\" @(#)netintro.4 8.2 (Berkeley) 11/30/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 26, 2010
|
.Dd April 14, 2010
|
||||||
.Dt NETINTRO 4
|
.Dt NETINTRO 4
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -292,8 +292,11 @@ field of
|
|||||||
struct passed in as parameter, and the length would include
|
struct passed in as parameter, and the length would include
|
||||||
the terminating nul character.
|
the terminating nul character.
|
||||||
If there is not enough space to hold the interface length,
|
If there is not enough space to hold the interface length,
|
||||||
no copy would be done and an
|
no copy would be done and the
|
||||||
error would be returned.
|
.Va buffer
|
||||||
|
field of
|
||||||
|
.Va ifru_buffer
|
||||||
|
would be set to NULL.
|
||||||
The kernel will store the buffer length in the
|
The kernel will store the buffer length in the
|
||||||
.Va length
|
.Va length
|
||||||
field upon return, regardless whether the buffer itself is
|
field upon return, regardless whether the buffer itself is
|
||||||
|
@ -2049,14 +2049,13 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
|
|||||||
case SIOCGIFDESCR:
|
case SIOCGIFDESCR:
|
||||||
error = 0;
|
error = 0;
|
||||||
sx_slock(&ifdescr_sx);
|
sx_slock(&ifdescr_sx);
|
||||||
if (ifp->if_description == NULL) {
|
if (ifp->if_description == NULL)
|
||||||
ifr->ifr_buffer.length = 0;
|
|
||||||
error = ENOMSG;
|
error = ENOMSG;
|
||||||
} else {
|
else {
|
||||||
/* space for terminating nul */
|
/* space for terminating nul */
|
||||||
descrlen = strlen(ifp->if_description) + 1;
|
descrlen = strlen(ifp->if_description) + 1;
|
||||||
if (ifr->ifr_buffer.length < descrlen)
|
if (ifr->ifr_buffer.length < descrlen)
|
||||||
error = ENAMETOOLONG;
|
ifr->ifr_buffer.buffer = NULL;
|
||||||
else
|
else
|
||||||
error = copyout(ifp->if_description,
|
error = copyout(ifp->if_description,
|
||||||
ifr->ifr_buffer.buffer, descrlen);
|
ifr->ifr_buffer.buffer, descrlen);
|
||||||
|
Loading…
Reference in New Issue
Block a user