android_kernel_sony_sdm845/drivers/hid/uhid.c
Michael Bestas 81b4ee0bd4
Merge remote-tracking branch 'common/android-4.9-q' into android12-4.9-sdm845
* common/android-4.9-q:
  Linux 4.9.309
  llc: only change llc->dev when bind() succeeds
  mac80211: fix potential double free on mesh join
  crypto: qat - disable registration of algorithms
  ACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU
  ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3
  ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board
  netfilter: nf_tables: initialize registers in nft_do_chain()
  ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec
  ALSA: cmipci: Restore aux vol on suspend/resume
  ALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB
  ALSA: pcm: Add stream lock during PCM reset ioctl operations
  llc: fix netdevice reference leaks in llc_ui_bind()
  staging: fbtft: fb_st7789v: reset display before initialization
  net: ipv6: fix skb_over_panic in __ip6_append_data
  nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
  Linux 4.9.308
  Input: aiptek - properly check endpoint type
  usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
  usb: gadget: rndis: prevent integer overflow in rndis_set_response()
  atm: eni: Add check for dma_map_single
  net/packet: fix slab-out-of-bounds access in packet_recvmsg()
  fs: sysfs_emit: Remove PAGE_SIZE alignment check
  kselftest/vm: fix tests build with old libc
  sfc: extend the locking on mcdi->seqno
  tcp: make tcp_read_sock() more robust
  nl80211: Update bss channel on channel switch for P2P_CLIENT
  atm: firestream: check the return value of ioremap() in fs_init()
  can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when fully ready
  ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE
  MIPS: smp: fill in sibling and core maps earlier
  ARM: dts: rockchip: fix a typo on rk3288 crypto-controller
  xfrm: Fix xfrm migrate issues when address family changes
  Linux 4.9.307
  btrfs: unlock newly allocated extent buffer after error
  ARM: fix Thumb2 regression with Spectre BHB
  batman-adv: Don't expect inter-netns unique iflink indices
  batman-adv: Request iflink once in batadv-on-batadv check
  staging: gdm724x: fix use after free in gdm_lte_rx()
  ARM: Spectre-BHB: provide empty stub for non-config
  selftests/memfd: clean up mapping in mfd_fail_write
  tracing: Ensure trace buffer is at least 4096 bytes large
  Revert "xen-netback: Check for hotplug-status existence before watching"
  net-sysfs: add check for netdevice being present to speed_show
  sctp: fix kernel-infoleak for SCTP sockets
  gpio: ts4900: Do not set DAT and OE together
  NFC: port100: fix use-after-free in port100_send_complete
  net/mlx5: Fix size field in bufferx_reg struct
  ax25: Fix NULL pointer dereference in ax25_kill_by_device
  net: ethernet: lpc_eth: Handle error for clk_enable
  ethernet: Fix error handling in xemaclite_of_probe
  qed: return status of qed_iov_get_link
  net: qlogic: check the return value of dma_alloc_coherent() in qed_vf_hw_prepare()
  Linux 4.9.306
  xen/netfront: react properly to failing gnttab_end_foreign_access_ref()
  xen/gnttab: fix gnttab_end_foreign_access() without page specified
  xen: remove gnttab_query_foreign_access()
  xen/gntalloc: don't use gnttab_query_foreign_access()
  xen/scsifront: don't use gnttab_query_foreign_access() for mapped status
  xen/netfront: don't use gnttab_query_foreign_access() for mapped status
  xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
  xen/grant-table: add gnttab_try_end_foreign_access()
  xen/xenbus: don't let xenbus_grant_ring() remove grants in error case
  ARM: fix build warning in proc-v7-bugs.c
  x86, modpost: Replace last remnants of RETPOLINE with CONFIG_RETPOLINE
  x86/build: Fix compiler support check for CONFIG_RETPOLINE
  ARM: Do not use NOCROSSREFS directive with ld.lld
  ARM: fix co-processor register typo
  ARM: fix build error when BPF_SYSCALL is disabled
  ARM: include unprivileged BPF status in Spectre V2 reporting
  ARM: Spectre-BHB workaround
  ARM: use LOADADDR() to get load address of sections
  ARM: early traps initialisation
  ARM: report Spectre v2 status through sysfs
  arm/arm64: smccc/psci: add arm_smccc_1_1_get_conduit()
  arm/arm64: Provide a wrapper for SMCCC 1.1 calls
  x86/speculation: Warn about eIBRS + LFENCE + Unprivileged eBPF + SMT
  x86/speculation: Warn about Spectre v2 LFENCE mitigation
  x86/speculation: Update link to AMD speculation whitepaper
  x86/speculation: Use generic retpoline by default on AMD
  x86/speculation: Include unprivileged eBPF status in Spectre v2 mitigation reporting
  Documentation/hw-vuln: Update spectre doc
  x86/speculation: Add eIBRS + Retpoline options
  x86/speculation: Rename RETPOLINE_AMD to RETPOLINE_LFENCE
  x86,bugs: Unconditionally allow spectre_v2=retpoline,amd
  x86/speculation: Merge one test in spectre_v2_user_select_mitigation()
  Documentation: refer to config RANDOMIZE_BASE for kernel address-space randomization
  Documentation: Add swapgs description to the Spectre v1 documentation
  Documentation: Add section about CPU vulnerabilities for Spectre
  x86/retpoline: Remove minimal retpoline support
  x86/retpoline: Make CONFIG_RETPOLINE depend on compiler support
  x86/speculation: Add RETPOLINE_AMD support to the inline asm CALL_NOSPEC variant
  Linux 4.9.305
  hamradio: fix macro redefine warning
  net: dcb: disable softirqs in dcbnl_flush_dev()
  memfd: fix F_SEAL_WRITE after shmem huge page allocated
  HID: add mapping for KEY_ALL_APPLICATIONS
  Input: elan_i2c - fix regulator enable count imbalance after suspend/resume
  Input: elan_i2c - move regulator_[en|dis]able() out of elan_[en|dis]able_power()
  net: chelsio: cxgb3: check the return value of pci_find_capability()
  soc: fsl: qe: Check of ioremap return value
  ARM: 9182/1: mmu: fix returns from early_param() and __setup() functions
  can: gs_usb: change active_channels's type from atomic_t to u8
  efivars: Respect "block" flag in efivar_entry_set_safe()
  net: arcnet: com20020: Fix null-ptr-deref in com20020pci_probe()
  net: sxgbe: fix return value of __setup handler
  net: stmmac: fix return value of __setup handler
  mac80211: fix forwarded mesh frames AC & queue selection
  firmware: qemu_fw_cfg: fix kobject leak in probe error path
  firmware: Fix a reference count leak.
  net: dcb: flush lingering app table entries for unregistered devices
  netfilter: nf_queue: fix possible use-after-free
  netfilter: nf_queue: don't assume sk is full socket
  xfrm: fix MTU regression
  ASoC: ops: Shift tested values in snd_soc_put_volsw() by +min
  ata: pata_hpt37x: fix PCI clock detection
  usb: gadget: clear related members when goto fail
  usb: gadget: don't release an existing dev->buf
  net: usb: cdc_mbim: avoid altsetting toggling for Telit FN990
  i2c: qup: allow COMPILE_TEST
  dmaengine: shdma: Fix runtime PM imbalance on error
  cifs: fix double free race when mount fails in cifs_get_root()
  Input: clear BTN_RIGHT/MIDDLE on buttonpads
  i2c: bcm2835: Avoid clock stretching timeouts
  mac80211_hwsim: initialize ieee80211_tx_info at hw_scan_work
  mac80211_hwsim: report NOACK frames in tx_status
  Linux 4.9.304
  fget: clarify and improve __fget_files() implementation
  memblock: use kfree() to release kmalloced memblock regions
  tty: n_gsm: fix proper link termination after failed open
  tty: n_gsm: fix encoding of control signal octet bit DV
  xhci: Prevent futile URB re-submissions due to incorrect return value.
  usb: dwc3: gadget: Let the interrupt handler disable bottom halves.
  USB: serial: option: add Telit LE910R1 compositions
  USB: serial: option: add support for DW5829e
  tracefs: Set the group ownership in apply_options() not parse_options()
  USB: gadget: validate endpoint index for xilinx udc
  usb: gadget: rndis: add spinlock for rndis response list
  Revert "USB: serial: ch341: add new Product ID for CH341A"
  ata: pata_hpt37x: disable primary channel on HPT371
  iio: adc: men_z188_adc: Fix a resource leak in an error handling path
  RDMA/ib_srp: Fix a deadlock
  configfs: fix a race in configfs_{,un}register_subsystem()
  net/mlx5e: Fix wrong return value on ioctl EEPROM query failure
  drm/edid: Always set RGB444
  openvswitch: Fix setting ipv6 fields causing hw csum failure
  gso: do not skip outer ip header in case of ipip and net_failover
  net: __pskb_pull_tail() & pskb_carve_frag_list() drop_monitor friends
  serial: 8250: of: Fix mapped region size when using reg-offset property
  serial: 8250: fix error handling in of_platform_serial_probe()
  USB: zaurus: support another broken Zaurus
  sr9700: sanity check for packet length
  parisc/unaligned: Fix ldw() and stw() unalignment handlers
  parisc/unaligned: Fix fldd and fstd unaligned handlers on 32-bit kernel
  vhost/vsock: don't check owner in vhost_vsock_stop() while releasing
  mtd: rawnand: brcmnand: Fixed incorrect sub-page ECC status
  Linux 4.9.303
  net: usb: qmi_wwan: Add support for Dell DW5829e
  tracing: Fix tp_printk option related with tp_printk_stop_on_boot
  ata: libata-core: Disable TRIM on M88V29
  NFS: Do not report writeback errors in nfs_getattr()
  KVM: x86/pmu: Use AMD64_RAW_EVENT_MASK for PERF_TYPE_RAW
  lib/iov_iter: initialize "flags" in new pipe_buffer
  i2c: brcmstb: fix support for DSL and CM variants
  EDAC: Fix calculation of returned address and next offset in edac_align_ptr()
  NFS: LOOKUP_DIRECTORY is also ok with symlinks
  ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw_range()
  ASoC: ops: Fix stereo change notifications in snd_soc_put_volsw()
  ALSA: hda: Fix missing codec probe on Shenker Dock 15
  ALSA: hda: Fix regression on forced probe mask option
  libsubcmd: Fix use-after-free for realloc(..., 0)
  drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit
  iwlwifi: pcie: fix locking when "HW not ready"
  vsock: remove vsock from connected table when connect is interrupted by a signal
  vsock: correct removal of socket from the list
  taskstats: Cleanup the use of task->exit_code
  xfrm: Don't accidentally set RTO_ONLINK in decode_session4()
  drm/radeon: Fix backlight control on iMac 12,1
  quota: make dquot_quota_sync return errors from ->sync_fs
  vfs: make freeze_super abort when sync_filesystem returns error
  ax25: improve the incomplete fix to avoid UAF and NPD bugs
  selftests/zram: Adapt the situation that /dev/zram0 is being used
  selftests/zram01.sh: Fix compression ratio calculation
  selftests/zram: Skip max_comp_streams interface on newer kernel
  net: ieee802154: at86rf230: Stop leaking skb's
  btrfs: send: in case of IO error log it
  parisc: Fix sglist access in ccio-dma.c
  parisc: Fix data TLB miss in sba_unmap_sg
  serial: parisc: GSC: fix build when IOSAPIC is not set
  net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
  Makefile.extrawarn: Move -Wunaligned-access to W=1
  UPSTREAM: net: fix skb_panic to output real address
  UPSTREAM: xfrm: Make function xfrmi_get_link_net() static
  UPSTREAM: xfrm: fix gro_cells leak when remove virtual xfrm interfaces
  UPSTREAM: xfrm interface: fix memory leak on creation
  UPSTREAM: xfrm: clone XFRMA_SET_MARK in xfrm_do_migrate
  UPSTREAM: xfrm/compat: Translate by copying XFRMA_UNSPEC attribute
  UPSTREAM: xfrm/compat: memset(0) 64-bit padding at right place
  UPSTREAM: xfrm/compat: Don't allocate memory with __GFP_ZERO
  UPSTREAM: xfrm/compat: Cleanup WARN()s that can be user-triggered
  UPSTREAM: net: xfrm: fix memory leak in xfrm_user_rcv_msg
  UPSTREAM: arm64/vdso: don't leak kernel addresses
  UPSTREAM: tracing: make PREEMPTIRQ_EVENTS depend on TRACING
  UPSTREAM: trace_uprobe: Use %lx to display offset
  UPSTREAM: kprobes: Fix random address output of blacklist file
  UPSTREAM: mm/huge_memory.c: __split_huge_page() use atomic ClearPageDirty()
  UPSTREAM: x86/realmode: Don't leak the trampoline kernel address
  UPSTREAM: bpf: bpf_prog_array_alloc() should return a generic non-rcu pointer
  UPSTREAM: bpf: fix rcu annotations in compute_effective_progs()
  UPSTREAM: optee: add writeback to valid memory type
  UPSTREAM: lib/test_printf.c: accept "ptrval" as valid result for plain 'p' tests
  UPSTREAM: kdb: use correct pointer when 'btc' calls 'btt'
  UPSTREAM: kdb: print real address of pointers instead of hashed addresses
  UPSTREAM: powerpc/traps: Fix the message printed when stack overflows
  UPSTREAM: f2fs: should use GFP_NOFS for directory inodes
  UPSTREAM: zram: off by one in read_block_state()
  UPSTREAM: tee: fix put order in teedev_close_context()
  UPSTREAM: vsprintf: Replace memory barrier with static_key for random_ptr_key update
  UPSTREAM: ARM: 8896/1: VDSO: Don't leak kernel addresses
  UPSTREAM: parisc: Show unhashed hardware inventory
  UPSTREAM: parisc: Show initial kernel memory layout unhashed
  UPSTREAM: parisc: Show unhashed HPA of Dino chip
  UPSTREAM: parisc: Show unhashed EISA EEPROM address
  UPSTREAM: HID: input: throttle battery uevents
  UPSTREAM: HID: steam: select CONFIG_POWER_SUPPLY
  UPSTREAM: HID: sony: Fix for broken buttons on DS3 USB dongles
  UPSTREAM: HID: input: do not report stylus battery state as "full"
  Linux 4.9.302
  HID: wacom: add USB_HID dependency
  hwmon: (dell-smm) Speed up setting of fan speed
  USB: serial: cp210x: add CPI Bulk Coin Recycler id
  USB: serial: cp210x: add NCR Retail IO box id
  USB: serial: ch341: add support for GW Instek USB2.0-Serial devices
  USB: serial: option: add ZTE MF286D modem
  USB: serial: ftdi_sio: add support for Brainboxes US-159/235/320
  usb: gadget: rndis: check size of RNDIS_MSG_SET command
  USB: gadget: validate interface OS descriptor requests
  usb: dwc3: gadget: Prevent core from processing stale TRBs
  n_tty: wake up poll(POLLRDNORM) on receiving data
  bpf: Add kconfig knob for disabling unpriv bpf by default
  vt_ioctl: add array_index_nospec to VT_ACTIVATE
  vt_ioctl: fix array_index_nospec in vt_setactivate
  tipc: rate limit warning for received illegal binding update
  net: fix a memleak when uncloning an skb dst and its metadata
  net: do not keep the dst cache when uncloning an skb dst and its metadata
  ipmr,ip6mr: acquire RTNL before calling ip[6]mr_free_table() on failure path
  bonding: pair enable_port with slave_arr_updates
  ARM: dts: imx6qdl-udoo: Properly describe the SD card detect
  staging: fbtft: Fix error path in fbtft_driver_module_init()
  ARM: dts: imx23-evk: Remove MX23_PAD_SSP1_DETECT from hog group
  usb: dwc2: gadget: don't try to disable ep0 in dwc2_hsotg_suspend
  scsi: target: iscsi: Make sure the np under each tpg is unique
  NFSv4 remove zero number of fs_locations entries error check
  nfs: nfs4clinet: check the return value of kstrdup()
  NFSv4 only print the label when its queried
  Revert "net: axienet: Wait for PhyRstCmplt after core reset"
  ALSA: line6: Fix misplaced backport of "Fix wrong altsetting for LINE6_PODHD500_1"
  serial: sh-sci: Fix misplaced backport of "Fix late enablement of AUTORTS"
  Input: i8042 - Fix misplaced backport of "add ASUS Zenbook Flip to noselftest list"
  NFSD: Clamp WRITE offsets
  NFS: Fix initialisation of nfs_client cl_flags field
  ima: Remove ima_policy file before directory
  integrity: check the return value of audit_log_start()
  Revert "tracefs: Have tracefs directories not set OTH permission bits by default"
  Linux 4.9.301
  tipc: improve size validations for received domain records
  moxart: fix potential use-after-free on remove path
  cgroup-v1: Require capabilities to set release_agent
  Linux 4.9.300
  ext4: fix error handling in ext4_restore_inline_data()
  EDAC/xgene: Fix deferred probing
  EDAC/altera: Fix deferred probing
  rtc: cmos: Evaluate century appropriate
  nfsd: nfsd4_setclientid_confirm mistakenly expires confirmed client.
  scsi: bnx2fc: Make bnx2fc_recv_frame() mp safe
  ASoC: fsl: Add missing error handling in pcm030_fabric_probe
  net: macsec: Verify that send_sci is on when setting Tx sci explicitly
  net: ieee802154: Return meaningful error codes from the netlink helpers
  spi: mediatek: Avoid NULL pointer crash in interrupt
  spi: bcm-qspi: check for valid cs before applying chip select
  iommu/amd: Fix loop timeout issue in iommu_ga_log_enable()
  drm/nouveau: fix off by one in BIOS boundary checking
  ASoC: ops: Reject out of bounds values in snd_soc_put_xr_sx()
  ASoC: ops: Reject out of bounds values in snd_soc_put_volsw_sx()
  ASoC: ops: Reject out of bounds values in snd_soc_put_volsw()
  af_packet: fix data-race in packet_setsockopt / packet_setsockopt
  rtnetlink: make sure to refresh master_dev/m_ops in __rtnl_newlink()
  net: amd-xgbe: Fix skb data length underflow
  net: amd-xgbe: ensure to reset the tx_timer_active flag
  ipheth: fix EOVERFLOW in ipheth_rcvbulk_callback
  netfilter: nat: limit port clash resolution attempts
  netfilter: nat: remove l4 protocol port rovers
  ipv4: tcp: send zero IPID in SYNACK messages
  ipv4: raw: lock the socket in raw_bind()
  hwmon: (lm90) Reduce maximum conversion rate for G781
  drm/msm: Fix wrong size calculation
  net-procfs: show net devices bound packet types
  NFSv4: nfs_atomic_open() can race when looking up a non-regular file
  NFSv4: Handle case where the lookup of a directory fails
  ipv4: avoid using shared IP generator for connected sockets
  net: fix information leakage in /proc/net/ptype
  ipv6_tunnel: Rate limit warning messages
  scsi: bnx2fc: Flush destroy_work queue before calling bnx2fc_interface_put()
  powerpc/32: Fix boot failure with GCC latent entropy plugin
  USB: core: Fix hang in usb_kill_urb by adding memory barriers
  usb: gadget: f_sourcesink: Fix isoc transfer for USB_SPEED_SUPER_PLUS
  usb-storage: Add unusual-devs entry for VL817 USB-SATA bridge
  tty: Add support for Brainboxes UC cards.
  tty: n_gsm: fix SW flow control encoding/handling
  serial: stm32: fix software flow control transfer
  PM: wakeup: simplify the output logic of pm_show_wakelocks()
  udf: Fix NULL ptr deref when converting from inline format
  udf: Restore i_lenAlloc when inode expansion fails
  scsi: zfcp: Fix failed recovery on gone remote port with non-NPIV FCP devices
  s390/hypfs: include z/VM guests with access control group set
  Bluetooth: refactor malicious adv data check
  can: bcm: fix UAF of bcm op
  BACKPORT: ipv6: Implement draft-ietf-6man-rfc4941bis
  Linux 4.9.299
  ion: Do not 'put' ION handle until after its final use
  ion: Protect kref from userspace manipulation
  ion: Fix use after free during ION_IOC_ALLOC
  ARM: 8800/1: use choice for kernel unwinders
  KVM: X86: MMU: Use the correct inherited permissions to get shadow page
  KVM: nVMX: fix EPT permissions as reported in exit qualification
  NFSv4: Initialise connection to the server in nfs4_alloc_client()
  media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
  drm/i915: Flush TLBs before releasing backing store
  Linux 4.9.298
  KVM: do not allow mapping valid but non-reference-counted pages
  KVM: Use kvm_pfn_t for local PFN variable in hva_to_pfn_remapped()
  KVM: do not assume PTE is writable after follow_pfn
  mm: add follow_pte_pmd()
  lib/timerqueue: Rely on rbtree semantics for next timer
  rbtree: cache leftmost node internally
  cipso,calipso: resolve a number of problems with the DOI refcounts
  gianfar: fix jumbo packets+napi+rx overrun crash
  gianfar: simplify FCS handling and fix memory leak
  drm/ttm/nouveau: don't call tt destroy callback on alloc failure.
  gup: document and work around "COW can break either way" issue
  Revert "gup: document and work around "COW can break either way" issue"
  lib82596: Fix IRQ check in sni_82596_probe
  scripts/dtc: dtx_diff: remove broken example from help text
  bcmgenet: add WOL IRQ check
  net_sched: restore "mpu xxx" handling
  dmaengine: at_xdmac: Fix at_xdmac_lld struct definition
  dmaengine: at_xdmac: Fix lld view setting
  dmaengine: at_xdmac: Print debug message after realeasing the lock
  dmaengine: at_xdmac: Don't start transactions at tx_submit level
  libcxgb: Don't accidentally set RTO_ONLINK in cxgb_find_route()
  netns: add schedule point in ops_exit_list()
  net: axienet: fix number of TX ring slots for available check
  net: axienet: Wait for PhyRstCmplt after core reset
  af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
  parisc: pdc_stable: Fix memory leak in pdcs_register_pathentries
  net/fsl: xgmac_mdio: Fix incorrect iounmap when removing module
  powerpc/fsl/dts: Enable WA for erratum A-009885 on fman3l MDIO buses
  RDMA/rxe: Fix a typo in opcode name
  RDMA/hns: Modify the mapping attribute of doorbell to device
  drm/radeon: fix error handling in radeon_driver_open_kms
  fuse: fix live lock in fuse_iget()
  fuse: fix bad inode
  ext4: don't use the orphan list when migrating an inode
  ext4: Fix BUG_ON in ext4_bread when write quota data
  ext4: set csum seed in tmp inode while migrating to extents
  iwlwifi: mvm: Increase the scan timeout guard to 30 seconds
  ubifs: Error path in ubifs_remount_rw() seems to wrongly free write buffers
  power: bq25890: Enable continuous conversion for ADC at charging
  ASoC: mediatek: mt8173: fix device_node leak
  scsi: sr: Don't use GFP_DMA
  MIPS: Octeon: Fix build errors using clang
  i2c: designware-pci: Fix to change data types of hcnt and lcnt parameters
  ALSA: seq: Set upper limit of processed events
  w1: Misuse of get_user()/put_user() reported by sparse
  i2c: mpc: Correct I2C reset procedure
  powerpc/smp: Move setup_profiling_timer() under CONFIG_PROFILING
  i2c: i801: Don't silently correct invalid transfer size
  powerpc/btext: add missing of_node_put
  powerpc/cell: add missing of_node_put
  powerpc/powernv: add missing of_node_put
  powerpc/6xx: add missing of_node_put
  parisc: Avoid calling faulthandler_disabled() twice
  serial: core: Keep mctrl register state and cached copy in sync
  serial: pl010: Drop CR register reset on set_termios
  dm space map common: add bounds check to sm_ll_lookup_bitmap()
  dm btree: add a defensive bounds check to insert_at()
  net: mdio: Demote probed message to debug print
  btrfs: remove BUG_ON(!eie) in find_parent_nodes
  btrfs: remove BUG_ON() in find_parent_nodes()
  ACPICA: Executer: Fix the REFCLASS_REFOF case in acpi_ex_opcode_1A_0T_1R()
  ACPICA: Utilities: Avoid deleting the same object twice in a row
  jffs2: GC deadlock reading a page that is used in jffs2_write_begin()
  um: registers: Rename function names to avoid conflicts and build problems
  ath9k: Fix out-of-bound memcpy in ath9k_hif_usb_rx_stream
  usb: hub: Add delay for SuperSpeed hub resume to let links transit to U0
  media: saa7146: hexium_gemini: Fix a NULL pointer dereference in hexium_attach()
  media: igorplugusb: receiver overflow should be reported
  net: bonding: debug: avoid printing debug logs when bond is not notifying peers
  ath10k: Fix tx hanging
  iwlwifi: mvm: synchronize with FW after multicast commands
  media: m920x: don't use stack on USB reads
  media: saa7146: hexium_orion: Fix a NULL pointer dereference in hexium_attach()
  floppy: Add max size check for user space request
  mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
  HSI: core: Fix return freed object in hsi_new_client
  gpiolib: acpi: Do not set the IRQ type if the IRQ is already in use
  media: b2c2: Add missing check in flexcop_pci_isr:
  HID: apple: Do not reset quirks when the Fn key is not found
  usb: gadget: f_fs: Use stream_open() for endpoint files
  ar5523: Fix null-ptr-deref with unexpected WDCMSG_TARGET_START reply
  fs: dlm: filter user dlm messages for kernel locks
  Bluetooth: Fix debugfs entry leak in hci_register_dev()
  RDMA/cxgb4: Set queue pair state when being queried
  mips: bcm63xx: add support for clk_set_parent()
  mips: lantiq: add support for clk_set_parent()
  misc: lattice-ecp3-config: Fix task hung when firmware load failed
  ASoC: samsung: idma: Check of ioremap return value
  dmaengine: pxa/mmp: stop referencing config->slave_id
  RDMA/core: Let ib_find_gid() continue search even after empty entry
  scsi: ufs: Fix race conditions related to driver data
  char/mwave: Adjust io port register size
  ALSA: oss: fix compile error when OSS_DEBUG is enabled
  powerpc/prom_init: Fix improper check of prom_getprop()
  RDMA/hns: Validate the pkey index
  ALSA: hda: Add missing rwsem around snd_ctl_remove() calls
  ALSA: PCM: Add missing rwsem around snd_ctl_remove() calls
  ALSA: jack: Add missing rwsem around snd_ctl_remove() calls
  ext4: avoid trim error on fs with small groups
  net: mcs7830: handle usb read errors properly
  pcmcia: fix setting of kthread task states
  can: xilinx_can: xcan_probe(): check for error irq
  can: softing: softing_startstop(): fix set but not used variable warning
  spi: spi-meson-spifc: Add missing pm_runtime_disable() in meson_spifc_probe
  fsl/fman: Check for null pointer after calling devm_ioremap
  ppp: ensure minimum packet size in ppp_write()
  pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in nonstatic_find_mem_region()
  pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in __nonstatic_find_io_region()
  usb: ftdi-elan: fix memory leak on device disconnect
  media: msi001: fix possible null-ptr-deref in msi001_probe()
  media: si2157: Fix "warm" tuner state detection
  media: saa7146: mxb: Fix a NULL pointer dereference in mxb_attach()
  media: dib8000: Fix a memleak in dib8000_init()
  floppy: Fix hang in watchdog when disk is ejected
  serial: amba-pl011: do not request memory region twice
  drm/radeon/radeon_kms: Fix a NULL pointer dereference in radeon_driver_open_kms()
  drm/amdgpu: Fix a NULL pointer dereference in amdgpu_connector_lcd_native_mode()
  arm64: dts: qcom: msm8916: fix MMC controller aliases
  netfilter: bridge: add support for pppoe filtering
  tty: serial: atmel: Call dma_async_issue_pending()
  tty: serial: atmel: Check return code of dmaengine_submit()
  crypto: qce - fix uaf on qce_ahash_register_one
  media: dmxdev: fix UAF when dvb_register_device() fails
  Bluetooth: stop proccessing malicious adv data
  wcn36xx: Indicate beacon not connection loss on MISSED_BEACON_IND
  Bluetooth: cmtp: fix possible panic when cmtp_init_sockets() fails
  shmem: fix a race between shmem_unused_huge_shrink and shmem_evict_inode
  PCI: Add function 1 DMA alias quirk for Marvell 88SE9125 SATA controller
  can: softing_cs: softingcs_probe(): fix memleak on registration failure
  media: stk1160: fix control-message timeouts
  media: pvrusb2: fix control-message timeouts
  media: redrat3: fix control-message timeouts
  media: dib0700: fix undefined behavior in tuner shutdown
  media: s2255: fix control-message timeouts
  media: cpia2: fix control-message timeouts
  media: em28xx: fix control-message timeouts
  media: mceusb: fix control-message timeouts
  media: flexcop-usb: fix control-message timeouts
  rtc: cmos: take rtc_lock while reading from CMOS
  nfc: llcp: fix NULL error pointer dereference on sendmsg() after failed bind()
  HID: wacom: Avoid using stale array indicies to read contact count
  HID: uhid: Fix worker destroying device without any protection
  rtlwifi: rtl8192cu: Fix WARNING when calling local_irq_restore() with interrupts enabled
  media: uvcvideo: fix division by zero at stream start
  drm/i915: Avoid bitwise vs logical OR warning in snb_wm_latency_quirk()
  staging: wlan-ng: Avoid bitwise vs logical OR warning in hfa384x_usb_throttlefn()
  random: fix data race on crng init time
  random: fix data race on crng_node_pool
  can: gs_usb: gs_can_start_xmit(): zero-initialize hf->{flags,reserved}
  can: gs_usb: fix use of uninitialized variable, detach device on reception of invalid USB data
  mfd: intel-lpss: Fix too early PM enablement in the ACPI ->probe()
  USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status
  USB: core: Fix bug in resuming hub's handling of wakeup requests
  Bluetooth: bfusb: fix division by zero in send path
  Linux 4.9.297
  power: reset: ltc2952: Fix use of floating point literals
  mISDN: change function names to avoid conflicts
  net: udp: fix alignment problem in udp4_seq_show()
  ip6_vti: initialize __ip6_tnl_parm struct in vti6_siocdevprivate
  scsi: libiscsi: Fix UAF in iscsi_conn_get_param()/iscsi_conn_teardown()
  phonet: refcount leak in pep_sock_accep
  arm64: sysreg: Move to use definitions for all the SCTLR bits
  arm64: move !VHE work to end of el2_setup
  arm64: reduce el2_setup branching
  arm64: Remove a redundancy in sysreg.h
  bug: split BUILD_BUG stuff out into <linux/build_bug.h>
  rndis_host: support Hytera digital radios
  xfs: map unwritten blocks in XFS_IOC_{ALLOC,FREE}SP just like fallocate
  sch_qfq: prevent shift-out-of-bounds in qfq_init_qdisc
  i40e: Fix incorrect netdev's real number of RX/TX queues
  mac80211: initialize variable have_higher_than_11mbit
  ieee802154: atusb: fix uninit value in atusb_set_extended_addr
  virtio_pci: Support surprise removal of virtio pci device
  tracing: Tag trace_percpu_buffer as a percpu pointer
  tracing: Fix check for trace_percpu_buffer validity in get_trace_buf()
  Bluetooth: btusb: Apply QCA Rome patches for some ATH3012 models
  Linux 4.9.296
  net: fix use-after-free in tw_timer_handler
  Input: spaceball - fix parsing of movement data packets
  Input: appletouch - initialize work before device registration
  scsi: vmw_pvscsi: Set residual data length conditionally
  usb: gadget: f_fs: Clear ffs_eventfd in ffs_data_clear.
  xhci: Fresco FL1100 controller should not have BROKEN_MSI quirk set.
  uapi: fix linux/nfc.h userspace compilation errors
  nfc: uapi: use kernel size_t to fix user-space builds
  fsl/fman: Fix missing put_device() call in fman_port_probe
  selinux: initialize proto variable in selinux_ip_postroute_compat()
  recordmcount.pl: fix typo in s390 mcount regex
  platform/x86: apple-gmux: use resource_size() with res
  HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option
  Linux 4.9.295
  phonet/pep: refuse to enable an unbound pipe
  hamradio: improve the incomplete fix to avoid NPD
  hamradio: defer ax25 kfree after unregister_netdev
  ax25: NPD bug when detaching AX25 device
  hwmon: (lm90) Do not report 'busy' status bit as alarm
  ARM: 9169/1: entry: fix Thumb2 bug in iWMMXt exception handling
  x86/pkey: Fix undefined behaviour with PKRU_WD_BIT
  ALSA: drivers: opl3: Fix incorrect use of vp->state
  ALSA: jack: Check the return value of kstrdup()
  hwmon: (lm90) Fix usage of CONFIG2 register in detect function
  drivers: net: smc911x: Check for error irq
  fjes: Check for error irq
  bonding: fix ad_actor_system option setting to default
  qlcnic: potential dereference null pointer of rx_queue->page_ring
  IB/qib: Fix memory leak in qib_user_sdma_queue_pkts()
  HID: holtek: fix mouse probing
  can: kvaser_usb: get CAN clock frequency from device
  net: usb: lan78xx: add Allied Telesis AT29M2-AF

 Conflicts:
	arch/arm64/kernel/vdso.c
	drivers/media/dvb-core/dmxdev.c
	drivers/staging/android/ion/ion-ioctl.c
	drivers/staging/android/ion/ion.c
	drivers/staging/android/ion/ion.h
	drivers/staging/android/ion/ion_priv.h
	drivers/usb/gadget/function/rndis.c
	drivers/usb/gadget/function/rndis.h
	net/ipv6/ip6_output.c

