Merge tag 'LA.UM.9.14.1.r1-14100-QCM6490.QSSI14.0' of https://git.codelinaro.org/clo/la/kernel/msm-5.4 into android13-5.4-lahaina

"LA.UM.9.14.1.r1-14100-QCM6490.QSSI14.0"

* tag 'LA.UM.9.14.1.r1-14100-QCM6490.QSSI14.0' of https://git.codelinaro.org/clo/la/kernel/msm-5.4:
  msm: adsprpc: use-after-free (UAF) in global maps
  sdxnightJar.config: kernel changes for TRIGGER target
  msm: mhi_dev: Add UCI support if client req > TRE length
  usb: gadget: f_cdev: Call function wakeup if func_wakeup_pending is set
  usb: gadget: f_cdev: Bail out from cer_resume if func_suspended
  msm: kgsl: Do not release dma and anon buffers if unmap fails
  ALSA: compress: Remove redefinition
  BACKPORT: media: venus: hfi: fix the check in session buffer requirement
  msm: kgsl: Do not free sharedmem if it cannot be unmapped
  ALSA: compress: allow pause and resume during draining
  securemsm-kernel: Fix multiple listener registration on same fd
  Configured process_madvise with upstream syscall number
  msm: kgsl: Limit the syncpoint count for AUX commands
  msm: kgsl: Prevent wrap around during user address mapping
  iommu: Fix missing return check of arm_lpae_init_pte

Change-Id: I59256059b3d15fed896a7ce58d09f0950829dabb
This commit is contained in:
Michael Bestas 2024-06-22 17:46:18 +03:00
commit bb1bc18ab1
No known key found for this signature in database
GPG key ID: CC95044519BE6669
6 changed files with 164 additions and 81 deletions

View file

