linux/drivers/usb/gadget/function/f_fs.c

4325 lines
102 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: GPL-2.0+
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/*
* f_fs.c -- user mode file system API for USB composite function controllers
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <mina86@mina86.com>
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
*
* Based on inode.c (GadgetFS) which was:
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003 Agilent Technologies
*/
/* #define DEBUG */
/* #define VERBOSE_DEBUG */
#include <linux/blkdev.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence.h>
#include <linux/dma-resv.h>
#include <linux/pagemap.h>
#include <linux/export.h>
#include <linux/fs_parser.h>
#include <linux/hid.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/sched/signal.h>
#include <linux/uio.h>
#include <linux/vmalloc.h>
#include <linux/unaligned.h>
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
#include <linux/usb/ccid.h>
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
#include <linux/usb/func_utils.h>
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
#include <linux/aio.h>
#include <linux/kthread.h>
#include <linux/poll.h>
#include <linux/eventfd.h>
#include "u_fs.h"
#include "u_os_desc.h"
#include "configfs.h"
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
#define MAX_ALT_SETTINGS 2 /* Allow up to 2 alt settings to be set. */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
#define DMABUF_ENQUEUE_TIMEOUT_MS 5000
MODULE_IMPORT_NS("DMA_BUF");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Reference counter handling */
static void ffs_data_get(struct ffs_data *ffs);
static void ffs_data_put(struct ffs_data *ffs);
/* Creates new ffs_data object. */
static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
__attribute__((malloc));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Opened counter handling. */
static void ffs_data_opened(struct ffs_data *ffs);
static void ffs_data_closed(struct ffs_data *ffs);
/* Called with ffs->mutex held; take over ownership of data. */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int __must_check
__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
static int __must_check
__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
/* The function structure ***************************************************/
struct ffs_ep;
struct ffs_function {
struct usb_configuration *conf;
struct usb_gadget *gadget;
struct ffs_data *ffs;
struct ffs_ep *eps;
u8 eps_revmap[16];
short *interfaces_nums;
struct usb_function function;
int cur_alt[MAX_CONFIG_INTERFACES];
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
};
static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
{
return container_of(f, struct ffs_function, function);
}
static inline enum ffs_setup_state
ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
{
return (enum ffs_setup_state)
cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static void ffs_func_eps_disable(struct ffs_function *func);
static int __must_check ffs_func_eps_enable(struct ffs_function *func);
static int ffs_func_bind(struct usb_configuration *,
struct usb_function *);
static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
static int ffs_func_get_alt(struct usb_function *f, unsigned int intf);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static void ffs_func_disable(struct usb_function *);
static int ffs_func_setup(struct usb_function *,
const struct usb_ctrlrequest *);
static bool ffs_func_req_match(struct usb_function *,
const struct usb_ctrlrequest *,
bool config0);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static void ffs_func_suspend(struct usb_function *);
static void ffs_func_resume(struct usb_function *);
static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
/* The endpoints structures *************************************************/
struct ffs_ep {
struct usb_ep *ep; /* P: ffs->eps_lock */
struct usb_request *req; /* P: epfile->mutex */
/* [0]: full speed, [1]: high speed, [2]: super speed */
struct usb_endpoint_descriptor *descs[3];
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
u8 num;
};
struct ffs_dmabuf_priv {
struct list_head entry;
struct kref ref;
struct ffs_data *ffs;
struct dma_buf_attachment *attach;
struct sg_table *sgt;
enum dma_data_direction dir;
spinlock_t lock;
u64 context;
struct usb_request *req; /* P: ffs->eps_lock */
struct usb_ep *ep; /* P: ffs->eps_lock */
};
struct ffs_dma_fence {
struct dma_fence base;
struct ffs_dmabuf_priv *priv;
struct work_struct work;
};
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
struct ffs_epfile {
/* Protects ep->ep and ep->req. */
struct mutex mutex;
struct ffs_data *ffs;
struct ffs_ep *ep; /* P: ffs->eps_lock */
struct dentry *dentry;
/*
* Buffer for holding data from partial reads which may happen since
* were rounding user read requests to a multiple of a max packet size.
*
* The pointer is initialised with NULL value and may be set by
* __ffs_epfile_read_data function to point to a temporary buffer.
*
* In normal operation, calls to __ffs_epfile_read_buffered will consume
* data from said buffer and eventually free it. Importantly, while the
* function is using the buffer, it sets the pointer to NULL. This is
* all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered
* can never run concurrently (they are synchronised by epfile->mutex)
* so the latter will not assign a new value to the pointer.
*
* Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is
* valid) and sets the pointer to READ_BUFFER_DROP value. This special
* value is crux of the synchronisation between ffs_func_eps_disable and
* __ffs_epfile_read_data.
*
* Once __ffs_epfile_read_data is about to finish it will try to set the
* pointer back to its old value (as described above), but seeing as the
* pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free
* the buffer.
*
* == State transitions ==
*
* ptr == NULL: (initial state)
* __ffs_epfile_read_buffer_free: go to ptr == DROP
* __ffs_epfile_read_buffered: nop
* __ffs_epfile_read_data allocates temp buffer: go to ptr == buf
* reading finishes: n/a, not in and reading state
* ptr == DROP:
* __ffs_epfile_read_buffer_free: nop
* __ffs_epfile_read_buffered: go to ptr == NULL
* __ffs_epfile_read_data allocates temp buffer: free buf, nop
* reading finishes: n/a, not in and reading state
* ptr == buf:
* __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP
* __ffs_epfile_read_buffered: go to ptr == NULL and reading
* __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered
* is always called first
* reading finishes: n/a, not in and reading state
* ptr == NULL and reading:
* __ffs_epfile_read_buffer_free: go to ptr == DROP and reading
* __ffs_epfile_read_buffered: n/a, mutex is held
* __ffs_epfile_read_data: n/a, mutex is held
* reading finishes and
* all data read: free buf, go to ptr == NULL
* otherwise: go to ptr == buf and reading
* ptr == DROP and reading:
* __ffs_epfile_read_buffer_free: nop
* __ffs_epfile_read_buffered: n/a, mutex is held
* __ffs_epfile_read_data: n/a, mutex is held
* reading finishes: free buf, go to ptr == DROP
*/
struct ffs_buffer *read_buffer;
#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
char name[5];
unsigned char in; /* P: ffs->eps_lock */
unsigned char isoc; /* P: ffs->eps_lock */
unsigned char _pad;
/* Protects dmabufs */
struct mutex dmabufs_mutex;
struct list_head dmabufs; /* P: dmabufs_mutex */
atomic_t seqno;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
};
struct ffs_buffer {
size_t length;
char *data;
char storage[] __counted_by(length);
};
/* ffs_io_data structure ***************************************************/
struct ffs_io_data {
bool aio;
bool read;
struct kiocb *kiocb;
struct iov_iter data;
const void *to_free;
char *buf;
struct mm_struct *mm;
struct work_struct work;
struct usb_ep *ep;
struct usb_request *req;
struct sg_table sgt;
bool use_sg;
struct ffs_data *ffs;
int status;
struct completion done;
};
struct ffs_desc_helper {
struct ffs_data *ffs;
unsigned interfaces_count;
unsigned eps_count;
};
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
static struct dentry *
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
const struct file_operations *fops);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Devices management *******************************************************/
DEFINE_MUTEX(ffs_lock);
EXPORT_SYMBOL_GPL(ffs_lock);
static struct ffs_dev *_ffs_find_dev(const char *name);
static struct ffs_dev *_ffs_alloc_dev(void);
static void _ffs_free_dev(struct ffs_dev *dev);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Misc helper functions ****************************************************/
static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
__attribute__((warn_unused_result, nonnull));
static char *ffs_prepare_buffer(const char __user *buf, size_t len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
__attribute__((warn_unused_result, nonnull));
/* Control file aka ep0 *****************************************************/
static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
{
struct ffs_data *ffs = req->context;
complete(&ffs->ep0req_completion);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
__releases(&ffs->ev.waitq.lock)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct usb_request *req = ffs->ep0req;
int ret;
if (!req) {
spin_unlock_irq(&ffs->ev.waitq.lock);
return -EINVAL;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
req->zero = len < le16_to_cpu(ffs->ev.setup.wLength);
spin_unlock_irq(&ffs->ev.waitq.lock);
req->buf = data;
req->length = len;
/*
* UDC layer requires to provide a buffer even for ZLP, but should
* not use it at all. Let's provide some poisoned pointer to catch
* possible bug in the driver.
*/
if (req->buf == NULL)
req->buf = (void *)0xDEADBABE;
reinit_completion(&ffs->ep0req_completion);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
if (ret) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb_ep_dequeue(ffs->gadget->ep0, req);
return -EINTR;
}
ffs->setup_state = FFS_NO_SETUP;
return req->status ? req->status : req->actual;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int __ffs_ep0_stall(struct ffs_data *ffs)
{
if (ffs->ev.can_stall) {
pr_vdebug("ep0 stall\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb_ep_set_halt(ffs->gadget->ep0);
ffs->setup_state = FFS_NO_SETUP;
return -EL2HLT;
} else {
pr_debug("bogus ep0 stall!\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -ESRCH;
}
}
static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
size_t len, loff_t *ptr)
{
struct ffs_data *ffs = file->private_data;
ssize_t ret;
char *data;
/* Fast check if setup was canceled */
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EIDRM;
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
/* Check state */
switch (ffs->state) {
case FFS_READ_DESCRIPTORS:
case FFS_READ_STRINGS:
/* Copy data */
if (len < 16) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EINVAL;
break;
}
data = ffs_prepare_buffer(buf, len);
if (IS_ERR(data)) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = PTR_ERR(data);
break;
}
/* Handle data */
if (ffs->state == FFS_READ_DESCRIPTORS) {
pr_info("read descriptors\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = __ffs_data_got_descs(ffs, data, len);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
ffs->state = FFS_READ_STRINGS;
ret = len;
} else {
pr_info("read strings\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = __ffs_data_got_strings(ffs, data, len);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
ret = ffs_epfiles_create(ffs);
if (ret) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->state = FFS_CLOSING;
break;
}
ffs->state = FFS_ACTIVE;
mutex_unlock(&ffs->mutex);
ret = ffs_ready(ffs);
if (ret < 0) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->state = FFS_CLOSING;
return ret;
}
return len;
}
break;
case FFS_ACTIVE:
data = NULL;
/*
* We're called from user space, we can use _irq
* rather then _irqsave
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_lock_irq(&ffs->ev.waitq.lock);
switch (ffs_setup_state_clear_cancelled(ffs)) {
case FFS_SETUP_CANCELLED:
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EIDRM;
goto done_spin;
case FFS_NO_SETUP:
ret = -ESRCH;
goto done_spin;
case FFS_SETUP_PENDING:
break;
}
/* FFS_SETUP_PENDING */
if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
spin_unlock_irq(&ffs->ev.waitq.lock);
ret = __ffs_ep0_stall(ffs);
break;
}
/* FFS_SETUP_PENDING and not stall */
len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_unlock_irq(&ffs->ev.waitq.lock);
data = ffs_prepare_buffer(buf, len);
if (IS_ERR(data)) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = PTR_ERR(data);
break;
}
spin_lock_irq(&ffs->ev.waitq.lock);
/*
* We are guaranteed to be still in FFS_ACTIVE state
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* but the state of setup could have changed from
* FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* to check for that. If that happened we copied data
* from user space in vain but it's unlikely.
*
* For sure we are not in FFS_NO_SETUP since this is
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
* transition can be performed and it's protected by
* mutex.
*/
if (ffs_setup_state_clear_cancelled(ffs) ==
FFS_SETUP_CANCELLED) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EIDRM;
done_spin:
spin_unlock_irq(&ffs->ev.waitq.lock);
} else {
/* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len);
}
kfree(data);
break;
default:
ret = -EBADFD;
break;
}
mutex_unlock(&ffs->mutex);
return ret;
}
/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
__releases(&ffs->ev.waitq.lock)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
/*
* n cannot be bigger than ffs->ev.count, which cannot be bigger than
* size of ffs->ev.types array (which is four) so that's how much space
* we reserve.
*/
struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
const size_t size = n * sizeof *events;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
unsigned i = 0;
memset(events, 0, size);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
do {
events[i].type = ffs->ev.types[i];
if (events[i].type == FUNCTIONFS_SETUP) {
events[i].u.setup = ffs->ev.setup;
ffs->setup_state = FFS_SETUP_PENDING;
}
} while (++i < n);
ffs->ev.count -= n;
if (ffs->ev.count)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
memmove(ffs->ev.types, ffs->ev.types + n,
ffs->ev.count * sizeof *ffs->ev.types);
spin_unlock_irq(&ffs->ev.waitq.lock);
mutex_unlock(&ffs->mutex);
return copy_to_user(buf, events, size) ? -EFAULT : size;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
size_t len, loff_t *ptr)
{
struct ffs_data *ffs = file->private_data;
char *data = NULL;
size_t n;
int ret;
/* Fast check if setup was canceled */
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EIDRM;
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
/* Check state */
if (ffs->state != FFS_ACTIVE) {
ret = -EBADFD;
goto done_mutex;
}
/*
* We're called from user space, we can use _irq rather then
* _irqsave
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_lock_irq(&ffs->ev.waitq.lock);
switch (ffs_setup_state_clear_cancelled(ffs)) {
case FFS_SETUP_CANCELLED:
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EIDRM;
break;
case FFS_NO_SETUP:
n = len / sizeof(struct usb_functionfs_event);
if (!n) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EINVAL;
break;
}
if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
ret = -EAGAIN;
break;
}
if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
ffs->ev.count)) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EINTR;
break;
}
/* unlocks spinlock */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return __ffs_ep0_read_events(ffs, buf,
min_t(size_t, n, ffs->ev.count));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
case FFS_SETUP_PENDING:
if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
spin_unlock_irq(&ffs->ev.waitq.lock);
ret = __ffs_ep0_stall(ffs);
goto done_mutex;
}
len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_unlock_irq(&ffs->ev.waitq.lock);
if (len) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
data = kmalloc(len, GFP_KERNEL);
if (!data) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -ENOMEM;
goto done_mutex;
}
}
spin_lock_irq(&ffs->ev.waitq.lock);
/* See ffs_ep0_write() */
if (ffs_setup_state_clear_cancelled(ffs) ==
FFS_SETUP_CANCELLED) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EIDRM;
break;
}
/* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len);
if ((ret > 0) && (copy_to_user(buf, data, len)))
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = -EFAULT;
goto done_mutex;
default:
ret = -EBADFD;
break;
}
spin_unlock_irq(&ffs->ev.waitq.lock);
done_mutex:
mutex_unlock(&ffs->mutex);
kfree(data);
return ret;
}
static int ffs_ep0_open(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = inode->i_private;
if (ffs->state == FFS_CLOSING)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EBUSY;
file->private_data = ffs;
ffs_data_opened(ffs);
usb: gadget: f_fs: Use stream_open() for endpoint files Function fs endpoint file operations are synchronized via an interruptible mutex wait. However we see threads that do ep file operations concurrently are getting blocked for the mutex lock in __fdget_pos(). This is an uninterruptible wait and we see hung task warnings and kernel panic if hung_task_panic systcl is enabled if host does not send/receive the data for long time. The reason for threads getting blocked in __fdget_pos() is due to the file position protection introduced by the commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX"). Since function fs endpoint files does not have the notion of the file position, switch to the stream mode. This will bypass the file position mutex and threads will be blocked in interruptible state for the function fs mutex. It should not affects user space as we are only changing the task state changes the task state from UNINTERRUPTIBLE to INTERRUPTIBLE while waiting for the USB transfers to be finished. However there is a slight change to the O_NONBLOCK behavior. Earlier threads that are using O_NONBLOCK are also getting blocked inside fdget_pos(). Now they reach to function fs and error code is returned. The non blocking behavior is actually honoured now. Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pavankumar Kondeti <quic_pkondeti@quicinc.com> Link: https://lore.kernel.org/r/1636712682-1226-1-git-send-email-quic_pkondeti@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-11-12 15:54:40 +05:30
return stream_open(inode, file);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int ffs_ep0_release(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = file->private_data;
ffs_data_closed(ffs);
return 0;
}
static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
{
struct ffs_data *ffs = file->private_data;
struct usb_gadget *gadget = ffs->gadget;
long ret;
if (code == FUNCTIONFS_INTERFACE_REVMAP) {
struct ffs_function *func = ffs->func;
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
} else if (gadget && gadget->ops->ioctl) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = gadget->ops->ioctl(gadget, code, value);
} else {
ret = -ENOTTY;
}
return ret;
}
static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
{
struct ffs_data *ffs = file->private_data;
__poll_t mask = EPOLLWRNORM;
int ret;
poll_wait(file, &ffs->ev.waitq, wait);
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
if (ret < 0)
return mask;
switch (ffs->state) {
case FFS_READ_DESCRIPTORS:
case FFS_READ_STRINGS:
mask |= EPOLLOUT;
break;
case FFS_ACTIVE:
switch (ffs->setup_state) {
case FFS_NO_SETUP:
if (ffs->ev.count)
mask |= EPOLLIN;
break;
case FFS_SETUP_PENDING:
case FFS_SETUP_CANCELLED:
mask |= (EPOLLIN | EPOLLOUT);
break;
}
break;
case FFS_CLOSING:
break;
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
case FFS_DEACTIVATED:
break;
}
mutex_unlock(&ffs->mutex);
return mask;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static const struct file_operations ffs_ep0_operations = {
.open = ffs_ep0_open,
.write = ffs_ep0_write,
.read = ffs_ep0_read,
.release = ffs_ep0_release,
.unlocked_ioctl = ffs_ep0_ioctl,
.poll = ffs_ep0_poll,
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
};
/* "Normal" endpoints operations ********************************************/
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
struct ffs_io_data *io_data = req->context;
if (req->status)
io_data->status = req->status;
else
io_data->status = req->actual;
complete(&io_data->done);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
{
ssize_t ret = copy_to_iter(data, data_len, iter);
if (ret == data_len)
return ret;
if (iov_iter_count(iter))
return -EFAULT;
/*
* Dear user space developer!
*
* TL;DR: To stop getting below error message in your kernel log, change
* user space code using functionfs to align read buffers to a max
* packet size.
*
* Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max
* packet size. When unaligned buffer is passed to functionfs, it
* internally uses a larger, aligned buffer so that such UDCs are happy.
*
* Unfortunately, this means that host may send more data than was
* requested in read(2) system call. f_fs doesnt know what to do with
* that excess data so it simply drops it.
*
* Was the buffer aligned in the first place, no such problem would
* happen.
*
* Data may be dropped only in AIO reads. Synchronous reads are handled
* by splitting a request into multiple parts. This splitting may still
* be a problem though so its likely best to align the buffer
* regardless of it being AIO or not..
*
* This only affects OUT endpoints, i.e. reading data with a read(2),
* aio_read(2) etc. system calls. Writing data to an IN endpoint is not
* affected.
*/
pr_err("functionfs read size %d > requested size %zd, dropping excess data. "
"Align read buffer size to max packet size to avoid the problem.\n",
data_len, ret);
return ret;
}
/*
* allocate a virtually contiguous buffer and create a scatterlist describing it
* @sg_table - pointer to a place to be filled with sg_table contents
* @size - required buffer size
*/
static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
{
struct page **pages;
void *vaddr, *ptr;
unsigned int n_pages;
int i;
vaddr = vmalloc(sz);
if (!vaddr)
return NULL;
n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages) {
vfree(vaddr);
return NULL;
}
for (i = 0, ptr = vaddr; i < n_pages; ++i, ptr += PAGE_SIZE)
pages[i] = vmalloc_to_page(ptr);
if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) {
kvfree(pages);
vfree(vaddr);
return NULL;
}
kvfree(pages);
return vaddr;
}
static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data,
size_t data_len)
{
if (io_data->use_sg)
return ffs_build_sg_list(&io_data->sgt, data_len);
return kmalloc(data_len, GFP_KERNEL);
}
static inline void ffs_free_buffer(struct ffs_io_data *io_data)
{
if (!io_data->buf)
return;
if (io_data->use_sg) {
sg_free_table(&io_data->sgt);
vfree(io_data->buf);
} else {
kfree(io_data->buf);
}
}
static void ffs_user_copy_worker(struct work_struct *work)
{
struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
work);
int ret = io_data->status;
bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
if (io_data->read && ret > 0) {
kthread_use_mm(io_data->mm);
ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
kthread_unuse_mm(io_data->mm);
}
io_data->kiocb->ki_complete(io_data->kiocb, ret);
if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd);
usb: gadget: f_fs: Fix race between aio_cancel() and AIO request complete FFS based applications can utilize the aio_cancel() callback to dequeue pending USB requests submitted to the UDC. There is a scenario where the FFS application issues an AIO cancel call, while the UDC is handling a soft disconnect. For a DWC3 based implementation, the callstack looks like the following: DWC3 Gadget FFS Application dwc3_gadget_soft_disconnect() ... --> dwc3_stop_active_transfers() --> dwc3_gadget_giveback(-ESHUTDOWN) --> ffs_epfile_async_io_complete() ffs_aio_cancel() --> usb_ep_free_request() --> usb_ep_dequeue() There is currently no locking implemented between the AIO completion handler and AIO cancel, so the issue occurs if the completion routine is running in parallel to an AIO cancel call coming from the FFS application. As the completion call frees the USB request (io_data->req) the FFS application is also referencing it for the usb_ep_dequeue() call. This can lead to accessing a stale/hanging pointer. commit b566d38857fc ("usb: gadget: f_fs: use io_data->status consistently") relocated the usb_ep_free_request() into ffs_epfile_async_io_complete(). However, in order to properly implement locking to mitigate this issue, the spinlock can't be added to ffs_epfile_async_io_complete(), as usb_ep_dequeue() (if successfully dequeuing a USB request) will call the function driver's completion handler in the same context. Hence, leading into a deadlock. Fix this issue by moving the usb_ep_free_request() back to ffs_user_copy_worker(), and ensuring that it explicitly sets io_data->req to NULL after freeing it within the ffs->eps_lock. This resolves the race condition above, as the ffs_aio_cancel() routine will not continue attempting to dequeue a request that has already been freed, or the ffs_user_copy_work() not freeing the USB request until the AIO cancel is done referencing it. This fix depends on commit b566d38857fc ("usb: gadget: f_fs: use io_data->status consistently") Fixes: 2e4c7553cd6f ("usb: gadget: f_fs: add aio support") Cc: stable <stable@kernel.org> # b566d38857fc ("usb: gadget: f_fs: use io_data->status consistently") Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com> Link: https://lore.kernel.org/r/20240409014059.6740-1-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-04-08 18:40:59 -07:00
usb_ep_free_request(io_data->ep, io_data->req);
if (io_data->read)
kfree(io_data->to_free);
ffs_free_buffer(io_data);
kfree(io_data);
}
static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
struct usb_request *req)
{
struct ffs_io_data *io_data = req->context;
struct ffs_data *ffs = io_data->ffs;
io_data->status = req->status ? req->status : req->actual;
INIT_WORK(&io_data->work, ffs_user_copy_worker);
queue_work(ffs->io_completion_wq, &io_data->work);
}
static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
{
/*
* See comment in struct ffs_epfile for full read_buffer pointer
* synchronisation story.
*/
struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP);
if (buf && buf != READ_BUFFER_DROP)
kfree(buf);
}
/* Assumes epfile->mutex is held. */
static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
struct iov_iter *iter)
{
/*
* Null out epfile->read_buffer so ffs_func_eps_disable does not free
* the buffer while we are using it. See comment in struct ffs_epfile
* for full read_buffer pointer synchronisation story.
*/
struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL);
ssize_t ret;
if (!buf || buf == READ_BUFFER_DROP)
return 0;
ret = copy_to_iter(buf->data, buf->length, iter);
if (buf->length == ret) {
kfree(buf);
return ret;
}
if (iov_iter_count(iter)) {
ret = -EFAULT;
} else {
buf->length -= ret;
buf->data += ret;
}
if (cmpxchg(&epfile->read_buffer, NULL, buf))
kfree(buf);
return ret;
}
/* Assumes epfile->mutex is held. */
static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
void *data, int data_len,
struct iov_iter *iter)
{
struct ffs_buffer *buf;
ssize_t ret = copy_to_iter(data, data_len, iter);
if (data_len == ret)
return ret;
if (iov_iter_count(iter))
return -EFAULT;
/* See ffs_copy_to_iter for more context. */
pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.",
data_len, ret);
data_len -= ret;
buf = kmalloc(struct_size(buf, storage, data_len), GFP_KERNEL);
if (!buf)
return -ENOMEM;
buf->length = data_len;
buf->data = buf->storage;
memcpy(buf->storage, data + ret, flex_array_size(buf, storage, data_len));
/*
* At this point read_buffer is NULL or READ_BUFFER_DROP (if
* ffs_func_eps_disable has been called in the meanwhile). See comment
* in struct ffs_epfile for full read_buffer pointer synchronisation
* story.
*/
if (cmpxchg(&epfile->read_buffer, NULL, buf))
kfree(buf);
return ret;
}
static struct ffs_ep *ffs_epfile_wait_ep(struct file *file)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct ffs_epfile *epfile = file->private_data;
struct ffs_ep *ep;
int ret;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Wait for endpoint to be enabled */
ep = epfile->ep;
if (!ep) {
if (file->f_flags & O_NONBLOCK)
return ERR_PTR(-EAGAIN);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = wait_event_interruptible(
epfile->ffs->wait, (ep = epfile->ep));
if (ret)
return ERR_PTR(-EINTR);
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ep;
}
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
struct usb_request *req;
struct ffs_ep *ep;
char *data = NULL;
ssize_t ret, data_len = -EINVAL;
int halt;
/* Are we still active? */
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
ep = ffs_epfile_wait_ep(file);
if (IS_ERR(ep))
return PTR_ERR(ep);
/* Do we halt? */
halt = (!io_data->read == !epfile->in);
if (halt && epfile->isoc)
return -EINVAL;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* We will be using request and read_buffer */
ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
if (ret)
goto error;
/* Allocate & copy */
if (!halt) {
struct usb_gadget *gadget;
/*
* Do we have buffered data from previous partial read? Check
* that for synchronous case only because we do not have
* facility to wake up a pending asynchronous read and push
* buffered data to it which we would need to make things behave
* consistently.
*/
if (!io_data->aio && io_data->read) {
ret = __ffs_epfile_read_buffered(epfile, &io_data->data);
if (ret)
goto error_mutex;
}
/*
* if we _do_ wait above, the epfile->ffs->gadget might be NULL
* before the waiting completes, so do not assign to 'gadget'
* earlier
*/
gadget = epfile->ffs->gadget;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
if (epfile->ep != ep) {
ret = -ESHUTDOWN;
goto error_lock;
}
data_len = iov_iter_count(&io_data->data);
/*
* Controller may require buffer size to be aligned to
* maxpacketsize of an out endpoint.
*/
if (io_data->read)
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_unlock_irq(&epfile->ffs->eps_lock);
data = ffs_alloc_buffer(io_data, data_len);
if (!data) {
ret = -ENOMEM;
goto error_mutex;
}
if (!io_data->read &&
!copy_from_iter_full(data, data_len, &io_data->data)) {
ret = -EFAULT;
goto error_mutex;
}
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_lock_irq(&epfile->ffs->eps_lock);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (epfile->ep != ep) {
/* In the meantime, endpoint got disabled or changed. */
ret = -ESHUTDOWN;
} else if (halt) {
ret = usb_ep_set_halt(ep->ep);
if (!ret)
ret = -EBADMSG;
} else if (data_len == -EINVAL) {
/*
* Sanity Check: even though data_len can't be used
* uninitialized at the time I write this comment, some
* compilers complain about this situation.
* In order to keep the code clean from warnings, data_len is
* being initialized to -EINVAL during its declaration, which
* means we can't rely on compiler anymore to warn no future
* changes won't result in data_len being used uninitialized.
* For such reason, we're adding this redundant sanity check
* here.
*/
WARN(1, "%s: data_len == -EINVAL\n", __func__);
ret = -EINVAL;
} else if (!io_data->aio) {
usb: f_fs: avoid race condition with ffs_epfile_io_complete ffs_epfile_io and ffs_epfile_io_complete runs in different context, but there is no synchronization between them. consider the following scenario: 1) ffs_epfile_io interrupted by sigal while wait_for_completion_interruptible 2) then ffs_epfile_io set ret to -EINTR 3) just before or during usb_ep_dequeue, the request completed 4) ffs_epfile_io return with -EINTR In this case, ffs_epfile_io tell caller no transfer success but actually it may has been done. This break the caller's pipe. Below script can help test it (adbd is the process which lies on f_fs). while true do pkill -19 adbd #SIGSTOP pkill -18 adbd #SIGCONT sleep 0.1 done To avoid this, just dequeue the request first. After usb_ep_dequeue, the request must be done or canceled. With this change, we can ensure no race condition in f_fs driver. But actually I found some of the udc driver has analogical issue in its dequeue implementation. For example, 1) the dequeue function hold the controller's lock. 2) before driver request controller to stop transfer, a request completed. 3) the controller trigger a interrupt, but its irq handler need wait dequeue function to release the lock. 4) dequeue function give back the request with negative status, and release lock. 5) irq handler get lock but the request has already been given back. So, the dequeue implementation should take care of this case. IMO, it can be done as below steps to dequeue a already started request, 1) request controller to stop transfer on the given ep. HW know the actual transfer status. 2) after hw stop transfer, driver scan if there are any completed one. 3) if found, process it with real status. if no, the request can canceled. Signed-off-by: "Du, Changbin" <changbin.du@intel.com> [mina86@mina86.com: rebased on top of refactoring commits] Signed-off-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2015-12-29 14:36:58 +08:00
bool interrupted = false;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
req = ep->req;
if (io_data->use_sg) {
req->buf = NULL;
req->sg = io_data->sgt.sgl;
req->num_sgs = io_data->sgt.nents;
} else {
req->buf = data;
req->num_sgs = 0;
}
req->length = data_len;
io_data->buf = data;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
init_completion(&io_data->done);
req->context = io_data;
req->complete = ffs_epfile_io_complete;
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
if (ret < 0)
goto error_lock;
spin_unlock_irq(&epfile->ffs->eps_lock);
if (wait_for_completion_interruptible(&io_data->done)) {
spin_lock_irq(&epfile->ffs->eps_lock);
if (epfile->ep != ep) {
ret = -ESHUTDOWN;
goto error_lock;
}
usb: f_fs: avoid race condition with ffs_epfile_io_complete ffs_epfile_io and ffs_epfile_io_complete runs in different context, but there is no synchronization between them. consider the following scenario: 1) ffs_epfile_io interrupted by sigal while wait_for_completion_interruptible 2) then ffs_epfile_io set ret to -EINTR 3) just before or during usb_ep_dequeue, the request completed 4) ffs_epfile_io return with -EINTR In this case, ffs_epfile_io tell caller no transfer success but actually it may has been done. This break the caller's pipe. Below script can help test it (adbd is the process which lies on f_fs). while true do pkill -19 adbd #SIGSTOP pkill -18 adbd #SIGCONT sleep 0.1 done To avoid this, just dequeue the request first. After usb_ep_dequeue, the request must be done or canceled. With this change, we can ensure no race condition in f_fs driver. But actually I found some of the udc driver has analogical issue in its dequeue implementation. For example, 1) the dequeue function hold the controller's lock. 2) before driver request controller to stop transfer, a request completed. 3) the controller trigger a interrupt, but its irq handler need wait dequeue function to release the lock. 4) dequeue function give back the request with negative status, and release lock. 5) irq handler get lock but the request has already been given back. So, the dequeue implementation should take care of this case. IMO, it can be done as below steps to dequeue a already started request, 1) request controller to stop transfer on the given ep. HW know the actual transfer status. 2) after hw stop transfer, driver scan if there are any completed one. 3) if found, process it with real status. if no, the request can canceled. Signed-off-by: "Du, Changbin" <changbin.du@intel.com> [mina86@mina86.com: rebased on top of refactoring commits] Signed-off-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
2015-12-29 14:36:58 +08:00
/*
* To avoid race condition with ffs_epfile_io_complete,
* dequeue the request first then check
* status. usb_ep_dequeue API should guarantee no race
* condition with req->complete callback.
*/
usb_ep_dequeue(ep->ep, req);
spin_unlock_irq(&epfile->ffs->eps_lock);
wait_for_completion(&io_data->done);
interrupted = io_data->status < 0;
}
if (interrupted)
ret = -EINTR;
else if (io_data->read && io_data->status > 0)
ret = __ffs_epfile_read_data(epfile, data, io_data->status,
&io_data->data);
else
ret = io_data->status;
goto error_mutex;
usb: gadget: ffs: Forbid usb_ep_alloc_request from sleeping Found using DEBUG_ATOMIC_SLEEP while submitting an AIO read operation: [ 100.853642] BUG: sleeping function called from invalid context at mm/slab.h:421 [ 100.861148] in_atomic(): 1, irqs_disabled(): 1, pid: 1880, name: python [ 100.867954] 2 locks held by python/1880: [ 100.867961] #0: (&epfile->mutex){....}, at: [<f8188627>] ffs_mutex_lock+0x27/0x30 [usb_f_fs] [ 100.868020] #1: (&(&ffs->eps_lock)->rlock){....}, at: [<f818ad4b>] ffs_epfile_io.isra.17+0x24b/0x590 [usb_f_fs] [ 100.868076] CPU: 1 PID: 1880 Comm: python Not tainted 4.14.0-edison+ #118 [ 100.868085] Hardware name: Intel Corporation Merrifield/BODEGA BAY, BIOS 542 2015.01.21:18.19.48 [ 100.868093] Call Trace: [ 100.868122] dump_stack+0x47/0x62 [ 100.868156] ___might_sleep+0xfd/0x110 [ 100.868182] __might_sleep+0x68/0x70 [ 100.868217] kmem_cache_alloc_trace+0x4b/0x200 [ 100.868248] ? dwc3_gadget_ep_alloc_request+0x24/0xe0 [dwc3] [ 100.868302] dwc3_gadget_ep_alloc_request+0x24/0xe0 [dwc3] [ 100.868343] usb_ep_alloc_request+0x16/0xc0 [udc_core] [ 100.868386] ffs_epfile_io.isra.17+0x444/0x590 [usb_f_fs] [ 100.868424] ? _raw_spin_unlock_irqrestore+0x27/0x40 [ 100.868457] ? kiocb_set_cancel_fn+0x57/0x60 [ 100.868477] ? ffs_ep0_poll+0xc0/0xc0 [usb_f_fs] [ 100.868512] ffs_epfile_read_iter+0xfe/0x157 [usb_f_fs] [ 100.868551] ? security_file_permission+0x9c/0xd0 [ 100.868587] ? rw_verify_area+0xac/0x120 [ 100.868633] aio_read+0x9d/0x100 [ 100.868692] ? __fget+0xa2/0xd0 [ 100.868727] ? __might_sleep+0x68/0x70 [ 100.868763] SyS_io_submit+0x471/0x680 [ 100.868878] do_int80_syscall_32+0x4e/0xd0 [ 100.868921] entry_INT80_32+0x2a/0x2a [ 100.868932] EIP: 0xb7fbb676 [ 100.868941] EFLAGS: 00000292 CPU: 1 [ 100.868951] EAX: ffffffda EBX: b7aa2000 ECX: 00000002 EDX: b7af8368 [ 100.868961] ESI: b7fbb660 EDI: b7aab000 EBP: bfb6c658 ESP: bfb6c638 [ 100.868973] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2017-11-26 06:52:53 +00:00
} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
ret = -ENOMEM;
} else {
if (io_data->use_sg) {
req->buf = NULL;
req->sg = io_data->sgt.sgl;
req->num_sgs = io_data->sgt.nents;
} else {
req->buf = data;
req->num_sgs = 0;
}
req->length = data_len;
io_data->buf = data;
io_data->ep = ep->ep;
io_data->req = req;
io_data->ffs = epfile->ffs;
req->context = io_data;
req->complete = ffs_epfile_async_io_complete;
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
if (ret) {
io_data->req = NULL;
usb_ep_free_request(ep->ep, req);
goto error_lock;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
ret = -EIOCBQUEUED;
/*
* Do not kfree the buffer in this function. It will be freed
* by ffs_user_copy_worker.
*/
data = NULL;
}
error_lock:
spin_unlock_irq(&epfile->ffs->eps_lock);
error_mutex:
mutex_unlock(&epfile->mutex);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
error:
usb: gadget: f_fs: don't free buffer prematurely The following kernel panic happens due to the io_data buffer gets deallocated before the async io is completed. Add a check for the case where io_data buffer should be deallocated by ffs_user_copy_worker. [ 41.663334] BUG: unable to handle kernel NULL pointer dereference at 0000000000000048 [ 41.672099] #PF error: [normal kernel read fault] [ 41.677356] PGD 20c974067 P4D 20c974067 PUD 20c973067 PMD 0 [ 41.683687] Oops: 0000 [#1] PREEMPT SMP [ 41.687976] CPU: 1 PID: 7 Comm: kworker/u8:0 Tainted: G U 5.0.0-quilt-2e5dc0ac-00790-gd8c79f2-dirty #2 [ 41.705309] Workqueue: adb ffs_user_copy_worker [ 41.705316] RIP: 0010:__vunmap+0x2a/0xc0 [ 41.705318] Code: 0f 1f 44 00 00 48 85 ff 0f 84 87 00 00 00 55 f7 c7 ff 0f 00 00 48 89 e5 41 55 41 89 f5 41 54 53 48 89 fb 75 71 e8 56 d7 ff ff <4c> 8b 60 48 4d 85 e4 74 76 48 89 df e8 25 ff ff ff 45 85 ed 74 46 [ 41.705320] RSP: 0018:ffffbc3a40053df0 EFLAGS: 00010286 [ 41.705322] RAX: 0000000000000000 RBX: ffffbc3a406f1000 RCX: 0000000000000000 [ 41.705323] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 00000000ffffffff [ 41.705324] RBP: ffffbc3a40053e08 R08: 000000000001fb79 R09: 0000000000000037 [ 41.705325] R10: ffffbc3a40053b68 R11: ffffbc3a40053cad R12: fffffffffffffff2 [ 41.705326] R13: 0000000000000001 R14: 0000000000000000 R15: ffffffffffffffff [ 41.705328] FS: 0000000000000000(0000) GS:ffff9e2977a80000(0000) knlGS:0000000000000000 [ 41.705329] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 41.705330] CR2: 0000000000000048 CR3: 000000020c994000 CR4: 00000000003406e0 [ 41.705331] Call Trace: [ 41.705338] vfree+0x50/0xb0 [ 41.705341] ffs_user_copy_worker+0xe9/0x1c0 [ 41.705344] process_one_work+0x19f/0x3e0 [ 41.705348] worker_thread+0x3f/0x3b0 [ 41.829766] kthread+0x12b/0x150 [ 41.833371] ? process_one_work+0x3e0/0x3e0 [ 41.838045] ? kthread_create_worker_on_cpu+0x70/0x70 [ 41.843695] ret_from_fork+0x3a/0x50 [ 41.847689] Modules linked in: hci_uart bluetooth ecdh_generic rfkill_gpio dwc3_pci dwc3 snd_usb_audio mei_me tpm_crb snd_usbmidi_lib xhci_pci xhci_hcd mei tpm snd_hwdep cfg80211 snd_soc_skl snd_soc_skl_ipc snd_soc_sst_ipc snd_soc_sst_dsp snd_hda_ext_core snd_hda_core videobuf2_dma_sg crlmodule [ 41.876880] CR2: 0000000000000048 [ 41.880584] ---[ end trace 2bc4addff0f2e673 ]--- [ 41.891346] RIP: 0010:__vunmap+0x2a/0xc0 [ 41.895734] Code: 0f 1f 44 00 00 48 85 ff 0f 84 87 00 00 00 55 f7 c7 ff 0f 00 00 48 89 e5 41 55 41 89 f5 41 54 53 48 89 fb 75 71 e8 56 d7 ff ff <4c> 8b 60 48 4d 85 e4 74 76 48 89 df e8 25 ff ff ff 45 85 ed 74 46 [ 41.916740] RSP: 0018:ffffbc3a40053df0 EFLAGS: 00010286 [ 41.922583] RAX: 0000000000000000 RBX: ffffbc3a406f1000 RCX: 0000000000000000 [ 41.930563] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 00000000ffffffff [ 41.938540] RBP: ffffbc3a40053e08 R08: 000000000001fb79 R09: 0000000000000037 [ 41.946520] R10: ffffbc3a40053b68 R11: ffffbc3a40053cad R12: fffffffffffffff2 [ 41.954502] R13: 0000000000000001 R14: 0000000000000000 R15: ffffffffffffffff [ 41.962482] FS: 0000000000000000(0000) GS:ffff9e2977a80000(0000) knlGS:0000000000000000 [ 41.971536] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 41.977960] CR2: 0000000000000048 CR3: 000000020c994000 CR4: 00000000003406e0 [ 41.985930] Kernel panic - not syncing: Fatal exception [ 41.991817] Kernel Offset: 0x16000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff) [ 42.009525] Rebooting in 10 seconds.. [ 52.014376] ACPI MEMORY or I/O RESET_REG. Fixes: 772a7a724f69 ("usb: gadget: f_fs: Allow scatter-gather buffers") Signed-off-by: Fei Yang <fei.yang@intel.com> Reviewed-by: Manu Gautam <mgautam@codeaurora.org> Tested-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2019-03-19 22:32:20 -07:00
if (ret != -EIOCBQUEUED) /* don't free if there is iocb queued */
ffs_free_buffer(io_data);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
}
static int
ffs_epfile_open(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
file->private_data = epfile;
ffs_data_opened(epfile->ffs);
usb: gadget: f_fs: Use stream_open() for endpoint files Function fs endpoint file operations are synchronized via an interruptible mutex wait. However we see threads that do ep file operations concurrently are getting blocked for the mutex lock in __fdget_pos(). This is an uninterruptible wait and we see hung task warnings and kernel panic if hung_task_panic systcl is enabled if host does not send/receive the data for long time. The reason for threads getting blocked in __fdget_pos() is due to the file position protection introduced by the commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX"). Since function fs endpoint files does not have the notion of the file position, switch to the stream mode. This will bypass the file position mutex and threads will be blocked in interruptible state for the function fs mutex. It should not affects user space as we are only changing the task state changes the task state from UNINTERRUPTIBLE to INTERRUPTIBLE while waiting for the USB transfers to be finished. However there is a slight change to the O_NONBLOCK behavior. Earlier threads that are using O_NONBLOCK are also getting blocked inside fdget_pos(). Now they reach to function fs and error code is returned. The non blocking behavior is actually honoured now. Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pavankumar Kondeti <quic_pkondeti@quicinc.com> Link: https://lore.kernel.org/r/1636712682-1226-1-git-send-email-quic_pkondeti@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-11-12 15:54:40 +05:30
return stream_open(inode, file);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int ffs_aio_cancel(struct kiocb *kiocb)
{
struct ffs_io_data *io_data = kiocb->private;
int value;
if (io_data && io_data->ep && io_data->req)
value = usb_ep_dequeue(io_data->ep, io_data->req);
else
value = -EINVAL;
return value;
}
static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
{
struct ffs_io_data io_data, *p = &io_data;
ssize_t res;
if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->aio = true;
} else {
memset(p, 0, sizeof(*p));
p->aio = false;
}
p->read = false;
p->kiocb = kiocb;
p->data = *from;
p->mm = current->mm;
kiocb->private = p;
if (p->aio)
kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
res = ffs_epfile_io(kiocb->ki_filp, p);
if (res == -EIOCBQUEUED)
return res;
if (p->aio)
kfree(p);
else
*from = p->data;
return res;
}
static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
{
struct ffs_io_data io_data, *p = &io_data;
ssize_t res;
if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->aio = true;
} else {
memset(p, 0, sizeof(*p));
p->aio = false;
}
p->read = true;
p->kiocb = kiocb;
if (p->aio) {
p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
if (!iter_is_ubuf(&p->data) && !p->to_free) {
kfree(p);
return -ENOMEM;
}
} else {
p->data = *to;
p->to_free = NULL;
}
p->mm = current->mm;
kiocb->private = p;
if (p->aio)
kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
res = ffs_epfile_io(kiocb->ki_filp, p);
if (res == -EIOCBQUEUED)
return res;
if (p->aio) {
kfree(p->to_free);
kfree(p);
} else {
*to = p->data;
}
return res;
}
static void ffs_dmabuf_release(struct kref *ref)
{
struct ffs_dmabuf_priv *priv = container_of(ref, struct ffs_dmabuf_priv, ref);
struct dma_buf_attachment *attach = priv->attach;
struct dma_buf *dmabuf = attach->dmabuf;
pr_vdebug("FFS DMABUF release\n");
dma_resv_lock(dmabuf->resv, NULL);
dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
dma_resv_unlock(dmabuf->resv);
dma_buf_detach(attach->dmabuf, attach);
dma_buf_put(dmabuf);
kfree(priv);
}
static void ffs_dmabuf_get(struct dma_buf_attachment *attach)
{
struct ffs_dmabuf_priv *priv = attach->importer_priv;
kref_get(&priv->ref);
}
static void ffs_dmabuf_put(struct dma_buf_attachment *attach)
{
struct ffs_dmabuf_priv *priv = attach->importer_priv;
kref_put(&priv->ref, ffs_dmabuf_release);
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int
ffs_epfile_release(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
struct ffs_dmabuf_priv *priv, *tmp;
struct ffs_data *ffs = epfile->ffs;
mutex_lock(&epfile->dmabufs_mutex);
/* Close all attached DMABUFs */
list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) {
/* Cancel any pending transfer */
spin_lock_irq(&ffs->eps_lock);
if (priv->ep && priv->req)
usb_ep_dequeue(priv->ep, priv->req);
spin_unlock_irq(&ffs->eps_lock);
list_del(&priv->entry);
ffs_dmabuf_put(priv->attach);
}
mutex_unlock(&epfile->dmabufs_mutex);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
__ffs_epfile_read_buffer_free(epfile);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_data_closed(epfile->ffs);
return 0;
}
static void ffs_dmabuf_cleanup(struct work_struct *work)
{
struct ffs_dma_fence *dma_fence =
container_of(work, struct ffs_dma_fence, work);
struct ffs_dmabuf_priv *priv = dma_fence->priv;
struct dma_buf_attachment *attach = priv->attach;
struct dma_fence *fence = &dma_fence->base;
ffs_dmabuf_put(attach);
dma_fence_put(fence);
}
static void ffs_dmabuf_signal_done(struct ffs_dma_fence *dma_fence, int ret)
{
struct ffs_dmabuf_priv *priv = dma_fence->priv;
struct dma_fence *fence = &dma_fence->base;
bool cookie = dma_fence_begin_signalling();
dma_fence_get(fence);
fence->error = ret;
dma_fence_signal(fence);
dma_fence_end_signalling(cookie);
/*
* The fence will be unref'd in ffs_dmabuf_cleanup.
* It can't be done here, as the unref functions might try to lock
* the resv object, which would deadlock.
*/
INIT_WORK(&dma_fence->work, ffs_dmabuf_cleanup);
queue_work(priv->ffs->io_completion_wq, &dma_fence->work);
}
static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep,
struct usb_request *req)
{
pr_vdebug("FFS: DMABUF transfer complete, status=%d\n", req->status);
ffs_dmabuf_signal_done(req->context, req->status);
usb_ep_free_request(ep, req);
}
static const char *ffs_dmabuf_get_driver_name(struct dma_fence *fence)
{
return "functionfs";
}
static const char *ffs_dmabuf_get_timeline_name(struct dma_fence *fence)
{
return "";
}
static void ffs_dmabuf_fence_release(struct dma_fence *fence)
{
struct ffs_dma_fence *dma_fence =
container_of(fence, struct ffs_dma_fence, base);
kfree(dma_fence);
}
static const struct dma_fence_ops ffs_dmabuf_fence_ops = {
.get_driver_name = ffs_dmabuf_get_driver_name,
.get_timeline_name = ffs_dmabuf_get_timeline_name,
.release = ffs_dmabuf_fence_release,
};
static int ffs_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
{
if (!nonblock)
return dma_resv_lock_interruptible(dmabuf->resv, NULL);
if (!dma_resv_trylock(dmabuf->resv))
return -EBUSY;
return 0;
}
static struct dma_buf_attachment *
ffs_dmabuf_find_attachment(struct ffs_epfile *epfile, struct dma_buf *dmabuf)
{
struct device *dev = epfile->ffs->gadget->dev.parent;
struct dma_buf_attachment *attach = NULL;
struct ffs_dmabuf_priv *priv;
mutex_lock(&epfile->dmabufs_mutex);
list_for_each_entry(priv, &epfile->dmabufs, entry) {
if (priv->attach->dev == dev
&& priv->attach->dmabuf == dmabuf) {
attach = priv->attach;
break;
}
}
if (attach)
ffs_dmabuf_get(attach);
mutex_unlock(&epfile->dmabufs_mutex);
return attach ?: ERR_PTR(-EPERM);
}
static int ffs_dmabuf_attach(struct file *file, int fd)
{
bool nonblock = file->f_flags & O_NONBLOCK;
struct ffs_epfile *epfile = file->private_data;
struct usb_gadget *gadget = epfile->ffs->gadget;
struct dma_buf_attachment *attach;
struct ffs_dmabuf_priv *priv;
enum dma_data_direction dir;
struct sg_table *sg_table;
struct dma_buf *dmabuf;
int err;
if (!gadget || !gadget->sg_supported)
return -EPERM;
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
attach = dma_buf_attach(dmabuf, gadget->dev.parent);
if (IS_ERR(attach)) {
err = PTR_ERR(attach);
goto err_dmabuf_put;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
err = -ENOMEM;
goto err_dmabuf_detach;
}
dir = epfile->in ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
err = ffs_dma_resv_lock(dmabuf, nonblock);
if (err)
goto err_free_priv;
sg_table = dma_buf_map_attachment(attach, dir);
dma_resv_unlock(dmabuf->resv);
if (IS_ERR(sg_table)) {
err = PTR_ERR(sg_table);
goto err_free_priv;
}
attach->importer_priv = priv;
priv->sgt = sg_table;
priv->dir = dir;
priv->ffs = epfile->ffs;
priv->attach = attach;
spin_lock_init(&priv->lock);
kref_init(&priv->ref);
priv->context = dma_fence_context_alloc(1);
mutex_lock(&epfile->dmabufs_mutex);
list_add(&priv->entry, &epfile->dmabufs);
mutex_unlock(&epfile->dmabufs_mutex);
return 0;
err_free_priv:
kfree(priv);
err_dmabuf_detach:
dma_buf_detach(dmabuf, attach);
err_dmabuf_put:
dma_buf_put(dmabuf);
return err;
}
static int ffs_dmabuf_detach(struct file *file, int fd)
{
struct ffs_epfile *epfile = file->private_data;
struct ffs_data *ffs = epfile->ffs;
struct device *dev = ffs->gadget->dev.parent;
struct ffs_dmabuf_priv *priv, *tmp;
struct dma_buf *dmabuf;
int ret = -EPERM;
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
mutex_lock(&epfile->dmabufs_mutex);
list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) {
if (priv->attach->dev == dev
&& priv->attach->dmabuf == dmabuf) {
/* Cancel any pending transfer */
spin_lock_irq(&ffs->eps_lock);
if (priv->ep && priv->req)
usb_ep_dequeue(priv->ep, priv->req);
spin_unlock_irq(&ffs->eps_lock);
list_del(&priv->entry);
/* Unref the reference from ffs_dmabuf_attach() */
ffs_dmabuf_put(priv->attach);
ret = 0;
break;
}
}
mutex_unlock(&epfile->dmabufs_mutex);
dma_buf_put(dmabuf);
return ret;
}
static int ffs_dmabuf_transfer(struct file *file,
const struct usb_ffs_dmabuf_transfer_req *req)
{
bool nonblock = file->f_flags & O_NONBLOCK;
struct ffs_epfile *epfile = file->private_data;
struct dma_buf_attachment *attach;
struct ffs_dmabuf_priv *priv;
struct ffs_dma_fence *fence;
struct usb_request *usb_req;
enum dma_resv_usage resv_dir;
struct dma_buf *dmabuf;
unsigned long timeout;
struct ffs_ep *ep;
bool cookie;
u32 seqno;
long retl;
int ret;
if (req->flags & ~USB_FFS_DMABUF_TRANSFER_MASK)
return -EINVAL;
dmabuf = dma_buf_get(req->fd);
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
if (req->length > dmabuf->size || req->length == 0) {
ret = -EINVAL;
goto err_dmabuf_put;
}
attach = ffs_dmabuf_find_attachment(epfile, dmabuf);
if (IS_ERR(attach)) {
ret = PTR_ERR(attach);
goto err_dmabuf_put;
}
priv = attach->importer_priv;
ep = ffs_epfile_wait_ep(file);
if (IS_ERR(ep)) {
ret = PTR_ERR(ep);
goto err_attachment_put;
}
ret = ffs_dma_resv_lock(dmabuf, nonblock);
if (ret)
goto err_attachment_put;
/* Make sure we don't have writers */
timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS);
retl = dma_resv_wait_timeout(dmabuf->resv,
dma_resv_usage_rw(epfile->in),
true, timeout);
if (retl == 0)
retl = -EBUSY;
if (retl < 0) {
ret = (int)retl;
goto err_resv_unlock;
}
ret = dma_resv_reserve_fences(dmabuf->resv, 1);
if (ret)
goto err_resv_unlock;
fence = kmalloc(sizeof(*fence), GFP_KERNEL);
if (!fence) {
ret = -ENOMEM;
goto err_resv_unlock;
}
fence->priv = priv;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
if (epfile->ep != ep) {
ret = -ESHUTDOWN;
goto err_fence_put;
}
usb_req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
if (!usb_req) {
ret = -ENOMEM;
goto err_fence_put;
}
/*
* usb_ep_queue() guarantees that all transfers are processed in the
* order they are enqueued, so we can use a simple incrementing
* sequence number for the dma_fence.
*/
seqno = atomic_add_return(1, &epfile->seqno);
dma_fence_init(&fence->base, &ffs_dmabuf_fence_ops,
&priv->lock, priv->context, seqno);
resv_dir = epfile->in ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ;
dma_resv_add_fence(dmabuf->resv, &fence->base, resv_dir);
dma_resv_unlock(dmabuf->resv);
/* Now that the dma_fence is in place, queue the transfer. */
usb_req->length = req->length;
usb_req->buf = NULL;
usb_req->sg = priv->sgt->sgl;
usb_req->num_sgs = sg_nents_for_len(priv->sgt->sgl, req->length);
usb_req->sg_was_mapped = true;
usb_req->context = fence;
usb_req->complete = ffs_epfile_dmabuf_io_complete;
cookie = dma_fence_begin_signalling();
ret = usb_ep_queue(ep->ep, usb_req, GFP_ATOMIC);
dma_fence_end_signalling(cookie);
if (!ret) {
priv->req = usb_req;
priv->ep = ep->ep;
} else {
pr_warn("FFS: Failed to queue DMABUF: %d\n", ret);
ffs_dmabuf_signal_done(fence, ret);
usb_ep_free_request(ep->ep, usb_req);
}
spin_unlock_irq(&epfile->ffs->eps_lock);
dma_buf_put(dmabuf);
return ret;
err_fence_put:
spin_unlock_irq(&epfile->ffs->eps_lock);
dma_fence_put(&fence->base);
err_resv_unlock:
dma_resv_unlock(dmabuf->resv);
err_attachment_put:
ffs_dmabuf_put(attach);
err_dmabuf_put:
dma_buf_put(dmabuf);
return ret;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static long ffs_epfile_ioctl(struct file *file, unsigned code,
unsigned long value)
{
struct ffs_epfile *epfile = file->private_data;
struct ffs_ep *ep;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
int ret;
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
switch (code) {
case FUNCTIONFS_DMABUF_ATTACH:
{
int fd;
if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) {
ret = -EFAULT;
break;
}
return ffs_dmabuf_attach(file, fd);
}
case FUNCTIONFS_DMABUF_DETACH:
{
int fd;
if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) {
ret = -EFAULT;
break;
}
return ffs_dmabuf_detach(file, fd);
}
case FUNCTIONFS_DMABUF_TRANSFER:
{
struct usb_ffs_dmabuf_transfer_req req;
if (copy_from_user(&req, (void __user *)value, sizeof(req))) {
ret = -EFAULT;
break;
}
return ffs_dmabuf_transfer(file, &req);
}
default:
break;
}
/* Wait for endpoint to be enabled */
ep = ffs_epfile_wait_ep(file);
if (IS_ERR(ep))
return PTR_ERR(ep);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
if (epfile->ep != ep) {
spin_unlock_irq(&epfile->ffs->eps_lock);
return -ESHUTDOWN;
}
switch (code) {
case FUNCTIONFS_FIFO_STATUS:
ret = usb_ep_fifo_status(epfile->ep->ep);
break;
case FUNCTIONFS_FIFO_FLUSH:
usb_ep_fifo_flush(epfile->ep->ep);
ret = 0;
break;
case FUNCTIONFS_CLEAR_HALT:
ret = usb_ep_clear_halt(epfile->ep->ep);
break;
case FUNCTIONFS_ENDPOINT_REVMAP:
ret = epfile->ep->num;
break;
case FUNCTIONFS_ENDPOINT_DESC:
{
int desc_idx;
struct usb_endpoint_descriptor desc1, *desc;
switch (epfile->ffs->gadget->speed) {
case USB_SPEED_SUPER:
2020-10-27 16:07:31 -07:00
case USB_SPEED_SUPER_PLUS:
desc_idx = 2;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
case USB_SPEED_HIGH:
desc_idx = 1;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
default:
desc_idx = 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
desc = epfile->ep->descs[desc_idx];
memcpy(&desc1, desc, desc->bLength);
spin_unlock_irq(&epfile->ffs->eps_lock);
ret = copy_to_user((void __user *)value, &desc1, desc1.bLength);
if (ret)
ret = -EFAULT;
return ret;
}
default:
ret = -ENOTTY;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
spin_unlock_irq(&epfile->ffs->eps_lock);
return ret;
}
static const struct file_operations ffs_epfile_operations = {
.open = ffs_epfile_open,
.write_iter = ffs_epfile_write_iter,
.read_iter = ffs_epfile_read_iter,
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
.release = ffs_epfile_release,
.unlocked_ioctl = ffs_epfile_ioctl,
.compat_ioctl = compat_ptr_ioctl,
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
};
/* File system and super block operations ***********************************/
/*
* Mounting the file system creates a controller file, used first for
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* function configuration then later for event monitoring.
*/
static struct inode *__must_check
ffs_sb_make_inode(struct super_block *sb, void *data,
const struct file_operations *fops,
const struct inode_operations *iops,
struct ffs_file_perms *perms)
{
struct inode *inode;
inode = new_inode(sb);
if (inode) {
struct timespec64 ts = inode_set_ctime_current(inode);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
inode->i_ino = get_next_ino();
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
inode->i_mode = perms->mode;
inode->i_uid = perms->uid;
inode->i_gid = perms->gid;
inode_set_atime_to_ts(inode, ts);
inode_set_mtime_to_ts(inode, ts);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
inode->i_private = data;
if (fops)
inode->i_fop = fops;
if (iops)
inode->i_op = iops;
}
return inode;
}
/* Create "regular" file */
static struct dentry *ffs_sb_create_file(struct super_block *sb,
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
const char *name, void *data,
const struct file_operations *fops)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct ffs_data *ffs = sb->s_fs_info;
struct dentry *dentry;
struct inode *inode;
dentry = d_alloc_name(sb->s_root, name);
if (!dentry)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return NULL;
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
if (!inode) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
dput(dentry);
return NULL;
}
d_add(dentry, inode);
return dentry;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
/* Super block */
static const struct super_operations ffs_sb_operations = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
};
struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
bool no_disconnect;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
struct ffs_data *ffs_data;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
};
static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct ffs_sb_fill_data *data = fc->fs_private;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
struct inode *inode;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
struct ffs_data *ffs = data->ffs_data;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->sb = sb;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
data->ffs_data = NULL;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
sb->s_fs_info = ffs;
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time ago with promise that one day it will be possible to implement page cache with bigger chunks than PAGE_SIZE. This promise never materialized. And unlikely will. We have many places where PAGE_CACHE_SIZE assumed to be equal to PAGE_SIZE. And it's constant source of confusion on whether PAGE_CACHE_* or PAGE_* constant should be used in a particular case, especially on the border between fs and mm. Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much breakage to be doable. Let's stop pretending that pages in page cache are special. They are not. The changes are pretty straight-forward: - <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>; - <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>; - PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN}; - page_cache_get() -> get_page(); - page_cache_release() -> put_page(); This patch contains automated changes generated with coccinelle using script below. For some reason, coccinelle doesn't patch header files. I've called spatch for them manually. The only adjustment after coccinelle is revert of changes to PAGE_CAHCE_ALIGN definition: we are going to drop it later. There are few places in the code where coccinelle didn't reach. I'll fix them manually in a separate patch. Comments and documentation also will be addressed with the separate patch. virtual patch @@ expression E; @@ - E << (PAGE_CACHE_SHIFT - PAGE_SHIFT) + E @@ expression E; @@ - E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) + E @@ @@ - PAGE_CACHE_SHIFT + PAGE_SHIFT @@ @@ - PAGE_CACHE_SIZE + PAGE_SIZE @@ @@ - PAGE_CACHE_MASK + PAGE_MASK @@ expression E; @@ - PAGE_CACHE_ALIGN(E) + PAGE_ALIGN(E) @@ expression E; @@ - page_cache_get(E) + get_page(E) @@ expression E; @@ - page_cache_release(E) + put_page(E) Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Acked-by: Michal Hocko <mhocko@suse.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 15:29:47 +03:00
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
sb->s_magic = FUNCTIONFS_MAGIC;
sb->s_op = &ffs_sb_operations;
sb->s_time_gran = 1;
/* Root inode */
data->perms.mode = data->root_mode;
inode = ffs_sb_make_inode(sb, NULL,
&simple_dir_operations,
&simple_dir_inode_operations,
&data->perms);
sb->s_root = d_make_root(inode);
if (!sb->s_root)
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
return -ENOMEM;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* EP0 file */
if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
return -ENOMEM;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return 0;
}
enum {
Opt_no_disconnect,
Opt_rmode,
Opt_fmode,
Opt_mode,
Opt_uid,
Opt_gid,
};
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static const struct fs_parameter_spec ffs_fs_fs_parameters[] = {
fsparam_bool ("no_disconnect", Opt_no_disconnect),
fsparam_u32 ("rmode", Opt_rmode),
fsparam_u32 ("fmode", Opt_fmode),
fsparam_u32 ("mode", Opt_mode),
fsparam_u32 ("uid", Opt_uid),
fsparam_u32 ("gid", Opt_gid),
{}
};
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct ffs_sb_fill_data *data = fc->fs_private;
struct fs_parse_result result;
int opt;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result);
if (opt < 0)
return opt;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
switch (opt) {
case Opt_no_disconnect:
data->no_disconnect = result.boolean;
break;
case Opt_rmode:
data->root_mode = (result.uint_32 & 0555) | S_IFDIR;
break;
case Opt_fmode:
data->perms.mode = (result.uint_32 & 0666) | S_IFREG;
break;
case Opt_mode:
data->root_mode = (result.uint_32 & 0555) | S_IFDIR;
data->perms.mode = (result.uint_32 & 0666) | S_IFREG;
break;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
case Opt_uid:
data->perms.uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(data->perms.uid))
goto unmapped_value;
break;
case Opt_gid:
data->perms.gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(data->perms.gid))
goto unmapped_value;
break;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
default:
return -ENOPARAM;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
return 0;
unmapped_value:
return invalf(fc, "%s: unmapped value: %u", param->key, result.uint_32);
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/*
* Set up the superblock for a mount.
*/
static int ffs_fs_get_tree(struct fs_context *fc)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct ffs_sb_fill_data *ctx = fc->fs_private;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
struct ffs_data *ffs;
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
int ret;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (!fc->source)
return invalf(fc, "No source specified");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs = ffs_data_new(fc->source);
if (!ffs)
return -ENOMEM;
ffs->file_perms = ctx->perms;
ffs->no_disconnect = ctx->no_disconnect;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
ffs->dev_name = kstrdup(fc->source, GFP_KERNEL);
if (!ffs->dev_name) {
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
ffs_data_put(ffs);
return -ENOMEM;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
}
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
ret = ffs_acquire_dev(ffs->dev_name, ffs);
if (ret) {
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
ffs_data_put(ffs);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
return ret;
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
}
ctx->ffs_data = ffs;
return get_tree_nodev(fc, ffs_sb_fill);
}
static void ffs_fs_free_fc(struct fs_context *fc)
{
struct ffs_sb_fill_data *ctx = fc->fs_private;
if (ctx) {
if (ctx->ffs_data) {
ffs_data_put(ctx->ffs_data);
}
kfree(ctx);
USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-09-20 17:14:21 +01:00
}
}
static const struct fs_context_operations ffs_fs_context_ops = {
.free = ffs_fs_free_fc,
.parse_param = ffs_fs_parse_param,
.get_tree = ffs_fs_get_tree,
};
static int ffs_fs_init_fs_context(struct fs_context *fc)
{
struct ffs_sb_fill_data *ctx;
ctx = kzalloc(sizeof(struct ffs_sb_fill_data), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->perms.mode = S_IFREG | 0600;
ctx->perms.uid = GLOBAL_ROOT_UID;
ctx->perms.gid = GLOBAL_ROOT_GID;
ctx->root_mode = S_IFDIR | 0500;
ctx->no_disconnect = false;
fc->fs_private = ctx;
fc->ops = &ffs_fs_context_ops;
return 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static void
ffs_fs_kill_sb(struct super_block *sb)
{
kill_litter_super(sb);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
if (sb->s_fs_info)
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
ffs_data_closed(sb->s_fs_info);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static struct file_system_type ffs_fs_type = {
.owner = THIS_MODULE,
.name = "functionfs",
.init_fs_context = ffs_fs_init_fs_context,
.parameters = ffs_fs_fs_parameters,
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
.kill_sb = ffs_fs_kill_sb,
};
fs: Limit sys_mount to only request filesystem modules. Modify the request_module to prefix the file system type with "fs-" and add aliases to all of the filesystems that can be built as modules to match. A common practice is to build all of the kernel code and leave code that is not commonly needed as modules, with the result that many users are exposed to any bug anywhere in the kernel. Looking for filesystems with a fs- prefix limits the pool of possible modules that can be loaded by mount to just filesystems trivially making things safer with no real cost. Using aliases means user space can control the policy of which filesystem modules are auto-loaded by editing /etc/modprobe.d/*.conf with blacklist and alias directives. Allowing simple, safe, well understood work-arounds to known problematic software. This also addresses a rare but unfortunate problem where the filesystem name is not the same as it's module name and module auto-loading would not work. While writing this patch I saw a handful of such cases. The most significant being autofs that lives in the module autofs4. This is relevant to user namespaces because we can reach the request module in get_fs_type() without having any special permissions, and people get uncomfortable when a user specified string (in this case the filesystem type) goes all of the way to request_module. After having looked at this issue I don't think there is any particular reason to perform any filtering or permission checks beyond making it clear in the module request that we want a filesystem module. The common pattern in the kernel is to call request_module() without regards to the users permissions. In general all a filesystem module does once loaded is call register_filesystem() and go to sleep. Which means there is not much attack surface exposed by loading a filesytem module unless the filesystem is mounted. In a user namespace filesystems are not mounted unless .fs_flags = FS_USERNS_MOUNT, which most filesystems do not set today. Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Acked-by: Kees Cook <keescook@chromium.org> Reported-by: Kees Cook <keescook@google.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2013-03-02 19:39:14 -08:00
MODULE_ALIAS_FS("functionfs");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Driver's main init/cleanup functions *************************************/
static int functionfs_init(void)
{
int ret;
ret = register_filesystem(&ffs_fs_type);
if (!ret)
pr_info("file system registered\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
else
pr_err("failed registering file system (%d)\n", ret);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
}
static void functionfs_cleanup(void)
{
pr_info("unloading\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
unregister_filesystem(&ffs_fs_type);
}
/* ffs_data and ffs_function construction and destruction code **************/
static void ffs_data_clear(struct ffs_data *ffs);
static void ffs_data_reset(struct ffs_data *ffs);
static void ffs_data_get(struct ffs_data *ffs)
{
refcount_inc(&ffs->ref);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static void ffs_data_opened(struct ffs_data *ffs)
{
refcount_inc(&ffs->ref);
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static void ffs_data_put(struct ffs_data *ffs)
{
if (refcount_dec_and_test(&ffs->ref)) {
pr_info("%s(): freeing\n", __func__);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_data_clear(ffs);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
ffs_release_dev(ffs->private_data);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
completion: Use simple wait queues completion uses a wait_queue_head_t to enqueue waiters. wait_queue_head_t contains a spinlock_t to protect the list of waiters which excludes it from being used in truly atomic context on a PREEMPT_RT enabled kernel. The spinlock in the wait queue head cannot be replaced by a raw_spinlock because: - wait queues can have custom wakeup callbacks, which acquire other spinlock_t locks and have potentially long execution times - wake_up() walks an unbounded number of list entries during the wake up and may wake an unbounded number of waiters. For simplicity and performance reasons complete() should be usable on PREEMPT_RT enabled kernels. completions do not use custom wakeup callbacks and are usually single waiter, except for a few corner cases. Replace the wait queue in the completion with a simple wait queue (swait), which uses a raw_spinlock_t for protecting the waiter list and therefore is safe to use inside truly atomic regions on PREEMPT_RT. There is no semantical or functional change: - completions use the exclusive wait mode which is what swait provides - complete() wakes one exclusive waiter - complete_all() wakes all waiters while holding the lock which protects the wait queue against newly incoming waiters. The conversion to swait preserves this behaviour. complete_all() might cause unbound latencies with a large number of waiters being woken at once, but most complete_all() usage sites are either in testing or initialization code or have only a really small number of concurrent waiters which for now does not cause a latency problem. Keep it simple for now. The fixup of the warning check in the USB gadget driver is just a straight forward conversion of the lockless waiter check from one waitqueue type to the other. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Davidlohr Bueso <dbueso@suse.de> Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lkml.kernel.org/r/20200321113242.317954042@linutronix.de
2020-03-21 12:26:00 +01:00
swait_active(&ffs->ep0req_completion.wait) ||
waitqueue_active(&ffs->wait));
destroy_workqueue(ffs->io_completion_wq);
kfree(ffs->dev_name);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
kfree(ffs);
}
}
static void ffs_data_closed(struct ffs_data *ffs)
{
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
struct ffs_epfile *epfiles;
unsigned long flags;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (atomic_dec_and_test(&ffs->opened)) {
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED;
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
spin_lock_irqsave(&ffs->eps_lock, flags);
epfiles = ffs->epfiles;
ffs->epfiles = NULL;
spin_unlock_irqrestore(&ffs->eps_lock,
flags);
if (epfiles)
ffs_epfiles_destroy(epfiles,
ffs->eps_count);
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
if (ffs->setup_state == FFS_SETUP_PENDING)
__ffs_ep0_stall(ffs);
} else {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
}
if (atomic_read(&ffs->opened) < 0) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
ffs_data_put(ffs);
}
static struct ffs_data *ffs_data_new(const char *dev_name)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
if (!ffs)
return NULL;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
if (!ffs->io_completion_wq) {
kfree(ffs);
return NULL;
}
refcount_set(&ffs->ref, 1);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
atomic_set(&ffs->opened, 0);
ffs->state = FFS_READ_DESCRIPTORS;
mutex_init(&ffs->mutex);
spin_lock_init(&ffs->eps_lock);
init_waitqueue_head(&ffs->ev.waitq);
init_waitqueue_head(&ffs->wait);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
init_completion(&ffs->ep0req_completion);
/* XXX REVISIT need to update it in some places, or do we? */
ffs->ev.can_stall = 1;
return ffs;
}
static void ffs_data_clear(struct ffs_data *ffs)
{
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
struct ffs_epfile *epfiles;
unsigned long flags;
usb: gadget: ffs: fix: Always call ffs_closed() in ffs_data_clear() Originally FFS_FL_CALL_CLOSED_CALLBACK flag has been used to indicate if we should call ffs_closed_callback(). Commit 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") changed its semantic to indicate if we should call ffs_closed() function which does a little bit more. This situation leads to: [ 122.362269] ------------[ cut here ]------------ [ 122.362287] WARNING: CPU: 2 PID: 2384 at drivers/usb/gadget/function/f_fs.c:3417 ffs_ep0_write+0x730/0x810 [usb_f_fs]() [ 122.362292] Modules linked in: [ 122.362555] CPU: 2 PID: 2384 Comm: adbd Tainted: G W 4.1.0-0.rc4.git0.1.1.fc22.i686 #1 [ 122.362561] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 07/25/2014 [ 122.362567] c0d1f947 415badfa 00000000 d1029e64 c0a86e54 00000000 d1029e94 c045b937 [ 122.362584] c0c37f94 00000002 00000950 f9b313d4 00000d59 f9b2ebf0 f9b2ebf0 fffffff0 [ 122.362600] 00000003 deb53d00 d1029ea4 c045ba42 00000009 00000000 d1029f08 f9b2ebf0 [ 122.362617] Call Trace: [ 122.362633] [<c0a86e54>] dump_stack+0x41/0x52 [ 122.362645] [<c045b937>] warn_slowpath_common+0x87/0xc0 [ 122.362658] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362668] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362678] [<c045ba42>] warn_slowpath_null+0x22/0x30 [ 122.362689] [<f9b2ebf0>] ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362702] [<f9b2e4c0>] ? ffs_ep0_read+0x380/0x380 [usb_f_fs] [ 122.362712] [<c05a1c1f>] __vfs_write+0x2f/0x100 [ 122.362722] [<c05a42f2>] ? __sb_start_write+0x52/0x110 [ 122.362731] [<c05a2534>] vfs_write+0x94/0x1b0 [ 122.362740] [<c0a8a1c0>] ? mutex_lock+0x10/0x30 [ 122.362749] [<c05a2f41>] SyS_write+0x51/0xb0 [ 122.362759] [<c0a8c71f>] sysenter_do_call+0x12/0x12 [ 122.362766] ---[ end trace 0673d3467cecf8db ]--- in some cases (reproduction path below). This commit get back semantic of that flag and ensures that ffs_closed() is called always when needed but ffs_closed_callback() is called only if this flag is set. Reproduction path: Compile kernel without any UDC driver or bound some gadget to existing one and then: $ modprobe g_ffs $ mount none -t functionfs mount_point $ ffs-example mount_point This will fail with -ENODEV as there is no udc. $ ffs-example mount_point This will fail with -EBUSY because ffs_data has not been properly cleaned up. Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2015-05-22 17:25:18 +02:00
ffs_closed(ffs);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
BUG_ON(ffs->gadget);
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
spin_lock_irqsave(&ffs->eps_lock, flags);
epfiles = ffs->epfiles;
ffs->epfiles = NULL;
spin_unlock_irqrestore(&ffs->eps_lock, flags);
/*
* potential race possible between ffs_func_eps_disable
* & ffs_epfile_release therefore maintaining a local
* copy of epfile will save us from use-after-free.
*/
if (epfiles) {
ffs_epfiles_destroy(epfiles, ffs->eps_count);
usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear. ffs_data_clear is indirectly called from both ffs_fs_kill_sb and ffs_ep0_release, so it ends up being called twice when userland closes ep0 and then unmounts f_fs. If userland provided an eventfd along with function's USB descriptors, it ends up calling eventfd_ctx_put as many times, causing a refcount underflow. NULL-ify ffs_eventfd to prevent these extraneous eventfd_ctx_put calls. Also, set epfiles to NULL right after de-allocating it, for readability. For completeness, ffs_data_clear actually ends up being called thrice, the last call being before the whole ffs structure gets freed, so when this specific sequence happens there is a second underflow happening (but not being reported): /sys/kernel/debug/tracing# modprobe usb_f_fs /sys/kernel/debug/tracing# echo ffs_data_clear > set_ftrace_filter /sys/kernel/debug/tracing# echo function > current_tracer /sys/kernel/debug/tracing# echo 1 > tracing_on (setup gadget, run and kill function userland process, teardown gadget) /sys/kernel/debug/tracing# echo 0 > tracing_on /sys/kernel/debug/tracing# cat trace smartcard-openp-436 [000] ..... 1946.208786: ffs_data_clear <-ffs_data_closed smartcard-openp-431 [000] ..... 1946.279147: ffs_data_clear <-ffs_data_closed smartcard-openp-431 [000] .n... 1946.905512: ffs_data_clear <-ffs_data_put Warning output corresponding to above trace: [ 1946.284139] WARNING: CPU: 0 PID: 431 at lib/refcount.c:28 refcount_warn_saturate+0x110/0x15c [ 1946.293094] refcount_t: underflow; use-after-free. [ 1946.298164] Modules linked in: usb_f_ncm(E) u_ether(E) usb_f_fs(E) hci_uart(E) btqca(E) btrtl(E) btbcm(E) btintel(E) bluetooth(E) nls_ascii(E) nls_cp437(E) vfat(E) fat(E) bcm2835_v4l2(CE) bcm2835_mmal_vchiq(CE) videobuf2_vmalloc(E) videobuf2_memops(E) sha512_generic(E) videobuf2_v4l2(E) sha512_arm(E) videobuf2_common(E) videodev(E) cpufreq_dt(E) snd_bcm2835(CE) brcmfmac(E) mc(E) vc4(E) ctr(E) brcmutil(E) snd_soc_core(E) snd_pcm_dmaengine(E) drbg(E) snd_pcm(E) snd_timer(E) snd(E) soundcore(E) drm_kms_helper(E) cec(E) ansi_cprng(E) rc_core(E) syscopyarea(E) raspberrypi_cpufreq(E) sysfillrect(E) sysimgblt(E) cfg80211(E) max17040_battery(OE) raspberrypi_hwmon(E) fb_sys_fops(E) regmap_i2c(E) ecdh_generic(E) rfkill(E) ecc(E) bcm2835_rng(E) rng_core(E) vchiq(CE) leds_gpio(E) libcomposite(E) fuse(E) configfs(E) ip_tables(E) x_tables(E) autofs4(E) ext4(E) crc16(E) mbcache(E) jbd2(E) crc32c_generic(E) sdhci_iproc(E) sdhci_pltfm(E) sdhci(E) [ 1946.399633] CPU: 0 PID: 431 Comm: smartcard-openp Tainted: G C OE 5.15.0-1-rpi #1 Debian 5.15.3-1 [ 1946.417950] Hardware name: BCM2835 [ 1946.425442] Backtrace: [ 1946.432048] [<c08d60a0>] (dump_backtrace) from [<c08d62ec>] (show_stack+0x20/0x24) [ 1946.448226] r7:00000009 r6:0000001c r5:c04a948c r4:c0a64e2c [ 1946.458412] [<c08d62cc>] (show_stack) from [<c08d9ae0>] (dump_stack+0x28/0x30) [ 1946.470380] [<c08d9ab8>] (dump_stack) from [<c0123500>] (__warn+0xe8/0x154) [ 1946.482067] r5:c04a948c r4:c0a71dc8 [ 1946.490184] [<c0123418>] (__warn) from [<c08d6948>] (warn_slowpath_fmt+0xa0/0xe4) [ 1946.506758] r7:00000009 r6:0000001c r5:c0a71dc8 r4:c0a71e04 [ 1946.517070] [<c08d68ac>] (warn_slowpath_fmt) from [<c04a948c>] (refcount_warn_saturate+0x110/0x15c) [ 1946.535309] r8:c0100224 r7:c0dfcb84 r6:ffffffff r5:c3b84c00 r4:c24a17c0 [ 1946.546708] [<c04a937c>] (refcount_warn_saturate) from [<c0380134>] (eventfd_ctx_put+0x48/0x74) [ 1946.564476] [<c03800ec>] (eventfd_ctx_put) from [<bf5464e8>] (ffs_data_clear+0xd0/0x118 [usb_f_fs]) [ 1946.582664] r5:c3b84c00 r4:c2695b00 [ 1946.590668] [<bf546418>] (ffs_data_clear [usb_f_fs]) from [<bf547cc0>] (ffs_data_closed+0x9c/0x150 [usb_f_fs]) [ 1946.609608] r5:bf54d014 r4:c2695b00 [ 1946.617522] [<bf547c24>] (ffs_data_closed [usb_f_fs]) from [<bf547da0>] (ffs_fs_kill_sb+0x2c/0x30 [usb_f_fs]) [ 1946.636217] r7:c0dfcb84 r6:c3a12260 r5:bf54d014 r4:c229f000 [ 1946.646273] [<bf547d74>] (ffs_fs_kill_sb [usb_f_fs]) from [<c0326d50>] (deactivate_locked_super+0x54/0x9c) [ 1946.664893] r5:bf54d014 r4:c229f000 [ 1946.672921] [<c0326cfc>] (deactivate_locked_super) from [<c0326df8>] (deactivate_super+0x60/0x64) [ 1946.690722] r5:c2a09000 r4:c229f000 [ 1946.698706] [<c0326d98>] (deactivate_super) from [<c0349a28>] (cleanup_mnt+0xe4/0x14c) [ 1946.715553] r5:c2a09000 r4:00000000 [ 1946.723528] [<c0349944>] (cleanup_mnt) from [<c0349b08>] (__cleanup_mnt+0x1c/0x20) [ 1946.739922] r7:c0dfcb84 r6:c3a12260 r5:c3a126fc r4:00000000 [ 1946.750088] [<c0349aec>] (__cleanup_mnt) from [<c0143d10>] (task_work_run+0x84/0xb8) [ 1946.766602] [<c0143c8c>] (task_work_run) from [<c010bdc8>] (do_work_pending+0x470/0x56c) [ 1946.783540] r7:5ac3c35a r6:c0d0424c r5:c200bfb0 r4:c200a000 [ 1946.793614] [<c010b958>] (do_work_pending) from [<c01000c0>] (slow_work_pending+0xc/0x20) [ 1946.810553] Exception stack(0xc200bfb0 to 0xc200bff8) [ 1946.820129] bfa0: 00000000 00000000 000000aa b5e21430 [ 1946.837104] bfc0: bef867a0 00000001 bef86840 00000034 bef86838 bef86790 bef86794 bef867a0 [ 1946.854125] bfe0: 00000000 bef86798 b67b7a1c b6d626a4 60000010 b5a23760 [ 1946.865335] r10:00000000 r9:c200a000 r8:c0100224 r7:00000034 r6:bef86840 r5:00000001 [ 1946.881914] r4:bef867a0 [ 1946.888793] ---[ end trace 7387f2a9725b28d0 ]--- Fixes: 5e33f6fdf735 ("usb: gadget: ffs: add eventfd notification about ffs events") Cc: stable <stable@vger.kernel.org> Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com> Link: https://lore.kernel.org/r/f79eeea29f3f98de6782a064ec0f7351ad2f598f.1639793920.git.plr.vincent@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-12-18 02:18:40 +00:00
ffs->epfiles = NULL;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear. ffs_data_clear is indirectly called from both ffs_fs_kill_sb and ffs_ep0_release, so it ends up being called twice when userland closes ep0 and then unmounts f_fs. If userland provided an eventfd along with function's USB descriptors, it ends up calling eventfd_ctx_put as many times, causing a refcount underflow. NULL-ify ffs_eventfd to prevent these extraneous eventfd_ctx_put calls. Also, set epfiles to NULL right after de-allocating it, for readability. For completeness, ffs_data_clear actually ends up being called thrice, the last call being before the whole ffs structure gets freed, so when this specific sequence happens there is a second underflow happening (but not being reported): /sys/kernel/debug/tracing# modprobe usb_f_fs /sys/kernel/debug/tracing# echo ffs_data_clear > set_ftrace_filter /sys/kernel/debug/tracing# echo function > current_tracer /sys/kernel/debug/tracing# echo 1 > tracing_on (setup gadget, run and kill function userland process, teardown gadget) /sys/kernel/debug/tracing# echo 0 > tracing_on /sys/kernel/debug/tracing# cat trace smartcard-openp-436 [000] ..... 1946.208786: ffs_data_clear <-ffs_data_closed smartcard-openp-431 [000] ..... 1946.279147: ffs_data_clear <-ffs_data_closed smartcard-openp-431 [000] .n... 1946.905512: ffs_data_clear <-ffs_data_put Warning output corresponding to above trace: [ 1946.284139] WARNING: CPU: 0 PID: 431 at lib/refcount.c:28 refcount_warn_saturate+0x110/0x15c [ 1946.293094] refcount_t: underflow; use-after-free. [ 1946.298164] Modules linked in: usb_f_ncm(E) u_ether(E) usb_f_fs(E) hci_uart(E) btqca(E) btrtl(E) btbcm(E) btintel(E) bluetooth(E) nls_ascii(E) nls_cp437(E) vfat(E) fat(E) bcm2835_v4l2(CE) bcm2835_mmal_vchiq(CE) videobuf2_vmalloc(E) videobuf2_memops(E) sha512_generic(E) videobuf2_v4l2(E) sha512_arm(E) videobuf2_common(E) videodev(E) cpufreq_dt(E) snd_bcm2835(CE) brcmfmac(E) mc(E) vc4(E) ctr(E) brcmutil(E) snd_soc_core(E) snd_pcm_dmaengine(E) drbg(E) snd_pcm(E) snd_timer(E) snd(E) soundcore(E) drm_kms_helper(E) cec(E) ansi_cprng(E) rc_core(E) syscopyarea(E) raspberrypi_cpufreq(E) sysfillrect(E) sysimgblt(E) cfg80211(E) max17040_battery(OE) raspberrypi_hwmon(E) fb_sys_fops(E) regmap_i2c(E) ecdh_generic(E) rfkill(E) ecc(E) bcm2835_rng(E) rng_core(E) vchiq(CE) leds_gpio(E) libcomposite(E) fuse(E) configfs(E) ip_tables(E) x_tables(E) autofs4(E) ext4(E) crc16(E) mbcache(E) jbd2(E) crc32c_generic(E) sdhci_iproc(E) sdhci_pltfm(E) sdhci(E) [ 1946.399633] CPU: 0 PID: 431 Comm: smartcard-openp Tainted: G C OE 5.15.0-1-rpi #1 Debian 5.15.3-1 [ 1946.417950] Hardware name: BCM2835 [ 1946.425442] Backtrace: [ 1946.432048] [<c08d60a0>] (dump_backtrace) from [<c08d62ec>] (show_stack+0x20/0x24) [ 1946.448226] r7:00000009 r6:0000001c r5:c04a948c r4:c0a64e2c [ 1946.458412] [<c08d62cc>] (show_stack) from [<c08d9ae0>] (dump_stack+0x28/0x30) [ 1946.470380] [<c08d9ab8>] (dump_stack) from [<c0123500>] (__warn+0xe8/0x154) [ 1946.482067] r5:c04a948c r4:c0a71dc8 [ 1946.490184] [<c0123418>] (__warn) from [<c08d6948>] (warn_slowpath_fmt+0xa0/0xe4) [ 1946.506758] r7:00000009 r6:0000001c r5:c0a71dc8 r4:c0a71e04 [ 1946.517070] [<c08d68ac>] (warn_slowpath_fmt) from [<c04a948c>] (refcount_warn_saturate+0x110/0x15c) [ 1946.535309] r8:c0100224 r7:c0dfcb84 r6:ffffffff r5:c3b84c00 r4:c24a17c0 [ 1946.546708] [<c04a937c>] (refcount_warn_saturate) from [<c0380134>] (eventfd_ctx_put+0x48/0x74) [ 1946.564476] [<c03800ec>] (eventfd_ctx_put) from [<bf5464e8>] (ffs_data_clear+0xd0/0x118 [usb_f_fs]) [ 1946.582664] r5:c3b84c00 r4:c2695b00 [ 1946.590668] [<bf546418>] (ffs_data_clear [usb_f_fs]) from [<bf547cc0>] (ffs_data_closed+0x9c/0x150 [usb_f_fs]) [ 1946.609608] r5:bf54d014 r4:c2695b00 [ 1946.617522] [<bf547c24>] (ffs_data_closed [usb_f_fs]) from [<bf547da0>] (ffs_fs_kill_sb+0x2c/0x30 [usb_f_fs]) [ 1946.636217] r7:c0dfcb84 r6:c3a12260 r5:bf54d014 r4:c229f000 [ 1946.646273] [<bf547d74>] (ffs_fs_kill_sb [usb_f_fs]) from [<c0326d50>] (deactivate_locked_super+0x54/0x9c) [ 1946.664893] r5:bf54d014 r4:c229f000 [ 1946.672921] [<c0326cfc>] (deactivate_locked_super) from [<c0326df8>] (deactivate_super+0x60/0x64) [ 1946.690722] r5:c2a09000 r4:c229f000 [ 1946.698706] [<c0326d98>] (deactivate_super) from [<c0349a28>] (cleanup_mnt+0xe4/0x14c) [ 1946.715553] r5:c2a09000 r4:00000000 [ 1946.723528] [<c0349944>] (cleanup_mnt) from [<c0349b08>] (__cleanup_mnt+0x1c/0x20) [ 1946.739922] r7:c0dfcb84 r6:c3a12260 r5:c3a126fc r4:00000000 [ 1946.750088] [<c0349aec>] (__cleanup_mnt) from [<c0143d10>] (task_work_run+0x84/0xb8) [ 1946.766602] [<c0143c8c>] (task_work_run) from [<c010bdc8>] (do_work_pending+0x470/0x56c) [ 1946.783540] r7:5ac3c35a r6:c0d0424c r5:c200bfb0 r4:c200a000 [ 1946.793614] [<c010b958>] (do_work_pending) from [<c01000c0>] (slow_work_pending+0xc/0x20) [ 1946.810553] Exception stack(0xc200bfb0 to 0xc200bff8) [ 1946.820129] bfa0: 00000000 00000000 000000aa b5e21430 [ 1946.837104] bfc0: bef867a0 00000001 bef86840 00000034 bef86838 bef86790 bef86794 bef867a0 [ 1946.854125] bfe0: 00000000 bef86798 b67b7a1c b6d626a4 60000010 b5a23760 [ 1946.865335] r10:00000000 r9:c200a000 r8:c0100224 r7:00000034 r6:bef86840 r5:00000001 [ 1946.881914] r4:bef867a0 [ 1946.888793] ---[ end trace 7387f2a9725b28d0 ]--- Fixes: 5e33f6fdf735 ("usb: gadget: ffs: add eventfd notification about ffs events") Cc: stable <stable@vger.kernel.org> Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com> Link: https://lore.kernel.org/r/f79eeea29f3f98de6782a064ec0f7351ad2f598f.1639793920.git.plr.vincent@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-12-18 02:18:40 +00:00
if (ffs->ffs_eventfd) {
eventfd_ctx_put(ffs->ffs_eventfd);
usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear. ffs_data_clear is indirectly called from both ffs_fs_kill_sb and ffs_ep0_release, so it ends up being called twice when userland closes ep0 and then unmounts f_fs. If userland provided an eventfd along with function's USB descriptors, it ends up calling eventfd_ctx_put as many times, causing a refcount underflow. NULL-ify ffs_eventfd to prevent these extraneous eventfd_ctx_put calls. Also, set epfiles to NULL right after de-allocating it, for readability. For completeness, ffs_data_clear actually ends up being called thrice, the last call being before the whole ffs structure gets freed, so when this specific sequence happens there is a second underflow happening (but not being reported): /sys/kernel/debug/tracing# modprobe usb_f_fs /sys/kernel/debug/tracing# echo ffs_data_clear > set_ftrace_filter /sys/kernel/debug/tracing# echo function > current_tracer /sys/kernel/debug/tracing# echo 1 > tracing_on (setup gadget, run and kill function userland process, teardown gadget) /sys/kernel/debug/tracing# echo 0 > tracing_on /sys/kernel/debug/tracing# cat trace smartcard-openp-436 [000] ..... 1946.208786: ffs_data_clear <-ffs_data_closed smartcard-openp-431 [000] ..... 1946.279147: ffs_data_clear <-ffs_data_closed smartcard-openp-431 [000] .n... 1946.905512: ffs_data_clear <-ffs_data_put Warning output corresponding to above trace: [ 1946.284139] WARNING: CPU: 0 PID: 431 at lib/refcount.c:28 refcount_warn_saturate+0x110/0x15c [ 1946.293094] refcount_t: underflow; use-after-free. [ 1946.298164] Modules linked in: usb_f_ncm(E) u_ether(E) usb_f_fs(E) hci_uart(E) btqca(E) btrtl(E) btbcm(E) btintel(E) bluetooth(E) nls_ascii(E) nls_cp437(E) vfat(E) fat(E) bcm2835_v4l2(CE) bcm2835_mmal_vchiq(CE) videobuf2_vmalloc(E) videobuf2_memops(E) sha512_generic(E) videobuf2_v4l2(E) sha512_arm(E) videobuf2_common(E) videodev(E) cpufreq_dt(E) snd_bcm2835(CE) brcmfmac(E) mc(E) vc4(E) ctr(E) brcmutil(E) snd_soc_core(E) snd_pcm_dmaengine(E) drbg(E) snd_pcm(E) snd_timer(E) snd(E) soundcore(E) drm_kms_helper(E) cec(E) ansi_cprng(E) rc_core(E) syscopyarea(E) raspberrypi_cpufreq(E) sysfillrect(E) sysimgblt(E) cfg80211(E) max17040_battery(OE) raspberrypi_hwmon(E) fb_sys_fops(E) regmap_i2c(E) ecdh_generic(E) rfkill(E) ecc(E) bcm2835_rng(E) rng_core(E) vchiq(CE) leds_gpio(E) libcomposite(E) fuse(E) configfs(E) ip_tables(E) x_tables(E) autofs4(E) ext4(E) crc16(E) mbcache(E) jbd2(E) crc32c_generic(E) sdhci_iproc(E) sdhci_pltfm(E) sdhci(E) [ 1946.399633] CPU: 0 PID: 431 Comm: smartcard-openp Tainted: G C OE 5.15.0-1-rpi #1 Debian 5.15.3-1 [ 1946.417950] Hardware name: BCM2835 [ 1946.425442] Backtrace: [ 1946.432048] [<c08d60a0>] (dump_backtrace) from [<c08d62ec>] (show_stack+0x20/0x24) [ 1946.448226] r7:00000009 r6:0000001c r5:c04a948c r4:c0a64e2c [ 1946.458412] [<c08d62cc>] (show_stack) from [<c08d9ae0>] (dump_stack+0x28/0x30) [ 1946.470380] [<c08d9ab8>] (dump_stack) from [<c0123500>] (__warn+0xe8/0x154) [ 1946.482067] r5:c04a948c r4:c0a71dc8 [ 1946.490184] [<c0123418>] (__warn) from [<c08d6948>] (warn_slowpath_fmt+0xa0/0xe4) [ 1946.506758] r7:00000009 r6:0000001c r5:c0a71dc8 r4:c0a71e04 [ 1946.517070] [<c08d68ac>] (warn_slowpath_fmt) from [<c04a948c>] (refcount_warn_saturate+0x110/0x15c) [ 1946.535309] r8:c0100224 r7:c0dfcb84 r6:ffffffff r5:c3b84c00 r4:c24a17c0 [ 1946.546708] [<c04a937c>] (refcount_warn_saturate) from [<c0380134>] (eventfd_ctx_put+0x48/0x74) [ 1946.564476] [<c03800ec>] (eventfd_ctx_put) from [<bf5464e8>] (ffs_data_clear+0xd0/0x118 [usb_f_fs]) [ 1946.582664] r5:c3b84c00 r4:c2695b00 [ 1946.590668] [<bf546418>] (ffs_data_clear [usb_f_fs]) from [<bf547cc0>] (ffs_data_closed+0x9c/0x150 [usb_f_fs]) [ 1946.609608] r5:bf54d014 r4:c2695b00 [ 1946.617522] [<bf547c24>] (ffs_data_closed [usb_f_fs]) from [<bf547da0>] (ffs_fs_kill_sb+0x2c/0x30 [usb_f_fs]) [ 1946.636217] r7:c0dfcb84 r6:c3a12260 r5:bf54d014 r4:c229f000 [ 1946.646273] [<bf547d74>] (ffs_fs_kill_sb [usb_f_fs]) from [<c0326d50>] (deactivate_locked_super+0x54/0x9c) [ 1946.664893] r5:bf54d014 r4:c229f000 [ 1946.672921] [<c0326cfc>] (deactivate_locked_super) from [<c0326df8>] (deactivate_super+0x60/0x64) [ 1946.690722] r5:c2a09000 r4:c229f000 [ 1946.698706] [<c0326d98>] (deactivate_super) from [<c0349a28>] (cleanup_mnt+0xe4/0x14c) [ 1946.715553] r5:c2a09000 r4:00000000 [ 1946.723528] [<c0349944>] (cleanup_mnt) from [<c0349b08>] (__cleanup_mnt+0x1c/0x20) [ 1946.739922] r7:c0dfcb84 r6:c3a12260 r5:c3a126fc r4:00000000 [ 1946.750088] [<c0349aec>] (__cleanup_mnt) from [<c0143d10>] (task_work_run+0x84/0xb8) [ 1946.766602] [<c0143c8c>] (task_work_run) from [<c010bdc8>] (do_work_pending+0x470/0x56c) [ 1946.783540] r7:5ac3c35a r6:c0d0424c r5:c200bfb0 r4:c200a000 [ 1946.793614] [<c010b958>] (do_work_pending) from [<c01000c0>] (slow_work_pending+0xc/0x20) [ 1946.810553] Exception stack(0xc200bfb0 to 0xc200bff8) [ 1946.820129] bfa0: 00000000 00000000 000000aa b5e21430 [ 1946.837104] bfc0: bef867a0 00000001 bef86840 00000034 bef86838 bef86790 bef86794 bef867a0 [ 1946.854125] bfe0: 00000000 bef86798 b67b7a1c b6d626a4 60000010 b5a23760 [ 1946.865335] r10:00000000 r9:c200a000 r8:c0100224 r7:00000034 r6:bef86840 r5:00000001 [ 1946.881914] r4:bef867a0 [ 1946.888793] ---[ end trace 7387f2a9725b28d0 ]--- Fixes: 5e33f6fdf735 ("usb: gadget: ffs: add eventfd notification about ffs events") Cc: stable <stable@vger.kernel.org> Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com> Link: https://lore.kernel.org/r/f79eeea29f3f98de6782a064ec0f7351ad2f598f.1639793920.git.plr.vincent@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-12-18 02:18:40 +00:00
ffs->ffs_eventfd = NULL;
}
kfree(ffs->raw_descs_data);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
kfree(ffs->raw_strings);
kfree(ffs->stringtabs);
}
static void ffs_data_reset(struct ffs_data *ffs)
{
ffs_data_clear(ffs);
ffs->raw_descs_data = NULL;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->raw_descs = NULL;
ffs->raw_strings = NULL;
ffs->stringtabs = NULL;
ffs->raw_descs_length = 0;
ffs->fs_descs_count = 0;
ffs->hs_descs_count = 0;
ffs->ss_descs_count = 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->strings_count = 0;
ffs->interfaces_count = 0;
ffs->eps_count = 0;
ffs->ev.count = 0;
ffs->state = FFS_READ_DESCRIPTORS;
ffs->setup_state = FFS_NO_SETUP;
ffs->flags = 0;
ffs->ms_os_descs_ext_prop_count = 0;
ffs->ms_os_descs_ext_prop_name_len = 0;
ffs->ms_os_descs_ext_prop_data_len = 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
{
struct usb_gadget_strings **lang;
int first_id;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb: gadget: f_fs: Remove WARN_ON in functionfs_bind This commit addresses an issue related to below kernel panic where panic_on_warn is enabled. It is caused by the unnecessary use of WARN_ON in functionsfs_bind, which easily leads to the following scenarios. 1.adb_write in adbd 2. UDC write via configfs ================= ===================== ->usb_ffs_open_thread() ->UDC write ->open_functionfs() ->configfs_write_iter() ->adb_open() ->gadget_dev_desc_UDC_store() ->adb_write() ->usb_gadget_register_driver_owner ->driver_register() ->StartMonitor() ->bus_add_driver() ->adb_read() ->gadget_bind_driver() <times-out without BIND event> ->configfs_composite_bind() ->usb_add_function() ->open_functionfs() ->ffs_func_bind() ->adb_open() ->functionfs_bind() <ffs->state !=FFS_ACTIVE> The adb_open, adb_read, and adb_write operations are invoked from the daemon, but trying to bind the function is a process that is invoked by UDC write through configfs, which opens up the possibility of a race condition between the two paths. In this race scenario, the kernel panic occurs due to the WARN_ON from functionfs_bind when panic_on_warn is enabled. This commit fixes the kernel panic by removing the unnecessary WARN_ON. Kernel panic - not syncing: kernel: panic_on_warn set ... [ 14.542395] Call trace: [ 14.542464] ffs_func_bind+0x1c8/0x14a8 [ 14.542468] usb_add_function+0xcc/0x1f0 [ 14.542473] configfs_composite_bind+0x468/0x588 [ 14.542478] gadget_bind_driver+0x108/0x27c [ 14.542483] really_probe+0x190/0x374 [ 14.542488] __driver_probe_device+0xa0/0x12c [ 14.542492] driver_probe_device+0x3c/0x220 [ 14.542498] __driver_attach+0x11c/0x1fc [ 14.542502] bus_for_each_dev+0x104/0x160 [ 14.542506] driver_attach+0x24/0x34 [ 14.542510] bus_add_driver+0x154/0x270 [ 14.542514] driver_register+0x68/0x104 [ 14.542518] usb_gadget_register_driver_owner+0x48/0xf4 [ 14.542523] gadget_dev_desc_UDC_store+0xf8/0x144 [ 14.542526] configfs_write_iter+0xf0/0x138 Fixes: ddf8abd25994 ("USB: f_fs: the FunctionFS driver") Cc: stable <stable@kernel.org> Signed-off-by: Akash M <akash.m5@samsung.com> Link: https://lore.kernel.org/r/20241219125221.1679-1-akash.m5@samsung.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-12-19 18:22:19 +05:30
if ((ffs->state != FFS_ACTIVE
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
|| test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
return -EBADFD;
first_id = usb_string_ids_n(cdev, ffs->strings_count);
if (first_id < 0)
return first_id;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
if (!ffs->ep0req)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -ENOMEM;
ffs->ep0req->complete = ffs_ep0_complete;
ffs->ep0req->context = ffs;
lang = ffs->stringtabs;
if (lang) {
for (; *lang; ++lang) {
struct usb_string *str = (*lang)->strings;
int id = first_id;
for (; str->s; ++id, ++str)
str->id = id;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
ffs->gadget = cdev->gadget;
ffs_data_get(ffs);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return 0;
}
static void functionfs_unbind(struct ffs_data *ffs)
{
if (!WARN_ON(!ffs->gadget)) {
/* dequeue before freeing ep0req */
usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
mutex_lock(&ffs->mutex);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
ffs->ep0req = NULL;
ffs->gadget = NULL;
clear_bit(FFS_FL_BOUND, &ffs->flags);
mutex_unlock(&ffs->mutex);
ffs_data_put(ffs);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
}
static int ffs_epfiles_create(struct ffs_data *ffs)
{
struct ffs_epfile *epfile, *epfiles;
unsigned i, count;
count = ffs->eps_count;
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (!epfiles)
return -ENOMEM;
epfile = epfiles;
for (i = 1; i <= count; ++i, ++epfile) {
epfile->ffs = ffs;
mutex_init(&epfile->mutex);
mutex_init(&epfile->dmabufs_mutex);
INIT_LIST_HEAD(&epfile->dmabufs);
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
else
sprintf(epfile->name, "ep%u", i);
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
epfile,
&ffs_epfile_operations);
if (!epfile->dentry) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_epfiles_destroy(epfiles, i - 1);
return -ENOMEM;
}
}
ffs->epfiles = epfiles;
return 0;
}
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (epfile->dentry) {
simple_recursive_removal(epfile->dentry, NULL);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
epfile->dentry = NULL;
}
}
kfree(epfiles);
}
static void ffs_func_eps_disable(struct ffs_function *func)
{
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
struct ffs_ep *ep;
struct ffs_epfile *epfile;
unsigned short count;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
unsigned long flags;
spin_lock_irqsave(&func->ffs->eps_lock, flags);
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
count = func->ffs->eps_count;
epfile = func->ffs->epfiles;
ep = func->eps;
while (count--) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* pending requests get nuked */
if (ep->ep)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb_ep_disable(ep->ep);
++ep;
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
if (epfile) {
epfile->ep = NULL;
__ffs_epfile_read_buffer_free(epfile);
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
++epfile;
}
}
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int ffs_func_eps_enable(struct ffs_function *func)
{
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
struct ffs_data *ffs;
struct ffs_ep *ep;
struct ffs_epfile *epfile;
unsigned short count;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&func->ffs->eps_lock, flags);
usb: f_fs: Fix use-after-free for epfile Consider a case where ffs_func_eps_disable is called from ffs_func_disable as part of composition switch and at the same time ffs_epfile_release get called from userspace. ffs_epfile_release will free up the read buffer and call ffs_data_closed which in turn destroys ffs->epfiles and mark it as NULL. While this was happening the driver has already initialized the local epfile in ffs_func_eps_disable which is now freed and waiting to acquire the spinlock. Once spinlock is acquired the driver proceeds with the stale value of epfile and tries to free the already freed read buffer causing use-after-free. Following is the illustration of the race: CPU1 CPU2 ffs_func_eps_disable epfiles (local copy) ffs_epfile_release ffs_data_closed if (last file closed) ffs_data_reset ffs_data_clear ffs_epfiles_destroy spin_lock dereference epfiles Fix this races by taking epfiles local copy & assigning it under spinlock and if epfiles(local) is null then update it in ffs->epfiles then finally destroy it. Extending the scope further from the race, protecting the ep related structures, and concurrent accesses. Fixes: a9e6f83c2df1 ("usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable") Co-developed-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com> Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/1643256595-10797-1-git-send-email-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-27 09:39:55 +05:30
ffs = func->ffs;
ep = func->eps;
epfile = ffs->epfiles;
count = ffs->eps_count;
while(count--) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ep->ep->driver_data = ep;
ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
if (ret) {
pr_err("%s: config_ep_by_speed(%s) returned %d\n",
__func__, ep->ep->name, ret);
break;
usb: gadget: f_fs: avoid out of bounds access on comp_desc Companion descriptor is only used for SuperSpeed endpoints, if the endpoints are HighSpeed or FullSpeed, the Companion descriptor will not allocated, so we can only access it if gadget is SuperSpeed. I can reproduce this issue on Rockchip platform rk3368 SoC which supports USB 2.0, and use functionfs for ADB. Kernel build with CONFIG_KASAN=y and CONFIG_SLUB_DEBUG=y report the following BUG: ================================================================== BUG: KASAN: slab-out-of-bounds in ffs_func_set_alt+0x224/0x3a0 at addr ffffffc0601f6509 Read of size 1 by task swapper/0/0 ============================================================================ BUG kmalloc-256 (Not tainted): kasan: bad access detected ---------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Allocated in ffs_func_bind+0x52c/0x99c age=1275 cpu=0 pid=1 alloc_debug_processing+0x128/0x17c ___slab_alloc.constprop.58+0x50c/0x610 __slab_alloc.isra.55.constprop.57+0x24/0x34 __kmalloc+0xe0/0x250 ffs_func_bind+0x52c/0x99c usb_add_function+0xd8/0x1d4 configfs_composite_bind+0x48c/0x570 udc_bind_to_driver+0x6c/0x170 usb_udc_attach_driver+0xa4/0xd0 gadget_dev_desc_UDC_store+0xcc/0x118 configfs_write_file+0x1a0/0x1f8 __vfs_write+0x64/0x174 vfs_write+0xe4/0x200 SyS_write+0x68/0xc8 el0_svc_naked+0x24/0x28 INFO: Freed in inode_doinit_with_dentry+0x3f0/0x7c4 age=1275 cpu=7 pid=247 ... Call trace: [<ffffff900808aab4>] dump_backtrace+0x0/0x230 [<ffffff900808acf8>] show_stack+0x14/0x1c [<ffffff90084ad420>] dump_stack+0xa0/0xc8 [<ffffff90082157cc>] print_trailer+0x188/0x198 [<ffffff9008215948>] object_err+0x3c/0x4c [<ffffff900821b5ac>] kasan_report+0x324/0x4dc [<ffffff900821aa38>] __asan_load1+0x24/0x50 [<ffffff90089eb750>] ffs_func_set_alt+0x224/0x3a0 [<ffffff90089d3760>] composite_setup+0xdcc/0x1ac8 [<ffffff90089d7394>] android_setup+0x124/0x1a0 [<ffffff90089acd18>] _setup+0x54/0x74 [<ffffff90089b6b98>] handle_ep0+0x3288/0x4390 [<ffffff90089b9b44>] dwc_otg_pcd_handle_out_ep_intr+0x14dc/0x2ae4 [<ffffff90089be85c>] dwc_otg_pcd_handle_intr+0x1ec/0x298 [<ffffff90089ad680>] dwc_otg_pcd_irq+0x10/0x20 [<ffffff9008116328>] handle_irq_event_percpu+0x124/0x3ac [<ffffff9008116610>] handle_irq_event+0x60/0xa0 [<ffffff900811af30>] handle_fasteoi_irq+0x10c/0x1d4 [<ffffff9008115568>] generic_handle_irq+0x30/0x40 [<ffffff90081159b4>] __handle_domain_irq+0xac/0xdc [<ffffff9008080e9c>] gic_handle_irq+0x64/0xa4 ... Memory state around the buggy address: ffffffc0601f6400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffffffc0601f6480: 00 00 00 00 00 00 00 00 00 00 06 fc fc fc fc fc >ffffffc0601f6500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffffffc0601f6580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffffffc0601f6600: fc fc fc fc fc fc fc fc 00 00 00 00 00 00 00 00 ================================================================== Signed-off-by: William Wu <william.wu@rock-chips.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2017-04-25 17:45:48 +08:00
}
ret = usb_ep_enable(ep->ep);
if (!ret) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
epfile->ep = ep;
epfile->in = usb_endpoint_dir_in(ep->ep->desc);
epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
} else {
break;
}
++ep;
++epfile;
}
wake_up_interruptible(&ffs->wait);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
return ret;
}
/* Parsing and building descriptors and strings *****************************/
/*
* This validates if data pointed by data is a valid USB descriptor as
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* well as record how many interfaces, endpoints and strings are
* required by given configuration. Returns address after the
* descriptor or NULL if data is invalid.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
enum ffs_entity_type {
FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
};
enum ffs_os_desc_type {
FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
};
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
u8 *valuep,
struct usb_descriptor_header *desc,
void *priv);
typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
struct usb_os_desc_header *h, void *data,
unsigned len, void *priv);
static int __must_check ffs_do_single_desc(char *data, unsigned len,
ffs_entity_callback entity,
usb: gadget: f_fs: add capability for dfu functional descriptor Add the ability for the USB FunctionFS (FFS) gadget driver to be able to create Device Firmware Upgrade (DFU) functional descriptors. [1] This patch allows implementation of DFU in userspace using the FFS gadget. The DFU protocol uses the control pipe (ep0) for all messaging so only the addition of the DFU functional descriptor is needed in the kernel driver. The DFU functional descriptor is written to the ep0 file along with any other descriptors during FFS setup. DFU requires an interface descriptor followed by the DFU functional descriptor. This patch includes documentation of the added descriptor for DFU and conversion of some existing documentation to kernel-doc format so that it can be included in the generated docs. An implementation of DFU 1.1 that implements just the runtime descriptor using the FunctionFS gadget (with rebooting into u-boot for DFU mode) has been tested on an i.MX8 Nano. An implementation of DFU 1.1 that implements both runtime and DFU mode using the FunctionFS gadget has been tested on Xilinx Zynq UltraScale+. Note that for the best performance of firmware update file transfers, the userspace program should respond as quick as possible to the setup packets. [1] https://www.usb.org/sites/default/files/DFU_1.1.pdf Signed-off-by: David Sands <david.sands@biamp.com> Co-developed-by: Chris Wulff <crwulff@gmail.com> Signed-off-by: Chris Wulff <crwulff@gmail.com> Link: https://lore.kernel.org/r/20240811000004.1395888-2-crwulff@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-08-10 20:00:05 -04:00
void *priv, int *current_class, int *current_subclass)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct usb_descriptor_header *_ds = (void *)data;
u8 length;
int ret;
/* At least two bytes are required: length and type */
if (len < 2) {
pr_vdebug("descriptor too short\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
}
/* If we have at least as many bytes as the descriptor takes? */
length = _ds->bLength;
if (len < length) {
pr_vdebug("descriptor longer then available data\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
}
#define __entity_check_INTERFACE(val) 1
#define __entity_check_STRING(val) (val)
#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK)
#define __entity(type, val) do { \
pr_vdebug("entity " #type "(%02x)\n", (val)); \
if (!__entity_check_ ##type(val)) { \
pr_vdebug("invalid entity's value\n"); \
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL; \
} \
ret = entity(FFS_ ##type, &val, _ds, priv); \
if (ret < 0) { \
pr_debug("entity " #type "(%02x); ret = %d\n", \
(val), ret); \
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret; \
} \
} while (0)
/* Parse descriptor depending on type. */
switch (_ds->bDescriptorType) {
case USB_DT_DEVICE:
case USB_DT_CONFIG:
case USB_DT_STRING:
case USB_DT_DEVICE_QUALIFIER:
/* function can't have any of those */
pr_vdebug("descriptor reserved for gadget: %d\n",
_ds->bDescriptorType);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
case USB_DT_INTERFACE: {
struct usb_interface_descriptor *ds = (void *)_ds;
pr_vdebug("interface descriptor\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (length != sizeof *ds)
goto inv_length;
__entity(INTERFACE, ds->bInterfaceNumber);
if (ds->iInterface)
__entity(STRING, ds->iInterface);
*current_class = ds->bInterfaceClass;
usb: gadget: f_fs: add capability for dfu functional descriptor Add the ability for the USB FunctionFS (FFS) gadget driver to be able to create Device Firmware Upgrade (DFU) functional descriptors. [1] This patch allows implementation of DFU in userspace using the FFS gadget. The DFU protocol uses the control pipe (ep0) for all messaging so only the addition of the DFU functional descriptor is needed in the kernel driver. The DFU functional descriptor is written to the ep0 file along with any other descriptors during FFS setup. DFU requires an interface descriptor followed by the DFU functional descriptor. This patch includes documentation of the added descriptor for DFU and conversion of some existing documentation to kernel-doc format so that it can be included in the generated docs. An implementation of DFU 1.1 that implements just the runtime descriptor using the FunctionFS gadget (with rebooting into u-boot for DFU mode) has been tested on an i.MX8 Nano. An implementation of DFU 1.1 that implements both runtime and DFU mode using the FunctionFS gadget has been tested on Xilinx Zynq UltraScale+. Note that for the best performance of firmware update file transfers, the userspace program should respond as quick as possible to the setup packets. [1] https://www.usb.org/sites/default/files/DFU_1.1.pdf Signed-off-by: David Sands <david.sands@biamp.com> Co-developed-by: Chris Wulff <crwulff@gmail.com> Signed-off-by: Chris Wulff <crwulff@gmail.com> Link: https://lore.kernel.org/r/20240811000004.1395888-2-crwulff@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-08-10 20:00:05 -04:00
*current_subclass = ds->bInterfaceSubClass;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
break;
case USB_DT_ENDPOINT: {
struct usb_endpoint_descriptor *ds = (void *)_ds;
pr_vdebug("endpoint descriptor\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (length != USB_DT_ENDPOINT_SIZE &&
length != USB_DT_ENDPOINT_AUDIO_SIZE)
goto inv_length;
__entity(ENDPOINT, ds->bEndpointAddress);
}
break;
case USB_TYPE_CLASS | 0x01:
if (*current_class == USB_INTERFACE_CLASS_HID) {
pr_vdebug("hid descriptor\n");
if (length != sizeof(struct hid_descriptor))
goto inv_length;
break;
} else if (*current_class == USB_INTERFACE_CLASS_CCID) {
pr_vdebug("ccid descriptor\n");
if (length != sizeof(struct ccid_descriptor))
goto inv_length;
break;
usb: gadget: f_fs: add capability for dfu functional descriptor Add the ability for the USB FunctionFS (FFS) gadget driver to be able to create Device Firmware Upgrade (DFU) functional descriptors. [1] This patch allows implementation of DFU in userspace using the FFS gadget. The DFU protocol uses the control pipe (ep0) for all messaging so only the addition of the DFU functional descriptor is needed in the kernel driver. The DFU functional descriptor is written to the ep0 file along with any other descriptors during FFS setup. DFU requires an interface descriptor followed by the DFU functional descriptor. This patch includes documentation of the added descriptor for DFU and conversion of some existing documentation to kernel-doc format so that it can be included in the generated docs. An implementation of DFU 1.1 that implements just the runtime descriptor using the FunctionFS gadget (with rebooting into u-boot for DFU mode) has been tested on an i.MX8 Nano. An implementation of DFU 1.1 that implements both runtime and DFU mode using the FunctionFS gadget has been tested on Xilinx Zynq UltraScale+. Note that for the best performance of firmware update file transfers, the userspace program should respond as quick as possible to the setup packets. [1] https://www.usb.org/sites/default/files/DFU_1.1.pdf Signed-off-by: David Sands <david.sands@biamp.com> Co-developed-by: Chris Wulff <crwulff@gmail.com> Signed-off-by: Chris Wulff <crwulff@gmail.com> Link: https://lore.kernel.org/r/20240811000004.1395888-2-crwulff@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-08-10 20:00:05 -04:00
} else if (*current_class == USB_CLASS_APP_SPEC &&
*current_subclass == USB_SUBCLASS_DFU) {
pr_vdebug("dfu functional descriptor\n");
if (length != sizeof(struct usb_dfu_functional_descriptor))
goto inv_length;
break;
} else {
pr_vdebug("unknown descriptor: %d for class %d\n",
_ds->bDescriptorType, *current_class);
return -EINVAL;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
case USB_DT_OTG:
if (length != sizeof(struct usb_otg_descriptor))
goto inv_length;
break;
case USB_DT_INTERFACE_ASSOCIATION: {
struct usb_interface_assoc_descriptor *ds = (void *)_ds;
pr_vdebug("interface association descriptor\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (length != sizeof *ds)
goto inv_length;
if (ds->iFunction)
__entity(STRING, ds->iFunction);
}
break;
case USB_DT_SS_ENDPOINT_COMP:
pr_vdebug("EP SS companion descriptor\n");
if (length != sizeof(struct usb_ss_ep_comp_descriptor))
goto inv_length;
break;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
case USB_DT_OTHER_SPEED_CONFIG:
case USB_DT_INTERFACE_POWER:
case USB_DT_DEBUG:
case USB_DT_SECURITY:
case USB_DT_CS_RADIO_CONTROL:
/* TODO */
pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
default:
/* We should never be here */
pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
inv_length:
pr_vdebug("invalid length: %d (descriptor %d)\n",
_ds->bLength, _ds->bDescriptorType);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
}
#undef __entity
#undef __entity_check_DESCRIPTOR
#undef __entity_check_INTERFACE
#undef __entity_check_STRING
#undef __entity_check_ENDPOINT
return length;
}
static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
ffs_entity_callback entity, void *priv)
{
const unsigned _len = len;
unsigned long num = 0;
int current_class = -1;
usb: gadget: f_fs: add capability for dfu functional descriptor Add the ability for the USB FunctionFS (FFS) gadget driver to be able to create Device Firmware Upgrade (DFU) functional descriptors. [1] This patch allows implementation of DFU in userspace using the FFS gadget. The DFU protocol uses the control pipe (ep0) for all messaging so only the addition of the DFU functional descriptor is needed in the kernel driver. The DFU functional descriptor is written to the ep0 file along with any other descriptors during FFS setup. DFU requires an interface descriptor followed by the DFU functional descriptor. This patch includes documentation of the added descriptor for DFU and conversion of some existing documentation to kernel-doc format so that it can be included in the generated docs. An implementation of DFU 1.1 that implements just the runtime descriptor using the FunctionFS gadget (with rebooting into u-boot for DFU mode) has been tested on an i.MX8 Nano. An implementation of DFU 1.1 that implements both runtime and DFU mode using the FunctionFS gadget has been tested on Xilinx Zynq UltraScale+. Note that for the best performance of firmware update file transfers, the userspace program should respond as quick as possible to the setup packets. [1] https://www.usb.org/sites/default/files/DFU_1.1.pdf Signed-off-by: David Sands <david.sands@biamp.com> Co-developed-by: Chris Wulff <crwulff@gmail.com> Signed-off-by: Chris Wulff <crwulff@gmail.com> Link: https://lore.kernel.org/r/20240811000004.1395888-2-crwulff@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-08-10 20:00:05 -04:00
int current_subclass = -1;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
for (;;) {
int ret;
if (num == count)
data = NULL;
/* Record "descriptor" entity */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
if (ret < 0) {
pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
num, ret);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
}
if (!data)
return _len - len;
ret = ffs_do_single_desc(data, len, entity, priv,
usb: gadget: f_fs: add capability for dfu functional descriptor Add the ability for the USB FunctionFS (FFS) gadget driver to be able to create Device Firmware Upgrade (DFU) functional descriptors. [1] This patch allows implementation of DFU in userspace using the FFS gadget. The DFU protocol uses the control pipe (ep0) for all messaging so only the addition of the DFU functional descriptor is needed in the kernel driver. The DFU functional descriptor is written to the ep0 file along with any other descriptors during FFS setup. DFU requires an interface descriptor followed by the DFU functional descriptor. This patch includes documentation of the added descriptor for DFU and conversion of some existing documentation to kernel-doc format so that it can be included in the generated docs. An implementation of DFU 1.1 that implements just the runtime descriptor using the FunctionFS gadget (with rebooting into u-boot for DFU mode) has been tested on an i.MX8 Nano. An implementation of DFU 1.1 that implements both runtime and DFU mode using the FunctionFS gadget has been tested on Xilinx Zynq UltraScale+. Note that for the best performance of firmware update file transfers, the userspace program should respond as quick as possible to the setup packets. [1] https://www.usb.org/sites/default/files/DFU_1.1.pdf Signed-off-by: David Sands <david.sands@biamp.com> Co-developed-by: Chris Wulff <crwulff@gmail.com> Signed-off-by: Chris Wulff <crwulff@gmail.com> Link: https://lore.kernel.org/r/20240811000004.1395888-2-crwulff@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-08-10 20:00:05 -04:00
&current_class, &current_subclass);
if (ret < 0) {
pr_debug("%s returns %d\n", __func__, ret);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
}
len -= ret;
data += ret;
++num;
}
}
static int __ffs_data_do_entity(enum ffs_entity_type type,
u8 *valuep, struct usb_descriptor_header *desc,
void *priv)
{
struct ffs_desc_helper *helper = priv;
struct usb_endpoint_descriptor *d;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
switch (type) {
case FFS_DESCRIPTOR:
break;
case FFS_INTERFACE:
/*
* Interfaces are indexed from zero so if we
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* encountered interface "n" then there are at least
* "n+1" interfaces.
*/
if (*valuep >= helper->interfaces_count)
helper->interfaces_count = *valuep + 1;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
case FFS_STRING:
/*
* Strings are indexed from 1 (0 is reserved
* for languages list)
*/
if (*valuep > helper->ffs->strings_count)
helper->ffs->strings_count = *valuep;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
case FFS_ENDPOINT:
d = (void *)desc;
helper->eps_count++;
if (helper->eps_count >= FFS_MAX_EPS_COUNT)
return -EINVAL;
/* Check if descriptors for any speed were already parsed */
if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
helper->ffs->eps_addrmap[helper->eps_count] =
d->bEndpointAddress;
else if (helper->ffs->eps_addrmap[helper->eps_count] !=
d->bEndpointAddress)
return -EINVAL;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
}
return 0;
}
static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
struct usb_os_desc_header *desc)
{
u16 bcd_version = le16_to_cpu(desc->bcdVersion);
u16 w_index = le16_to_cpu(desc->wIndex);
usb: gadget: f_fs: Fix incorrect version checking of OS descs Currently, the USB gadget framework supports only version 1.0 of the MS OS descriptor. OS desc has a field bcdVersion indicating its version, with v1.0 represented by the value 0x100. However, __ffs_do_os_desc_header() was expecting the incorrect value 0x1, so allow the correct value 0x100. The bcdVersion field of the descriptor that is actually sent to the host is set by composite_setup() (in composite.c) to the fixed value 0x100. Therefore, it can be understood that __ffs_do_os_desc_header() is only performing a format check of the OS desc passed to functionfs. If a value other than 0x100 is accepted, there is no effect on communication over the USB bus. Indeed, until now __ffs_do_os_desc_header() has only accepted the incorrect value 0x1, but there was no problem with the communication over the USB bus. However, this can be confusing for functionfs userspace drivers. Since bcdVersion=0x100 is used in actual communication, functionfs should accept the value 0x100. Note that the correct value for bcdVersion in OS desc v1.0 is 0x100, but to avoid breaking old userspace drivers, the value 0x1 is also accepted as an exception. At this time, a message is output to notify the user to fix the userspace driver. Signed-off-by: Yuta Hayama <hayama@lineo.co.jp> Reviewed-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com> Link: https://lore.kernel.org/r/290f96db-1877-5137-373a-318e7b4f2dde@lineo.co.jp Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2023-02-28 17:56:37 +09:00
if (bcd_version == 0x1) {
pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. "
"Userspace driver should be fixed, accepting 0x0001 for compatibility.\n");
} else if (bcd_version != 0x100) {
pr_vdebug("unsupported os descriptors version: 0x%x\n",
bcd_version);
return -EINVAL;
}
switch (w_index) {
case 0x4:
*next_type = FFS_OS_DESC_EXT_COMPAT;
break;
case 0x5:
*next_type = FFS_OS_DESC_EXT_PROP;
break;
default:
pr_vdebug("unsupported os descriptor type: %d", w_index);
return -EINVAL;
}
return sizeof(*desc);
}
/*
* Process all extended compatibility/extended property descriptors
* of a feature descriptor
*/
static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
enum ffs_os_desc_type type,
u16 feature_count,
ffs_os_desc_callback entity,
void *priv,
struct usb_os_desc_header *h)
{
int ret;
const unsigned _len = len;
/* loop over all ext compat/ext prop descriptors */
while (feature_count--) {
ret = entity(type, h, data, len, priv);
if (ret < 0) {
pr_debug("bad OS descriptor, type: %d\n", type);
return ret;
}
data += ret;
len -= ret;
}
return _len - len;
}
/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
static int __must_check ffs_do_os_descs(unsigned count,
char *data, unsigned len,
ffs_os_desc_callback entity, void *priv)
{
const unsigned _len = len;
unsigned long num = 0;
for (num = 0; num < count; ++num) {
int ret;
enum ffs_os_desc_type type;
u16 feature_count;
struct usb_os_desc_header *desc = (void *)data;
if (len < sizeof(*desc))
return -EINVAL;
/*
* Record "descriptor" entity.
* Process dwLength, bcdVersion, wIndex, get b/wCount.
* Move the data pointer to the beginning of extended
* compatibilities proper or extended properties proper
* portions of the data
*/
if (le32_to_cpu(desc->dwLength) > len)
return -EINVAL;
ret = __ffs_do_os_desc_header(&type, desc);
if (ret < 0) {
pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
num, ret);
return ret;
}
/*
* 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
*/
feature_count = le16_to_cpu(desc->wCount);
if (type == FFS_OS_DESC_EXT_COMPAT &&
(feature_count > 255 || desc->Reserved))
return -EINVAL;
len -= ret;
data += ret;
/*
* Process all function/property descriptors
* of this Feature Descriptor
*/
ret = ffs_do_single_os_desc(data, len, type,
feature_count, entity, priv, desc);
if (ret < 0) {
pr_debug("%s returns %d\n", __func__, ret);
return ret;
}
len -= ret;
data += ret;
}
return _len - len;
}
/*
* Validate contents of the buffer from userspace related to OS descriptors.
*/
static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
struct usb_os_desc_header *h, void *data,
unsigned len, void *priv)
{
struct ffs_data *ffs = priv;
u8 length;
switch (type) {
case FFS_OS_DESC_EXT_COMPAT: {
struct usb_ext_compat_desc *d = data;
int i;
if (len < sizeof(*d) ||
d->bFirstInterfaceNumber >= ffs->interfaces_count)
return -EINVAL;
if (d->Reserved1 != 1) {
/*
* According to the spec, Reserved1 must be set to 1
* but older kernels incorrectly rejected non-zero
* values. We fix it here to avoid returning EINVAL
* in response to values we used to accept.
*/
pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n");
d->Reserved1 = 1;
}
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
if (d->Reserved2[i])
return -EINVAL;
length = sizeof(struct usb_ext_compat_desc);
}
break;
case FFS_OS_DESC_EXT_PROP: {
struct usb_ext_prop_desc *d = data;
u32 type, pdl;
u16 pnl;
if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
return -EINVAL;
length = le32_to_cpu(d->dwSize);
if (len < length)
return -EINVAL;
type = le32_to_cpu(d->dwPropertyDataType);
if (type < USB_EXT_PROP_UNICODE ||
type > USB_EXT_PROP_UNICODE_MULTI) {
pr_vdebug("unsupported os descriptor property type: %d",
type);
return -EINVAL;
}
pnl = le16_to_cpu(d->wPropertyNameLength);
if (length < 14 + pnl) {
pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
length, pnl, type);
return -EINVAL;
}
pdl = le32_to_cpu(*(__le32 *)((u8 *)data + 10 + pnl));
if (length != 14 + pnl + pdl) {
pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
length, pnl, pdl, type);
return -EINVAL;
}
++ffs->ms_os_descs_ext_prop_count;
/* property name reported to the host as "WCHAR"s */
ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
ffs->ms_os_descs_ext_prop_data_len += pdl;
}
break;
default:
pr_vdebug("unknown descriptor: %d\n", type);
return -EINVAL;
}
return length;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int __ffs_data_got_descs(struct ffs_data *ffs,
char *const _data, size_t len)
{
char *data = _data, *raw_descs;
unsigned os_descs_count = 0, counts[3], flags;
int ret = -EINVAL, i;
struct ffs_desc_helper helper;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (get_unaligned_le32(data + 4) != len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
switch (get_unaligned_le32(data)) {
case FUNCTIONFS_DESCRIPTORS_MAGIC:
flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
data += 8;
len -= 8;
break;
case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
flags = get_unaligned_le32(data + 8);
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
ffs->user_flags = flags;
if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
FUNCTIONFS_HAS_HS_DESC |
FUNCTIONFS_HAS_SS_DESC |
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
FUNCTIONFS_HAS_MS_OS_DESC |
FUNCTIONFS_VIRTUAL_ADDR |
FUNCTIONFS_EVENTFD |
FUNCTIONFS_ALL_CTRL_RECIP |
FUNCTIONFS_CONFIG0_SETUP)) {
ret = -ENOSYS;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
}
data += 12;
len -= 12;
break;
default:
goto error;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
if (flags & FUNCTIONFS_EVENTFD) {
if (len < 4)
goto error;
ffs->ffs_eventfd =
eventfd_ctx_fdget((int)get_unaligned_le32(data));
if (IS_ERR(ffs->ffs_eventfd)) {
ret = PTR_ERR(ffs->ffs_eventfd);
ffs->ffs_eventfd = NULL;
goto error;
}
data += 4;
len -= 4;
}
/* Read fs_count, hs_count and ss_count (if present) */
for (i = 0; i < 3; ++i) {
if (!(flags & (1 << i))) {
counts[i] = 0;
} else if (len < 4) {
goto error;
} else {
counts[i] = get_unaligned_le32(data);
data += 4;
len -= 4;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
if (flags & (1 << i)) {
if (len < 4) {
goto error;
}
os_descs_count = get_unaligned_le32(data);
data += 4;
len -= 4;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Read descriptors */
raw_descs = data;
helper.ffs = ffs;
for (i = 0; i < 3; ++i) {
if (!counts[i])
continue;
helper.interfaces_count = 0;
helper.eps_count = 0;
ret = ffs_do_descs(counts[i], data, len,
__ffs_data_do_entity, &helper);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
if (!ffs->eps_count && !ffs->interfaces_count) {
ffs->eps_count = helper.eps_count;
ffs->interfaces_count = helper.interfaces_count;
} else {
if (ffs->eps_count != helper.eps_count) {
ret = -EINVAL;
goto error;
}
if (ffs->interfaces_count != helper.interfaces_count) {
ret = -EINVAL;
goto error;
}
}
data += ret;
len -= ret;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
if (os_descs_count) {
ret = ffs_do_os_descs(os_descs_count, data, len,
__ffs_data_do_os_desc, ffs);
if (ret < 0)
goto error;
data += ret;
len -= ret;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (raw_descs == data || len) {
ret = -EINVAL;
goto error;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->raw_descs_data = _data;
ffs->raw_descs = raw_descs;
ffs->raw_descs_length = data - raw_descs;
ffs->fs_descs_count = counts[0];
ffs->hs_descs_count = counts[1];
ffs->ss_descs_count = counts[2];
ffs->ms_os_descs_count = os_descs_count;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return 0;
error:
kfree(_data);
return ret;
}
static int __ffs_data_got_strings(struct ffs_data *ffs,
char *const _data, size_t len)
{
u32 str_count, needed_count, lang_count;
struct usb_gadget_strings **stringtabs, *t;
const char *data = _data;
struct usb_string *s;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (len < 16 ||
get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
get_unaligned_le32(data + 4) != len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
str_count = get_unaligned_le32(data + 8);
lang_count = get_unaligned_le32(data + 12);
/* if one is zero the other must be zero */
if (!str_count != !lang_count)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
/* Do we have at least as many strings as descriptors need? */
needed_count = ffs->strings_count;
if (str_count < needed_count)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
/*
* If we don't need any strings just return and free all
* memory.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (!needed_count) {
kfree(_data);
return 0;
}
/* Allocate everything in one chunk so there's less maintenance. */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
unsigned i = 0;
vla_group(d);
vla_item(d, struct usb_gadget_strings *, stringtabs,
size_add(lang_count, 1));
vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
vla_item(d, struct usb_string, strings,
size_mul(lang_count, (needed_count + 1)));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
if (!vlabuf) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
kfree(_data);
return -ENOMEM;
}
/* Initialize the VLA pointers */
stringtabs = vla_ptr(vlabuf, d, stringtabs);
t = vla_ptr(vlabuf, d, stringtab);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
i = lang_count;
do {
*stringtabs++ = t++;
} while (--i);
*stringtabs = NULL;
/* stringtabs = vlabuf = d_stringtabs for later kfree */
stringtabs = vla_ptr(vlabuf, d, stringtabs);
t = vla_ptr(vlabuf, d, stringtab);
s = vla_ptr(vlabuf, d, strings);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
/* For each language */
data += 16;
len -= 16;
do { /* lang_count > 0 so we can use do-while */
unsigned needed = needed_count;
u32 str_per_lang = str_count;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (len < 3)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error_free;
t->language = get_unaligned_le16(data);
t->strings = s;
++t;
data += 2;
len -= 2;
/* For each string */
do { /* str_count > 0 so we can use do-while */
size_t length = strnlen(data, len);
if (length == len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error_free;
/*
* User may provide more strings then we need,
* if that's the case we simply ignore the
* rest
*/
if (needed) {
/*
* s->id will be set while adding
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* function to configuration so for
* now just leave garbage here.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
s->s = data;
--needed;
++s;
}
data += length + 1;
len -= length + 1;
} while (--str_per_lang);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
s->id = 0; /* terminator */
s->s = NULL;
++s;
} while (--lang_count);
/* Some garbage left? */
if (len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error_free;
/* Done! */
ffs->stringtabs = stringtabs;
ffs->raw_strings = _data;
return 0;
error_free:
kfree(stringtabs);
error:
kfree(_data);
return -EINVAL;
}
/* Events handling and management *******************************************/
static void __ffs_event_add(struct ffs_data *ffs,
enum usb_functionfs_event_type type)
{
enum usb_functionfs_event_type rem_type1, rem_type2 = type;
int neg = 0;
/*
* Abort any unhandled setup
*
* We do not need to worry about some cmpxchg() changing value
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* of ffs->setup_state without holding the lock because when
* state is FFS_SETUP_PENDING cmpxchg() in several places in
* the source does nothing.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELLED;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/*
* Logic of this function guarantees that there are at most four pending
* evens on ffs->ev.types queue. This is important because the queue
* has space for four elements only and __ffs_ep0_read_events function
* depends on that limit as well. If more event types are added, those
* limits have to be revisited or guaranteed to still hold.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
switch (type) {
case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
fallthrough;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
case FUNCTIONFS_SUSPEND:
case FUNCTIONFS_SETUP:
rem_type1 = type;
/* Discard all similar events */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
case FUNCTIONFS_BIND:
case FUNCTIONFS_UNBIND:
case FUNCTIONFS_DISABLE:
case FUNCTIONFS_ENABLE:
/* Discard everything other then power management. */
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
rem_type1 = FUNCTIONFS_SUSPEND;
rem_type2 = FUNCTIONFS_RESUME;
neg = 1;
break;
default:
WARN(1, "%d: unknown event, this should not happen\n", type);
return;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
{
u8 *ev = ffs->ev.types, *out = ev;
unsigned n = ffs->ev.count;
for (; n; --n, ++ev)
if ((*ev == rem_type1 || *ev == rem_type2) == neg)
*out++ = *ev;
else
pr_vdebug("purging event %d\n", *ev);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->ev.count = out - ffs->ev.types;
}
pr_vdebug("adding event %d\n", type);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq);
if (ffs->ffs_eventfd)
eventfd_signal(ffs->ffs_eventfd);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static void ffs_event_add(struct ffs_data *ffs,
enum usb_functionfs_event_type type)
{
unsigned long flags;
spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
__ffs_event_add(ffs, type);
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
}
/* Bind/unbind USB function hooks *******************************************/
static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
{
int i;
for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
if (ffs->eps_addrmap[i] == endpoint_address)
return i;
return -ENOENT;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
{
struct usb_endpoint_descriptor *ds = (void *)desc;
struct ffs_function *func = priv;
struct ffs_ep *ffs_ep;
unsigned ep_desc_id;
int idx;
static const char *speed_names[] = { "full", "high", "super" };
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (type != FFS_DESCRIPTOR)
return 0;
/*
* If ss_descriptors is not NULL, we are reading super speed
* descriptors; if hs_descriptors is not NULL, we are reading high
* speed descriptors; otherwise, we are reading full speed
* descriptors.
*/
if (func->function.ss_descriptors) {
ep_desc_id = 2;
func->function.ss_descriptors[(long)valuep] = desc;
} else if (func->function.hs_descriptors) {
ep_desc_id = 1;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
func->function.hs_descriptors[(long)valuep] = desc;
} else {
ep_desc_id = 0;
func->function.fs_descriptors[(long)valuep] = desc;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
return 0;
idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
if (idx < 0)
return idx;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_ep = func->eps + idx;
if (ffs_ep->descs[ep_desc_id]) {
pr_err("two %sspeed descriptors for EP %d\n",
speed_names[ep_desc_id],
usb_endpoint_num(ds));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
}
ffs_ep->descs[ep_desc_id] = ds;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_dump_mem(": Original ep desc", ds, ds->bLength);
if (ffs_ep->ep) {
ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
if (!ds->wMaxPacketSize)
ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
} else {
struct usb_request *req;
struct usb_ep *ep;
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
u8 bEndpointAddress;
u16 wMaxPacketSize;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
/*
* We back up bEndpointAddress because autoconfig overwrites
* it with physical endpoint address.
*/
bEndpointAddress = ds->bEndpointAddress;
/*
* We back up wMaxPacketSize because autoconfig treats
* endpoint descriptors as if they were full speed.
*/
wMaxPacketSize = ds->wMaxPacketSize;
pr_vdebug("autoconfig\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ep = usb_ep_autoconfig(func->gadget, ds);
if (!ep)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -ENOTSUPP;
ep->driver_data = func->eps + idx;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
req = usb_ep_alloc_request(ep, GFP_KERNEL);
if (!req)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -ENOMEM;
ffs_ep->ep = ep;
ffs_ep->req = req;
func->eps_revmap[ds->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK] = idx + 1;
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
/*
* If we use virtual address mapping, we restore
* original bEndpointAddress value.
*/
if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
ds->bEndpointAddress = bEndpointAddress;
/*
* Restore wMaxPacketSize which was potentially
* overwritten by autoconfig.
*/
ds->wMaxPacketSize = wMaxPacketSize;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
return 0;
}
static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
{
struct ffs_function *func = priv;
unsigned idx;
u8 newValue;
switch (type) {
default:
case FFS_DESCRIPTOR:
/* Handled in previous pass by __ffs_func_bind_do_descs() */
return 0;
case FFS_INTERFACE:
idx = *valuep;
if (func->interfaces_nums[idx] < 0) {
int id = usb_interface_id(func->conf, &func->function);
if (id < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return id;
func->interfaces_nums[idx] = id;
}
newValue = func->interfaces_nums[idx];
break;
case FFS_STRING:
/* String' IDs are allocated when fsf_data is bound to cdev */
newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
break;
case FFS_ENDPOINT:
/*
* USB_DT_ENDPOINT are handled in
* __ffs_func_bind_do_descs().
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (desc->bDescriptorType == USB_DT_ENDPOINT)
return 0;
idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
if (!func->eps[idx].ep)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -EINVAL;
{
struct usb_endpoint_descriptor **descs;
descs = func->eps[idx].descs;
newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
}
break;
}
pr_vdebug("%02x -> %02x\n", *valuep, newValue);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
*valuep = newValue;
return 0;
}
static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
struct usb_os_desc_header *h, void *data,
unsigned len, void *priv)
{
struct ffs_function *func = priv;
u8 length = 0;
switch (type) {
case FFS_OS_DESC_EXT_COMPAT: {
struct usb_ext_compat_desc *desc = data;
struct usb_os_desc_table *t;
t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
memcpy(t->os_desc->ext_compat_id, &desc->IDs,
sizeof_field(struct usb_ext_compat_desc, IDs));
length = sizeof(*desc);
}
break;
case FFS_OS_DESC_EXT_PROP: {
struct usb_ext_prop_desc *desc = data;
struct usb_os_desc_table *t;
struct usb_os_desc_ext_prop *ext_prop;
char *ext_prop_name;
char *ext_prop_data;
t = &func->function.os_desc_table[h->interface];
t->if_id = func->interfaces_nums[h->interface];
ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
ext_prop->data_len = le32_to_cpu(*(__le32 *)
usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
length = ext_prop->name_len + ext_prop->data_len + 14;
ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
func->ffs->ms_os_descs_ext_prop_name_avail +=
ext_prop->name_len;
ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
func->ffs->ms_os_descs_ext_prop_data_avail +=
ext_prop->data_len;
memcpy(ext_prop_data,
usb_ext_prop_data_ptr(data, ext_prop->name_len),
ext_prop->data_len);
/* unicode data reported to the host as "WCHAR"s */
switch (ext_prop->type) {
case USB_EXT_PROP_UNICODE:
case USB_EXT_PROP_UNICODE_ENV:
case USB_EXT_PROP_UNICODE_LINK:
case USB_EXT_PROP_UNICODE_MULTI:
ext_prop->data_len *= 2;
break;
}
ext_prop->data = ext_prop_data;
memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
ext_prop->name_len);
/* property name reported to the host as "WCHAR"s */
ext_prop->name_len *= 2;
ext_prop->name = ext_prop_name;
t->os_desc->ext_prop_len +=
ext_prop->name_len + ext_prop->data_len + 14;
++t->os_desc->ext_prop_count;
list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
}
break;
default:
pr_vdebug("unknown descriptor: %d\n", type);
}
return length;
}
static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
struct usb_configuration *c)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct f_fs_opts *ffs_opts =
container_of(f->fi, struct f_fs_opts, func_inst);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
struct ffs_data *ffs_data;
int ret;
/*
* Legacy gadget triggers binding in functionfs_ready_callback,
* which already uses locking; taking the same lock here would
* cause a deadlock.
*
* Configfs-enabled gadgets however do need ffs_dev_lock.
*/
if (!ffs_opts->no_configfs)
ffs_dev_lock();
ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
ffs_data = ffs_opts->dev->ffs_data;
if (!ffs_opts->no_configfs)
ffs_dev_unlock();
if (ret)
return ERR_PTR(ret);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
func->ffs = ffs_data;
func->conf = c;
func->gadget = c->cdev->gadget;
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
* in each configuration its functions are bound in sequence
* with list_for_each_entry, so we assume no race condition
* with regard to ffs_opts->bound access
*/
if (!ffs_opts->refcnt) {
ret = functionfs_bind(func->ffs, c->cdev);
if (ret)
return ERR_PTR(ret);
}
ffs_opts->refcnt++;
func->function.strings = func->ffs->stringtabs;
return ffs_opts;
}
static int _ffs_func_bind(struct usb_configuration *c,
struct usb_function *f)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
const int full = !!func->ffs->fs_descs_count;
const int high = !!func->ffs->hs_descs_count;
const int super = !!func->ffs->ss_descs_count;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
int fs_len, hs_len, ss_len, ret, i;
struct ffs_ep *eps_ptr;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Make it a single chunk, less management later on */
vla_group(d);
vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
full ? ffs->fs_descs_count + 1 : 0);
vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
high ? ffs->hs_descs_count + 1 : 0);
vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
super ? ffs->ss_descs_count + 1 : 0);
vla_item_with_sz(d, short, inums, ffs->interfaces_count);
vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
c->cdev->use_os_string ? ffs->interfaces_count : 0);
vla_item_with_sz(d, char[16], ext_compat,
c->cdev->use_os_string ? ffs->interfaces_count : 0);
vla_item_with_sz(d, struct usb_os_desc, os_desc,
c->cdev->use_os_string ? ffs->interfaces_count : 0);
vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
ffs->ms_os_descs_ext_prop_count);
vla_item_with_sz(d, char, ext_prop_name,
ffs->ms_os_descs_ext_prop_name_len);
vla_item_with_sz(d, char, ext_prop_data,
ffs->ms_os_descs_ext_prop_data_len);
vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
char *vlabuf;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Has descriptors only for speeds gadget does not support */
if (!(full | high | super))
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -ENOTSUPP;
/* Allocate a single chunk, less management later on */
vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
if (!vlabuf)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return -ENOMEM;
ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
ffs->ms_os_descs_ext_prop_name_avail =
vla_ptr(vlabuf, d, ext_prop_name);
ffs->ms_os_descs_ext_prop_data_avail =
vla_ptr(vlabuf, d, ext_prop_data);
/* Copy descriptors */
memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
ffs->raw_descs_length);
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
eps_ptr = vla_ptr(vlabuf, d, eps);
for (i = 0; i < ffs->eps_count; i++)
eps_ptr[i].num = -1;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Save pointers
* d_eps == vlabuf, func->eps used to kfree vlabuf later
*/
func->eps = vla_ptr(vlabuf, d, eps);
func->interfaces_nums = vla_ptr(vlabuf, d, inums);
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/*
* Go through all the endpoint descriptors and allocate
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* endpoints first, so that later we can rewrite the endpoint
* numbers without worrying that it may be described later on.
*/
if (full) {
func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
fs_len = ffs_do_descs(ffs->fs_descs_count,
vla_ptr(vlabuf, d, raw_descs),
d_raw_descs__sz,
__ffs_func_bind_do_descs, func);
if (fs_len < 0) {
ret = fs_len;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
} else {
fs_len = 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
if (high) {
func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
hs_len = ffs_do_descs(ffs->hs_descs_count,
vla_ptr(vlabuf, d, raw_descs) + fs_len,
d_raw_descs__sz - fs_len,
__ffs_func_bind_do_descs, func);
if (hs_len < 0) {
ret = hs_len;
goto error;
}
} else {
hs_len = 0;
}
if (super) {
2020-10-27 16:07:31 -07:00
func->function.ss_descriptors = func->function.ssp_descriptors =
vla_ptr(vlabuf, d, ss_descs);
ss_len = ffs_do_descs(ffs->ss_descs_count,
vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
d_raw_descs__sz - fs_len - hs_len,
__ffs_func_bind_do_descs, func);
if (ss_len < 0) {
ret = ss_len;
goto error;
}
} else {
ss_len = 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
/*
* Now handle interface numbers allocation and interface and
* endpoint numbers rewriting. We can do that in one go
* now.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ret = ffs_do_descs(ffs->fs_descs_count +
(high ? ffs->hs_descs_count : 0) +
(super ? ffs->ss_descs_count : 0),
vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
__ffs_func_bind_do_nums, func);
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
goto error;
func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
if (c->cdev->use_os_string) {
for (i = 0; i < ffs->interfaces_count; ++i) {
struct usb_os_desc *desc;
desc = func->function.os_desc_table[i].os_desc =
vla_ptr(vlabuf, d, os_desc) +
i * sizeof(struct usb_os_desc);
desc->ext_compat_id =
vla_ptr(vlabuf, d, ext_compat) + i * 16;
INIT_LIST_HEAD(&desc->ext_prop);
}
ret = ffs_do_os_descs(ffs->ms_os_descs_count,
vla_ptr(vlabuf, d, raw_descs) +
fs_len + hs_len + ss_len,
d_raw_descs__sz - fs_len - hs_len -
ss_len,
__ffs_func_bind_do_os_desc, func);
if (ret < 0)
goto error;
}
func->function.os_desc_n =
c->cdev->use_os_string ? ffs->interfaces_count : 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* And we're done */
ffs_event_add(ffs, FUNCTIONFS_BIND);
return 0;
error:
/* XXX Do we need to release all claimed endpoints here? */
return ret;
}
static int ffs_func_bind(struct usb_configuration *c,
struct usb_function *f)
{
struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
struct ffs_function *func = ffs_func_from_usb(f);
int ret;
if (IS_ERR(ffs_opts))
return PTR_ERR(ffs_opts);
ret = _ffs_func_bind(c, f);
if (ret && !--ffs_opts->refcnt)
functionfs_unbind(func->ffs);
return ret;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Other USB function hooks *************************************************/
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
static void ffs_reset_work(struct work_struct *work)
{
struct ffs_data *ffs = container_of(work,
struct ffs_data, reset_work);
ffs_data_reset(ffs);
}
static int ffs_func_get_alt(struct usb_function *f,
unsigned int interface)
{
struct ffs_function *func = ffs_func_from_usb(f);
int intf = ffs_func_revmap_intf(func, interface);
return (intf < 0) ? intf : func->cur_alt[interface];
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
int ret = 0, intf;
if (alt > MAX_ALT_SETTINGS)
return -EINVAL;
intf = ffs_func_revmap_intf(func, interface);
if (intf < 0)
return intf;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (ffs->func)
ffs_func_eps_disable(ffs->func);
usb: gadget: f_fs: add "no_disconnect" mode Since we can compose gadgets from many functions, there is the problem related to gadget breakage while FunctionFS daemon being closed. FFS function is userspace code so there is no way to know when it will close files (it doesn't matter what is the reason of this situation, it can be daemon logic, program breakage, process kill or any other). So when we have another function in gadget which, for example, sends some amount of data, does some software update or implements some real-time functionality, we may want to keep the gadget connected despite FFS function is no longer functional. We can't just remove one of functions from gadget since it has been enumerated, so the only way to keep entire gadget working is to make broken FFS function deactivated but still visible to host. For this purpose this patch introduces "no_disconnect" mode. It can be enabled by setting mount option "no_disconnect=1", and results with defering function disconnect to the moment of reopen ep0 file or filesystem unmount. After closing all endpoint files, FunctionFS is set to state FFS_DEACTIVATED. When ffs->state == FFS_DEACTIVATED: - function is still bound and visible to host, - setup requests are automatically stalled, - transfers on other endpoints are refused, - epfiles, except ep0, are deleted from the filesystem, - opening ep0 causes the function to be closed, and then FunctionFS is ready for descriptors and string write, - altsetting change causes the function to be closed - we want to keep function alive until another functions are potentialy used, altsetting change means that another configuration is being selected or USB cable was unplugged, which indicates that we don't need to stay longer in FFS_DEACTIVATED state - unmounting of the FunctionFS instance causes the function to be closed. Tested-by: David Cohen <david.a.cohen@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-12-18 09:55:10 +01:00
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
ffs->func = func;
ret = ffs_func_eps_enable(func);
if (ret >= 0) {
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_event_add(ffs, FUNCTIONFS_ENABLE);
func->cur_alt[interface] = alt;
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
}
static void ffs_func_disable(struct usb_function *f)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
if (ffs->func)
ffs_func_eps_disable(ffs->func);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return;
}
if (ffs->state == FFS_ACTIVE) {
ffs->func = NULL;
ffs_event_add(ffs, FUNCTIONFS_DISABLE);
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static int ffs_func_setup(struct usb_function *f,
const struct usb_ctrlrequest *creq)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
unsigned long flags;
int ret;
pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex));
pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength));
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/*
* Most requests directed to interface go through here
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
* (notable exceptions are set/get interface) so we need to
* handle them. All other either handled by composite or
* passed to usb_configuration->setup() (if one is set). No
* matter, we will handle requests directed to endpoint here
* as well (as it's straightforward). Other request recipient
* types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP
* is being used.
*/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
switch (creq->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
break;
case USB_RECIP_ENDPOINT:
ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
if (ret < 0)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return ret;
usb: gadget: f_fs: virtual endpoint address mapping This patch introduces virtual endpoint address mapping. It separates function logic form physical endpoint addresses making it more hardware independent. Following modifications changes user space API, so to enable them user have to switch on the FUNCTIONFS_VIRTUAL_ADDR flag in descriptors. Endpoints are now refered using virtual endpoint addresses chosen by user in endpoint descpriptors. This applies to each context when endpoint address can be used: - when accessing endpoint files in FunctionFS filesystemi (in file name), - in setup requests directed to specific endpoint (in wIndex field), - in descriptors returned by FUNCTIONFS_ENDPOINT_DESC ioctl. In endpoint file names the endpoint address number is formatted as double-digit hexadecimal value ("ep%02x") which has few advantages - it is easy to parse, allows to easly recognize endpoint direction basing on its name (IN endpoint number starts with digit 8, and OUT with 0) which can be useful for debugging purpose, and it makes easier to introduce further features allowing to use each endpoint number in both directions to have more endpoints available for function if hardware supports this (for example we could have ep01 which is endpoint 1 with OUT direction, and ep81 which is endpoint 1 with IN direction). Physical endpoint address can be still obtained using ioctl named FUNCTIONFS_ENDPOINT_REVMAP, but now it's not neccesary to handle USB transactions properly. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-09-09 08:23:17 +02:00
if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
ret = func->ffs->eps_addrmap[ret];
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
break;
default:
if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP)
ret = le16_to_cpu(creq->wIndex);
else
return -EOPNOTSUPP;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
ffs->ev.setup = *creq;
ffs->ev.setup.wIndex = cpu_to_le16(ret);
__ffs_event_add(ffs, FUNCTIONFS_SETUP);
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
return ffs->ev.setup.wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
}
static bool ffs_func_req_match(struct usb_function *f,
const struct usb_ctrlrequest *creq,
bool config0)
{
struct ffs_function *func = ffs_func_from_usb(f);
if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP))
return false;
switch (creq->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
return (ffs_func_revmap_intf(func,
le16_to_cpu(creq->wIndex)) >= 0);
case USB_RECIP_ENDPOINT:
return (ffs_func_revmap_ep(func,
le16_to_cpu(creq->wIndex)) >= 0);
default:
return (bool) (func->ffs->user_flags &
FUNCTIONFS_ALL_CTRL_RECIP);
}
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static void ffs_func_suspend(struct usb_function *f)
{
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
}
static void ffs_func_resume(struct usb_function *f)
{
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
}
/* Endpoint and interface numbers reverse mapping ***************************/
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
{
num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
return num ? num : -EDOM;
}
static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
{
short *nums = func->interfaces_nums;
unsigned count = func->ffs->interfaces_count;
for (; count; --count, ++nums) {
if (*nums >= 0 && *nums == intf)
return nums - func->interfaces_nums;
}
return -EDOM;
}
/* Devices management *******************************************************/
static LIST_HEAD(ffs_devices);
static struct ffs_dev *_ffs_do_find_dev(const char *name)
{
struct ffs_dev *dev;
2017-03-10 22:45:58 +01:00
if (!name)
return NULL;
list_for_each_entry(dev, &ffs_devices, entry) {
if (strcmp(dev->name, name) == 0)
return dev;
}
return NULL;
}
/*
* ffs_lock must be taken by the caller of this function
*/
static struct ffs_dev *_ffs_get_single_dev(void)
{
struct ffs_dev *dev;
if (list_is_singular(&ffs_devices)) {
dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
if (dev->single)
return dev;
}
return NULL;
}
/*
* ffs_lock must be taken by the caller of this function
*/
static struct ffs_dev *_ffs_find_dev(const char *name)
{
struct ffs_dev *dev;
dev = _ffs_get_single_dev();
if (dev)
return dev;
return _ffs_do_find_dev(name);
}
/* Configfs support *********************************************************/
static inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_fs_opts,
func_inst.group);
}
static ssize_t f_fs_opts_ready_show(struct config_item *item, char *page)
{
struct f_fs_opts *opts = to_ffs_opts(item);
int ready;
ffs_dev_lock();
ready = opts->dev->desc_ready;
ffs_dev_unlock();
return sprintf(page, "%d\n", ready);
}
CONFIGFS_ATTR_RO(f_fs_opts_, ready);
static struct configfs_attribute *ffs_attrs[] = {
&f_fs_opts_attr_ready,
NULL,
};
static void ffs_attr_release(struct config_item *item)
{
struct f_fs_opts *opts = to_ffs_opts(item);
usb_put_function_instance(&opts->func_inst);
}
static struct configfs_item_operations ffs_item_ops = {
.release = ffs_attr_release,
};
static const struct config_item_type ffs_func_type = {
.ct_item_ops = &ffs_item_ops,
.ct_attrs = ffs_attrs,
.ct_owner = THIS_MODULE,
};
/* Function registration interface ******************************************/
static void ffs_free_inst(struct usb_function_instance *f)
{
struct f_fs_opts *opts;
opts = to_f_fs_opts(f);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
ffs_release_dev(opts->dev);
ffs_dev_lock();
_ffs_free_dev(opts->dev);
ffs_dev_unlock();
kfree(opts);
}
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
{
if (strlen(name) >= sizeof_field(struct ffs_dev, name))
return -ENAMETOOLONG;
2017-03-10 22:45:58 +01:00
return ffs_name_dev(to_f_fs_opts(fi)->dev, name);
}
static struct usb_function_instance *ffs_alloc_inst(void)
{
struct f_fs_opts *opts;
struct ffs_dev *dev;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.set_inst_name = ffs_set_inst_name;
opts->func_inst.free_func_inst = ffs_free_inst;
ffs_dev_lock();
dev = _ffs_alloc_dev();
ffs_dev_unlock();
if (IS_ERR(dev)) {
kfree(opts);
return ERR_CAST(dev);
}
opts->dev = dev;
dev->opts = opts;
config_group_init_type_name(&opts->func_inst.group, "",
&ffs_func_type);
return &opts->func_inst;
}
static void ffs_free(struct usb_function *f)
{
kfree(ffs_func_from_usb(f));
}
static void ffs_func_unbind(struct usb_configuration *c,
struct usb_function *f)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
struct f_fs_opts *opts =
container_of(f->fi, struct f_fs_opts, func_inst);
struct ffs_ep *ep = func->eps;
unsigned count = ffs->eps_count;
unsigned long flags;
if (ffs->func == func) {
ffs_func_eps_disable(func);
ffs->func = NULL;
}
/* Drain any pending AIO completions */
drain_workqueue(ffs->io_completion_wq);
ffs_event_add(ffs, FUNCTIONFS_UNBIND);
if (!--opts->refcnt)
functionfs_unbind(ffs);
/* cleanup after autoconfig */
spin_lock_irqsave(&func->ffs->eps_lock, flags);
while (count--) {
if (ep->ep && ep->req)
usb_ep_free_request(ep->ep, ep->req);
ep->req = NULL;
++ep;
}
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
kfree(func->eps);
func->eps = NULL;
/*
* eps, descriptors and interfaces_nums are allocated in the
* same chunk so only one free is required.
*/
func->function.fs_descriptors = NULL;
func->function.hs_descriptors = NULL;
func->function.ss_descriptors = NULL;
2020-10-27 16:07:31 -07:00
func->function.ssp_descriptors = NULL;
func->interfaces_nums = NULL;
}
static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
{
struct ffs_function *func;
func = kzalloc(sizeof(*func), GFP_KERNEL);
if (!func)
return ERR_PTR(-ENOMEM);
func->function.name = "Function FS Gadget";
func->function.bind = ffs_func_bind;
func->function.unbind = ffs_func_unbind;
func->function.set_alt = ffs_func_set_alt;
func->function.get_alt = ffs_func_get_alt;
func->function.disable = ffs_func_disable;
func->function.setup = ffs_func_setup;
func->function.req_match = ffs_func_req_match;
func->function.suspend = ffs_func_suspend;
func->function.resume = ffs_func_resume;
func->function.free_func = ffs_free;
return &func->function;
}
/*
* ffs_lock must be taken by the caller of this function
*/
static struct ffs_dev *_ffs_alloc_dev(void)
{
struct ffs_dev *dev;
int ret;
if (_ffs_get_single_dev())
return ERR_PTR(-EBUSY);
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
if (list_empty(&ffs_devices)) {
ret = functionfs_init();
if (ret) {
kfree(dev);
return ERR_PTR(ret);
}
}
list_add(&dev->entry, &ffs_devices);
return dev;
}
2017-03-10 22:45:58 +01:00
int ffs_name_dev(struct ffs_dev *dev, const char *name)
{
struct ffs_dev *existing;
2017-03-10 22:45:58 +01:00
int ret = 0;
2017-03-10 22:45:58 +01:00
ffs_dev_lock();
2017-03-10 22:45:58 +01:00
existing = _ffs_do_find_dev(name);
if (!existing)
strscpy(dev->name, name, ARRAY_SIZE(dev->name));
2017-03-10 22:45:58 +01:00
else if (existing != dev)
ret = -EBUSY;
ffs_dev_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(ffs_name_dev);
int ffs_single_dev(struct ffs_dev *dev)
{
int ret;
ret = 0;
ffs_dev_lock();
if (!list_is_singular(&ffs_devices))
ret = -EBUSY;
else
dev->single = true;
ffs_dev_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(ffs_single_dev);
/*
* ffs_lock must be taken by the caller of this function
*/
static void _ffs_free_dev(struct ffs_dev *dev)
{
list_del(&dev->entry);
kfree(dev);
if (list_empty(&ffs_devices))
functionfs_cleanup();
}
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
{
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
int ret = 0;
struct ffs_dev *ffs_dev;
ffs_dev_lock();
ffs_dev = _ffs_find_dev(dev_name);
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
if (!ffs_dev) {
ret = -ENOENT;
} else if (ffs_dev->mounted) {
ret = -EBUSY;
} else if (ffs_dev->ffs_acquire_dev_callback &&
ffs_dev->ffs_acquire_dev_callback(ffs_dev)) {
ret = -ENOENT;
} else {
ffs_dev->mounted = true;
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
ffs_dev->ffs_data = ffs_data;
ffs_data->private_data = ffs_dev;
}
ffs_dev_unlock();
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
return ret;
}
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
static void ffs_release_dev(struct ffs_dev *ffs_dev)
{
ffs_dev_lock();
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
if (ffs_dev && ffs_dev->mounted) {
ffs_dev->mounted = false;
usb: gadget: f_fs: Fix setting of device and driver data cross-references FunctionFS device structure 'struct ffs_dev' and driver data structure 'struct ffs_data' are bound to each other with cross-reference pointers 'ffs_data->private_data' and 'ffs_dev->ffs_data'. While the first one is supposed to be valid through the whole life of 'struct ffs_data' (and while 'struct ffs_dev' exists non-freed), the second one is cleared in 'ffs_closed()' (called from 'ffs_data_reset()' or the last 'ffs_data_put()'). This can be called several times, alternating in different order with 'ffs_free_inst()', that, if possible, clears the other cross-reference. As a result, different cases of these calls order may leave stale cross-reference pointers, used when the pointed structure is already freed. Even if it occasionally doesn't cause kernel crash, this error is reported by KASAN-enabled kernel configuration. For example, the case [last 'ffs_data_put()' - 'ffs_free_inst()'] was fixed by commit cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst"). The other case ['ffs_data_reset()' - 'ffs_free_inst()' - 'ffs_data_put()'] now causes KASAN reported error [1], when 'ffs_data_reset()' clears 'ffs_dev->ffs_data', then 'ffs_free_inst()' frees the 'struct ffs_dev', but can't clear 'ffs_data->private_data', which is then accessed in 'ffs_closed()' called from 'ffs_data_put()'. This happens since 'ffs_dev->ffs_data' reference is cleared too early. Moreover, one more use case, when 'ffs_free_inst()' is called immediately after mounting FunctionFS device (that is before the descriptors are written and 'ffs_ready()' is called), and then 'ffs_data_reset()' or 'ffs_data_put()' is called from accessing "ep0" file or unmounting the device. This causes KASAN error report like [2], since 'ffs_dev->ffs_data' is not yet set when 'ffs_free_inst()' can't properly clear 'ffs_data->private_data', that is later accessed to freed structure. Fix these (and may be other) cases of stale pointers access by moving setting and clearing of the mentioned cross-references to the single places, setting both of them when 'struct ffs_data' is created and bound to 'struct ffs_dev', and clearing both of them when one of the structures is destroyed. It seems convenient to make this pointer initialization and structures binding in 'ffs_acquire_dev()' and make pointers clearing in 'ffs_release_dev()'. This required some changes in these functions parameters and return types. Also, 'ffs_release_dev()' calling requires some cleanup, fixing minor issues, like (1) 'ffs_release_dev()' is not called if 'ffs_free_inst()' is called without unmounting the device, and "release_dev" callback is not called at all, or (2) "release_dev" callback is called before "ffs_closed" callback on unmounting, which seems to be not correctly nested with "acquire_dev" and "ffs_ready" callbacks. Make this cleanup togther with other mentioned 'ffs_release_dev()' changes. [1] ================================================================== root@rcar-gen3:~# mkdir /dev/cfs root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 64.340664] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# cd /dev/ffs root@rcar-gen3:/dev/ffs# /home/root/ffs-test ffs-test: info: ep0: writing descriptors (in v2 format) [ 83.181442] read descriptors [ 83.186085] read strings ffs-test: info: ep0: writing strings ffs-test: dbg: ep1: starting ffs-test: dbg: ep2: starting ffs-test: info: ep1: starts ffs-test: info: ep2: starts ffs-test: info: ep0: starts ^C root@rcar-gen3:/dev/ffs# cd /home/root/ root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 98.935061] unloading root@rcar-gen3:~# umount /dev/ffs [ 102.734301] ================================================================== [ 102.742059] BUG: KASAN: use-after-free in ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.749683] Write of size 1 at addr ffff0004d46ff549 by task umount/2997 [ 102.756709] [ 102.758311] CPU: 0 PID: 2997 Comm: umount Not tainted 5.13.0-rc4+ #8 [ 102.764971] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 102.772179] Call trace: [ 102.774779] dump_backtrace+0x0/0x330 [ 102.778653] show_stack+0x20/0x2c [ 102.782152] dump_stack+0x11c/0x1ac [ 102.785833] print_address_description.constprop.0+0x30/0x274 [ 102.791862] kasan_report+0x14c/0x1c8 [ 102.795719] __asan_report_store1_noabort+0x34/0x58 [ 102.800840] ffs_release_dev+0x64/0xa8 [usb_f_fs] [ 102.805801] ffs_fs_kill_sb+0x50/0x84 [usb_f_fs] [ 102.810663] deactivate_locked_super+0xa0/0xf0 [ 102.815339] deactivate_super+0x98/0xac [ 102.819378] cleanup_mnt+0xd0/0x1b0 [ 102.823057] __cleanup_mnt+0x1c/0x28 [ 102.826823] task_work_run+0x104/0x180 [ 102.830774] do_notify_resume+0x458/0x14e0 [ 102.835083] work_pending+0xc/0x5f8 [ 102.838762] [ 102.840357] Allocated by task 2988: [ 102.844032] kasan_save_stack+0x28/0x58 [ 102.848071] kasan_set_track+0x28/0x3c [ 102.852016] ____kasan_kmalloc+0x84/0x9c [ 102.856142] __kasan_kmalloc+0x10/0x1c [ 102.860088] __kmalloc+0x214/0x2f8 [ 102.863678] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 102.868990] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 102.873942] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 102.880629] usb_get_function_instance+0x64/0x68 [libcomposite] [ 102.886858] function_make+0x128/0x1ec [libcomposite] [ 102.892185] configfs_mkdir+0x330/0x590 [configfs] [ 102.897245] vfs_mkdir+0x12c/0x1bc [ 102.900835] do_mkdirat+0x180/0x1d0 [ 102.904513] __arm64_sys_mkdirat+0x80/0x94 [ 102.908822] invoke_syscall+0xf8/0x25c [ 102.912772] el0_svc_common.constprop.0+0x150/0x1a0 [ 102.917891] do_el0_svc+0xa0/0xd4 [ 102.921386] el0_svc+0x24/0x34 [ 102.924613] el0_sync_handler+0xcc/0x154 [ 102.928743] el0_sync+0x198/0x1c0 [ 102.932238] [ 102.933832] Freed by task 2996: [ 102.937144] kasan_save_stack+0x28/0x58 [ 102.941181] kasan_set_track+0x28/0x3c [ 102.945128] kasan_set_free_info+0x28/0x4c [ 102.949435] ____kasan_slab_free+0x104/0x118 [ 102.953921] __kasan_slab_free+0x18/0x24 [ 102.958047] slab_free_freelist_hook+0x148/0x1f0 [ 102.962897] kfree+0x318/0x440 [ 102.966123] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 102.971075] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 102.977302] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 102.982344] config_item_put+0x140/0x1a4 [configfs] [ 102.987486] configfs_rmdir+0x3fc/0x518 [configfs] [ 102.992535] vfs_rmdir+0x114/0x234 [ 102.996122] do_rmdir+0x274/0x2b0 [ 102.999617] __arm64_sys_unlinkat+0x94/0xc8 [ 103.004015] invoke_syscall+0xf8/0x25c [ 103.007961] el0_svc_common.constprop.0+0x150/0x1a0 [ 103.013080] do_el0_svc+0xa0/0xd4 [ 103.016575] el0_svc+0x24/0x34 [ 103.019801] el0_sync_handler+0xcc/0x154 [ 103.023930] el0_sync+0x198/0x1c0 [ 103.027426] [ 103.029020] The buggy address belongs to the object at ffff0004d46ff500 [ 103.029020] which belongs to the cache kmalloc-128 of size 128 [ 103.042079] The buggy address is located 73 bytes inside of [ 103.042079] 128-byte region [ffff0004d46ff500, ffff0004d46ff580) [ 103.054236] The buggy address belongs to the page: [ 103.059262] page:0000000021aa849b refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff0004d46fee00 pfn:0x5146fe [ 103.070437] head:0000000021aa849b order:1 compound_mapcount:0 [ 103.076456] flags: 0x8000000000010200(slab|head|zone=2) [ 103.081948] raw: 8000000000010200 fffffc0013521a80 0000000d0000000d ffff0004c0002300 [ 103.090052] raw: ffff0004d46fee00 000000008020001e 00000001ffffffff 0000000000000000 [ 103.098150] page dumped because: kasan: bad access detected [ 103.103985] [ 103.105578] Memory state around the buggy address: [ 103.110602] ffff0004d46ff400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.118161] ffff0004d46ff480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.125726] >ffff0004d46ff500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.133284] ^ [ 103.139120] ffff0004d46ff580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 103.146679] ffff0004d46ff600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 103.154238] ================================================================== [ 103.161792] Disabling lock debugging due to kernel taint [ 103.167319] Unable to handle kernel paging request at virtual address 0037801d6000018e [ 103.175406] Mem abort info: [ 103.178457] ESR = 0x96000004 [ 103.181609] EC = 0x25: DABT (current EL), IL = 32 bits [ 103.187020] SET = 0, FnV = 0 [ 103.190185] EA = 0, S1PTW = 0 [ 103.193417] Data abort info: [ 103.196385] ISV = 0, ISS = 0x00000004 [ 103.200315] CM = 0, WnR = 0 [ 103.203366] [0037801d6000018e] address between user and kernel address ranges [ 103.210611] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 103.216231] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk sata_rc4 [ 103.259233] CPU: 0 PID: 2997 Comm: umount Tainted: G B 5.13.0-rc4+ #8 [ 103.267031] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 103.273951] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 103.280001] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.285197] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 103.290385] sp : ffff800014777a80 [ 103.293725] x29: ffff800014777a80 x28: ffff0004d7649c80 x27: 0000000000000000 [ 103.300931] x26: ffff800014777fb0 x25: ffff60009aec9394 x24: ffff0004d7649ca4 [ 103.308136] x23: 1fffe0009a3d063a x22: dfff800000000000 x21: ffff0004d1e831d0 [ 103.315340] x20: e1c000eb00000bb4 x19: ffff0004d1e83000 x18: 0000000000000000 [ 103.322545] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 103.329748] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000012ef658 [ 103.336952] x11: ffff7000012ef658 x10: 0720072007200720 x9 : ffff800011322648 [ 103.344157] x8 : ffff800014777818 x7 : ffff80000977b2c7 x6 : 0000000000000000 [ 103.351359] x5 : 0000000000000001 x4 : ffff7000012ef659 x3 : 0000000000000001 [ 103.358562] x2 : 0000000000000000 x1 : 1c38001d6000018e x0 : e1c000eb00000c70 [ 103.365766] Call trace: [ 103.368235] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 103.373076] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 103.377829] ffs_data_closed+0x1ec/0x244 [usb_f_fs] [ 103.382755] ffs_fs_kill_sb+0x70/0x84 [usb_f_fs] [ 103.387420] deactivate_locked_super+0xa0/0xf0 [ 103.391905] deactivate_super+0x98/0xac [ 103.395776] cleanup_mnt+0xd0/0x1b0 [ 103.399299] __cleanup_mnt+0x1c/0x28 [ 103.402906] task_work_run+0x104/0x180 [ 103.406691] do_notify_resume+0x458/0x14e0 [ 103.410823] work_pending+0xc/0x5f8 [ 103.414351] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 103.420490] ---[ end trace 57b43a50e8244f57 ]--- Segmentation fault root@rcar-gen3:~# ================================================================== [2] ================================================================== root@rcar-gen3:~# mkdir /dev/ffs root@rcar-gen3:~# modprobe libcomposite root@rcar-gen3:~# root@rcar-gen3:~# mount -t configfs none /dev/cfs root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1 root@rcar-gen3:~# mkdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 54.766480] file system registered root@rcar-gen3:~# mount -t functionfs ffs /dev/ffs root@rcar-gen3:~# rmdir /dev/cfs/usb_gadget/g1/functions/ffs.ffs [ 63.197597] unloading root@rcar-gen3:~# cat /dev/ffs/ep0 cat: read error:[ 67.213506] ================================================================== [ 67.222095] BUG: KASAN: use-after-free in ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.229699] Write of size 1 at addr ffff0004c26e974a by task cat/2994 [ 67.236446] [ 67.238045] CPU: 0 PID: 2994 Comm: cat Not tainted 5.13.0-rc4+ #8 [ 67.244431] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.251624] Call trace: [ 67.254212] dump_backtrace+0x0/0x330 [ 67.258081] show_stack+0x20/0x2c [ 67.261579] dump_stack+0x11c/0x1ac [ 67.265260] print_address_description.constprop.0+0x30/0x274 [ 67.271286] kasan_report+0x14c/0x1c8 [ 67.275143] __asan_report_store1_noabort+0x34/0x58 [ 67.280265] ffs_data_clear+0x70/0x370 [usb_f_fs] [ 67.285220] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.290172] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.295305] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.300256] __fput+0x304/0x580 [ 67.303576] ____fput+0x18/0x24 [ 67.306893] task_work_run+0x104/0x180 [ 67.310846] do_notify_resume+0x458/0x14e0 [ 67.315154] work_pending+0xc/0x5f8 [ 67.318834] [ 67.320429] Allocated by task 2988: [ 67.324105] kasan_save_stack+0x28/0x58 [ 67.328144] kasan_set_track+0x28/0x3c [ 67.332090] ____kasan_kmalloc+0x84/0x9c [ 67.336217] __kasan_kmalloc+0x10/0x1c [ 67.340163] __kmalloc+0x214/0x2f8 [ 67.343754] kzalloc.constprop.0+0x14/0x20 [usb_f_fs] [ 67.349066] ffs_alloc_inst+0x8c/0x208 [usb_f_fs] [ 67.354017] try_get_usb_function_instance+0xf0/0x164 [libcomposite] [ 67.360705] usb_get_function_instance+0x64/0x68 [libcomposite] [ 67.366934] function_make+0x128/0x1ec [libcomposite] [ 67.372260] configfs_mkdir+0x330/0x590 [configfs] [ 67.377320] vfs_mkdir+0x12c/0x1bc [ 67.380911] do_mkdirat+0x180/0x1d0 [ 67.384589] __arm64_sys_mkdirat+0x80/0x94 [ 67.388899] invoke_syscall+0xf8/0x25c [ 67.392850] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.397969] do_el0_svc+0xa0/0xd4 [ 67.401464] el0_svc+0x24/0x34 [ 67.404691] el0_sync_handler+0xcc/0x154 [ 67.408819] el0_sync+0x198/0x1c0 [ 67.412315] [ 67.413909] Freed by task 2993: [ 67.417220] kasan_save_stack+0x28/0x58 [ 67.421257] kasan_set_track+0x28/0x3c [ 67.425204] kasan_set_free_info+0x28/0x4c [ 67.429513] ____kasan_slab_free+0x104/0x118 [ 67.434001] __kasan_slab_free+0x18/0x24 [ 67.438128] slab_free_freelist_hook+0x148/0x1f0 [ 67.442978] kfree+0x318/0x440 [ 67.446205] ffs_free_inst+0x164/0x2d8 [usb_f_fs] [ 67.451156] usb_put_function_instance+0x84/0xa4 [libcomposite] [ 67.457385] ffs_attr_release+0x18/0x24 [usb_f_fs] [ 67.462428] config_item_put+0x140/0x1a4 [configfs] [ 67.467570] configfs_rmdir+0x3fc/0x518 [configfs] [ 67.472626] vfs_rmdir+0x114/0x234 [ 67.476215] do_rmdir+0x274/0x2b0 [ 67.479710] __arm64_sys_unlinkat+0x94/0xc8 [ 67.484108] invoke_syscall+0xf8/0x25c [ 67.488055] el0_svc_common.constprop.0+0x150/0x1a0 [ 67.493175] do_el0_svc+0xa0/0xd4 [ 67.496671] el0_svc+0x24/0x34 [ 67.499896] el0_sync_handler+0xcc/0x154 [ 67.504024] el0_sync+0x198/0x1c0 [ 67.507520] [ 67.509114] The buggy address belongs to the object at ffff0004c26e9700 [ 67.509114] which belongs to the cache kmalloc-128 of size 128 [ 67.522171] The buggy address is located 74 bytes inside of [ 67.522171] 128-byte region [ffff0004c26e9700, ffff0004c26e9780) [ 67.534328] The buggy address belongs to the page: [ 67.539355] page:000000003177a217 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x5026e8 [ 67.549175] head:000000003177a217 order:1 compound_mapcount:0 [ 67.555195] flags: 0x8000000000010200(slab|head|zone=2) [ 67.560687] raw: 8000000000010200 fffffc0013037100 0000000c00000002 ffff0004c0002300 [ 67.568791] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 67.576890] page dumped because: kasan: bad access detected [ 67.582725] [ 67.584318] Memory state around the buggy address: [ 67.589343] ffff0004c26e9600: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.596903] ffff0004c26e9680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.604463] >ffff0004c26e9700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 67.612022] ^ [ 67.617860] ffff0004c26e9780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 67.625421] ffff0004c26e9800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 67.632981] ================================================================== [ 67.640535] Disabling lock debugging due to kernel taint File descriptor[ 67.646100] Unable to handle kernel paging request at virtual address fabb801d4000018d in bad state [ 67.655456] Mem abort info: [ 67.659619] ESR = 0x96000004 [ 67.662801] EC = 0x25: DABT (current EL), IL = 32 bits [ 67.668225] SET = 0, FnV = 0 [ 67.671375] EA = 0, S1PTW = 0 [ 67.674613] Data abort info: [ 67.677587] ISV = 0, ISS = 0x00000004 [ 67.681522] CM = 0, WnR = 0 [ 67.684588] [fabb801d4000018d] address between user and kernel address ranges [ 67.691849] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 67.697470] Modules linked in: usb_f_fs libcomposite configfs ath9k_htc led_class mac80211 libarc4 ath9k_common ath9k_hw ath cfg80211 aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce gf128mul sha2_ce sha1_ce evdev sata_rcar libata xhci_plat_hcd scsi_mod xhci_hcd rene4 [ 67.740467] CPU: 0 PID: 2994 Comm: cat Tainted: G B 5.13.0-rc4+ #8 [ 67.748005] Hardware name: Renesas Salvator-X board based on r8a77951 (DT) [ 67.754924] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) [ 67.760974] pc : ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.766178] lr : ffs_data_clear+0x124/0x370 [usb_f_fs] [ 67.771365] sp : ffff800014767ad0 [ 67.774706] x29: ffff800014767ad0 x28: ffff800009cf91c0 x27: ffff0004c54861a0 [ 67.781913] x26: ffff0004dc90b288 x25: 1fffe00099ec10f5 x24: 00000000000a801d [ 67.789118] x23: 1fffe00099f6953a x22: dfff800000000000 x21: ffff0004cfb4a9d0 [ 67.796322] x20: d5e000ea00000bb1 x19: ffff0004cfb4a800 x18: 0000000000000000 [ 67.803526] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 67.810730] x14: 0720072007200720 x13: 0720072007200720 x12: 1ffff000028ecefa [ 67.817934] x11: ffff7000028ecefa x10: 0720072007200720 x9 : ffff80001132c014 [ 67.825137] x8 : ffff8000147677d8 x7 : ffff8000147677d7 x6 : 0000000000000000 [ 67.832341] x5 : 0000000000000001 x4 : ffff7000028ecefb x3 : 0000000000000001 [ 67.839544] x2 : 0000000000000005 x1 : 1abc001d4000018d x0 : d5e000ea00000c6d [ 67.846748] Call trace: [ 67.849218] ffs_data_clear+0x138/0x370 [usb_f_fs] [ 67.854058] ffs_data_reset+0x20/0x304 [usb_f_fs] [ 67.858810] ffs_data_closed+0x240/0x244 [usb_f_fs] [ 67.863736] ffs_ep0_release+0x40/0x54 [usb_f_fs] [ 67.868488] __fput+0x304/0x580 [ 67.871665] ____fput+0x18/0x24 [ 67.874837] task_work_run+0x104/0x180 [ 67.878622] do_notify_resume+0x458/0x14e0 [ 67.882754] work_pending+0xc/0x5f8 [ 67.886282] Code: b4000a54 9102f280 12000802 d343fc01 (38f66821) [ 67.892422] ---[ end trace 6d7cedf53d7abbea ]--- Segmentation fault root@rcar-gen3:~# ================================================================== Fixes: 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") Fixes: 3262ad824307 ("usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference") Fixes: cdafb6d8b8da ("usb: gadget: f_fs: Fix use-after-free in ffs_free_inst") Reported-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com> Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com> Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com> Link: https://lore.kernel.org/r/20210603171507.22514-1-andrew_gabbasov@mentor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-06-03 12:15:07 -05:00
if (ffs_dev->ffs_data) {
ffs_dev->ffs_data->private_data = NULL;
ffs_dev->ffs_data = NULL;
}
if (ffs_dev->ffs_release_dev_callback)
ffs_dev->ffs_release_dev_callback(ffs_dev);
}
ffs_dev_unlock();
}
static int ffs_ready(struct ffs_data *ffs)
{
struct ffs_dev *ffs_obj;
int ret = 0;
ffs_dev_lock();
ffs_obj = ffs->private_data;
if (!ffs_obj) {
ret = -EINVAL;
goto done;
}
if (WARN_ON(ffs_obj->desc_ready)) {
ret = -EBUSY;
goto done;
}
ffs_obj->desc_ready = true;
usb: gadget: ffs: fix: Always call ffs_closed() in ffs_data_clear() Originally FFS_FL_CALL_CLOSED_CALLBACK flag has been used to indicate if we should call ffs_closed_callback(). Commit 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") changed its semantic to indicate if we should call ffs_closed() function which does a little bit more. This situation leads to: [ 122.362269] ------------[ cut here ]------------ [ 122.362287] WARNING: CPU: 2 PID: 2384 at drivers/usb/gadget/function/f_fs.c:3417 ffs_ep0_write+0x730/0x810 [usb_f_fs]() [ 122.362292] Modules linked in: [ 122.362555] CPU: 2 PID: 2384 Comm: adbd Tainted: G W 4.1.0-0.rc4.git0.1.1.fc22.i686 #1 [ 122.362561] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 07/25/2014 [ 122.362567] c0d1f947 415badfa 00000000 d1029e64 c0a86e54 00000000 d1029e94 c045b937 [ 122.362584] c0c37f94 00000002 00000950 f9b313d4 00000d59 f9b2ebf0 f9b2ebf0 fffffff0 [ 122.362600] 00000003 deb53d00 d1029ea4 c045ba42 00000009 00000000 d1029f08 f9b2ebf0 [ 122.362617] Call Trace: [ 122.362633] [<c0a86e54>] dump_stack+0x41/0x52 [ 122.362645] [<c045b937>] warn_slowpath_common+0x87/0xc0 [ 122.362658] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362668] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362678] [<c045ba42>] warn_slowpath_null+0x22/0x30 [ 122.362689] [<f9b2ebf0>] ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362702] [<f9b2e4c0>] ? ffs_ep0_read+0x380/0x380 [usb_f_fs] [ 122.362712] [<c05a1c1f>] __vfs_write+0x2f/0x100 [ 122.362722] [<c05a42f2>] ? __sb_start_write+0x52/0x110 [ 122.362731] [<c05a2534>] vfs_write+0x94/0x1b0 [ 122.362740] [<c0a8a1c0>] ? mutex_lock+0x10/0x30 [ 122.362749] [<c05a2f41>] SyS_write+0x51/0xb0 [ 122.362759] [<c0a8c71f>] sysenter_do_call+0x12/0x12 [ 122.362766] ---[ end trace 0673d3467cecf8db ]--- in some cases (reproduction path below). This commit get back semantic of that flag and ensures that ffs_closed() is called always when needed but ffs_closed_callback() is called only if this flag is set. Reproduction path: Compile kernel without any UDC driver or bound some gadget to existing one and then: $ modprobe g_ffs $ mount none -t functionfs mount_point $ ffs-example mount_point This will fail with -ENODEV as there is no udc. $ ffs-example mount_point This will fail with -EBUSY because ffs_data has not been properly cleaned up. Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2015-05-22 17:25:18 +02:00
if (ffs_obj->ffs_ready_callback) {
ret = ffs_obj->ffs_ready_callback(ffs);
usb: gadget: ffs: fix: Always call ffs_closed() in ffs_data_clear() Originally FFS_FL_CALL_CLOSED_CALLBACK flag has been used to indicate if we should call ffs_closed_callback(). Commit 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") changed its semantic to indicate if we should call ffs_closed() function which does a little bit more. This situation leads to: [ 122.362269] ------------[ cut here ]------------ [ 122.362287] WARNING: CPU: 2 PID: 2384 at drivers/usb/gadget/function/f_fs.c:3417 ffs_ep0_write+0x730/0x810 [usb_f_fs]() [ 122.362292] Modules linked in: [ 122.362555] CPU: 2 PID: 2384 Comm: adbd Tainted: G W 4.1.0-0.rc4.git0.1.1.fc22.i686 #1 [ 122.362561] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 07/25/2014 [ 122.362567] c0d1f947 415badfa 00000000 d1029e64 c0a86e54 00000000 d1029e94 c045b937 [ 122.362584] c0c37f94 00000002 00000950 f9b313d4 00000d59 f9b2ebf0 f9b2ebf0 fffffff0 [ 122.362600] 00000003 deb53d00 d1029ea4 c045ba42 00000009 00000000 d1029f08 f9b2ebf0 [ 122.362617] Call Trace: [ 122.362633] [<c0a86e54>] dump_stack+0x41/0x52 [ 122.362645] [<c045b937>] warn_slowpath_common+0x87/0xc0 [ 122.362658] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362668] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362678] [<c045ba42>] warn_slowpath_null+0x22/0x30 [ 122.362689] [<f9b2ebf0>] ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362702] [<f9b2e4c0>] ? ffs_ep0_read+0x380/0x380 [usb_f_fs] [ 122.362712] [<c05a1c1f>] __vfs_write+0x2f/0x100 [ 122.362722] [<c05a42f2>] ? __sb_start_write+0x52/0x110 [ 122.362731] [<c05a2534>] vfs_write+0x94/0x1b0 [ 122.362740] [<c0a8a1c0>] ? mutex_lock+0x10/0x30 [ 122.362749] [<c05a2f41>] SyS_write+0x51/0xb0 [ 122.362759] [<c0a8c71f>] sysenter_do_call+0x12/0x12 [ 122.362766] ---[ end trace 0673d3467cecf8db ]--- in some cases (reproduction path below). This commit get back semantic of that flag and ensures that ffs_closed() is called always when needed but ffs_closed_callback() is called only if this flag is set. Reproduction path: Compile kernel without any UDC driver or bound some gadget to existing one and then: $ modprobe g_ffs $ mount none -t functionfs mount_point $ ffs-example mount_point This will fail with -ENODEV as there is no udc. $ ffs-example mount_point This will fail with -EBUSY because ffs_data has not been properly cleaned up. Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2015-05-22 17:25:18 +02:00
if (ret)
goto done;
}
usb: gadget: ffs: fix: Always call ffs_closed() in ffs_data_clear() Originally FFS_FL_CALL_CLOSED_CALLBACK flag has been used to indicate if we should call ffs_closed_callback(). Commit 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") changed its semantic to indicate if we should call ffs_closed() function which does a little bit more. This situation leads to: [ 122.362269] ------------[ cut here ]------------ [ 122.362287] WARNING: CPU: 2 PID: 2384 at drivers/usb/gadget/function/f_fs.c:3417 ffs_ep0_write+0x730/0x810 [usb_f_fs]() [ 122.362292] Modules linked in: [ 122.362555] CPU: 2 PID: 2384 Comm: adbd Tainted: G W 4.1.0-0.rc4.git0.1.1.fc22.i686 #1 [ 122.362561] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 07/25/2014 [ 122.362567] c0d1f947 415badfa 00000000 d1029e64 c0a86e54 00000000 d1029e94 c045b937 [ 122.362584] c0c37f94 00000002 00000950 f9b313d4 00000d59 f9b2ebf0 f9b2ebf0 fffffff0 [ 122.362600] 00000003 deb53d00 d1029ea4 c045ba42 00000009 00000000 d1029f08 f9b2ebf0 [ 122.362617] Call Trace: [ 122.362633] [<c0a86e54>] dump_stack+0x41/0x52 [ 122.362645] [<c045b937>] warn_slowpath_common+0x87/0xc0 [ 122.362658] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362668] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362678] [<c045ba42>] warn_slowpath_null+0x22/0x30 [ 122.362689] [<f9b2ebf0>] ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362702] [<f9b2e4c0>] ? ffs_ep0_read+0x380/0x380 [usb_f_fs] [ 122.362712] [<c05a1c1f>] __vfs_write+0x2f/0x100 [ 122.362722] [<c05a42f2>] ? __sb_start_write+0x52/0x110 [ 122.362731] [<c05a2534>] vfs_write+0x94/0x1b0 [ 122.362740] [<c0a8a1c0>] ? mutex_lock+0x10/0x30 [ 122.362749] [<c05a2f41>] SyS_write+0x51/0xb0 [ 122.362759] [<c0a8c71f>] sysenter_do_call+0x12/0x12 [ 122.362766] ---[ end trace 0673d3467cecf8db ]--- in some cases (reproduction path below). This commit get back semantic of that flag and ensures that ffs_closed() is called always when needed but ffs_closed_callback() is called only if this flag is set. Reproduction path: Compile kernel without any UDC driver or bound some gadget to existing one and then: $ modprobe g_ffs $ mount none -t functionfs mount_point $ ffs-example mount_point This will fail with -ENODEV as there is no udc. $ ffs-example mount_point This will fail with -EBUSY because ffs_data has not been properly cleaned up. Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2015-05-22 17:25:18 +02:00
set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
done:
ffs_dev_unlock();
return ret;
}
static void ffs_closed(struct ffs_data *ffs)
{
struct ffs_dev *ffs_obj;
struct f_fs_opts *opts;
usb: gadget: f_fs: Fix possibe deadlock When system try to close /dev/usb-ffs/adb/ep0 on one core, at the same time another core try to attach new UDC, which will cause deadlock as below scenario. Thus we should release ffs lock before issuing unregister_gadget_item(). [ 52.642225] c1 ====================================================== [ 52.642228] c1 [ INFO: possible circular locking dependency detected ] [ 52.642236] c1 4.4.6+ #1 Tainted: G W O [ 52.642241] c1 ------------------------------------------------------- [ 52.642245] c1 usb ffs open/2808 is trying to acquire lock: [ 52.642270] c0 (udc_lock){+.+.+.}, at: [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642272] c1 but task is already holding lock: [ 52.642283] c0 (ffs_lock){+.+.+.}, at: [<ffffffc00066b244>] ffs_data_clear+0x30/0x140 [ 52.642285] c1 which lock already depends on the new lock. [ 52.642287] c1 the existing dependency chain (in reverse order) is: [ 52.642295] c0 -> #1 (ffs_lock){+.+.+.}: [ 52.642307] c0 [<ffffffc00012340c>] __lock_acquire+0x20f0/0x2238 [ 52.642314] c0 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642322] c0 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642328] c0 [<ffffffc00066f7bc>] ffs_func_bind+0x504/0x6e8 [ 52.642334] c0 [<ffffffc000654004>] usb_add_function+0x84/0x184 [ 52.642340] c0 [<ffffffc000658ca4>] configfs_composite_bind+0x264/0x39c [ 52.642346] c0 [<ffffffc00065b348>] udc_bind_to_driver+0x58/0x11c [ 52.642352] c0 [<ffffffc00065b49c>] usb_udc_attach_driver+0x90/0xc8 [ 52.642358] c0 [<ffffffc0006598e0>] gadget_dev_desc_UDC_store+0xd4/0x128 [ 52.642369] c0 [<ffffffc0002c14e8>] configfs_write_file+0xd0/0x13c [ 52.642376] c0 [<ffffffc00023c054>] vfs_write+0xb8/0x214 [ 52.642381] c0 [<ffffffc00023cad4>] SyS_write+0x54/0xb0 [ 52.642388] c0 [<ffffffc000085ff0>] el0_svc_naked+0x24/0x28 [ 52.642395] c0 -> #0 (udc_lock){+.+.+.}: [ 52.642401] c0 [<ffffffc00011e3d0>] print_circular_bug+0x84/0x2e4 [ 52.642407] c0 [<ffffffc000123454>] __lock_acquire+0x2138/0x2238 [ 52.642412] c0 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642420] c0 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642427] c0 [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642432] c0 [<ffffffc00065995c>] unregister_gadget_item+0x28/0x44 [ 52.642439] c0 [<ffffffc00066b34c>] ffs_data_clear+0x138/0x140 [ 52.642444] c0 [<ffffffc00066b374>] ffs_data_reset+0x20/0x6c [ 52.642450] c0 [<ffffffc00066efd0>] ffs_data_closed+0xac/0x12c [ 52.642454] c0 [<ffffffc00066f070>] ffs_ep0_release+0x20/0x2c [ 52.642460] c0 [<ffffffc00023dbe4>] __fput+0xb0/0x1f4 [ 52.642466] c0 [<ffffffc00023dd9c>] ____fput+0x20/0x2c [ 52.642473] c0 [<ffffffc0000ee944>] task_work_run+0xb4/0xe8 [ 52.642482] c0 [<ffffffc0000cd45c>] do_exit+0x360/0xb9c [ 52.642487] c0 [<ffffffc0000cf228>] do_group_exit+0x4c/0xb0 [ 52.642494] c0 [<ffffffc0000dd3c8>] get_signal+0x380/0x89c [ 52.642501] c0 [<ffffffc00008a8f0>] do_signal+0x154/0x518 [ 52.642507] c0 [<ffffffc00008af00>] do_notify_resume+0x70/0x78 [ 52.642512] c0 [<ffffffc000085ee8>] work_pending+0x1c/0x20 [ 52.642514] c1 other info that might help us debug this: [ 52.642517] c1 Possible unsafe locking scenario: [ 52.642518] c1 CPU0 CPU1 [ 52.642520] c1 ---- ---- [ 52.642525] c0 lock(ffs_lock); [ 52.642529] c0 lock(udc_lock); [ 52.642533] c0 lock(ffs_lock); [ 52.642537] c0 lock(udc_lock); [ 52.642539] c1 *** DEADLOCK *** [ 52.642543] c1 1 lock held by usb ffs open/2808: [ 52.642555] c0 #0: (ffs_lock){+.+.+.}, at: [<ffffffc00066b244>] ffs_data_clear+0x30/0x140 [ 52.642557] c1 stack backtrace: [ 52.642563] c1 CPU: 1 PID: 2808 Comm: usb ffs open Tainted: G [ 52.642565] c1 Hardware name: Spreadtrum SP9860g Board (DT) [ 52.642568] c1 Call trace: [ 52.642573] c1 [<ffffffc00008b430>] dump_backtrace+0x0/0x170 [ 52.642577] c1 [<ffffffc00008b5c0>] show_stack+0x20/0x28 [ 52.642583] c1 [<ffffffc000422694>] dump_stack+0xa8/0xe0 [ 52.642587] c1 [<ffffffc00011e548>] print_circular_bug+0x1fc/0x2e4 [ 52.642591] c1 [<ffffffc000123454>] __lock_acquire+0x2138/0x2238 [ 52.642595] c1 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642599] c1 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642604] c1 [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642608] c1 [<ffffffc00065995c>] unregister_gadget_item+0x28/0x44 [ 52.642613] c1 [<ffffffc00066b34c>] ffs_data_clear+0x138/0x140 [ 52.642618] c1 [<ffffffc00066b374>] ffs_data_reset+0x20/0x6c [ 52.642621] c1 [<ffffffc00066efd0>] ffs_data_closed+0xac/0x12c [ 52.642625] c1 [<ffffffc00066f070>] ffs_ep0_release+0x20/0x2c [ 52.642629] c1 [<ffffffc00023dbe4>] __fput+0xb0/0x1f4 [ 52.642633] c1 [<ffffffc00023dd9c>] ____fput+0x20/0x2c [ 52.642636] c1 [<ffffffc0000ee944>] task_work_run+0xb4/0xe8 [ 52.642640] c1 [<ffffffc0000cd45c>] do_exit+0x360/0xb9c [ 52.642644] c1 [<ffffffc0000cf228>] do_group_exit+0x4c/0xb0 [ 52.642647] c1 [<ffffffc0000dd3c8>] get_signal+0x380/0x89c [ 52.642651] c1 [<ffffffc00008a8f0>] do_signal+0x154/0x518 [ 52.642656] c1 [<ffffffc00008af00>] do_notify_resume+0x70/0x78 [ 52.642659] c1 [<ffffffc000085ee8>] work_pending+0x1c/0x20 Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2016-12-08 19:55:22 +08:00
struct config_item *ci;
ffs_dev_lock();
ffs_obj = ffs->private_data;
if (!ffs_obj)
goto done;
ffs_obj->desc_ready = false;
usb: gadget: ffs: fix: Always call ffs_closed() in ffs_data_clear() Originally FFS_FL_CALL_CLOSED_CALLBACK flag has been used to indicate if we should call ffs_closed_callback(). Commit 4b187fceec3c ("usb: gadget: FunctionFS: add devices management code") changed its semantic to indicate if we should call ffs_closed() function which does a little bit more. This situation leads to: [ 122.362269] ------------[ cut here ]------------ [ 122.362287] WARNING: CPU: 2 PID: 2384 at drivers/usb/gadget/function/f_fs.c:3417 ffs_ep0_write+0x730/0x810 [usb_f_fs]() [ 122.362292] Modules linked in: [ 122.362555] CPU: 2 PID: 2384 Comm: adbd Tainted: G W 4.1.0-0.rc4.git0.1.1.fc22.i686 #1 [ 122.362561] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 07/25/2014 [ 122.362567] c0d1f947 415badfa 00000000 d1029e64 c0a86e54 00000000 d1029e94 c045b937 [ 122.362584] c0c37f94 00000002 00000950 f9b313d4 00000d59 f9b2ebf0 f9b2ebf0 fffffff0 [ 122.362600] 00000003 deb53d00 d1029ea4 c045ba42 00000009 00000000 d1029f08 f9b2ebf0 [ 122.362617] Call Trace: [ 122.362633] [<c0a86e54>] dump_stack+0x41/0x52 [ 122.362645] [<c045b937>] warn_slowpath_common+0x87/0xc0 [ 122.362658] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362668] [<f9b2ebf0>] ? ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362678] [<c045ba42>] warn_slowpath_null+0x22/0x30 [ 122.362689] [<f9b2ebf0>] ffs_ep0_write+0x730/0x810 [usb_f_fs] [ 122.362702] [<f9b2e4c0>] ? ffs_ep0_read+0x380/0x380 [usb_f_fs] [ 122.362712] [<c05a1c1f>] __vfs_write+0x2f/0x100 [ 122.362722] [<c05a42f2>] ? __sb_start_write+0x52/0x110 [ 122.362731] [<c05a2534>] vfs_write+0x94/0x1b0 [ 122.362740] [<c0a8a1c0>] ? mutex_lock+0x10/0x30 [ 122.362749] [<c05a2f41>] SyS_write+0x51/0xb0 [ 122.362759] [<c0a8c71f>] sysenter_do_call+0x12/0x12 [ 122.362766] ---[ end trace 0673d3467cecf8db ]--- in some cases (reproduction path below). This commit get back semantic of that flag and ensures that ffs_closed() is called always when needed but ffs_closed_callback() is called only if this flag is set. Reproduction path: Compile kernel without any UDC driver or bound some gadget to existing one and then: $ modprobe g_ffs $ mount none -t functionfs mount_point $ ffs-example mount_point This will fail with -ENODEV as there is no udc. $ ffs-example mount_point This will fail with -EBUSY because ffs_data has not been properly cleaned up. Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
2015-05-22 17:25:18 +02:00
if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
ffs_obj->ffs_closed_callback)
ffs_obj->ffs_closed_callback(ffs);
if (ffs_obj->opts)
opts = ffs_obj->opts;
else
goto done;
if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
|| !kref_read(&opts->func_inst.group.cg_item.ci_kref))
goto done;
usb: gadget: f_fs: Fix possibe deadlock When system try to close /dev/usb-ffs/adb/ep0 on one core, at the same time another core try to attach new UDC, which will cause deadlock as below scenario. Thus we should release ffs lock before issuing unregister_gadget_item(). [ 52.642225] c1 ====================================================== [ 52.642228] c1 [ INFO: possible circular locking dependency detected ] [ 52.642236] c1 4.4.6+ #1 Tainted: G W O [ 52.642241] c1 ------------------------------------------------------- [ 52.642245] c1 usb ffs open/2808 is trying to acquire lock: [ 52.642270] c0 (udc_lock){+.+.+.}, at: [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642272] c1 but task is already holding lock: [ 52.642283] c0 (ffs_lock){+.+.+.}, at: [<ffffffc00066b244>] ffs_data_clear+0x30/0x140 [ 52.642285] c1 which lock already depends on the new lock. [ 52.642287] c1 the existing dependency chain (in reverse order) is: [ 52.642295] c0 -> #1 (ffs_lock){+.+.+.}: [ 52.642307] c0 [<ffffffc00012340c>] __lock_acquire+0x20f0/0x2238 [ 52.642314] c0 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642322] c0 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642328] c0 [<ffffffc00066f7bc>] ffs_func_bind+0x504/0x6e8 [ 52.642334] c0 [<ffffffc000654004>] usb_add_function+0x84/0x184 [ 52.642340] c0 [<ffffffc000658ca4>] configfs_composite_bind+0x264/0x39c [ 52.642346] c0 [<ffffffc00065b348>] udc_bind_to_driver+0x58/0x11c [ 52.642352] c0 [<ffffffc00065b49c>] usb_udc_attach_driver+0x90/0xc8 [ 52.642358] c0 [<ffffffc0006598e0>] gadget_dev_desc_UDC_store+0xd4/0x128 [ 52.642369] c0 [<ffffffc0002c14e8>] configfs_write_file+0xd0/0x13c [ 52.642376] c0 [<ffffffc00023c054>] vfs_write+0xb8/0x214 [ 52.642381] c0 [<ffffffc00023cad4>] SyS_write+0x54/0xb0 [ 52.642388] c0 [<ffffffc000085ff0>] el0_svc_naked+0x24/0x28 [ 52.642395] c0 -> #0 (udc_lock){+.+.+.}: [ 52.642401] c0 [<ffffffc00011e3d0>] print_circular_bug+0x84/0x2e4 [ 52.642407] c0 [<ffffffc000123454>] __lock_acquire+0x2138/0x2238 [ 52.642412] c0 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642420] c0 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642427] c0 [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642432] c0 [<ffffffc00065995c>] unregister_gadget_item+0x28/0x44 [ 52.642439] c0 [<ffffffc00066b34c>] ffs_data_clear+0x138/0x140 [ 52.642444] c0 [<ffffffc00066b374>] ffs_data_reset+0x20/0x6c [ 52.642450] c0 [<ffffffc00066efd0>] ffs_data_closed+0xac/0x12c [ 52.642454] c0 [<ffffffc00066f070>] ffs_ep0_release+0x20/0x2c [ 52.642460] c0 [<ffffffc00023dbe4>] __fput+0xb0/0x1f4 [ 52.642466] c0 [<ffffffc00023dd9c>] ____fput+0x20/0x2c [ 52.642473] c0 [<ffffffc0000ee944>] task_work_run+0xb4/0xe8 [ 52.642482] c0 [<ffffffc0000cd45c>] do_exit+0x360/0xb9c [ 52.642487] c0 [<ffffffc0000cf228>] do_group_exit+0x4c/0xb0 [ 52.642494] c0 [<ffffffc0000dd3c8>] get_signal+0x380/0x89c [ 52.642501] c0 [<ffffffc00008a8f0>] do_signal+0x154/0x518 [ 52.642507] c0 [<ffffffc00008af00>] do_notify_resume+0x70/0x78 [ 52.642512] c0 [<ffffffc000085ee8>] work_pending+0x1c/0x20 [ 52.642514] c1 other info that might help us debug this: [ 52.642517] c1 Possible unsafe locking scenario: [ 52.642518] c1 CPU0 CPU1 [ 52.642520] c1 ---- ---- [ 52.642525] c0 lock(ffs_lock); [ 52.642529] c0 lock(udc_lock); [ 52.642533] c0 lock(ffs_lock); [ 52.642537] c0 lock(udc_lock); [ 52.642539] c1 *** DEADLOCK *** [ 52.642543] c1 1 lock held by usb ffs open/2808: [ 52.642555] c0 #0: (ffs_lock){+.+.+.}, at: [<ffffffc00066b244>] ffs_data_clear+0x30/0x140 [ 52.642557] c1 stack backtrace: [ 52.642563] c1 CPU: 1 PID: 2808 Comm: usb ffs open Tainted: G [ 52.642565] c1 Hardware name: Spreadtrum SP9860g Board (DT) [ 52.642568] c1 Call trace: [ 52.642573] c1 [<ffffffc00008b430>] dump_backtrace+0x0/0x170 [ 52.642577] c1 [<ffffffc00008b5c0>] show_stack+0x20/0x28 [ 52.642583] c1 [<ffffffc000422694>] dump_stack+0xa8/0xe0 [ 52.642587] c1 [<ffffffc00011e548>] print_circular_bug+0x1fc/0x2e4 [ 52.642591] c1 [<ffffffc000123454>] __lock_acquire+0x2138/0x2238 [ 52.642595] c1 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642599] c1 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642604] c1 [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642608] c1 [<ffffffc00065995c>] unregister_gadget_item+0x28/0x44 [ 52.642613] c1 [<ffffffc00066b34c>] ffs_data_clear+0x138/0x140 [ 52.642618] c1 [<ffffffc00066b374>] ffs_data_reset+0x20/0x6c [ 52.642621] c1 [<ffffffc00066efd0>] ffs_data_closed+0xac/0x12c [ 52.642625] c1 [<ffffffc00066f070>] ffs_ep0_release+0x20/0x2c [ 52.642629] c1 [<ffffffc00023dbe4>] __fput+0xb0/0x1f4 [ 52.642633] c1 [<ffffffc00023dd9c>] ____fput+0x20/0x2c [ 52.642636] c1 [<ffffffc0000ee944>] task_work_run+0xb4/0xe8 [ 52.642640] c1 [<ffffffc0000cd45c>] do_exit+0x360/0xb9c [ 52.642644] c1 [<ffffffc0000cf228>] do_group_exit+0x4c/0xb0 [ 52.642647] c1 [<ffffffc0000dd3c8>] get_signal+0x380/0x89c [ 52.642651] c1 [<ffffffc00008a8f0>] do_signal+0x154/0x518 [ 52.642656] c1 [<ffffffc00008af00>] do_notify_resume+0x70/0x78 [ 52.642659] c1 [<ffffffc000085ee8>] work_pending+0x1c/0x20 Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2016-12-08 19:55:22 +08:00
ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
ffs_dev_unlock();
if (test_bit(FFS_FL_BOUND, &ffs->flags))
unregister_gadget_item(ci);
usb: gadget: f_fs: Fix possibe deadlock When system try to close /dev/usb-ffs/adb/ep0 on one core, at the same time another core try to attach new UDC, which will cause deadlock as below scenario. Thus we should release ffs lock before issuing unregister_gadget_item(). [ 52.642225] c1 ====================================================== [ 52.642228] c1 [ INFO: possible circular locking dependency detected ] [ 52.642236] c1 4.4.6+ #1 Tainted: G W O [ 52.642241] c1 ------------------------------------------------------- [ 52.642245] c1 usb ffs open/2808 is trying to acquire lock: [ 52.642270] c0 (udc_lock){+.+.+.}, at: [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642272] c1 but task is already holding lock: [ 52.642283] c0 (ffs_lock){+.+.+.}, at: [<ffffffc00066b244>] ffs_data_clear+0x30/0x140 [ 52.642285] c1 which lock already depends on the new lock. [ 52.642287] c1 the existing dependency chain (in reverse order) is: [ 52.642295] c0 -> #1 (ffs_lock){+.+.+.}: [ 52.642307] c0 [<ffffffc00012340c>] __lock_acquire+0x20f0/0x2238 [ 52.642314] c0 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642322] c0 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642328] c0 [<ffffffc00066f7bc>] ffs_func_bind+0x504/0x6e8 [ 52.642334] c0 [<ffffffc000654004>] usb_add_function+0x84/0x184 [ 52.642340] c0 [<ffffffc000658ca4>] configfs_composite_bind+0x264/0x39c [ 52.642346] c0 [<ffffffc00065b348>] udc_bind_to_driver+0x58/0x11c [ 52.642352] c0 [<ffffffc00065b49c>] usb_udc_attach_driver+0x90/0xc8 [ 52.642358] c0 [<ffffffc0006598e0>] gadget_dev_desc_UDC_store+0xd4/0x128 [ 52.642369] c0 [<ffffffc0002c14e8>] configfs_write_file+0xd0/0x13c [ 52.642376] c0 [<ffffffc00023c054>] vfs_write+0xb8/0x214 [ 52.642381] c0 [<ffffffc00023cad4>] SyS_write+0x54/0xb0 [ 52.642388] c0 [<ffffffc000085ff0>] el0_svc_naked+0x24/0x28 [ 52.642395] c0 -> #0 (udc_lock){+.+.+.}: [ 52.642401] c0 [<ffffffc00011e3d0>] print_circular_bug+0x84/0x2e4 [ 52.642407] c0 [<ffffffc000123454>] __lock_acquire+0x2138/0x2238 [ 52.642412] c0 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642420] c0 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642427] c0 [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642432] c0 [<ffffffc00065995c>] unregister_gadget_item+0x28/0x44 [ 52.642439] c0 [<ffffffc00066b34c>] ffs_data_clear+0x138/0x140 [ 52.642444] c0 [<ffffffc00066b374>] ffs_data_reset+0x20/0x6c [ 52.642450] c0 [<ffffffc00066efd0>] ffs_data_closed+0xac/0x12c [ 52.642454] c0 [<ffffffc00066f070>] ffs_ep0_release+0x20/0x2c [ 52.642460] c0 [<ffffffc00023dbe4>] __fput+0xb0/0x1f4 [ 52.642466] c0 [<ffffffc00023dd9c>] ____fput+0x20/0x2c [ 52.642473] c0 [<ffffffc0000ee944>] task_work_run+0xb4/0xe8 [ 52.642482] c0 [<ffffffc0000cd45c>] do_exit+0x360/0xb9c [ 52.642487] c0 [<ffffffc0000cf228>] do_group_exit+0x4c/0xb0 [ 52.642494] c0 [<ffffffc0000dd3c8>] get_signal+0x380/0x89c [ 52.642501] c0 [<ffffffc00008a8f0>] do_signal+0x154/0x518 [ 52.642507] c0 [<ffffffc00008af00>] do_notify_resume+0x70/0x78 [ 52.642512] c0 [<ffffffc000085ee8>] work_pending+0x1c/0x20 [ 52.642514] c1 other info that might help us debug this: [ 52.642517] c1 Possible unsafe locking scenario: [ 52.642518] c1 CPU0 CPU1 [ 52.642520] c1 ---- ---- [ 52.642525] c0 lock(ffs_lock); [ 52.642529] c0 lock(udc_lock); [ 52.642533] c0 lock(ffs_lock); [ 52.642537] c0 lock(udc_lock); [ 52.642539] c1 *** DEADLOCK *** [ 52.642543] c1 1 lock held by usb ffs open/2808: [ 52.642555] c0 #0: (ffs_lock){+.+.+.}, at: [<ffffffc00066b244>] ffs_data_clear+0x30/0x140 [ 52.642557] c1 stack backtrace: [ 52.642563] c1 CPU: 1 PID: 2808 Comm: usb ffs open Tainted: G [ 52.642565] c1 Hardware name: Spreadtrum SP9860g Board (DT) [ 52.642568] c1 Call trace: [ 52.642573] c1 [<ffffffc00008b430>] dump_backtrace+0x0/0x170 [ 52.642577] c1 [<ffffffc00008b5c0>] show_stack+0x20/0x28 [ 52.642583] c1 [<ffffffc000422694>] dump_stack+0xa8/0xe0 [ 52.642587] c1 [<ffffffc00011e548>] print_circular_bug+0x1fc/0x2e4 [ 52.642591] c1 [<ffffffc000123454>] __lock_acquire+0x2138/0x2238 [ 52.642595] c1 [<ffffffc000123b54>] lock_acquire+0xe4/0x298 [ 52.642599] c1 [<ffffffc000aaf6e8>] mutex_lock_nested+0x7c/0x3cc [ 52.642604] c1 [<ffffffc00065aeec>] usb_gadget_unregister_driver+0x3c/0xc8 [ 52.642608] c1 [<ffffffc00065995c>] unregister_gadget_item+0x28/0x44 [ 52.642613] c1 [<ffffffc00066b34c>] ffs_data_clear+0x138/0x140 [ 52.642618] c1 [<ffffffc00066b374>] ffs_data_reset+0x20/0x6c [ 52.642621] c1 [<ffffffc00066efd0>] ffs_data_closed+0xac/0x12c [ 52.642625] c1 [<ffffffc00066f070>] ffs_ep0_release+0x20/0x2c [ 52.642629] c1 [<ffffffc00023dbe4>] __fput+0xb0/0x1f4 [ 52.642633] c1 [<ffffffc00023dd9c>] ____fput+0x20/0x2c [ 52.642636] c1 [<ffffffc0000ee944>] task_work_run+0xb4/0xe8 [ 52.642640] c1 [<ffffffc0000cd45c>] do_exit+0x360/0xb9c [ 52.642644] c1 [<ffffffc0000cf228>] do_group_exit+0x4c/0xb0 [ 52.642647] c1 [<ffffffc0000dd3c8>] get_signal+0x380/0x89c [ 52.642651] c1 [<ffffffc00008a8f0>] do_signal+0x154/0x518 [ 52.642656] c1 [<ffffffc00008af00>] do_notify_resume+0x70/0x78 [ 52.642659] c1 [<ffffffc000085ee8>] work_pending+0x1c/0x20 Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
2016-12-08 19:55:22 +08:00
return;
done:
ffs_dev_unlock();
}
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
/* Misc helper functions ****************************************************/
static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
{
return nonblock
? mutex_trylock(mutex) ? 0 : -EAGAIN
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
: mutex_lock_interruptible(mutex);
}
static char *ffs_prepare_buffer(const char __user *buf, size_t len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
{
char *data;
if (!len)
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
return NULL;
data = memdup_user(buf, len);
if (IS_ERR(data))
return data;
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
pr_vdebug("Buffer from user space:\n");
USB: f_fs: the FunctionFS driver The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). >From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-05-05 12:53:14 +02:00
ffs_dump_mem("", data, len);
return data;
}
DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
usb: gadget: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/libcomposite.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_acm.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_ss_lb.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/u_serial.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_serial.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_obex.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/u_ether.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_ncm.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_ecm.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_phonet.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_eem.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_ecm_subset.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_rndis.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_mass_storage.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_fs.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_uac1.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_uac1_legacy.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_uac2.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_uvc.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_midi.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_midi2.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_hid.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_printer.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/function/usb_f_tcm.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/legacy/g_zero.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/legacy/g_midi.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/usb/gadget/legacy/g_dbgp.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com> Link: https://lore.kernel.org/r/20240605-md-drivers-usb-gadget-v1-1-29847a46aad3@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-06-05 20:57:08 -07:00
MODULE_DESCRIPTION("user mode file system API for USB composite function controllers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Nazarewicz");