Change-Id: I5132ec2ed3ff01e17e9cfbeed813098fede7f84c
2022-03-31 22:52:51 +03:00

827 lines
19 KiB
C

/*
* User-space I/O driver support for HID subsystem
* Copyright (c) 2012 David Herrmann
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/atomic.h>
#include <linux/compat.h>
#include <linux/cred.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/uhid.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/eventpoll.h>
#define UHID_NAME "uhid"
#define UHID_BUFSIZE 32
static DEFINE_MUTEX(uhid_open_mutex);
struct uhid_device {
struct mutex devlock;
/* This flag tracks whether the HID device is usable for commands from
* userspace. The flag is already set before hid_add_device(), which
* runs in workqueue context, to allow hid_add_device() to communicate
* with userspace.
* However, if hid_add_device() fails, the flag is cleared without
* holding devlock.
* We guarantee that if @running changes from true to false while you're
* holding @devlock, it's still fine to access @hid.
*/
bool running;
__u8 *rd_data;
uint rd_size;
/* When this is NULL, userspace may use UHID_CREATE/UHID_CREATE2. */
struct hid_device *hid;
struct uhid_event input_buf;
wait_queue_head_t waitq;
spinlock_t qlock;
__u8 head;
__u8 tail;
struct uhid_event *outq[UHID_BUFSIZE];
/* blocking GET_REPORT support; state changes protected by qlock */
struct mutex report_lock;
wait_queue_head_t report_wait;
bool report_running;
u32 report_id;
u32 report_type;
struct uhid_event report_buf;
struct work_struct worker;
};
static struct miscdevice uhid_misc;
static void uhid_device_add_worker(struct work_struct *work)
{
struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
int ret;
ret = hid_add_device(uhid->hid);
if (ret) {
hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
/* We used to call hid_destroy_device() here, but that's really
* messy to get right because we have to coordinate with
* concurrent writes from userspace that might be in the middle
* of using uhid->hid.
* Just leave uhid->hid as-is for now, and clean it up when
* userspace tries to close or reinitialize the uhid instance.
*
* However, we do have to clear the ->running flag and do a
* wakeup to make sure userspace knows that the device is gone.
*/
uhid->running = false;
wake_up_interruptible(&uhid->report_wait);
}
}
static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
{
__u8 newhead;
newhead = (uhid->head + 1) % UHID_BUFSIZE;
if (newhead != uhid->tail) {
uhid->outq[uhid->head] = ev;
uhid->head = newhead;
wake_up_interruptible(&uhid->waitq);
} else {
hid_warn(uhid->hid, "Output queue is full\n");
kfree(ev);
}
}
static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
{
unsigned long flags;
struct uhid_event *ev;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return -ENOMEM;
ev->type = event;
spin_lock_irqsave(&uhid->qlock, flags);
uhid_queue(uhid, ev);
spin_unlock_irqrestore(&uhid->qlock, flags);
return 0;
}
static int uhid_hid_start(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
struct uhid_event *ev;
unsigned long flags;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return -ENOMEM;
ev->type = UHID_START;
if (hid->report_enum[HID_FEATURE_REPORT].numbered)
ev->u.start.dev_flags |= UHID_DEV_NUMBERED_FEATURE_REPORTS;
if (hid->report_enum[HID_OUTPUT_REPORT].numbered)
ev->u.start.dev_flags |= UHID_DEV_NUMBERED_OUTPUT_REPORTS;
if (hid->report_enum[HID_INPUT_REPORT].numbered)
ev->u.start.dev_flags |= UHID_DEV_NUMBERED_INPUT_REPORTS;
spin_lock_irqsave(&uhid->qlock, flags);
uhid_queue(uhid, ev);
spin_unlock_irqrestore(&uhid->qlock, flags);
return 0;
}
static void uhid_hid_stop(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
hid->claimed = 0;
uhid_queue_event(uhid, UHID_STOP);
}
static int uhid_hid_open(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
return uhid_queue_event(uhid, UHID_OPEN);
}
static void uhid_hid_close(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
uhid_queue_event(uhid, UHID_CLOSE);
}
static int uhid_hid_parse(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
}
/* must be called with report_lock held */
static int __uhid_report_queue_and_wait(struct uhid_device *uhid,
struct uhid_event *ev,
__u32 *report_id)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&uhid->qlock, flags);
*report_id = ++uhid->report_id;
uhid->report_type = ev->type + 1;
uhid->report_running = true;
uhid_queue(uhid, ev);
spin_unlock_irqrestore(&uhid->qlock, flags);
ret = wait_event_interruptible_timeout(uhid->report_wait,
!uhid->report_running || !uhid->running,
5 * HZ);
if (!ret || !uhid->running || uhid->report_running)
ret = -EIO;
else if (ret < 0)
ret = -ERESTARTSYS;
else
ret = 0;
uhid->report_running = false;
return ret;
}
static void uhid_report_wake_up(struct uhid_device *uhid, u32 id,
const struct uhid_event *ev)
{
unsigned long flags;
spin_lock_irqsave(&uhid->qlock, flags);
/* id for old report; drop it silently */
if (uhid->report_type != ev->type || uhid->report_id != id)
goto unlock;
if (!uhid->report_running)
goto unlock;
memcpy(&uhid->report_buf, ev, sizeof(*ev));
uhid->report_running = false;
wake_up_interruptible(&uhid->report_wait);
unlock:
spin_unlock_irqrestore(&uhid->qlock, flags);
}
static int uhid_hid_get_report(struct hid_device *hid, unsigned char rnum,
u8 *buf, size_t count, u8 rtype)
{
struct uhid_device *uhid = hid->driver_data;
struct uhid_get_report_reply_req *req;
struct uhid_event *ev;
int ret;
if (!uhid->running)
return -EIO;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return -ENOMEM;
ev->type = UHID_GET_REPORT;
ev->u.get_report.rnum = rnum;
ev->u.get_report.rtype = rtype;
ret = mutex_lock_interruptible(&uhid->report_lock);
if (ret) {
kfree(ev);
return ret;
}
/* this _always_ takes ownership of @ev */
ret = __uhid_report_queue_and_wait(uhid, ev, &ev->u.get_report.id);
if (ret)
goto unlock;
req = &uhid->report_buf.u.get_report_reply;
if (req->err) {
ret = -EIO;
} else {
ret = min3(count, (size_t)req->size, (size_t)UHID_DATA_MAX);
memcpy(buf, req->data, ret);
}
unlock:
mutex_unlock(&uhid->report_lock);
return ret;
}
static int uhid_hid_set_report(struct hid_device *hid, unsigned char rnum,
const u8 *buf, size_t count, u8 rtype)
{
struct uhid_device *uhid = hid->driver_data;
struct uhid_event *ev;
int ret;
if (!uhid->running || count > UHID_DATA_MAX)
return -EIO;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return -ENOMEM;
ev->type = UHID_SET_REPORT;
ev->u.set_report.rnum = rnum;
ev->u.set_report.rtype = rtype;
ev->u.set_report.size = count;
memcpy(ev->u.set_report.data, buf, count);
ret = mutex_lock_interruptible(&uhid->report_lock);
if (ret) {
kfree(ev);
return ret;
}
/* this _always_ takes ownership of @ev */
ret = __uhid_report_queue_and_wait(uhid, ev, &ev->u.set_report.id);
if (ret)
goto unlock;
if (uhid->report_buf.u.set_report_reply.err)
ret = -EIO;
else
ret = count;
unlock:
mutex_unlock(&uhid->report_lock);
return ret;
}
static int uhid_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype,
int reqtype)
{
u8 u_rtype;
switch (rtype) {
case HID_FEATURE_REPORT:
u_rtype = UHID_FEATURE_REPORT;
break;
case HID_OUTPUT_REPORT:
u_rtype = UHID_OUTPUT_REPORT;
break;
case HID_INPUT_REPORT:
u_rtype = UHID_INPUT_REPORT;
break;
default:
return -EINVAL;
}
switch (reqtype) {
case HID_REQ_GET_REPORT:
return uhid_hid_get_report(hid, reportnum, buf, len, u_rtype);
case HID_REQ_SET_REPORT:
return uhid_hid_set_report(hid, reportnum, buf, len, u_rtype);
default:
return -EIO;
}
}
static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type)
{
struct uhid_device *uhid = hid->driver_data;
__u8 rtype;
unsigned long flags;
struct uhid_event *ev;
switch (report_type) {
case HID_FEATURE_REPORT:
rtype = UHID_FEATURE_REPORT;
break;
case HID_OUTPUT_REPORT:
rtype = UHID_OUTPUT_REPORT;
break;
default:
return -EINVAL;
}
if (count < 1 || count > UHID_DATA_MAX)
return -EINVAL;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return -ENOMEM;
ev->type = UHID_OUTPUT;
ev->u.output.size = count;
ev->u.output.rtype = rtype;
memcpy(ev->u.output.data, buf, count);
spin_lock_irqsave(&uhid->qlock, flags);
uhid_queue(uhid, ev);
spin_unlock_irqrestore(&uhid->qlock, flags);
return count;
}
static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
{
return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
}
struct hid_ll_driver uhid_hid_driver = {
.start = uhid_hid_start,
.stop = uhid_hid_stop,
.open = uhid_hid_open,
.close = uhid_hid_close,
.parse = uhid_hid_parse,
.raw_request = uhid_hid_raw_request,
.output_report = uhid_hid_output_report,
};
EXPORT_SYMBOL_GPL(uhid_hid_driver);
#ifdef CONFIG_COMPAT
/* Apparently we haven't stepped on these rakes enough times yet. */
struct uhid_create_req_compat {
__u8 name[128];
__u8 phys[64];
__u8 uniq[64];
compat_uptr_t rd_data;
__u16 rd_size;
__u16 bus;
__u32 vendor;
__u32 product;
__u32 version;
__u32 country;
} __attribute__((__packed__));
static int uhid_event_from_user(const char __user *buffer, size_t len,
struct uhid_event *event)
{
if (in_compat_syscall()) {
u32 type;
if (get_user(type, buffer))
return -EFAULT;
if (type == UHID_CREATE) {
/*
* This is our messed up request with compat pointer.
* It is largish (more than 256 bytes) so we better
* allocate it from the heap.
*/
struct uhid_create_req_compat *compat;
compat = kzalloc(sizeof(*compat), GFP_KERNEL);
if (!compat)
return -ENOMEM;
buffer += sizeof(type);
len -= sizeof(type);
if (copy_from_user(compat, buffer,
min(len, sizeof(*compat)))) {
kfree(compat);
return -EFAULT;
}
/* Shuffle the data over to proper structure */
event->type = type;
memcpy(event->u.create.name, compat->name,
sizeof(compat->name));
memcpy(event->u.create.phys, compat->phys,
sizeof(compat->phys));
memcpy(event->u.create.uniq, compat->uniq,
sizeof(compat->uniq));
event->u.create.rd_data = compat_ptr(compat->rd_data);
event->u.create.rd_size = compat->rd_size;
event->u.create.bus = compat->bus;
event->u.create.vendor = compat->vendor;
event->u.create.product = compat->product;
event->u.create.version = compat->version;
event->u.create.country = compat->country;
kfree(compat);
return 0;
}
/* All others can be copied directly */
}
if (copy_from_user(event, buffer, min(len, sizeof(*event))))
return -EFAULT;
return 0;
}
#else
static int uhid_event_from_user(const char __user *buffer, size_t len,
struct uhid_event *event)
{
if (copy_from_user(event, buffer, min(len, sizeof(*event))))
return -EFAULT;
return 0;
}
#endif
static int uhid_dev_create2(struct uhid_device *uhid,
const struct uhid_event *ev)
{
struct hid_device *hid;
size_t rd_size, len;
void *rd_data;
int ret;
if (uhid->hid)
return -EALREADY;
rd_size = ev->u.create2.rd_size;
if (rd_size <= 0 || rd_size > HID_MAX_DESCRIPTOR_SIZE)
return -EINVAL;
rd_data = kmemdup(ev->u.create2.rd_data, rd_size, GFP_KERNEL);
if (!rd_data)
return -ENOMEM;
uhid->rd_size = rd_size;
uhid->rd_data = rd_data;
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
goto err_free;
}
len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1;
strncpy(hid->name, ev->u.create2.name, len);
len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1;
strncpy(hid->phys, ev->u.create2.phys, len);
len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1;
strncpy(hid->uniq, ev->u.create2.uniq, len);
hid->ll_driver = &uhid_hid_driver;
hid->bus = ev->u.create2.bus;
hid->vendor = ev->u.create2.vendor;
hid->product = ev->u.create2.product;
hid->version = ev->u.create2.version;
hid->country = ev->u.create2.country;
hid->driver_data = uhid;
hid->dev.parent = uhid_misc.this_device;
uhid->hid = hid;
uhid->running = true;
/* Adding of a HID device is done through a worker, to allow HID drivers
* which use feature requests during .probe to work, without they would
* be blocked on devlock, which is held by uhid_char_write.
*/
schedule_work(&uhid->worker);
return 0;
err_free:
kfree(uhid->rd_data);
uhid->rd_data = NULL;
uhid->rd_size = 0;
return ret;
}
static int uhid_dev_create(struct uhid_device *uhid,
struct uhid_event *ev)
{
struct uhid_create_req orig;
orig = ev->u.create;
if (orig.rd_size <= 0 || orig.rd_size > HID_MAX_DESCRIPTOR_SIZE)
return -EINVAL;
if (copy_from_user(&ev->u.create2.rd_data, orig.rd_data, orig.rd_size))
return -EFAULT;
memcpy(ev->u.create2.name, orig.name, sizeof(orig.name));
memcpy(ev->u.create2.phys, orig.phys, sizeof(orig.phys));
memcpy(ev->u.create2.uniq, orig.uniq, sizeof(orig.uniq));
ev->u.create2.rd_size = orig.rd_size;
ev->u.create2.bus = orig.bus;
ev->u.create2.vendor = orig.vendor;
ev->u.create2.product = orig.product;
ev->u.create2.version = orig.version;
ev->u.create2.country = orig.country;
return uhid_dev_create2(uhid, ev);
}
static int uhid_dev_destroy(struct uhid_device *uhid)
{
if (!uhid->hid)
return -EINVAL;
uhid->running = false;
wake_up_interruptible(&uhid->report_wait);
cancel_work_sync(&uhid->worker);
hid_destroy_device(uhid->hid);
uhid->hid = NULL;
kfree(uhid->rd_data);
return 0;
}
static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
{
if (!uhid->running)
return -EINVAL;
hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
return 0;
}
static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
{
if (!uhid->running)
return -EINVAL;
hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
return 0;
}
static int uhid_dev_get_report_reply(struct uhid_device *uhid,
struct uhid_event *ev)
{
if (!uhid->running)
return -EINVAL;
uhid_report_wake_up(uhid, ev->u.get_report_reply.id, ev);
return 0;
}
static int uhid_dev_set_report_reply(struct uhid_device *uhid,
struct uhid_event *ev)
{
if (!uhid->running)
return -EINVAL;
uhid_report_wake_up(uhid, ev->u.set_report_reply.id, ev);
return 0;
}
static int uhid_char_open(struct inode *inode, struct file *file)
{
struct uhid_device *uhid;
uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
if (!uhid)
return -ENOMEM;
mutex_init(&uhid->devlock);
mutex_init(&uhid->report_lock);
spin_lock_init(&uhid->qlock);
init_waitqueue_head(&uhid->waitq);
init_waitqueue_head(&uhid->report_wait);
uhid->running = false;
INIT_WORK(&uhid->worker, uhid_device_add_worker);
file->private_data = uhid;
nonseekable_open(inode, file);
return 0;
}
static int uhid_char_release(struct inode *inode, struct file *file)
{
struct uhid_device *uhid = file->private_data;
unsigned int i;
uhid_dev_destroy(uhid);
for (i = 0; i < UHID_BUFSIZE; ++i)
kfree(uhid->outq[i]);
kfree(uhid);
return 0;
}
static ssize_t uhid_char_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct uhid_device *uhid = file->private_data;
int ret;
unsigned long flags;
size_t len;
/* they need at least the "type" member of uhid_event */
if (count < sizeof(__u32))
return -EINVAL;
try_again:
if (file->f_flags & O_NONBLOCK) {
if (uhid->head == uhid->tail)
return -EAGAIN;
} else {
ret = wait_event_interruptible(uhid->waitq,
uhid->head != uhid->tail);
if (ret)
return ret;
}
ret = mutex_lock_interruptible(&uhid->devlock);
if (ret)
return ret;
if (uhid->head == uhid->tail) {
mutex_unlock(&uhid->devlock);
goto try_again;
} else {
len = min(count, sizeof(**uhid->outq));
if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) {
ret = -EFAULT;
} else {
kfree(uhid->outq[uhid->tail]);
uhid->outq[uhid->tail] = NULL;
spin_lock_irqsave(&uhid->qlock, flags);
uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
spin_unlock_irqrestore(&uhid->qlock, flags);
}
}
mutex_unlock(&uhid->devlock);
return ret ? ret : len;
}
static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct uhid_device *uhid = file->private_data;
int ret;
size_t len;
/* we need at least the "type" member of uhid_event */
if (count < sizeof(__u32))
return -EINVAL;
ret = mutex_lock_interruptible(&uhid->devlock);
if (ret)
return ret;
memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
len = min(count, sizeof(uhid->input_buf));
ret = uhid_event_from_user(buffer, len, &uhid->input_buf);
if (ret)
goto unlock;
switch (uhid->input_buf.type) {
case UHID_CREATE:
/*
* 'struct uhid_create_req' contains a __user pointer which is
* copied from, so it's unsafe to allow this with elevated
* privileges (e.g. from a setuid binary) or via kernel_write().
*/
if (file->f_cred != current_cred() || uaccess_kernel()) {
pr_err_once("UHID_CREATE from different security context by process %d (%s), this is not allowed.\n",
task_tgid_vnr(current), current->comm);
ret = -EACCES;
goto unlock;
}
ret = uhid_dev_create(uhid, &uhid->input_buf);
break;
case UHID_CREATE2:
ret = uhid_dev_create2(uhid, &uhid->input_buf);
break;
case UHID_DESTROY:
ret = uhid_dev_destroy(uhid);
break;
case UHID_INPUT:
ret = uhid_dev_input(uhid, &uhid->input_buf);
break;
case UHID_INPUT2:
ret = uhid_dev_input2(uhid, &uhid->input_buf);
break;
case UHID_GET_REPORT_REPLY:
ret = uhid_dev_get_report_reply(uhid, &uhid->input_buf);
break;
case UHID_SET_REPORT_REPLY:
ret = uhid_dev_set_report_reply(uhid, &uhid->input_buf);
break;
default:
ret = -EOPNOTSUPP;
}
unlock:
mutex_unlock(&uhid->devlock);
/* return "count" not "len" to not confuse the caller */
return ret ? ret : count;
}
static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
{
struct uhid_device *uhid = file->private_data;
unsigned int mask = POLLOUT | POLLWRNORM; /* uhid is always writable */
poll_wait(file, &uhid->waitq, wait);
if (uhid->head != uhid->tail)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static const struct file_operations uhid_fops = {
.owner = THIS_MODULE,
.open = uhid_char_open,
.release = uhid_char_release,
.read = uhid_char_read,
.write = uhid_char_write,
.poll = uhid_char_poll,
.llseek = no_llseek,
};
static struct miscdevice uhid_misc = {
.fops = &uhid_fops,
.minor = UHID_MINOR,
.name = UHID_NAME,
};
module_misc_device(uhid_misc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
MODULE_ALIAS_MISCDEV(UHID_MINOR);
MODULE_ALIAS("devname:" UHID_NAME);