mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-20 00:33:57 +00:00
Make the data returned by devinfo harder to overflow.
Rather than using fixed-length strings, pack them into a string table to return. Also expand the buffer from ~300 charaters to 3k. This should be enough, even for USB. This fixes a problem where USB pnp info is truncated on return to userland. Differential Revision: https://reviews.freebsd.org/D15629
This commit is contained in:
parent
92376fa76c
commit
c580ca4cf4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=334414
|
@ -5264,8 +5264,9 @@ sysctl_devices(SYSCTL_HANDLER_ARGS)
|
||||||
u_int namelen = arg2;
|
u_int namelen = arg2;
|
||||||
int index;
|
int index;
|
||||||
device_t dev;
|
device_t dev;
|
||||||
struct u_device udev; /* XXX this is a bit big */
|
struct u_device *udev;
|
||||||
int error;
|
int error;
|
||||||
|
char *walker, *ep;
|
||||||
|
|
||||||
if (namelen != 2)
|
if (namelen != 2)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
@ -5286,24 +5287,45 @@ sysctl_devices(SYSCTL_HANDLER_ARGS)
|
||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate the return array.
|
* Populate the return item, careful not to overflow the buffer.
|
||||||
*/
|
*/
|
||||||
bzero(&udev, sizeof(udev));
|
udev = malloc(sizeof(*udev), M_BUS, M_WAITOK | M_ZERO);
|
||||||
udev.dv_handle = (uintptr_t)dev;
|
if (udev == NULL)
|
||||||
udev.dv_parent = (uintptr_t)dev->parent;
|
return (ENOMEM);
|
||||||
if (dev->nameunit != NULL)
|
udev->dv_handle = (uintptr_t)dev;
|
||||||
strlcpy(udev.dv_name, dev->nameunit, sizeof(udev.dv_name));
|
udev->dv_parent = (uintptr_t)dev->parent;
|
||||||
if (dev->desc != NULL)
|
udev->dv_devflags = dev->devflags;
|
||||||
strlcpy(udev.dv_desc, dev->desc, sizeof(udev.dv_desc));
|
udev->dv_flags = dev->flags;
|
||||||
if (dev->driver != NULL && dev->driver->name != NULL)
|
udev->dv_state = dev->state;
|
||||||
strlcpy(udev.dv_drivername, dev->driver->name,
|
walker = udev->dv_fields;
|
||||||
sizeof(udev.dv_drivername));
|
ep = walker + sizeof(udev->dv_fields);
|
||||||
bus_child_pnpinfo_str(dev, udev.dv_pnpinfo, sizeof(udev.dv_pnpinfo));
|
#define CP(src) \
|
||||||
bus_child_location_str(dev, udev.dv_location, sizeof(udev.dv_location));
|
if ((src) == NULL) \
|
||||||
udev.dv_devflags = dev->devflags;
|
*walker++ = '\0'; \
|
||||||
udev.dv_flags = dev->flags;
|
else { \
|
||||||
udev.dv_state = dev->state;
|
strlcpy(walker, (src), ep - walker); \
|
||||||
error = SYSCTL_OUT(req, &udev, sizeof(udev));
|
walker += strlen(walker) + 1; \
|
||||||
|
} \
|
||||||
|
if (walker >= ep) \
|
||||||
|
break;
|
||||||
|
|
||||||
|
do {
|
||||||
|
CP(dev->nameunit);
|
||||||
|
CP(dev->desc);
|
||||||
|
CP(dev->driver != NULL ? dev->driver->name : NULL);
|
||||||
|
bus_child_pnpinfo_str(dev, walker, ep - walker);
|
||||||
|
walker += strlen(walker) + 1;
|
||||||
|
if (walker >= ep)
|
||||||
|
break;
|
||||||
|
bus_child_location_str(dev, walker, ep - walker);
|
||||||
|
walker += strlen(walker) + 1;
|
||||||
|
if (walker >= ep)
|
||||||
|
break;
|
||||||
|
*walker++ = '\0';
|
||||||
|
} while (0);
|
||||||
|
#undef CP
|
||||||
|
error = SYSCTL_OUT(req, udev, sizeof(*udev));
|
||||||
|
free(udev, M_BUS);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
*/
|
*/
|
||||||
struct u_businfo {
|
struct u_businfo {
|
||||||
int ub_version; /**< @brief interface version */
|
int ub_version; /**< @brief interface version */
|
||||||
#define BUS_USER_VERSION 1
|
#define BUS_USER_VERSION 2
|
||||||
int ub_generation; /**< @brief generation count */
|
int ub_generation; /**< @brief generation count */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,20 +63,23 @@ typedef enum device_state {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Device information exported to userspace.
|
* @brief Device information exported to userspace.
|
||||||
|
* The strings are placed one after the other, separated by NUL characters.
|
||||||
|
* Fields should be added after the last one and order maintained for compatibility
|
||||||
*/
|
*/
|
||||||
|
#define BUS_USER_BUFFER (3*1024)
|
||||||
struct u_device {
|
struct u_device {
|
||||||
uintptr_t dv_handle;
|
uintptr_t dv_handle;
|
||||||
uintptr_t dv_parent;
|
uintptr_t dv_parent;
|
||||||
|
|
||||||
char dv_name[32]; /**< @brief Name of device in tree. */
|
|
||||||
char dv_desc[32]; /**< @brief Driver description */
|
|
||||||
char dv_drivername[32]; /**< @brief Driver name */
|
|
||||||
char dv_pnpinfo[128]; /**< @brief Plug and play info */
|
|
||||||
char dv_location[128]; /**< @brief Where is the device? */
|
|
||||||
uint32_t dv_devflags; /**< @brief API Flags for device */
|
uint32_t dv_devflags; /**< @brief API Flags for device */
|
||||||
uint16_t dv_flags; /**< @brief flags for dev state */
|
uint16_t dv_flags; /**< @brief flags for dev state */
|
||||||
device_state_t dv_state; /**< @brief State of attachment */
|
device_state_t dv_state; /**< @brief State of attachment */
|
||||||
/* XXX more driver info? */
|
char dv_fields[BUS_USER_BUFFER]; /**< @brief NUL terminated fields */
|
||||||
|
/* name (name of the device in tree) */
|
||||||
|
/* desc (driver description) */
|
||||||
|
/* drivername (Name of driver without unit number) */
|
||||||
|
/* pnpinfo (Plug and play information from bus) */
|
||||||
|
/* location (Location of device on parent */
|
||||||
|
/* NUL */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags exported via dv_flags. */
|
/* Flags exported via dv_flags. */
|
||||||
|
|
Loading…
Reference in a new issue