@ -66,6 +66,7 @@ CONFIG_INTERCONNECT_QCOM=y
CONFIG_DEBUG_FS=y
CONFIG_ARCH_SDXNIGHTJAR=y
CONFIG_ETHERNET=y
CONFIG_IP_NF_TARGET_TRIGGER_MODULE=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_AGERE is not set

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
/* Uncomment this block to log an error on every VERIFY failure */
@ -1108,64 +1108,43 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl)
} while (free);
}
static void fastrpc_mmap_add_global(struct fastrpc_mmap *map)
{
struct fastrpc_apps *me = &gfa;
unsigned long irq_flags = 0;
spin_lock_irqsave(&me->hlock, irq_flags);
hlist_add_head(&map->hn, &me->maps);
spin_unlock_irqrestore(&me->hlock, irq_flags);
}
static void fastrpc_mmap_add(struct fastrpc_mmap *map)
{
if (map->flags == ADSP_MMAP_HEAP_ADDR ||
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
struct fastrpc_apps *me = &gfa;
struct fastrpc_file *fl = map->fl;
spin_lock(&me->hlock);
hlist_add_head(&map->hn, &me->maps);
spin_unlock(&me->hlock);
} else {
struct fastrpc_file *fl = map->fl;
hlist_add_head(&map->hn, &fl->maps);
}
hlist_add_head(&map->hn, &fl->maps);
}
static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
uintptr_t va, size_t len, int mflags, int refs,
struct fastrpc_mmap **ppmap)
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_mmap *match = NULL, *map = NULL;
struct hlist_node *n;
if ((va + len) < va)
return -EFAULT;
if (mflags == ADSP_MMAP_HEAP_ADDR ||
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
spin_lock(&me->hlock);
hlist_for_each_entry_safe(map, n, &me->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
map->fd == fd) {
if (refs) {
if (map->refs + 1 == INT_MAX) {
spin_unlock(&me->hlock);
return -ETOOMANYREFS;
}
map->refs++;
}
match = map;
break;
}
}
spin_unlock(&me->hlock);
} else {
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
map->fd == fd) {
if (refs) {
if (map->refs + 1 == INT_MAX)
return -ETOOMANYREFS;
map->refs++;
}
match = map;
break;
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
map->fd == fd) {
if (refs) {
if (map->refs + 1 == INT_MAX)
return -ETOOMANYREFS;
map->refs++;
}
match = map;
break;
}
}
if (match) {
@ -1641,7 +1620,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
}
map->len = len;
fastrpc_mmap_add(map);
if ((mflags != ADSP_MMAP_HEAP_ADDR) &&
(mflags != ADSP_MMAP_REMOTE_HEAP_ADDR))
fastrpc_mmap_add(map);
*ppmap = map;
bail:
@ -4039,6 +4020,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_file *fl,
spin_lock(&me->hlock);
mem->in_use = true;
spin_unlock(&me->hlock);
fastrpc_mmap_add_global(mem);
}
phys = mem->phys;
size = mem->size;
@ -4772,7 +4754,7 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl)
me->enable_ramdump = false;
bail:
if (err && match)
fastrpc_mmap_add(match);
fastrpc_mmap_add_global(match);
return err;
}
@ -4901,7 +4883,11 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
bail:
if (err && map) {
mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(map);
if ((map->flags == ADSP_MMAP_HEAP_ADDR) ||
(map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR))
fastrpc_mmap_add_global(map);
else
fastrpc_mmap_add(map);
mutex_unlock(&fl->map_mutex);
}
mutex_unlock(&fl->internal_map_mutex);
@ -4988,6 +4974,9 @@ static int fastrpc_internal_mem_map(struct fastrpc_file *fl,
if (err)
goto bail;
ud->m.vaddrout = map->raddr;
if (ud->m.flags == ADSP_MMAP_HEAP_ADDR ||
ud->m.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
fastrpc_mmap_add_global(map);
bail:
if (err) {
pr_err("adsprpc: %s failed to map fd %d flags %d err %d\n",
@ -5050,7 +5039,11 @@ bail:
/* Add back to map list in case of error to unmap on DSP */
if (map) {
mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(map);
if ((map->flags == ADSP_MMAP_HEAP_ADDR) ||
(map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR))
fastrpc_mmap_add_global(map);
else
fastrpc_mmap_add(map);
mutex_unlock(&fl->map_mutex);
}
}
@ -5119,6 +5112,9 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
if (err)
goto bail;
map->raddr = raddr;
if (ud->flags == ADSP_MMAP_HEAP_ADDR ||
ud->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
fastrpc_mmap_add_global(map);
}
ud->vaddrout = raddr;
bail:

View file

@ -2278,6 +2278,12 @@ static int mhi_dev_process_tre_ring(struct mhi_dev *mhi,
ch = &mhi->ch[ring->id - mhi->ch_ring_start];
reason.ch_id = ch->ch_id;
reason.reason = MHI_DEV_TRE_AVAILABLE;
/*
* Save lowest value of tre_len to split packets in UCI layer
* for write request of size more than tre_len.
*/
if (!ch->tre_size || ch->tre_size > el->tre.len)
ch->tre_size = el->tre.len;
/* Invoke a callback to let the client know its data is ready.
* Copy this event to the clients context so that it can be
@ -3466,7 +3472,7 @@ int mhi_dev_read_channel(struct mhi_req *mreq)
uint64_t read_from_loc;
ssize_t bytes_read = 0;
size_t write_to_loc = 0;
uint32_t usr_buf_remaining;
uint32_t usr_buf_remaining, tre_size;
int td_done = 0, rc = 0;
struct mhi_dev_client *handle_client;
@ -3509,10 +3515,9 @@ int mhi_dev_read_channel(struct mhi_req *mreq)
}
el = &ring->ring_cache[ring->rd_offset];
mhi_log(MHI_MSG_VERBOSE, "evtptr : 0x%llx\n",
el->tre.data_buf_ptr);
mhi_log(MHI_MSG_VERBOSE, "evntlen : 0x%x, offset:%lu\n",
el->tre.len, ring->rd_offset);
mhi_log(MHI_MSG_VERBOSE,
"TRE.PTR: 0x%llx, TRE.LEN: 0x%x, rd offset: %lu\n",
el->tre.data_buf_ptr, el->tre.len, ring->rd_offset);
if (ch->tre_loc) {
bytes_to_read = min(usr_buf_remaining,
@ -3531,17 +3536,15 @@ int mhi_dev_read_channel(struct mhi_req *mreq)
ch->tre_loc = el->tre.data_buf_ptr;
ch->tre_size = el->tre.len;
ch->tre_bytes_left = ch->tre_size;
mhi_log(MHI_MSG_VERBOSE,
"user_buf_remaining %d, ch->tre_size %d\n",
usr_buf_remaining, ch->tre_size);
bytes_to_read = min(usr_buf_remaining, ch->tre_size);
tre_size = el->tre.len;
ch->tre_bytes_left = el->tre.len;
mhi_log(MHI_MSG_VERBOSE, "user_buf_remaining %d, tre_size %d\n",
usr_buf_remaining, el->tre.len);
bytes_to_read = min(usr_buf_remaining, tre_size);
}
bytes_read += bytes_to_read;
addr_offset = ch->tre_size - ch->tre_bytes_left;
addr_offset = el->tre.len - ch->tre_bytes_left;
read_from_loc = ch->tre_loc + addr_offset;
write_to_loc = (size_t) mreq->buf +
(mreq->len - usr_buf_remaining);

View file

@ -391,6 +391,7 @@ struct uci_client {
int (*read)(struct uci_client *h, int *bytes);
unsigned int tiocm;
unsigned int at_ctrl_mask;
int tre_len;
};
struct mhi_uci_ctxt_t {
@ -1466,8 +1467,9 @@ static ssize_t mhi_uci_client_write(struct file *file,
{
struct uci_client *uci_handle = NULL;
void *data_loc;
const char __user *cur_buf;
unsigned long memcpy_result;
int rc;
int rc = 0, tre_len, cur_rc = 0, count_left, cur_txfr_len;
if (!file || !buf || !count || !file->private_data) {
uci_log(UCI_DBG_DBG, "Invalid access to write\n");
@ -1475,6 +1477,8 @@ static ssize_t mhi_uci_client_write(struct file *file,
}
uci_handle = file->private_data;
tre_len = uci_handle->tre_len;
if (!uci_handle->send || !uci_handle->out_handle) {
uci_log(UCI_DBG_DBG, "Invalid handle or send\n");
return -EINVAL;
@ -1497,17 +1501,47 @@ static ssize_t mhi_uci_client_write(struct file *file,
count, uci_handle->out_chan_attr->max_packet_size);
}
data_loc = kmalloc(count, GFP_KERNEL);
if (!data_loc)
return -ENOMEM;
cur_txfr_len = count;
memcpy_result = copy_from_user(data_loc, buf, count);
if (memcpy_result) {
rc = -EFAULT;
goto error_memcpy;
if (!tre_len)
uci_log(UCI_DBG_ERROR, "tre_len is 0, not updated yet\n");
else if (count > tre_len) {
uci_log(UCI_DBG_DBG, "Write req size (%d) > tre_len (%d)\n", count, tre_len);
cur_txfr_len = tre_len;
}
rc = mhi_uci_send_packet(uci_handle, data_loc, count);
count_left = count;
cur_buf = buf;
do {
data_loc = kmalloc(cur_txfr_len, GFP_KERNEL);
if (!data_loc) {
uci_log(UCI_DBG_ERROR, "Memory allocation failed\n");
return -ENOMEM;
}
memcpy_result = copy_from_user(data_loc, cur_buf, cur_txfr_len);
if (memcpy_result) {
uci_log(UCI_DBG_ERROR, "Mem copy failed\n");
rc = -EFAULT;
goto error_memcpy;
}
cur_rc = mhi_uci_send_packet(uci_handle, data_loc, cur_txfr_len);
if (cur_rc != cur_txfr_len) {
uci_log(UCI_DBG_ERROR,
"Send failed with error %d, after sending %d data\n",
cur_rc, rc);
rc = cur_rc;
goto error_memcpy;
}
rc += cur_rc;
cur_buf += cur_txfr_len;
count_left -= cur_txfr_len;
if (count_left < tre_len)
cur_txfr_len = count_left;
} while (count_left);
if (rc == count)
return rc;
@ -1523,7 +1557,7 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb,
struct uci_client *uci_handle = NULL;
void *data_loc;
unsigned long memcpy_result;
int rc;
int rc = 0, tre_len, cur_rc = 0, count_left, cur_txfr_len;
struct file *file = iocb->ki_filp;
ssize_t count = iov_iter_count(buf);
@ -1533,6 +1567,8 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb,
}
uci_handle = file->private_data;
tre_len = uci_handle->tre_len;
if (!uci_handle->send || !uci_handle->out_handle) {
uci_log(UCI_DBG_DBG, "Invalid handle or send\n");
return -EINVAL;
@ -1555,17 +1591,44 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb,
count, uci_handle->out_chan_attr->max_packet_size);
}
data_loc = kmalloc(count, GFP_KERNEL);
if (!data_loc)
return -ENOMEM;
cur_txfr_len = count;
memcpy_result = copy_from_iter_full(data_loc, count, buf);
if (!memcpy_result) {
rc = -EFAULT;
goto error_memcpy;
if (!tre_len)
uci_log(UCI_DBG_ERROR, "tre_len is 0, not updated yet\n");
else if (count > tre_len) {
uci_log(UCI_DBG_DBG, "Write req size (%d) > tre_len (%d)\n", count, tre_len);
cur_txfr_len = tre_len;
}
rc = mhi_uci_send_packet(uci_handle, data_loc, count);
count_left = count;
do {
data_loc = kmalloc(cur_txfr_len, GFP_KERNEL);
if (!data_loc) {
uci_log(UCI_DBG_ERROR, "Memory allocation failed\n");
return -ENOMEM;
}
memcpy_result = copy_from_iter_full(data_loc, cur_txfr_len, buf);
if (!memcpy_result) {
uci_log(UCI_DBG_ERROR, "Mem copy failed\n");
rc = -EFAULT;
goto error_memcpy;
}
cur_rc = mhi_uci_send_packet(uci_handle, data_loc, cur_txfr_len);
if (cur_rc != cur_txfr_len) {
uci_log(UCI_DBG_ERROR,
"Send failed with error %d, after sending %d data\n",
cur_rc, rc);
rc = cur_rc;
goto error_memcpy;
}
rc += cur_rc;
count_left -= cur_txfr_len;
if (count_left < tre_len)
cur_txfr_len = count_left;
} while (count_left);
if (rc == count)
return rc;
@ -1683,6 +1746,7 @@ static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason)
uci_handle->in_chan);
if (reason->ch_id % 2) {
atomic_set(&uci_handle->write_data_ready, 1);
uci_handle->tre_len = uci_handle->out_handle->channel->tre_size;
wake_up(&uci_handle->write_wq);
} else {
atomic_set(&uci_handle->read_data_ready, 1);

View file

@ -554,12 +554,26 @@ static void usb_cser_start_rx(struct f_cdev *port);
static void usb_cser_resume(struct usb_function *f)
{
struct f_cdev *port = func_to_port(f);
struct usb_composite_dev *cdev = f->config->cdev;
unsigned long flags;
int ret;
struct usb_request *req, *t;
struct usb_ep *in;
/*
* Bail out if the interface is in USB3 Function Suspend state.
* In that case resume is done by Function Resume request (write).
*/
if ((cdev->gadget->speed >= USB_SPEED_SUPER) &&
port->func_is_suspended) {
if (port->func_wakeup_pending) {
ret = usb_func_wakeup(f);
port->func_wakeup_pending = (ret == -EAGAIN) ? true : false;
}
return;
}
pr_debug("%s\n", __func__);
port->is_suspended = false;
@ -1453,9 +1467,10 @@ ssize_t f_cdev_write(struct file *file,
spin_unlock_irqrestore(&port->port_lock, flags);
if (gadget->speed >= USB_SPEED_SUPER
&& port->func_is_suspended)
&& port->func_is_suspended) {
ret = usb_func_wakeup(func);
else
port->func_wakeup_pending = (ret == -EAGAIN) ? true : false;
} else
ret = usb_gadget_wakeup(gadget);
if (ret < 0 && ret != -EACCES && ret != -EAGAIN) {

View file

@ -59,6 +59,7 @@ struct snd_compr_runtime {
* @direction: stream direction, playback/recording
* @metadata_set: metadata set flag, true when set
* @next_track: has userspace signal next track transition, true when set
* @pause_in_draining: paused during draining state, true when set
* @private_data: pointer to DSP private data
*/
struct snd_compr_stream {
@ -70,6 +71,7 @@ struct snd_compr_stream {
enum snd_compr_direction direction;
bool metadata_set;
bool next_track;
bool pause_in_draining;
void *private_data;
#ifdef CONFIG_AUDIO_QGKI
struct snd_soc_pcm_runtime *be;
@ -140,6 +142,7 @@ struct snd_compr_ops {
* @direction: Playback or capture direction
* @lock: device lock
* @device: device id
* @use_pause_in_draining: allow pause in draining, true when set
*/
struct snd_compr {
const char *name;
@ -150,6 +153,7 @@ struct snd_compr {
unsigned int direction;
struct mutex lock;
int device;
bool use_pause_in_draining;
#ifdef CONFIG_SND_VERBOSE_PROCFS
/* private: */
char id[64];