From 4da60ccd5b62fb7de096e86b1f103a3f44efb3c9 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 10 Jan 2017 16:11:07 -0800 Subject: [PATCH 01/78] ANDROID: uid_sys_stats: rename uid_cputime.c to uid_sys_stats.c This module tracks cputime and io stats. Signed-off-by: Jin Qian Bug: 34198239 Change-Id: I9ee7d9e915431e0bb714b36b5a2282e1fdcc7342 Signed-off-by: anupritaisno1 --- drivers/misc/Kconfig | 5 +++-- drivers/misc/Makefile | 3 +-- drivers/misc/{uid_cputime.c => uid_sys_stats.c} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename drivers/misc/{uid_cputime.c => uid_sys_stats.c} (100%) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ff1f282a734e4..76ef801ea5e00 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -541,11 +541,12 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. -config UID_CPUTIME - tristate "Per-UID cpu time statistics" +config UID_SYS_STATS + tristate "Per-UID statistics" depends on PROFILING help Per UID based cpu time statistics exported to /proc/uid_cputime + Per UID based io statistics exported to /proc/uid_io config TSIF depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 94e0fe34ae72f..e873f9bae1953 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o -obj-$(CONFIG_UID_CPUTIME) += uid_cputime.o obj-$(CONFIG_TSIF) += msm_tsif.o obj-$(CONFIG_HAPTIC_ISA1200) += isa1200.o obj-$(CONFIG_QSEECOM) += qseecom.o @@ -72,4 +71,4 @@ obj-y += qcom/ #shankai@bsp, 2015/2/2, Add for :drv2605 kernel support obj-$(CONFIG_TI_DRV2605) += ti_drv2605.o #endif VENDOR_EDIT - +obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o diff --git a/drivers/misc/uid_cputime.c b/drivers/misc/uid_sys_stats.c similarity index 100% rename from drivers/misc/uid_cputime.c rename to drivers/misc/uid_sys_stats.c From 759a6d923dddfbbe6c9a8440911121cf64385536 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 10 Jan 2017 16:10:35 -0800 Subject: [PATCH 02/78] ANDROID: uid_cputime: add per-uid IO usage accounting IO usages are accounted in foreground and background buckets. For each uid, io usage is calculated in two steps. delta = current total of all uid tasks - previus total current bucket += delta Bucket is determined by current uid stat. Userspace writes to /proc/uid_procstat/set when uid stat is updated. /proc/uid_io/stats shows IO usage in this format. Signed-off-by: Jin Qian Bug: 34198239 Change-Id: I3369e59e063b1e5ee0dfe3804c711d93cb937c0c Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 249 ++++++++++++++++++++++++++++++++--- 1 file changed, 233 insertions(+), 16 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index c751188ce2aba..09cfa89c4a523 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -30,7 +30,24 @@ DECLARE_HASHTABLE(hash_table, UID_HASH_BITS); static DEFINE_MUTEX(uid_lock); -static struct proc_dir_entry *parent; +static struct proc_dir_entry *cpu_parent; +static struct proc_dir_entry *io_parent; +static struct proc_dir_entry *proc_parent; + +struct io_stats { + u64 read_bytes; + u64 write_bytes; + u64 rchar; + u64 wchar; +}; + +#define UID_STATE_FOREGROUND 0 +#define UID_STATE_BACKGROUND 1 +#define UID_STATE_BUCKET_SIZE 2 + +#define UID_STATE_TOTAL_CURR 2 +#define UID_STATE_TOTAL_LAST 3 +#define UID_STATE_SIZE 4 struct uid_entry { uid_t uid; @@ -40,6 +57,8 @@ struct uid_entry { cputime_t active_stime; unsigned long long active_power; unsigned long long power; + int state; + struct io_stats io[UID_STATE_SIZE]; struct hlist_node hash; }; @@ -72,7 +91,7 @@ static struct uid_entry *find_or_register_uid(uid_t uid) return uid_entry; } -static int uid_stat_show(struct seq_file *m, void *v) +static int uid_cputime_show(struct seq_file *m, void *v) { struct uid_entry *uid_entry; struct task_struct *task, *temp; @@ -131,13 +150,13 @@ static int uid_stat_show(struct seq_file *m, void *v) return 0; } -static int uid_stat_open(struct inode *inode, struct file *file) +static int uid_cputime_open(struct inode *inode, struct file *file) { - return single_open(file, uid_stat_show, PDE_DATA(inode)); + return single_open(file, uid_cputime_show, PDE_DATA(inode)); } -static const struct file_operations uid_stat_fops = { - .open = uid_stat_open, +static const struct file_operations uid_cputime_fops = { + .open = uid_cputime_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, @@ -196,6 +215,175 @@ static const struct file_operations uid_remove_fops = { .write = uid_remove_write, }; +static void add_uid_io_curr_stats(struct uid_entry *uid_entry, + struct task_struct *task) +{ + struct io_stats *io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; + + io_curr->read_bytes += task->ioac.read_bytes; + io_curr->write_bytes += + task->ioac.write_bytes - task->ioac.cancelled_write_bytes; + io_curr->rchar += task->ioac.rchar; + io_curr->wchar += task->ioac.wchar; +} + +static void clean_uid_io_last_stats(struct uid_entry *uid_entry, + struct task_struct *task) +{ + struct io_stats *io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; + + io_last->read_bytes -= task->ioac.read_bytes; + io_last->write_bytes -= + task->ioac.write_bytes - task->ioac.cancelled_write_bytes; + io_last->rchar -= task->ioac.rchar; + io_last->wchar -= task->ioac.wchar; +} + +static void update_io_stats_locked(void) +{ + struct uid_entry *uid_entry; + struct task_struct *task, *temp; + struct io_stats *io_bucket, *io_curr, *io_last; + unsigned long bkt; + + BUG_ON(!mutex_is_locked(&uid_lock)); + + hash_for_each(hash_table, bkt, uid_entry, hash) + memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, + sizeof(struct io_stats)); + + read_lock(&tasklist_lock); + do_each_thread(temp, task) { + uid_entry = find_or_register_uid(from_kuid_munged( + current_user_ns(), task_uid(task))); + if (!uid_entry) + continue; + add_uid_io_curr_stats(uid_entry, task); + } while_each_thread(temp, task); + read_unlock(&tasklist_lock); + + hash_for_each(hash_table, bkt, uid_entry, hash) { + io_bucket = &uid_entry->io[uid_entry->state]; + io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; + io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; + + io_bucket->read_bytes += + io_curr->read_bytes - io_last->read_bytes; + io_bucket->write_bytes += + io_curr->write_bytes - io_last->write_bytes; + io_bucket->rchar += io_curr->rchar - io_last->rchar; + io_bucket->wchar += io_curr->wchar - io_last->wchar; + + io_last->read_bytes = io_curr->read_bytes; + io_last->write_bytes = io_curr->write_bytes; + io_last->rchar = io_curr->rchar; + io_last->wchar = io_curr->wchar; + } +} + +static int uid_io_show(struct seq_file *m, void *v) +{ + struct uid_entry *uid_entry; + unsigned long bkt; + + mutex_lock(&uid_lock); + + update_io_stats_locked(); + + hash_for_each(hash_table, bkt, uid_entry, hash) { + seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu\n", + uid_entry->uid, + uid_entry->io[UID_STATE_FOREGROUND].rchar, + uid_entry->io[UID_STATE_FOREGROUND].wchar, + uid_entry->io[UID_STATE_FOREGROUND].read_bytes, + uid_entry->io[UID_STATE_FOREGROUND].write_bytes, + uid_entry->io[UID_STATE_BACKGROUND].rchar, + uid_entry->io[UID_STATE_BACKGROUND].wchar, + uid_entry->io[UID_STATE_BACKGROUND].read_bytes, + uid_entry->io[UID_STATE_BACKGROUND].write_bytes); + } + + mutex_unlock(&uid_lock); + + return 0; +} + +static int uid_io_open(struct inode *inode, struct file *file) +{ + return single_open(file, uid_io_show, PDE_DATA(inode)); +} + +static const struct file_operations uid_io_fops = { + .open = uid_io_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int uid_procstat_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, NULL); +} + +static ssize_t uid_procstat_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + struct task_struct *task, *temp; + struct uid_entry *uid_entry; + uid_t uid, task_uid; + int argc, state; + char input[128]; + + if (count >= sizeof(input)) + return -EINVAL; + + if (copy_from_user(input, buffer, count)) + return -EFAULT; + + input[count] = '\0'; + + argc = sscanf(input, "%u %d", &uid, &state); + if (argc != 2) + return -EINVAL; + + if (state != UID_STATE_BACKGROUND && state != UID_STATE_FOREGROUND) + return -EINVAL; + + mutex_lock(&uid_lock); + + uid_entry = find_or_register_uid(uid); + if (!uid_entry || uid_entry->state == state) { + mutex_unlock(&uid_lock); + return -EINVAL; + } + + memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, + sizeof(struct io_stats)); + + read_lock(&tasklist_lock); + do_each_thread(temp, task) { + task_uid = from_kuid_munged(current_user_ns(), task_uid(task)); + if (uid != task_uid) + continue; + add_uid_io_curr_stats(uid_entry, task); + } while_each_thread(temp, task); + read_unlock(&tasklist_lock); + + update_io_stats_locked(); + + uid_entry->state = state; + + mutex_unlock(&uid_lock); + + return count; +} + +static const struct file_operations uid_procstat_fops = { + .open = uid_procstat_open, + .release = single_release, + .write = uid_procstat_write, +}; + static int process_notifier(struct notifier_block *self, unsigned long cmd, void *v) { @@ -221,6 +409,9 @@ static int process_notifier(struct notifier_block *self, uid_entry->power += task->cpu_power; task->cpu_power = ULLONG_MAX; + update_io_stats_locked(); + clean_uid_io_last_stats(uid_entry, task); + exit: mutex_unlock(&uid_lock); return NOTIFY_OK; @@ -230,25 +421,51 @@ static struct notifier_block process_notifier_block = { .notifier_call = process_notifier, }; -static int __init proc_uid_cputime_init(void) +static int __init proc_uid_sys_stats_init(void) { hash_init(hash_table); - parent = proc_mkdir("uid_cputime", NULL); - if (!parent) { - pr_err("%s: failed to create proc entry\n", __func__); - return -ENOMEM; + cpu_parent = proc_mkdir("uid_cputime", NULL); + if (!cpu_parent) { + pr_err("%s: failed to create uid_cputime proc entry\n", + __func__); + goto err; } - proc_create_data("remove_uid_range", S_IWUGO, parent, &uid_remove_fops, - NULL); + proc_create_data("remove_uid_range", 0222, cpu_parent, + &uid_remove_fops, NULL); + proc_create_data("show_uid_stat", 0444, cpu_parent, + &uid_cputime_fops, NULL); - proc_create_data("show_uid_stat", S_IRUGO, parent, &uid_stat_fops, - NULL); + io_parent = proc_mkdir("uid_io", NULL); + if (!io_parent) { + pr_err("%s: failed to create uid_io proc entry\n", + __func__); + goto err; + } + + proc_create_data("stats", 0444, io_parent, + &uid_io_fops, NULL); + + proc_parent = proc_mkdir("uid_procstat", NULL); + if (!io_parent) { + pr_err("%s: failed to create uid_procstat proc entry\n", + __func__); + goto err; + } + + proc_create_data("set", 0222, proc_parent, + &uid_procstat_fops, NULL); profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block); return 0; + +err: + remove_proc_subtree("uid_cputime", NULL); + remove_proc_subtree("uid_io", NULL); + remove_proc_subtree("uid_procstat", NULL); + return -ENOMEM; } -early_initcall(proc_uid_cputime_init); +early_initcall(proc_uid_sys_stats_init); From 1714fc463456524b0c14f29918a7e59c77159c67 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 17 Jan 2017 17:26:07 -0800 Subject: [PATCH 03/78] ANDROID: uid_sys_stats: allow writing same state Signed-off-by: Jin Qian Bug: 34360629 Change-Id: Ia748351e07910b1febe54f0484ca1be58c4eb9c7 Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 09cfa89c4a523..1491456b23ccc 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -352,11 +352,16 @@ static ssize_t uid_procstat_write(struct file *file, mutex_lock(&uid_lock); uid_entry = find_or_register_uid(uid); - if (!uid_entry || uid_entry->state == state) { + if (!uid_entry) { mutex_unlock(&uid_lock); return -EINVAL; } + if (uid_entry->state == state) { + mutex_unlock(&uid_lock); + return 0; + } + memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, sizeof(struct io_stats)); From 9e742d6f1f4d4489b8a6c68e9cd56031cbe4901f Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Thu, 19 Jan 2017 16:34:34 -0800 Subject: [PATCH 04/78] ANDROID: uid_sys_stats: return full size when state is not changed. Userspace keeps retrying when it sees nothing is written. Bug: 34364961 Change-Id: Ie288c90c6a206fb863dcad010094fcd1373767aa Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 1491456b23ccc..61422de6f7bf4 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -359,7 +359,7 @@ static ssize_t uid_procstat_write(struct file *file, if (uid_entry->state == state) { mutex_unlock(&uid_lock); - return 0; + return count; } memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, From 12c69946624ff7bbabf275627b04ff0a567f0526 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Thu, 16 Feb 2017 18:07:05 -0800 Subject: [PATCH 05/78] ANDROID: uid_sys_stats: remove unnecessary code in procstat switch No need to aggregate the switched uid separately since update_io_stats_locked covers all uids. Bug: 34198239 Change-Id: Ifed347264b910de02e3f3c8dec95d1a2dbde58c0 Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 61422de6f7bf4..2652bb6d2e588 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -328,9 +328,8 @@ static int uid_procstat_open(struct inode *inode, struct file *file) static ssize_t uid_procstat_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - struct task_struct *task, *temp; struct uid_entry *uid_entry; - uid_t uid, task_uid; + uid_t uid; int argc, state; char input[128]; @@ -362,18 +361,6 @@ static ssize_t uid_procstat_write(struct file *file, return count; } - memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, - sizeof(struct io_stats)); - - read_lock(&tasklist_lock); - do_each_thread(temp, task) { - task_uid = from_kuid_munged(current_user_ns(), task_uid(task)); - if (uid != task_uid) - continue; - add_uid_io_curr_stats(uid_entry, task); - } while_each_thread(temp, task); - read_unlock(&tasklist_lock); - update_io_stats_locked(); uid_entry->state = state; From f12bb77ce17cac73e8ff2047497b424d46284234 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 28 Feb 2017 15:09:42 -0800 Subject: [PATCH 06/78] ANDROID: uid_sys_stats: fix negative write bytes. A task can cancel writes made by other tasks. In rare cases, cancelled_write_bytes is larger than write_bytes if the task itself didn't make any write. This doesn't affect total size but may cause confusion when looking at IO usage on individual tasks. Bug: 35851986 Change-Id: If6cb549aeef9e248e18d804293401bb2b91918ca Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 2652bb6d2e588..bdb440e2fb059 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -215,14 +215,21 @@ static const struct file_operations uid_remove_fops = { .write = uid_remove_write, }; +static u64 compute_write_bytes(struct task_struct *task) +{ + if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes) + return 0; + + return task->ioac.write_bytes - task->ioac.cancelled_write_bytes; +} + static void add_uid_io_curr_stats(struct uid_entry *uid_entry, struct task_struct *task) { struct io_stats *io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; io_curr->read_bytes += task->ioac.read_bytes; - io_curr->write_bytes += - task->ioac.write_bytes - task->ioac.cancelled_write_bytes; + io_curr->write_bytes += compute_write_bytes(task); io_curr->rchar += task->ioac.rchar; io_curr->wchar += task->ioac.wchar; } @@ -233,8 +240,7 @@ static void clean_uid_io_last_stats(struct uid_entry *uid_entry, struct io_stats *io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; io_last->read_bytes -= task->ioac.read_bytes; - io_last->write_bytes -= - task->ioac.write_bytes - task->ioac.cancelled_write_bytes; + io_last->write_bytes -= compute_write_bytes(task); io_last->rchar -= task->ioac.rchar; io_last->wchar -= task->ioac.wchar; } From 261ab7dac9f1cc01b76605c8f524768e0d6b5aec Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Thu, 2 Mar 2017 13:32:59 -0800 Subject: [PATCH 07/78] ANDROID: sched: add a counter to track fsync Change-Id: I6c138de5b2332eea70f57e098134d1d141247b3f Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- fs/sync.c | 1 + include/linux/sched.h | 8 ++++++++ include/linux/task_io_accounting.h | 2 ++ include/linux/task_io_accounting_ops.h | 1 + 4 files changed, 12 insertions(+) diff --git a/fs/sync.c b/fs/sync.c index 1022b89727e5f..4e93b274a2c18 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -205,6 +205,7 @@ static int do_fsync(unsigned int fd, int datasync) if (f.file) { ret = vfs_fsync(f.file, datasync); fdput(f); + inc_syscfs(current); } return ret; } diff --git a/include/linux/sched.h b/include/linux/sched.h index 3bf2401492365..aeb29890c8d57 100755 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -3231,6 +3231,11 @@ static inline void inc_syscw(struct task_struct *tsk) { tsk->ioac.syscw++; } + +static inline void inc_syscfs(struct task_struct *tsk) +{ + tsk->ioac.syscfs++; +} #else static inline void add_rchar(struct task_struct *tsk, ssize_t amt) { @@ -3247,6 +3252,9 @@ static inline void inc_syscr(struct task_struct *tsk) static inline void inc_syscw(struct task_struct *tsk) { } +static inline void inc_syscfs(struct task_struct *tsk) +{ +} #endif #ifndef TASK_SIZE_OF diff --git a/include/linux/task_io_accounting.h b/include/linux/task_io_accounting.h index bdf855c2856fb..2dd338fdf8815 100644 --- a/include/linux/task_io_accounting.h +++ b/include/linux/task_io_accounting.h @@ -18,6 +18,8 @@ struct task_io_accounting { u64 syscr; /* # of write syscalls */ u64 syscw; + /* # of fsync syscalls */ + u64 syscfs; #endif /* CONFIG_TASK_XACCT */ #ifdef CONFIG_TASK_IO_ACCOUNTING diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h index 4d090f9ee6087..1b505c804af34 100644 --- a/include/linux/task_io_accounting_ops.h +++ b/include/linux/task_io_accounting_ops.h @@ -96,6 +96,7 @@ static inline void task_chr_io_accounting_add(struct task_io_accounting *dst, dst->wchar += src->wchar; dst->syscr += src->syscr; dst->syscw += src->syscw; + dst->syscfs += src->syscfs; } #else static inline void task_chr_io_accounting_add(struct task_io_accounting *dst, From f32280ab88b6ae8281bf827dd442b7a7666ee644 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Thu, 2 Mar 2017 13:39:43 -0800 Subject: [PATCH 08/78] ANDROID: uid_sys_stats: account for fsync syscalls Change-Id: Ie888d8a0f4ec7a27dea86dc4afba8e6fd4203488 Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index bdb440e2fb059..be1cfdca9e133 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -39,6 +39,7 @@ struct io_stats { u64 write_bytes; u64 rchar; u64 wchar; + u64 fsync; }; #define UID_STATE_FOREGROUND 0 @@ -232,6 +233,7 @@ static void add_uid_io_curr_stats(struct uid_entry *uid_entry, io_curr->write_bytes += compute_write_bytes(task); io_curr->rchar += task->ioac.rchar; io_curr->wchar += task->ioac.wchar; + io_curr->fsync += task->ioac.syscfs; } static void clean_uid_io_last_stats(struct uid_entry *uid_entry, @@ -243,6 +245,7 @@ static void clean_uid_io_last_stats(struct uid_entry *uid_entry, io_last->write_bytes -= compute_write_bytes(task); io_last->rchar -= task->ioac.rchar; io_last->wchar -= task->ioac.wchar; + io_last->fsync -= task->ioac.syscfs; } static void update_io_stats_locked(void) @@ -279,11 +282,13 @@ static void update_io_stats_locked(void) io_curr->write_bytes - io_last->write_bytes; io_bucket->rchar += io_curr->rchar - io_last->rchar; io_bucket->wchar += io_curr->wchar - io_last->wchar; + io_bucket->fsync += io_curr->fsync - io_last->fsync; io_last->read_bytes = io_curr->read_bytes; io_last->write_bytes = io_curr->write_bytes; io_last->rchar = io_curr->rchar; io_last->wchar = io_curr->wchar; + io_last->fsync = io_curr->fsync; } } @@ -297,7 +302,7 @@ static int uid_io_show(struct seq_file *m, void *v) update_io_stats_locked(); hash_for_each(hash_table, bkt, uid_entry, hash) { - seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu\n", + seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", uid_entry->uid, uid_entry->io[UID_STATE_FOREGROUND].rchar, uid_entry->io[UID_STATE_FOREGROUND].wchar, @@ -306,7 +311,9 @@ static int uid_io_show(struct seq_file *m, void *v) uid_entry->io[UID_STATE_BACKGROUND].rchar, uid_entry->io[UID_STATE_BACKGROUND].wchar, uid_entry->io[UID_STATE_BACKGROUND].read_bytes, - uid_entry->io[UID_STATE_BACKGROUND].write_bytes); + uid_entry->io[UID_STATE_BACKGROUND].write_bytes, + uid_entry->io[UID_STATE_FOREGROUND].fsync, + uid_entry->io[UID_STATE_BACKGROUND].fsync); } mutex_unlock(&uid_lock); From 1d100c6d84a233c66f50d2a09b2e8da66d0a136f Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Mon, 13 Mar 2017 12:22:21 -0700 Subject: [PATCH 09/78] ANDROID: uid_sys_stats: change to use rt_mutex We see this happens multiple times in heavy workload in systrace and AMS stuck in uid_lock. Running process: Process 953 Running thread: android.ui State: Uninterruptible Sleep Start: 1,025.628 ms Duration: 27,955.949 ms On CPU: Running instead: system_server Args: {kernel callsite when blocked:: "uid_procstat_write+0xb8/0x144"} Changing to rt_mutex can mitigate the priority inversion Bug: 34991231 Bug: 34193533 Change-Id: I481baad840b7bc2dfa9b9a59b4dff93cafb90077 Test: on marlin Signed-off-by: Wei Wang Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index be1cfdca9e133..b0a324be8bb2b 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ #define UID_HASH_BITS 10 DECLARE_HASHTABLE(hash_table, UID_HASH_BITS); -static DEFINE_MUTEX(uid_lock); +static DEFINE_RT_MUTEX(uid_lock); static struct proc_dir_entry *cpu_parent; static struct proc_dir_entry *io_parent; static struct proc_dir_entry *proc_parent; @@ -100,7 +101,7 @@ static int uid_cputime_show(struct seq_file *m, void *v) cputime_t stime; unsigned long bkt; - mutex_lock(&uid_lock); + rt_mutex_lock(&uid_lock); hash_for_each(hash_table, bkt, uid_entry, hash) { uid_entry->active_stime = 0; @@ -114,7 +115,7 @@ static int uid_cputime_show(struct seq_file *m, void *v) current_user_ns(), task_uid(task))); if (!uid_entry) { read_unlock(&tasklist_lock); - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); pr_err("%s: failed to find the uid_entry for uid %d\n", __func__, from_kuid_munged(current_user_ns(), task_uid(task))); @@ -147,7 +148,7 @@ static int uid_cputime_show(struct seq_file *m, void *v) total_power); } - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return 0; } @@ -194,7 +195,7 @@ static ssize_t uid_remove_write(struct file *file, kstrtol(end_uid, 10, &uid_end) != 0) { return -EINVAL; } - mutex_lock(&uid_lock); + rt_mutex_lock(&uid_lock); for (; uid_start <= uid_end; uid_start++) { hash_for_each_possible_safe(hash_table, uid_entry, tmp, @@ -206,7 +207,7 @@ static ssize_t uid_remove_write(struct file *file, } } - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return count; } @@ -255,7 +256,7 @@ static void update_io_stats_locked(void) struct io_stats *io_bucket, *io_curr, *io_last; unsigned long bkt; - BUG_ON(!mutex_is_locked(&uid_lock)); + BUG_ON(!rt_mutex_is_locked(&uid_lock)); hash_for_each(hash_table, bkt, uid_entry, hash) memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, @@ -297,7 +298,7 @@ static int uid_io_show(struct seq_file *m, void *v) struct uid_entry *uid_entry; unsigned long bkt; - mutex_lock(&uid_lock); + rt_mutex_lock(&uid_lock); update_io_stats_locked(); @@ -316,7 +317,7 @@ static int uid_io_show(struct seq_file *m, void *v) uid_entry->io[UID_STATE_BACKGROUND].fsync); } - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return 0; } @@ -361,16 +362,16 @@ static ssize_t uid_procstat_write(struct file *file, if (state != UID_STATE_BACKGROUND && state != UID_STATE_FOREGROUND) return -EINVAL; - mutex_lock(&uid_lock); + rt_mutex_lock(&uid_lock); uid_entry = find_or_register_uid(uid); if (!uid_entry) { - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return -EINVAL; } if (uid_entry->state == state) { - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return count; } @@ -378,7 +379,7 @@ static ssize_t uid_procstat_write(struct file *file, uid_entry->state = state; - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return count; } @@ -400,7 +401,7 @@ static int process_notifier(struct notifier_block *self, if (!task) return NOTIFY_OK; - mutex_lock(&uid_lock); + rt_mutex_lock(&uid_lock); uid = from_kuid_munged(current_user_ns(), task_uid(task)); uid_entry = find_or_register_uid(uid); if (!uid_entry) { @@ -418,7 +419,7 @@ static int process_notifier(struct notifier_block *self, clean_uid_io_last_stats(uid_entry, task); exit: - mutex_unlock(&uid_lock); + rt_mutex_unlock(&uid_lock); return NOTIFY_OK; } From 300b05b80873cf8105dd04e5aae061aef67aa2ff Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 14 Mar 2017 16:28:36 -0700 Subject: [PATCH 10/78] ANDROID: uid_sys_stats: fix typo in init Change-Id: I8a41b331c973898015d11d2018257727083f7910 Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index b0a324be8bb2b..ee8e5bc5c2b1d 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -454,7 +454,7 @@ static int __init proc_uid_sys_stats_init(void) &uid_io_fops, NULL); proc_parent = proc_mkdir("uid_procstat", NULL); - if (!io_parent) { + if (!proc_parent) { pr_err("%s: failed to create uid_procstat proc entry\n", __func__); goto err; From 16a4c1186cdc5cb900a68478ef311e32de726431 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Thu, 13 Apr 2017 17:07:58 -0700 Subject: [PATCH 11/78] ANDROID: uid_sys_stats: reduce update_io_stats overhead Replaced read_lock with rcu_read_lock to reduce time that preemption is disabled. Added a function to update io stats for specific uid and moved hash table lookup, user_namespace out of loops. Bug: 37319300 Change-Id: I2b81b5cd3b6399b40d08c3c14b42cad044556970 Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 61 ++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index ee8e5bc5c2b1d..094cb9739c079 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -249,28 +249,28 @@ static void clean_uid_io_last_stats(struct uid_entry *uid_entry, io_last->fsync -= task->ioac.syscfs; } -static void update_io_stats_locked(void) +static void update_io_stats_all_locked(void) { struct uid_entry *uid_entry; struct task_struct *task, *temp; struct io_stats *io_bucket, *io_curr, *io_last; + struct user_namespace *user_ns = current_user_ns(); unsigned long bkt; - - BUG_ON(!rt_mutex_is_locked(&uid_lock)); + uid_t uid; hash_for_each(hash_table, bkt, uid_entry, hash) memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, sizeof(struct io_stats)); - read_lock(&tasklist_lock); + rcu_read_lock(); do_each_thread(temp, task) { - uid_entry = find_or_register_uid(from_kuid_munged( - current_user_ns(), task_uid(task))); + uid = from_kuid_munged(user_ns, task_uid(task)); + uid_entry = find_or_register_uid(uid); if (!uid_entry) continue; add_uid_io_curr_stats(uid_entry, task); } while_each_thread(temp, task); - read_unlock(&tasklist_lock); + rcu_read_unlock(); hash_for_each(hash_table, bkt, uid_entry, hash) { io_bucket = &uid_entry->io[uid_entry->state]; @@ -293,6 +293,47 @@ static void update_io_stats_locked(void) } } +static void update_io_stats_uid_locked(uid_t target_uid) +{ + struct uid_entry *uid_entry; + struct task_struct *task, *temp; + struct io_stats *io_bucket, *io_curr, *io_last; + struct user_namespace *user_ns = current_user_ns(); + + uid_entry = find_or_register_uid(target_uid); + if (!uid_entry) + return; + + memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, + sizeof(struct io_stats)); + + rcu_read_lock(); + do_each_thread(temp, task) { + if (from_kuid_munged(user_ns, task_uid(task)) != target_uid) + continue; + add_uid_io_curr_stats(uid_entry, task); + } while_each_thread(temp, task); + rcu_read_unlock(); + + io_bucket = &uid_entry->io[uid_entry->state]; + io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; + io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; + + io_bucket->read_bytes += + io_curr->read_bytes - io_last->read_bytes; + io_bucket->write_bytes += + io_curr->write_bytes - io_last->write_bytes; + io_bucket->rchar += io_curr->rchar - io_last->rchar; + io_bucket->wchar += io_curr->wchar - io_last->wchar; + io_bucket->fsync += io_curr->fsync - io_last->fsync; + + io_last->read_bytes = io_curr->read_bytes; + io_last->write_bytes = io_curr->write_bytes; + io_last->rchar = io_curr->rchar; + io_last->wchar = io_curr->wchar; + io_last->fsync = io_curr->fsync; +} + static int uid_io_show(struct seq_file *m, void *v) { struct uid_entry *uid_entry; @@ -300,7 +341,7 @@ static int uid_io_show(struct seq_file *m, void *v) rt_mutex_lock(&uid_lock); - update_io_stats_locked(); + update_io_stats_all_locked(); hash_for_each(hash_table, bkt, uid_entry, hash) { seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", @@ -375,7 +416,7 @@ static ssize_t uid_procstat_write(struct file *file, return count; } - update_io_stats_locked(); + update_io_stats_uid_locked(uid); uid_entry->state = state; @@ -415,7 +456,7 @@ static int process_notifier(struct notifier_block *self, uid_entry->power += task->cpu_power; task->cpu_power = ULLONG_MAX; - update_io_stats_locked(); + update_io_stats_uid_locked(uid); clean_uid_io_last_stats(uid_entry, task); exit: From d7736f71351458bb9044c7a2b3140ae00353719f Mon Sep 17 00:00:00 2001 From: Ganesh Mahendran Date: Tue, 25 Apr 2017 18:07:43 +0800 Subject: [PATCH 12/78] ANDROID: uid_sys_stats: fix access of task_uid(task) struct task_struct *task should be proteced by tasklist_lock. Change-Id: Iefcd13442a9b9d855a2bbcde9fd838a4132fee58 Signed-off-by: Ganesh Mahendran (cherry picked from commit 90d78776c4a0e13fb7ee5bd0787f04a1730631a6) Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 094cb9739c079..e0d123f207e96 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -97,9 +97,11 @@ static int uid_cputime_show(struct seq_file *m, void *v) { struct uid_entry *uid_entry; struct task_struct *task, *temp; + struct user_namespace *user_ns = current_user_ns(); cputime_t utime; cputime_t stime; unsigned long bkt; + uid_t uid; rt_mutex_lock(&uid_lock); @@ -111,14 +113,13 @@ static int uid_cputime_show(struct seq_file *m, void *v) read_lock(&tasklist_lock); do_each_thread(temp, task) { - uid_entry = find_or_register_uid(from_kuid_munged( - current_user_ns(), task_uid(task))); + uid = from_kuid_munged(user_ns, task_uid(task)); + uid_entry = find_or_register_uid(uid); if (!uid_entry) { read_unlock(&tasklist_lock); rt_mutex_unlock(&uid_lock); pr_err("%s: failed to find the uid_entry for uid %d\n", - __func__, from_kuid_munged(current_user_ns(), - task_uid(task))); + __func__, uid); return -ENOMEM; } /* if this task is exiting, we have already accounted for the From 2be3a1e0637514fa60a0937165f42bfd3a0b2b0b Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Mon, 22 May 2017 12:08:06 -0700 Subject: [PATCH 13/78] ANDROID: uid_sys_stats: defer io stats calulation for dead tasks Store sum of dead task io stats in uid_entry and defer uid io calulation until next uid proc stat change or dumpsys. Bug: 37754877 Change-Id: I970f010a4c841c5ca26d0efc7e027414c3c952e0 Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 107 ++++++++++++++--------------------- 1 file changed, 42 insertions(+), 65 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index e0d123f207e96..d4ef4977e1114 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -49,7 +49,8 @@ struct io_stats { #define UID_STATE_TOTAL_CURR 2 #define UID_STATE_TOTAL_LAST 3 -#define UID_STATE_SIZE 4 +#define UID_STATE_DEAD_TASKS 4 +#define UID_STATE_SIZE 5 struct uid_entry { uid_t uid; @@ -226,35 +227,44 @@ static u64 compute_write_bytes(struct task_struct *task) return task->ioac.write_bytes - task->ioac.cancelled_write_bytes; } -static void add_uid_io_curr_stats(struct uid_entry *uid_entry, - struct task_struct *task) +static void add_uid_io_stats(struct uid_entry *uid_entry, + struct task_struct *task, int slot) { - struct io_stats *io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; + struct io_stats *io_slot = &uid_entry->io[slot]; - io_curr->read_bytes += task->ioac.read_bytes; - io_curr->write_bytes += compute_write_bytes(task); - io_curr->rchar += task->ioac.rchar; - io_curr->wchar += task->ioac.wchar; - io_curr->fsync += task->ioac.syscfs; + io_slot->read_bytes += task->ioac.read_bytes; + io_slot->write_bytes += compute_write_bytes(task); + io_slot->rchar += task->ioac.rchar; + io_slot->wchar += task->ioac.wchar; + io_slot->fsync += task->ioac.syscfs; } -static void clean_uid_io_last_stats(struct uid_entry *uid_entry, - struct task_struct *task) +static void compute_uid_io_bucket_stats(struct io_stats *io_bucket, + struct io_stats *io_curr, + struct io_stats *io_last, + struct io_stats *io_dead) { - struct io_stats *io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; + io_bucket->read_bytes += io_curr->read_bytes + io_dead->read_bytes - + io_last->read_bytes; + io_bucket->write_bytes += io_curr->write_bytes + io_dead->write_bytes - + io_last->write_bytes; + io_bucket->rchar += io_curr->rchar + io_dead->rchar - io_last->rchar; + io_bucket->wchar += io_curr->wchar + io_dead->wchar - io_last->wchar; + io_bucket->fsync += io_curr->fsync + io_dead->fsync - io_last->fsync; - io_last->read_bytes -= task->ioac.read_bytes; - io_last->write_bytes -= compute_write_bytes(task); - io_last->rchar -= task->ioac.rchar; - io_last->wchar -= task->ioac.wchar; - io_last->fsync -= task->ioac.syscfs; + io_last->read_bytes = io_curr->read_bytes; + io_last->write_bytes = io_curr->write_bytes; + io_last->rchar = io_curr->rchar; + io_last->wchar = io_curr->wchar; + io_last->fsync = io_curr->fsync; + + memset(io_dead, 0, sizeof(struct io_stats)); } static void update_io_stats_all_locked(void) { struct uid_entry *uid_entry; struct task_struct *task, *temp; - struct io_stats *io_bucket, *io_curr, *io_last; struct user_namespace *user_ns = current_user_ns(); unsigned long bkt; uid_t uid; @@ -269,70 +279,38 @@ static void update_io_stats_all_locked(void) uid_entry = find_or_register_uid(uid); if (!uid_entry) continue; - add_uid_io_curr_stats(uid_entry, task); + add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR); } while_each_thread(temp, task); rcu_read_unlock(); hash_for_each(hash_table, bkt, uid_entry, hash) { - io_bucket = &uid_entry->io[uid_entry->state]; - io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; - io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; - - io_bucket->read_bytes += - io_curr->read_bytes - io_last->read_bytes; - io_bucket->write_bytes += - io_curr->write_bytes - io_last->write_bytes; - io_bucket->rchar += io_curr->rchar - io_last->rchar; - io_bucket->wchar += io_curr->wchar - io_last->wchar; - io_bucket->fsync += io_curr->fsync - io_last->fsync; - - io_last->read_bytes = io_curr->read_bytes; - io_last->write_bytes = io_curr->write_bytes; - io_last->rchar = io_curr->rchar; - io_last->wchar = io_curr->wchar; - io_last->fsync = io_curr->fsync; + compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state], + &uid_entry->io[UID_STATE_TOTAL_CURR], + &uid_entry->io[UID_STATE_TOTAL_LAST], + &uid_entry->io[UID_STATE_DEAD_TASKS]); } } -static void update_io_stats_uid_locked(uid_t target_uid) +static void update_io_stats_uid_locked(struct uid_entry *uid_entry) { - struct uid_entry *uid_entry; struct task_struct *task, *temp; - struct io_stats *io_bucket, *io_curr, *io_last; struct user_namespace *user_ns = current_user_ns(); - uid_entry = find_or_register_uid(target_uid); - if (!uid_entry) - return; - memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0, sizeof(struct io_stats)); rcu_read_lock(); do_each_thread(temp, task) { - if (from_kuid_munged(user_ns, task_uid(task)) != target_uid) + if (from_kuid_munged(user_ns, task_uid(task)) != uid_entry->uid) continue; - add_uid_io_curr_stats(uid_entry, task); + add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR); } while_each_thread(temp, task); rcu_read_unlock(); - io_bucket = &uid_entry->io[uid_entry->state]; - io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR]; - io_last = &uid_entry->io[UID_STATE_TOTAL_LAST]; - - io_bucket->read_bytes += - io_curr->read_bytes - io_last->read_bytes; - io_bucket->write_bytes += - io_curr->write_bytes - io_last->write_bytes; - io_bucket->rchar += io_curr->rchar - io_last->rchar; - io_bucket->wchar += io_curr->wchar - io_last->wchar; - io_bucket->fsync += io_curr->fsync - io_last->fsync; - - io_last->read_bytes = io_curr->read_bytes; - io_last->write_bytes = io_curr->write_bytes; - io_last->rchar = io_curr->rchar; - io_last->wchar = io_curr->wchar; - io_last->fsync = io_curr->fsync; + compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state], + &uid_entry->io[UID_STATE_TOTAL_CURR], + &uid_entry->io[UID_STATE_TOTAL_LAST], + &uid_entry->io[UID_STATE_DEAD_TASKS]); } static int uid_io_show(struct seq_file *m, void *v) @@ -417,7 +395,7 @@ static ssize_t uid_procstat_write(struct file *file, return count; } - update_io_stats_uid_locked(uid); + update_io_stats_uid_locked(uid_entry); uid_entry->state = state; @@ -457,8 +435,7 @@ static int process_notifier(struct notifier_block *self, uid_entry->power += task->cpu_power; task->cpu_power = ULLONG_MAX; - update_io_stats_uid_locked(uid); - clean_uid_io_last_stats(uid_entry, task); + add_uid_io_stats(uid_entry, task, UID_STATE_DEAD_TASKS); exit: rt_mutex_unlock(&uid_lock); From 5bb369e994031e64ad5d729384342fd5591ab95f Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Tue, 8 Aug 2017 12:02:13 -0700 Subject: [PATCH 14/78] uid_sys_stats: fix overflow when io usage delta is negative Setuid can cause negative delta. Check this and update total usage only if delta is positive. Bug: 64317562 Change-Id: I4818c246db66cabf3b11d277faceedec1678694a Signed-off-by: Jin Qian Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index d4ef4977e1114..3c031f9b0cdb2 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -244,13 +244,29 @@ static void compute_uid_io_bucket_stats(struct io_stats *io_bucket, struct io_stats *io_last, struct io_stats *io_dead) { - io_bucket->read_bytes += io_curr->read_bytes + io_dead->read_bytes - + s64 delta; + + delta = io_curr->read_bytes + io_dead->read_bytes - io_last->read_bytes; - io_bucket->write_bytes += io_curr->write_bytes + io_dead->write_bytes - + if (delta > 0) + io_bucket->read_bytes += delta; + + delta = io_curr->write_bytes + io_dead->write_bytes - io_last->write_bytes; - io_bucket->rchar += io_curr->rchar + io_dead->rchar - io_last->rchar; - io_bucket->wchar += io_curr->wchar + io_dead->wchar - io_last->wchar; - io_bucket->fsync += io_curr->fsync + io_dead->fsync - io_last->fsync; + if (delta > 0) + io_bucket->write_bytes += delta; + + delta = io_curr->rchar + io_dead->rchar - io_last->rchar; + if (delta > 0) + io_bucket->rchar += delta; + + delta = io_curr->wchar + io_dead->wchar - io_last->wchar; + if (delta > 0) + io_bucket->wchar += delta; + + delta = io_curr->fsync + io_dead->fsync - io_last->fsync; + if (delta > 0) + io_bucket->fsync += delta; io_last->read_bytes = io_curr->read_bytes; io_last->write_bytes = io_curr->write_bytes; From a9ab9678074e9ce2af7ba6cd8a53e782960db564 Mon Sep 17 00:00:00 2001 From: Artem Borisov Date: Sat, 13 Jan 2018 18:03:40 +0300 Subject: [PATCH 15/78] ANDROID: uid_sys_stats: fix the comment It is not uid_cputime.c anymore. Change-Id: I7effc2a449c1f9cba9d86a7b122a9c05fc266405 Signed-off-by: Artem Borisov Signed-off-by: anupritaisno1 --- drivers/misc/uid_sys_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 3c031f9b0cdb2..2aa7246700b16 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -1,4 +1,4 @@ -/* drivers/misc/uid_cputime.c +/* drivers/misc/uid_sys_stats.c * * Copyright (C) 2014 - 2015 Google, Inc. * From f8573ce40f7f8128ce589a51db516bf656aed6ed Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Tue, 11 Apr 2017 14:40:31 +0530 Subject: [PATCH 16/78] ANDROID: Skip building uid_sys_stats and keyreset drivers as modules Few Android drivers viz. uid_sys_stats and keyreset/combo fail to build as kernel modules. uid_sys_stats.ko failed for undefined "tasklist_lock", which got un-exported in commit c59923a15 ("remove the tasklist_lock export"). Quoting from the commit, "Modules have no business looking at it, and all instances in drivers have been due to use of too-lowlevel APIs. Having this symbol exported prevents moving to more scalable locking schemes for the task list.". So instead of exporting tasklist_lock again, lets not build uid_sys_stats driver as module. Similarly skip building keyreset driver as module which call sys_sync() syscall. To keep things in perspective we don't build these drivers as modules in later kernels (android-4.4/4.9) as well. Change-Id: I6371df72d79c7ad0f0c08e6ebf7e16f1b0970761 Signed-off-by: Amit Pundir Signed-off-by: anupritaisno1 --- drivers/input/Kconfig | 5 +---- drivers/misc/Kconfig | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index bb469e32c6082..e16f43657689b 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -175,15 +175,12 @@ config INPUT_APMPOWER module will be called apm-power. config INPUT_KEYRESET - tristate "Reset key" + bool "Reset key" depends on INPUT select INPUT_KEYCOMBO ---help--- Say Y here if you want to reboot when some keys are pressed; - To compile this driver as a module, choose M here: the - module will be called keyreset. - config INPUT_KEYCOMBO tristate "Key combo" depends on INPUT diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 76ef801ea5e00..c33115e2771cd 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -542,7 +542,7 @@ config SRAM areas found on many SoCs. config UID_SYS_STATS - tristate "Per-UID statistics" + bool "Per-UID statistics" depends on PROFILING help Per UID based cpu time statistics exported to /proc/uid_cputime From 28646f5cde67ca020e0e7d15d13e70fa3ba1b330 Mon Sep 17 00:00:00 2001 From: Ganesh Mahendran Date: Wed, 24 May 2017 10:28:27 +0800 Subject: [PATCH 17/78] ANDROID: Kconfig: add depends for UID_SYS_STATS uid_io depends on TASK_XACCT and TASK_IO_ACCOUNTING. So add depends in Kconfig before compiling code. Change-Id: Ie6bf57ec7c2eceffadf4da0fc2aca001ce10c36e Signed-off-by: Ganesh Mahendran Signed-off-by: anupritaisno1 --- drivers/misc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c33115e2771cd..88b808f346416 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -543,7 +543,7 @@ config SRAM config UID_SYS_STATS bool "Per-UID statistics" - depends on PROFILING + depends on PROFILING && TASK_XACCT && TASK_IO_ACCOUNTING help Per UID based cpu time statistics exported to /proc/uid_cputime Per UID based io statistics exported to /proc/uid_io From 0657d7f351525d7085e304bb3d47d1e446cfb7a0 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 9 Feb 2016 12:31:42 -0800 Subject: [PATCH 18/78] android: recommended.cfg: enable taskstats CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y Signed-off-by: Mark Salyzyn Bug: 21334988 Bug: 26966375 Change-Id: I17b097ae4ea6c63c2e9fddd9544e3f06d49b609d Signed-off-by: anupritaisno1 --- android/configs/android-recommended.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg index 960b9de2860d2..4dd3b4585033d 100644 --- a/android/configs/android-recommended.cfg +++ b/android/configs/android-recommended.cfg @@ -109,6 +109,10 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y CONFIG_TIMER_STATS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y From fcde433f51cbf28f58130ea681ea416698bb7c89 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Thu, 4 Jan 2018 21:04:31 +0800 Subject: [PATCH 19/78] scsi: libsas: fix memory leak in sas_smp_get_phy_events()CVE-2018-7757 We've got a memory leak with the following producer: while true; do cat /sys/class/sas_phy/phy-1:0:12/invalid_dword_count >/dev/null; done The buffer req is allocated and not freed after we return. Fix it. Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") Signed-off-by: Jason Yan CC: John Garry CC: chenqilin CC: chenxiang Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: anupritaisno1 --- drivers/scsi/libsas/sas_expander.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 446b85110a1fc..09625081b56c0 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -684,6 +684,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); out: + kfree(req); kfree(resp); return res; From 012b626a5c9dac12ccf1ebb885236ac396644b9f Mon Sep 17 00:00:00 2001 From: BobZhome Date: Sun, 1 Apr 2018 10:38:21 -0400 Subject: [PATCH 20/78] [PATCH] floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl CVE-2018-7755 FromBrian Belleville Date Wed, 7 Mar 2018 16:02:45 -0800 The final field of a floppy_struct is the field name, which is a pointer to a string in kernel memory. The kernel pointer should not be copied to user memory. The FDGETPRM ioctl copies a floppy_struct to user memory, including the name field. This pointer cannot be used by the user, and it will leak a kernel address to user-space, which will reveal the location of kernel code and data and undermine KASLR protection. Instead, copy the floppy_struct except for the name field. Signed-off-by: Brian Belleville Signed-off-by: anupritaisno1 --- drivers/block/floppy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index eb3575b3fbf08..08a8f1217c22b 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3445,6 +3445,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int (struct floppy_struct **)&outparam); if (ret) return ret; + size = offsetof(struct floppy_struct, name); break; case FDMSGON: UDP->flags |= FTD_MSG; From 55b020e66a75533f94950bce885ea78b10e135eb Mon Sep 17 00:00:00 2001 From: BobZhome Date: Sun, 1 Apr 2018 10:56:45 -0400 Subject: [PATCH 21/78] [PATCH] floppy: Don't print kernel addresses to log in show_floppy CVE-2018-7273 From Brian Belleville Date Tue, 20 Feb 2018 14:54:25 -0800 Outputting kernel addresses will reveal the locations of kernel code and data. Change the cases in show_floppy that print fd_timer.work.func and fd_timeout.work.func to use the %pf format specifier, which will print the symbol name, like what is done for the other function pointers printed by show_floppy. No longer output the value of cont. The variable cont is a pointer that can hold the address of kernel global variables. Signed-off-by: Brian Belleville https://lkml.org/lkml/2018/2/20/669 Signed-off-by: anupritaisno1 --- drivers/block/floppy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 08a8f1217c22b..33788cb1ffc64 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1796,11 +1796,11 @@ static void show_floppy(void) if (work_pending(&floppy_work)) pr_info("floppy_work.func=%pf\n", floppy_work.func); if (delayed_work_pending(&fd_timer)) - pr_info("delayed work.function=%p expires=%ld\n", + pr_info("delayed work.function=%pf expires=%ld\n", fd_timer.work.func, fd_timer.timer.expires - jiffies); if (delayed_work_pending(&fd_timeout)) - pr_info("timer_function=%p expires=%ld\n", + pr_info("timer_function=%pf expires=%ld\n", fd_timeout.work.func, fd_timeout.timer.expires - jiffies); From 9eb71954317c8608e08e7b34d7cfa8d9827e4466 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 19 Feb 2018 01:24:15 +0100 Subject: [PATCH 22/78] netfilter: ebtables: CONFIG_COMPAT: don't trust userland offsets CVE-2018-1068 We need to make sure the offsets are not out of range of the total size. Also check that they are in ascending order. The WARN_ON triggered by syzkaller (it sets panic_on_warn) is changed to also bail out, no point in continuing parsing. Briefly tested with simple ruleset of -A INPUT --limit 1/s' --log plus jump to custom chains using 32bit ebtables binary. Reported-by: Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: anupritaisno1 --- net/bridge/netfilter/ebtables.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 6651a7797d46a..924af39089ead 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -2010,7 +2010,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, if (match_kern) match_kern->match_size = ret; - WARN_ON(type == EBT_COMPAT_TARGET && size_left); + if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) + return -EINVAL; + match32 = (struct compat_ebt_entry_mwt *) buf; } @@ -2067,6 +2069,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, * * offsets are relative to beginning of struct ebt_entry (i.e., 0). */ + for (i = 0; i < 4 ; ++i) { + if (offsets[i] >= *total) + return -EINVAL; + if (i == 0) + continue; + if (offsets[i-1] > offsets[i]) + return -EINVAL; + } + for (i = 0, j = 1 ; j < 4 ; j++, i++) { struct compat_ebt_entry_mwt *match32; unsigned int size; From a8326536246117cbf71f9e781cf762f18fd03597 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Jul 2017 12:34:40 +0200 Subject: [PATCH 23/78] ALSA: msnd: Optimize / harden DSP and MIDI loops CVE-2017-9985 The ISA msnd drivers have loops fetching the ring-buffer head, tail and size values inside the loops. Such codes are inefficient and fragile. This patch optimizes it, and also adds the sanity check to avoid the endless loops. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196131 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196133 Signed-off-by: Takashi Iwai Signed-off-by: anupritaisno1 --- sound/isa/msnd/msnd_midi.c | 30 +++++++++++++++--------------- sound/isa/msnd/msnd_pinnacle.c | 23 ++++++++++++----------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c index ffc67fd80c23d..58e59cd3c95c0 100644 --- a/sound/isa/msnd/msnd_midi.c +++ b/sound/isa/msnd/msnd_midi.c @@ -120,24 +120,24 @@ void snd_msndmidi_input_read(void *mpuv) unsigned long flags; struct snd_msndmidi *mpu = mpuv; void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF; + u16 head, tail, size; spin_lock_irqsave(&mpu->input_lock, flags); - while (readw(mpu->dev->MIDQ + JQS_wTail) != - readw(mpu->dev->MIDQ + JQS_wHead)) { - u16 wTmp, val; - val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead)); - - if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, - &mpu->mode)) - snd_rawmidi_receive(mpu->substream_input, - (unsigned char *)&val, 1); - - wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1; - if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize)) - writew(0, mpu->dev->MIDQ + JQS_wHead); - else - writew(wTmp, mpu->dev->MIDQ + JQS_wHead); + head = readw(mpu->dev->MIDQ + JQS_wHead); + tail = readw(mpu->dev->MIDQ + JQS_wTail); + size = readw(mpu->dev->MIDQ + JQS_wSize); + if (head > size || tail > size) + goto out; + while (head != tail) { + unsigned char val = readw(pwMIDQData + 2 * head); + + if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) + snd_rawmidi_receive(mpu->substream_input, &val, 1); + if (++head > size) + head = 0; + writew(head, mpu->dev->MIDQ + JQS_wHead); } + out: spin_unlock_irqrestore(&mpu->input_lock, flags); } EXPORT_SYMBOL(snd_msndmidi_input_read); diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 3a7946ebbe238..f7659ecbba0d8 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -170,23 +170,24 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id) { struct snd_msnd *chip = dev_id; void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF; + u16 head, tail, size; /* Send ack to DSP */ /* inb(chip->io + HP_RXL); */ /* Evaluate queued DSP messages */ - while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) { - u16 wTmp; - - snd_msnd_eval_dsp_msg(chip, - readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead))); - - wTmp = readw(chip->DSPQ + JQS_wHead) + 1; - if (wTmp > readw(chip->DSPQ + JQS_wSize)) - writew(0, chip->DSPQ + JQS_wHead); - else - writew(wTmp, chip->DSPQ + JQS_wHead); + head = readw(chip->DSPQ + JQS_wHead); + tail = readw(chip->DSPQ + JQS_wTail); + size = readw(chip->DSPQ + JQS_wSize); + if (head > size || tail > size) + goto out; + while (head != tail) { + snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head)); + if (++head > size) + head = 0; + writew(head, chip->DSPQ + JQS_wHead); } + out: /* Send ack to DSP */ inb(chip->io + HP_RXL); return IRQ_HANDLED; From 8a22089a108fbc43b11332482e397419a87092fa Mon Sep 17 00:00:00 2001 From: Roberto Pereira Date: Tue, 10 Oct 2017 17:14:48 -0700 Subject: [PATCH 24/78] ANDROID: scsi: Add segment checking in sg_read CVE-2017-13168 Bug: 65023233 Signed-off-by: Roberto Pereira Change-Id: Ib45f402cf304f9b8bf18884738f92b9c3db55573 Signed-off-by: anupritaisno1 --- drivers/scsi/sg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index aadd3b048f314..4bd31b6adedef 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -400,6 +400,9 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) struct sg_header *old_hdr = NULL; int retval = 0; + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n", From 5f7f7b38d04742f85ec385704de3eb533856a3c3 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 2 May 2017 12:36:48 -0700 Subject: [PATCH 25/78] ASoC: core: Don't assign an out-of-bounds address to rtd_aux When card->num_aux_devs is zero, card->rtd_aux is assigned an out-of-bounds address. This was found by KASan at runtime: ================================================================== BUG: KASAN: slab-out-of-bounds in msm_audrx_init+0xaa8/0xba4 at addr ffffffc14021ec18 Read of size 8 by task kworker/u8:9/264 page:ffffffbdc5008000 count:1 mapcount:0 mapping: (null) index:0x0 flags: 0x4000000000004000(head) page dumped because: kasan: bad access detected CPU: 3 PID: 264 Comm: kworker/u8:9 Tainted: G B W 3.18.31-Sultan #39 Hardware name: Qualcomm Technologies, Inc. MSM 8996 v3.0 + PMI8996 MTP (DT) Workqueue: deferwq deferred_probe_work_func Call trace: [] dump_backtrace+0x0/0x298 [] show_stack+0x14/0x1c [] dump_stack+0x98/0xc0 [] kasan_report+0x3a4/0x4e8 [] __asan_load8+0x24/0x7c [] msm_audrx_init+0xaa8/0xba4 [] snd_soc_register_card+0x10ac/0x1c04 [] msm8996_asoc_machine_probe+0xd9c/0xf1c [] platform_drv_probe+0x50/0xa4 [] driver_probe_device+0x114/0x2e0 [] __device_attach+0x40/0x64 [] bus_for_each_drv+0xac/0xdc [] device_attach+0x94/0xc0 [] bus_probe_device+0x48/0xf0 [] deferred_probe_work_func+0xa0/0xd0 [] process_one_work+0x324/0x50c [] worker_thread+0x4a4/0x624 [] kthread+0x138/0x14c Memory state around the buggy address: ffffffc14021eb00: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe ffffffc14021eb80: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe >ffffffc14021ec00: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe ^ ffffffc14021ec80: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe ffffffc14021ed00: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe ================================================================== Change-Id: I5e5cf2f672753c483917142b6ebf1330995b20a5 Signed-off-by: Sultanxda Signed-off-by: anupritaisno1 --- sound/soc/soc-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 83b13d6f6096b..5f5b4fb342a48 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3653,7 +3653,11 @@ int snd_soc_register_card(struct snd_soc_card *card) if (card->rtd == NULL) return -ENOMEM; card->num_rtd = 0; - card->rtd_aux = &card->rtd[card->num_links]; + + if (card->num_aux_devs > 0) + card->rtd_aux = &card->rtd[card->num_links]; + else + card->rtd_aux = NULL; for (i = 0; i < card->num_links; i++) card->rtd[i].dai_link = &card->dai_link[i]; From 03685008f75adb1d682278189820e80d160c38e9 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sun, 9 Apr 2017 14:49:48 -0700 Subject: [PATCH 26/78] power: msm-core: Fix mutex not getting unlocked in error path When this copy_to_user() fails, the mutex won't be unlocked. Fix it. Change-Id: Ide7a7ed9ca8a8d33dafd2060a0c24c57e6396ea8 Signed-off-by: Sultanxda Signed-off-by: anupritaisno1 --- drivers/power/qcom/msm-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 1b9872a4150df..1b98a090c36cd 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -528,7 +528,7 @@ static long msm_core_ioctl(struct file *file, unsigned int cmd, node->sp->voltage, sizeof(uint32_t) * node->sp->num_of_freqs); if (ret) - break; + goto unlock; for (i = 0; i < node->sp->num_of_freqs; i++) { ret = copy_to_user((void __user *)&argp->freq[i], &node->sp->table[i].frequency, From 02ae403ce4daf13911efe82ba95ab7fb4301cd0e Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sat, 4 Mar 2017 13:58:42 -0800 Subject: [PATCH 27/78] cpufreq: interactive: Skip timer when policy->min == policy->max When the minfreq is set to the maxfreq, there is nothing to really do: the CPU is already running at its maxfreq. In this scenario, just do nothing and re-arm the timer. Signed-off-by: Sultanxda This happens when strong boosts get dispatched by our BoostFramework. Change-Id: Ic95e2f52901965b40d07f055bb93a6a614a5d79c Signed-off-by: Alex Naidis Signed-off-by: anupritaisno1 --- drivers/cpufreq/cpufreq_interactive.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index ba888b776d775..a9ec016a57379 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -435,6 +435,8 @@ static void cpufreq_interactive_timer(unsigned long data) return; if (!ppol->governor_enabled) goto exit; + if (ppol->policy->min == ppol->policy->max) + goto rearm; fcpu = cpumask_first(ppol->policy->related_cpus); now = ktime_to_us(ktime_get()); From 2324d3c9ee0014afc461ac0f019eed3273693093 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 21 Mar 2017 10:12:10 -0700 Subject: [PATCH 28/78] msm: mdss: Don't cache the address of a stack variable in timings init When the panel timings are parsed, a stack-allocated variable is used to store the parsed data; however, this creates two problems. The first problem is that this creates a memory leak since a kstrdup() address is stored into the stack-allocated variable at the end of the mdss_dsi_panel_timing_from_dt() function. The second problem this creates is that the address of the stack-allocated variable is stored into the current_timing struct member (inside mdss_dsi_panel_timing_switch()) for future use in the driver. Since the data that current_timing points to is expected to persist long after init, allocate memory for the timing settings to fix the issues. Change-Id: I2bbc957b229a010c1b5701f2e40e42e65cd88b2d Signed-off-by: Sultanxda Signed-off-by: anupritaisno1 --- drivers/video/msm/mdss/mdss_dsi_panel.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c index 69d1644877f2e..bcb44e5b00f2a 100755 --- a/drivers/video/msm/mdss/mdss_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_dsi_panel.c @@ -2048,19 +2048,24 @@ static int mdss_dsi_panel_parse_display_timings(struct device_node *np, timings_np = of_get_child_by_name(np, "qcom,mdss-dsi-display-timings"); if (!timings_np) { - struct dsi_panel_timing pt; - memset(&pt, 0, sizeof(struct dsi_panel_timing)); + struct dsi_panel_timing *pt; + + pt = kzalloc(sizeof(*pt), GFP_KERNEL); + if (!pt) + return -ENOMEM; /* * display timings node is not available, fallback to reading * timings directly from root node instead */ pr_debug("reading display-timings from panel node\n"); - rc = mdss_dsi_panel_timing_from_dt(np, &pt); + rc = mdss_dsi_panel_timing_from_dt(np, pt); if (!rc) { mdss_dsi_panel_config_res_properties(np, - panel_data->panel_info.sim_panel_mode, &pt); - rc = mdss_dsi_panel_timing_switch(ctrl, &pt.timing); + panel_data->panel_info.sim_panel_mode, pt); + rc = mdss_dsi_panel_timing_switch(ctrl, &pt->timing); + } else { + kfree(pt); } return rc; } From 3b0841ebbabb5846fe792a5d5ddd89decc344002 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 26 May 2016 17:21:05 -0700 Subject: [PATCH 29/78] UPSTREAM: timer: Export destroy_hrtimer_on_stack() hrtimer_init_on_stack() needs a matching call to destroy_hrtimer_on_stack(), so both need to be exported. Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller (cherry picked from commit c08376ac97cb202ec65320f3d90d5c4c5e2adb0b) [astrachan: Fixes i386-allmodconfig build failure in vsoc.ko noticed by 01.org kbuild-all project building kernel/msm] Bug: 70214720 Change-Id: If4d5c466255019322ea21ef38ee5b1b382cce969 Signed-off-by: Alistair Strachan --- kernel/hrtimer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index bbd1dee81fdd8..116b2276032cc 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -480,6 +480,7 @@ void destroy_hrtimer_on_stack(struct hrtimer *timer) { debug_object_free(timer, &hrtimer_debug_descr); } +EXPORT_SYMBOL_GPL(destroy_hrtimer_on_stack); #else static inline void debug_hrtimer_init(struct hrtimer *timer) { } From 658f4b70c6c135fd4618ad47be7a0d9fa2cdf1f9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 24 Apr 2018 18:06:56 -0700 Subject: [PATCH 30/78] ANDROID: sdcardfs: Don't d_drop in d_revalidate After d_revalidate returns 0, the vfs will call d_invalidate, which will call d_drop itself, along with other cleanup. Bug: 78262592 Change-Id: Idbb30e008c05d62edf2217679cb6a5517d8d1a2c Signed-off-by: Daniel Rosenberg Signed-off-by: anupritaisno1 --- fs/sdcardfs/dentry.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 8a35955534ab3..e33707897cbcc 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -51,7 +51,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) * whether the base obbpath has been changed or not */ if (is_obbpath_invalid(dentry)) { - d_drop(dentry); return 0; } @@ -65,7 +64,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) { err = lower_dentry->d_op->d_revalidate(lower_dentry, flags); if (err == 0) { - d_drop(dentry); goto out; } } @@ -73,14 +71,12 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) spin_lock(&lower_dentry->d_lock); if (d_unhashed(lower_dentry)) { spin_unlock(&lower_dentry->d_lock); - d_drop(dentry); err = 0; goto out; } spin_unlock(&lower_dentry->d_lock); if (parent_lower_dentry != lower_cur_parent_dentry) { - d_drop(dentry); err = 0; goto out; } @@ -94,7 +90,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) } if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) { - __d_drop(dentry); err = 0; } @@ -113,7 +108,6 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if (inode) { data = top_data_get(SDCARDFS_I(inode)); if (!data || data->abandoned) { - d_drop(dentry); err = 0; } if (data) From da73c0e9f791354364342dac9e5e08e4321e5282 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 17 Nov 2016 11:24:20 -0800 Subject: [PATCH 31/78] UPSTREAM: dm bufio: avoid sleeping while holding the dm_bufio lock We've seen in-field reports showing _lots_ (18 in one case, 41 in another) of tasks all sitting there blocked on: mutex_lock+0x4c/0x68 dm_bufio_shrink_count+0x38/0x78 shrink_slab.part.54.constprop.65+0x100/0x464 shrink_zone+0xa8/0x198 In the two cases analyzed, we see one task that looks like this: Workqueue: kverityd verity_prefetch_io __switch_to+0x9c/0xa8 __schedule+0x440/0x6d8 schedule+0x94/0xb4 schedule_timeout+0x204/0x27c schedule_timeout_uninterruptible+0x44/0x50 wait_iff_congested+0x9c/0x1f0 shrink_inactive_list+0x3a0/0x4cc shrink_lruvec+0x418/0x5cc shrink_zone+0x88/0x198 try_to_free_pages+0x51c/0x588 __alloc_pages_nodemask+0x648/0xa88 __get_free_pages+0x34/0x7c alloc_buffer+0xa4/0x144 __bufio_new+0x84/0x278 dm_bufio_prefetch+0x9c/0x154 verity_prefetch_io+0xe8/0x10c process_one_work+0x240/0x424 worker_thread+0x2fc/0x424 kthread+0x10c/0x114 ...and that looks to be the one holding the mutex. The problem has been reproduced on fairly easily: 0. Be running Chrome OS w/ verity enabled on the root filesystem 1. Pick test patch: http://crosreview.com/412360 2. Install launchBalloons.sh and balloon.arm from http://crbug.com/468342 ...that's just a memory stress test app. 3. On a 4GB rk3399 machine, run nice ./launchBalloons.sh 4 900 100000 ...that tries to eat 4 * 900 MB of memory and keep accessing. 4. Login to the Chrome web browser and restore many tabs With that, I've seen printouts like: DOUG: long bufio 90758 ms ...and stack trace always show's we're in dm_bufio_prefetch(). The problem is that we try to allocate memory with GFP_NOIO while we're holding the dm_bufio lock. Instead we should be using GFP_NOWAIT. Using GFP_NOIO can cause us to sleep while holding the lock and that causes the above problems. The current behavior explained by David Rientjes: It will still try reclaim initially because __GFP_WAIT (or __GFP_KSWAPD_RECLAIM) is set by GFP_NOIO. This is the cause of contention on dm_bufio_lock() that the thread holds. You want to pass GFP_NOWAIT instead of GFP_NOIO to alloc_buffer() when holding a mutex that can be contended by a concurrent slab shrinker (if count_objects didn't use a trylock, this pattern would trivially deadlock). This change significantly increases responsiveness of the system while in this state. It makes a real difference because it unblocks kswapd. In the bug report analyzed, kswapd was hung: kswapd0 D ffffffc000204fd8 0 72 2 0x00000000 Call trace: [] __switch_to+0x9c/0xa8 [] __schedule+0x440/0x6d8 [] schedule+0x94/0xb4 [] schedule_preempt_disabled+0x28/0x44 [] __mutex_lock_slowpath+0x120/0x1ac [] mutex_lock+0x4c/0x68 [] dm_bufio_shrink_count+0x38/0x78 [] shrink_slab.part.54.constprop.65+0x100/0x464 [] shrink_zone+0xa8/0x198 [] balance_pgdat+0x328/0x508 [] kswapd+0x424/0x51c [] kthread+0x10c/0x114 [] ret_from_fork+0x10/0x40 By unblocking kswapd memory pressure should be reduced. Change-Id: I424022893c4934af71aaf52af00f90b17bca2561 Suggested-by: David Rientjes Reviewed-by: Guenter Roeck Signed-off-by: Douglas Anderson Signed-off-by: Mike Snitzer (cherry picked from commit 9ea61cac0b1ad0c09022f39fd97e9b99a2cfc2dc) Signed-off-by: Minchan Kim Signed-off-by: anupritaisno1 --- drivers/md/dm-bufio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 38eca8c634eab..775a150a8b4f9 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -756,7 +756,8 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client * dm-bufio is resistant to allocation failures (it just keeps * one buffer reserved in cases all the allocations fail). * So set flags to not try too hard: - * GFP_NOIO: don't recurse into the I/O layer + * GFP_NOWAIT: don't wait; if we need to sleep we'll release our + * mutex and wait ourselves. * __GFP_NORETRY: don't retry and rather return failure * __GFP_NOMEMALLOC: don't use emergency reserves * __GFP_NOWARN: don't print a warning in case of failure @@ -766,7 +767,7 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client */ while (1) { if (dm_bufio_cache_size_latch != 1) { - b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); if (b) return b; } From f056f657bd837175898d27db394267a72b1a85a3 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 11 Jun 2014 18:19:28 +0200 Subject: [PATCH 32/78] ktime: add ktime_after and ktime_before helper Add two minimal helper functions analogous to time_before() and time_after() that will later on both be needed by SCTP code. Change-Id: Ie6f609e8fbf7b28cd137a19d14504525eec321a6 Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Git-commit: 67cb9366ff5f99868100198efba5ca88aaa6ad25 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Sahitya Tummala Signed-off-by: anupritaisno1 --- include/linux/ktime.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/ktime.h b/include/linux/ktime.h index e6aacdbebafda..e48fb29c349b7 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -317,6 +317,30 @@ static inline u64 ktime_divns(const ktime_t kt, s64 div) # define ktime_divns(kt, div) (u64)((kt).tv64 / (div)) #endif +/** + * ktime_after - Compare if a ktime_t value is bigger than another one. + * @cmp1: comparable1 + * @cmp2: comparable2 + * + * Return: true if cmp1 happened after cmp2. + */ +static inline bool ktime_after(const ktime_t cmp1, const ktime_t cmp2) +{ + return ktime_compare(cmp1, cmp2) > 0; +} + +/** + * ktime_before - Compare if a ktime_t value is smaller than another one. + * @cmp1: comparable1 + * @cmp2: comparable2 + * + * Return: true if cmp1 happened before cmp2. + */ +static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2) +{ + return ktime_compare(cmp1, cmp2) < 0; +} + static inline s64 ktime_to_us(const ktime_t kt) { return ktime_divns(kt, NSEC_PER_USEC); From 100c47761702386f0a3263b0850950cec0d408ab Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 16 Jul 2014 21:03:56 +0000 Subject: [PATCH 33/78] ktime: Change ktime_set() to take 64bit seconds value In order to support dates past 2038 on 32bit systems, ktime_set() needs to handle 64bit second values. [ tglx: Removed the BITS_PER_LONG check ] Change-Id: I59037ff2d8b536aeda51061fd85601a596821154 Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz Git-commit: b17b20d70dcbe48dd1aa6aba073a60ddfce5d7db Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Sahitya Tummala Signed-off-by: anupritaisno1 --- include/linux/ktime.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/linux/ktime.h b/include/linux/ktime.h index e48fb29c349b7..638794b816ef2 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -71,13 +71,12 @@ typedef union ktime ktime_t; /* Kill this */ * * Return the ktime_t representation of the value */ -static inline ktime_t ktime_set(const long secs, const unsigned long nsecs) +static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs) { -#if (BITS_PER_LONG == 64) if (unlikely(secs >= KTIME_SEC_MAX)) return (ktime_t){ .tv64 = KTIME_MAX }; -#endif - return (ktime_t) { .tv64 = (s64)secs * NSEC_PER_SEC + (s64)nsecs }; + + return (ktime_t) { .tv64 = secs * NSEC_PER_SEC + (s64)nsecs }; } /* Subtract two ktime_t variables. rem = lhs -rhs: */ From 342a61e55f18e5ad90bf848794859b773cf7942c Mon Sep 17 00:00:00 2001 From: Bala Venkatesh Date: Wed, 18 Oct 2017 13:08:38 +0530 Subject: [PATCH 34/78] qcacld-2.0: Check vdev_id against wma->max_bssid Check vdev_id against wma->max_bssid in wma_mcc_vdev_tx_pause_evt_handler to avoid bufer overflow. Bug: 70237692 Change-Id: Ie47a0ed2f7f27f13a01e1b2cb365fae66b41b1df CRs-Fixed: 2119404 Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 0d634a767da18..069a4bef66d0a 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -31905,7 +31905,8 @@ static int wma_mcc_vdev_tx_pause_evt_handler(void *handle, u_int8_t *event, /* FW mapped vdev from ID * vdev_map = (1 << vdev_id) * So, host should unmap to ID */ - for (vdev_id = 0; vdev_map != 0; vdev_id++) + for (vdev_id = 0; vdev_map != 0 && vdev_id < wma->max_bssid; + vdev_id++) { if (!(vdev_map & 0x1)) { From 587b3d0677c86333e416d3a6104ed49239545b0c Mon Sep 17 00:00:00 2001 From: gaurank kathpalia Date: Thu, 30 Nov 2017 17:28:22 +0530 Subject: [PATCH 35/78] qcacld-2.0: Avoid possible buffer overwrite in wma_process_utf_event Check for the maximum allowed data that can be written into the buffer utf_event_info.data in the function wma_process_utf_event. Bug: 68992451 Change-Id: I9ee37470b7a3e7016941f871d3cf73eb12718758 CRs-Fixed: 2131653 Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 069a4bef66d0a..6dcd0225e6651 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -35109,6 +35109,14 @@ wma_process_utf_event(WMA_HANDLE handle, currentSeq); } + if ((datalen > MAX_UTF_EVENT_LENGTH) || + (wma_handle->utf_event_info.offset > + (MAX_UTF_EVENT_LENGTH - datalen))) { + WMA_LOGE("Excess data from firmware, offset:%zu, len:%d", + wma_handle->utf_event_info.offset, datalen); + return -EINVAL; + } + memcpy(&wma_handle->utf_event_info.data[wma_handle->utf_event_info.offset], &data[sizeof(segHdrInfo)], datalen); From 536343244f0c3847c4c942979a0d3b75b7b87e72 Mon Sep 17 00:00:00 2001 From: gaurank kathpalia Date: Tue, 3 Oct 2017 18:13:49 +0530 Subject: [PATCH 36/78] qcacld-2.0: Check for valid vdev ID in wma_nlo_match_evt_handler Check if the firmware is passing a valid vdev ID or not in the NLO match event and return error if vdev is invalid Bug: 68992442 Change-Id: I83f957ae084e17c20f607eb3862a131f3b311d23 CRs-Fixed: 2132377 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 6dcd0225e6651..95fd2dc6bbf5d 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -31757,6 +31757,11 @@ static int wma_nlo_match_evt_handler(void *handle, u_int8_t *event, nlo_event = param_buf->fixed_param; WMA_LOGD("PNO match event received for vdev %d", nlo_event->vdev_id); + if (nlo_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id in the NLO event %d", + nlo_event->vdev_id); + return -EINVAL; + } node = &wma->interfaces[nlo_event->vdev_id]; if (node) From 8e28f0a42306e8dce6553afc8a2ce7c66989ede9 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 31 Oct 2017 17:02:13 +0530 Subject: [PATCH 37/78] qcacld-2.0: Check for the max number of P2P NOA descriptors Check for the maximum number of P2P NOA descriptors in wma_send_bcn_buf_ll. Bug: 68992438 Change-Id: If7e5b3c53309412dc7d3cd748c2f5581898fbbfe CRs-Fixed: 2135600 Signed-off-by: Ahmed ElArabawy Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 95fd2dc6bbf5d..1d134f175ddd6 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -5342,6 +5342,12 @@ static void wma_send_bcn_buf_ll(tp_wma_handle wma, WMA_LOGE("%s: Invalid beacon buffer", __func__); return; } + if (WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info) > + WMI_P2P_MAX_NOA_DESCRIPTORS) { + WMA_LOGE("%s: Too many descriptors %d", __func__, + WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info)); + return; + } wmi_buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd)); if (!wmi_buf) { From 2b3043c6b864d4912bc96d90f914ee1d74b4dbe9 Mon Sep 17 00:00:00 2001 From: gaurank kathpalia Date: Thu, 28 Sep 2017 16:41:57 +0530 Subject: [PATCH 38/78] qcacld-2.0: Check for upper bound in P2P NOA event Check for the upper bounds for number of NOA descriptors received in the P2P NOA event. Bug: 68992432 Change-Id: Id7ecf064f2c25f378f76d795902713da8520507f CRs-Fixed: 2132226 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 1d134f175ddd6..4b2ab8144da18 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -5974,6 +5974,12 @@ static int wma_p2p_noa_event_handler(void *handle, u_int8_t *event, u_int32_t le descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); noa_ie.num_descriptors = (u_int8_t)descriptors; + if (noa_ie.num_descriptors > WMA_MAX_NOA_DESCRIPTORS) { + WMA_LOGD("Sizing down the no of desc %d to max", + noa_ie.num_descriptors); + noa_ie.num_descriptors = WMA_MAX_NOA_DESCRIPTORS; + } + WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, " "num_descriptors = %u", __func__, noa_ie.index, noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); From e08f38f75e6d6cbfc3255d08dfa7be25b9c74a52 Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Mon, 2 Oct 2017 14:02:29 -0700 Subject: [PATCH 39/78] qcacld-2.0: Set length of challenge text sent by SAP to 128 SIR_MAC_AUTH_CHALLENGE_LENGTH is updated to 253 from 128 as per IEEE spec due to connection fails between DUT-SAP and old ref-STA. Auth failure occurs as encrypted data sent by ref-STA is only 128 bytes instead of 253 bytes. Fix is to set length of challenge text sent by SAP to 128 bytes. Change-Id: I20eda5ffc0cca4dc4b64beece0740932e13eacb8 CRs-Fixed: 2103899 Bug: 67030205 Bug: 68992395 Signed-off-by: Srinivas Girigowda Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h | 1 + .../CORE/MAC/src/pe/lim/limProcessAuthFrame.c | 13 +++++++------ .../CORE/MAC/src/pe/lim/limSecurityUtils.h | 5 +++++ .../CORE/MAC/src/pe/lim/limSendManagementFrames.c | 7 ++++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h b/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h index 30bb3ca957ecc..ab5487456b62c 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h +++ b/drivers/staging/qcacld-2.0/CORE/MAC/inc/sirMacProtDef.h @@ -586,6 +586,7 @@ #define SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS 4 #define SIR_MAC_KEY_LENGTH 13 // WEP Maximum key length size #define SIR_MAC_AUTH_CHALLENGE_LENGTH 253 +#define SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH 128 #define SIR_MAC_WEP_IV_LENGTH 4 #define SIR_MAC_WEP_ICV_LENGTH 4 #define SIR_MAC_CHALLENGE_ID_LEN 2 diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c index 05591d0494441..7649251346384 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c @@ -290,7 +290,7 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse goto free; } - if (frameLen < LIM_ENCR_AUTH_BODY_LEN) + if (frameLen < LIM_ENCR_AUTH_BODY_LEN_SAP) { // Log error limLog(pMac, LOGE, @@ -966,9 +966,9 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse pAuthNode->fTimerStarted = 1; /* - * get random bytes and use as challenge text. + * get random bytes and use as challenge text */ - if( !VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes( 0, (tANI_U8 *)challengeTextArray, SIR_MAC_AUTH_CHALLENGE_LENGTH ) ) ) + if( !VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes( 0, (tANI_U8 *)challengeTextArray, SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH ) ) ) { limLog(pMac, LOGE,FL("Challenge text preparation failed in limProcessAuthFrame")); goto free; @@ -990,11 +990,12 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse pRxAuthFrameBody->authTransactionSeqNumber + 1; authFrame->authStatusCode = eSIR_MAC_SUCCESS_STATUS; + authFrame->type = SIR_MAC_CHALLENGE_TEXT_EID; - authFrame->length = SIR_MAC_AUTH_CHALLENGE_LENGTH; + authFrame->length = SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH; vos_mem_copy(authFrame->challengeText, pAuthNode->challengeText, - SIR_MAC_AUTH_CHALLENGE_LENGTH); + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH); limSendAuthMgmtFrame( pMac, authFrame, @@ -1596,7 +1597,7 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse if (vos_mem_compare(pRxAuthFrameBody->challengeText, pAuthNode->challengeText, - SIR_MAC_AUTH_CHALLENGE_LENGTH)) + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH)) { /// Challenge match. STA is autheticated ! diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h index 4fb961c3cebb7..3dd987b1fa9ad 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSecurityUtils.h @@ -48,6 +48,11 @@ SIR_MAC_WEP_ICV_LENGTH + \ SIR_MAC_CHALLENGE_ID_LEN) +#define LIM_ENCR_AUTH_BODY_LEN_SAP (SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + \ + SIR_MAC_CHALLENGE_ID_LEN + \ + SIR_MAC_AUTH_FRAME_INFO_LEN + \ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH) struct tLimPreAuthNode; tANI_U8 limIsAuthAlgoSupported(tpAniSirGlobal, tAniAuthType, tpPESession); diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c index ac0def36471c6..162d7ed91acf2 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limSendManagementFrames.c @@ -3516,10 +3516,11 @@ limSendAuthMgmtFrame(tpAniSirGlobal pMac, * transaction number, status code and 128 bytes * for challenge text. */ - + bodyLen = SIR_MAC_AUTH_FRAME_INFO_LEN + + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + + SIR_MAC_CHALLENGE_ID_LEN; frameLen = sizeof(tSirMacMgmtHdr) + - sizeof(tSirMacAuthFrame); - bodyLen = sizeof(tSirMacAuthFrameBody); + bodyLen; } break; From b444d3eb042ddb2aa040cf07a82fab3643da38ff Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Fri, 1 Dec 2017 14:57:46 -0800 Subject: [PATCH 40/78] qcacld-2.0: Add sanity check to limit mgmt frames data len Currently the mpdu_data_len in Rx pkt meta is not checked for upper bound in wma_form_rx_packet. Add sanity check to drop the packet if mpdu_data_len is greater than 2000 bytes. Also add upper bound check for frame_len in lim_process_auth_frame function. Change-Id: I387615127ab98ef43baa6f2570b0433af39a016e CRs-Fixed: 2133040 Bug: 68992395 Signed-off-by: Srinivas Girigowda Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c | 10 ++++++++++ .../CORE/MAC/src/pe/lim/limProcessAuthFrame.c | 3 ++- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c index 3ebe957c5d794..b09445f59fd45 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TLSHIM/tl_shim.c @@ -642,6 +642,16 @@ static int tlshim_mgmt_rx_process(void *context, u_int8_t *data, rx_pkt->pkt_meta.mpdu_data_len = hdr->buf_len - rx_pkt->pkt_meta.mpdu_hdr_len; + /* + * If the mpdu_data_len is greater than Max (2k), drop the frame + */ + if (rx_pkt->pkt_meta.mpdu_data_len > WMA_MAX_MGMT_MPDU_LEN) { + TLSHIM_LOGE("Data Len %d greater than max, dropping frame", + rx_pkt->pkt_meta.mpdu_data_len); + vos_mem_free(rx_pkt); + return 0; + } + /* * saved_beacon means this beacon is a duplicate of one * sent earlier. roamCandidateInd flag is used to indicate to diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c index 7649251346384..af5411e18eaf6 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessAuthFrame.c @@ -290,7 +290,8 @@ limProcessAuthFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession pse goto free; } - if (frameLen < LIM_ENCR_AUTH_BODY_LEN_SAP) + if ((frameLen < LIM_ENCR_AUTH_BODY_LEN_SAP) || + (frameLen > LIM_ENCR_AUTH_BODY_LEN_SAP)) { // Log error limLog(pMac, LOGE, diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h index f8f2028f79df4..c210ec094fa6b 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h @@ -101,6 +101,8 @@ #define FRAGMENT_SIZE 3072 +#define WMA_MAX_MGMT_MPDU_LEN 2000 + #define WMA_INVALID_VDEV_ID 0xFF #define MAX_MEM_CHUNKS 32 #define WMA_MAX_VDEV_SIZE 20 From 846cf9df5b6d678b5b143d861ec3a6f835457623 Mon Sep 17 00:00:00 2001 From: "Poddar, Siddarth" Date: Wed, 6 Dec 2017 12:44:30 +0530 Subject: [PATCH 41/78] qcacld-2.0: Fix potential buffer overflow in process_tx_info Check for buffer overflow for pktlog messages in process_tx_info function before doing mem copy. Bug: 72957136 Change-Id: Ic8ee17fa03a987468405c9978aa06ee849fa5661 CRs-Fixed: 2154331 Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c index 3db0b8758af21..79c7dc81915be 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/pktlog_internal.c @@ -307,6 +307,10 @@ process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, */ txctl_log.priv.frm_hdr = frm_hdr; adf_os_assert(txctl_log.priv.txdesc_ctl); + adf_os_assert(pl_hdr.size < sizeof(txctl_log.priv.txdesc_ctl)); + pl_hdr.size = (pl_hdr.size > sizeof(txctl_log.priv.txdesc_ctl)) + ? sizeof(txctl_log.priv.txdesc_ctl) : + pl_hdr.size; adf_os_mem_copy((void *)&txctl_log.priv.txdesc_ctl, ((void *)data + sizeof(struct ath_pktlog_hdr)), pl_hdr.size); From 777344b9f8371061df779738042787b607c8e50b Mon Sep 17 00:00:00 2001 From: Tiger Yu Date: Wed, 6 Dec 2017 13:43:46 +0800 Subject: [PATCH 42/78] qcacld-2.0: Fix potential buffer overflow in ol_rx_flush_handler Check for the validity of tid when received the htt message of HTT_T2H_MSG_TYPE_RX_FLUSH & HTT_T2H_MSG_TYPE_RX_PN_IND from firmware to ensure the buffer overflow does not happen. And correct the sequence number type from signed int to unsigned. Bug: 72957235 Change-Id: I1d333acddfcfafcd23d8ba8da676384d28d0a471 CRs-Fixed: 2149399 Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c | 8 ++++---- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c | 14 +++++++++++--- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h | 4 ++-- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c | 15 ++++++++++++--- .../CORE/SERVICES/COMMON/ol_htt_rx_api.h | 4 ++-- .../CORE/SERVICES/COMMON/ol_txrx_htt_api.h | 4 ++-- 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c index b736a970c5750..6bdc9f628eac1 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c @@ -172,7 +172,7 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) { u_int16_t peer_id; u_int8_t tid; - int seq_num_start, seq_num_end; + u_int16_t seq_num_start, seq_num_end; enum htt_rx_flush_action action; peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word); @@ -675,7 +675,7 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { { u_int16_t peer_id; u_int8_t tid, pn_ie_cnt, *pn_ie=NULL; - int seq_num_start, seq_num_end; + u_int16_t seq_num_start, seq_num_end; /*First dword */ peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); @@ -1077,8 +1077,8 @@ void htt_rx_frag_ind_flush_seq_num_range( htt_pdev_handle pdev, adf_nbuf_t rx_frag_ind_msg, - int *seq_num_start, - int *seq_num_end) + u_int16_t *seq_num_start, + u_int16_t *seq_num_end) { u_int32_t *msg_word; diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c index 358d6d660c3bf..420683bf9cf5c 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -192,12 +192,20 @@ ol_rx_frag_indication_handler( u_int8_t tid) { u_int16_t seq_num; - int seq_num_start, seq_num_end; + u_int16_t seq_num_start, seq_num_end; struct ol_txrx_peer_t *peer; htt_pdev_handle htt_pdev; adf_nbuf_t head_msdu, tail_msdu; void *rx_mpdu_desc; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", + __FUNCTION__, + tid); + return; + } + htt_pdev = pdev->htt_pdev; peer = ol_txrx_peer_find_by_id(pdev, peer_id); @@ -245,7 +253,7 @@ ol_rx_reorder_flush_frag( htt_pdev_handle htt_pdev, struct ol_txrx_peer_t *peer, unsigned tid, - int seq_num) + u_int16_t seq_num) { struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; int seq; diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h index 737c299873057..7750f2456fd68 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -165,7 +165,7 @@ ol_rx_reorder_flush_frag( htt_pdev_handle htt_pdev, struct ol_txrx_peer_t *peer, unsigned tid, - int seq_num); + u_int16_t seq_num); static inline void xor_block( diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c index e1ffff092a92f..05f54907bb509 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c @@ -583,6 +583,14 @@ ol_rx_flush_handler( struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; htt_pdev_handle htt_pdev = pdev->htt_pdev; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", + __FUNCTION__, + tid); + return; + } + peer = ol_txrx_peer_find_by_id(pdev, peer_id); if (peer) { vdev = peer->vdev; @@ -622,8 +630,8 @@ ol_rx_pn_ind_handler( ol_txrx_pdev_handle pdev, u_int16_t peer_id, u_int8_t tid, - int seq_num_start, - int seq_num_end, + u_int16_t seq_num_start, + u_int16_t seq_num_end, u_int8_t pn_ie_cnt, u_int8_t *pn_ie) { @@ -635,7 +643,8 @@ ol_rx_pn_ind_handler( adf_nbuf_t head_msdu = NULL; adf_nbuf_t tail_msdu = NULL; htt_pdev_handle htt_pdev = pdev->htt_pdev; - int seq_num, i=0; + u_int16_t seq_num; + int i=0; peer = ol_txrx_peer_find_by_id(pdev, peer_id); diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h index b8e98250a4be7..ba043dbdc4e65 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_htt_rx_api.h @@ -833,8 +833,8 @@ void htt_rx_frag_ind_flush_seq_num_range( htt_pdev_handle pdev, adf_nbuf_t rx_frag_ind_msg, - int *seq_num_start, - int *seq_num_end); + u_int16_t *seq_num_start, + u_int16_t *seq_num_end); /** * @brief Return the HL rx desc size * @param pdev - the HTT instance the rx data was received on diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h index 0baafe0f6bdec..8d42b0f061146 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_htt_api.h @@ -617,8 +617,8 @@ ol_rx_pn_ind_handler( ol_txrx_pdev_handle pdev, u_int16_t peer_id, u_int8_t tid, - int seq_num_start, - int seq_num_end, + u_int16_t seq_num_start, + u_int16_t seq_num_end, u_int8_t pn_ie_cnt, u_int8_t *pn_ie); From a2b4bed87a94ade2d7da3906c76011b470a2eadc Mon Sep 17 00:00:00 2001 From: Tiger Yu Date: Fri, 1 Dec 2017 10:13:56 +0800 Subject: [PATCH 43/78] qcacld-2.0: Fix potential buffer overflow in htt_t2h_lp_msg_handler Check for the validity of peer_id when received the htt message of HTT_T2H_MSG_TYPE_PEER_MAP or HTT_T2H_MSG_TYPE_PEER_UNMAP from firmware to ensure the buffer overflow does not happen. Bug: 72956997 Change-Id: I2c589e9f8a99ba18b7ee629b80732fbc5e2c1f44 CRs-Fixed: 2147119 Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c index 6bdc9f628eac1..f20152b1783d5 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c @@ -297,6 +297,14 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) peer_mac_addr = htt_t2h_mac_addr_deswizzle( (u_int8_t *) (msg_word+1), &mac_addr_deswizzle_buf[0]); + if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { + adf_os_print("%s: HTT_T2H_MSG_TYPE_PEER_MAP," + "invalid peer_id, %u\n", + __FUNCTION__, + peer_id); + break; + } + ol_rx_peer_map_handler( pdev->txrx_pdev, peer_id, vdev_id, peer_mac_addr, 1/*can tx*/); break; @@ -306,6 +314,14 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) u_int16_t peer_id; peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); + if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { + adf_os_print("%s: HTT_T2H_MSG_TYPE_PEER_UNMAP," + "invalid peer_id, %u\n", + __FUNCTION__, + peer_id); + break; + } + ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id); break; } From 3e10f776d4e0e8d8a31190d274078f731c86d1ca Mon Sep 17 00:00:00 2001 From: Vignesh Viswanathan Date: Mon, 20 Nov 2017 23:34:12 +0530 Subject: [PATCH 44/78] qcacld-2.0: Fix buffer overrun in function ProcSetReqInternal In function ProcSetReqInternal, valueLen is obtained from the message buffer pParam. This valueLen is used as argument to the function GetStrValue where the contents of the buffer pParam is copied to pMac->cfg.gSBuffer for valueLen number of bytes. However the array pMac->cfg.gSBuffer is a static array of size CFG_MAX_STR_LEN. If the value of valueLen exceeds CFG_MAX_STR_LEN, a buffer overwrite will occur in GetStrValue. Add Sanity check to make sure valueLen does not exceed CFG_MAX_STR_LEN. Bug: 72957177 Change-Id: I9bf3a502d4b73c37e7b4ece963e7ce493274c893 CRs-Fixed: 2143847 Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c index 943ba48cab560..947f848401406 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/cfg/cfgProcMsg.c @@ -2712,7 +2712,8 @@ ProcSetReqInternal(tpAniSirGlobal pMac, tANI_U16 length, tANI_U32 *pParam, tANI_ // Process string parameter else { - if (valueLenRoundedUp4 > length) + if ((valueLenRoundedUp4 > length) || + (valueLen > CFG_MAX_STR_LEN)) { PELOGE(cfgLog(pMac, LOGE, FL("Invalid string length %d" "in set param %d (tot %d)"), valueLen, From 7d24cbf4a29bb1a37a7cb13d77fe1ccc204bb795 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 20 Dec 2017 12:49:54 +0530 Subject: [PATCH 45/78] qcacld-2.0: Fix buffer overread in wma_extscan_hotlist_match_event_handler In function wma_extscan_hotlist_match_event_handler, numap and src_hotlist are received from the FW. src_hotlist is pointer to the hostist data and is looped for numap times and copied to the local buffer dest_hotlist. If the value of numap is not equal to the number of src_hotlist data present in the buffer, buffer overread would occur during memcpy. Add check to validate the len of the buffer received from the FW is not less than the size of fixparam struct + (numap * src_hostlist structure) Bug: 72956920 Change-Id: Idbcb680b64eca399b27f9e7edeccbac21bf8ddfb CRs-Fixed: 2148646 Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 4b2ab8144da18..f19de1c21bde3 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -3929,7 +3929,7 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, wmi_extscan_wlan_descriptor *src_hotlist; uint32_t numap; int j, ap_found = 0; - + uint32_t buf_len; tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context( VOS_MODULE_ID_PE, wma->vos_context); if (!pMac) { @@ -3959,6 +3959,13 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, __func__, numap); numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES; } + buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) + + (4 * sizeof(uint32_t)) + + (numap * sizeof(wmi_extscan_wlan_descriptor)); + if (buf_len > len) { + WMA_LOGE("Invalid buf len from FW %d numap %d", len, numap); + return -EINVAL; + } dest_hotlist = vos_mem_malloc(sizeof(*dest_hotlist) + sizeof(*dest_ap) * numap); if (!dest_hotlist) { From 41dd1a443634efdbbd4e8e19b0d28f2ccf2f7b61 Mon Sep 17 00:00:00 2001 From: tinlin Date: Thu, 11 Jan 2018 14:46:59 +0800 Subject: [PATCH 46/78] qcacld-2.0: Calculate buf_len properly for extscan hotlist event buffer Calculate buf_len properly for extscan hotlist event buffer in wma_extscan_hotlist_match_event_handler() Bug: 72956920 Change-Id: I2ae9d3b30dad2c6143d8014d655fdcc06b85eb1e CRs-Fixed: 2170578 Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index f19de1c21bde3..847892760d23c 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -3960,7 +3960,7 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES; } buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) + - (4 * sizeof(uint32_t)) + + WMI_TLV_HDR_SIZE + (numap * sizeof(wmi_extscan_wlan_descriptor)); if (buf_len > len) { WMA_LOGE("Invalid buf len from FW %d numap %d", len, numap); From dd885467dd0330877940000e7eeb489c68ac4b02 Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Wed, 14 Feb 2018 15:01:51 -0800 Subject: [PATCH 47/78] qcacld-2.0: Add sanity check for vdev id to prevent OOB access Add sanity check for vdev id in wma_vdev_start_resp_handler() to prevent out of bound memory access. Change-Id: I2a496e3f5b546d20813e7fce208c037f4bf68e42 CRs-Fixed: 2120424 Bug: 71501694 Signed-off-by: Srinivas Girigowda Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 847892760d23c..8c8826a1c0a85 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -1141,6 +1141,11 @@ static int wma_vdev_start_resp_handler(void *handle, u_int8_t *cmd_param_info, return -EINVAL; } + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id received from firmware"); + return -EINVAL; + } + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) { adf_os_spin_lock_bh(&wma->dfs_ic->chan_lock); wma->dfs_ic->disable_phy_err_processing = false; From fa69ae07a3f22b69939b8a71ca62ecce418ed3b1 Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Wed, 14 Feb 2018 15:34:55 -0800 Subject: [PATCH 48/78] qcacld-2.0: Add sanity check for vdev_id in wma_wow_wakeup_host_event Currently wake_info->vdev_id, recevied from the FW, is directly used to refer to wma->interfaces without validating if the vdev_id is valid. Add sanity check to make sure vdev_id is less than max_bssid before using it. Change-Id: If7612be6c5b3ca4fc541b4168995f58e7f92f3e5 CRs-Fixed: 2114363 Bug: 71501687 Signed-off-by: Srinivas Girigowda Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 8c8826a1c0a85..1b755e01de69e 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -21491,19 +21491,18 @@ static int wma_wow_wakeup_host_event(void *handle, u_int8_t *event, wake_info = param_buf->fixed_param; - if ((wake_info->wake_reason != WOW_REASON_UNSPECIFIED) || - (wake_info->wake_reason == WOW_REASON_UNSPECIFIED && - !wmi_get_runtime_pm_inprogress(wma->wmi_handle))) { + if (!wmi_get_runtime_pm_inprogress(wma->wmi_handle)) { if (wake_info->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: received invalid vdev_id %d", __func__, wake_info->vdev_id); return -EINVAL; } - WMA_LOGA("WOW wakeup host event received (reason: %s(%d)) for vdev %d", + + WMA_LOGA("WOW (%d) %s vdev:%d", + wake_info->wake_reason, wma_wow_wake_reason_str(wake_info->wake_reason, wma), wake_info->wake_reason, wake_info->vdev_id); - vos_wow_wakeup_host_event(wake_info->wake_reason); } vos_event_set(&wma->wma_resume_event); @@ -21555,6 +21554,12 @@ static int wma_wow_wakeup_host_event(void *handle, u_int8_t *event, #ifdef FEATURE_WLAN_SCAN_PNO case WOW_REASON_NLOD: wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_NLOD); + if (wake_info->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, wake_info->vdev_id); + return -EINVAL; + } + node = &wma->interfaces[wake_info->vdev_id]; if (node) { WMA_LOGD("NLO match happened"); From 8ffb8d256d8617ecf2c46b896073d3cdf1285095 Mon Sep 17 00:00:00 2001 From: hqu Date: Mon, 22 Jan 2018 15:07:06 +0800 Subject: [PATCH 49/78] qcacld-2.0: Add mutex lock for proc handlers It will have race condition issue when multiple threads access some fields of global shared variable ctl concurrently. Fix is to add mutex lock for proc handlers. Bug: 35470735 Change-Id: Ifba428ae6544ccbdae0547a63972ab241ae68d7c CRs-Fixed: 2173232 Signed-off-by: Ahmed ElArabawy Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c index a3c470b678a0d..ed6db1766188b 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -78,6 +78,8 @@ static struct ath_pktlog_info *g_pktlog_info; static struct proc_dir_entry *g_pktlog_pde; +static DEFINE_MUTEX(proc_mutex); + static int pktlog_attach(struct ol_softc *sc); static void pktlog_detach(struct ol_softc *sc); static int pktlog_open(struct inode *i, struct file *f); @@ -226,9 +228,11 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ol_ath_generic_softc_handle scn; struct ol_pktlog_dev_t *pl_dev; + mutex_lock(&proc_mutex); scn = (ol_ath_generic_softc_handle) ctl->extra1; if (!scn) { + mutex_unlock(&proc_mutex); printk("%s: Invalid scn context\n", __func__); ASSERT(0); return -EINVAL; @@ -237,6 +241,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, pl_dev = get_pl_handle((struct ol_softc *)scn); if (!pl_dev) { + mutex_unlock(&proc_mutex); printk("%s: Invalid pktlog context\n", __func__); ASSERT(0); return -ENODEV; @@ -266,6 +271,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ctl->data = NULL; ctl->maxlen = 0; + mutex_unlock(&proc_mutex); return ret; } @@ -283,9 +289,11 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ol_ath_generic_softc_handle scn; struct ol_pktlog_dev_t *pl_dev; + mutex_lock(&proc_mutex); scn = (ol_ath_generic_softc_handle) ctl->extra1; if (!scn) { + mutex_unlock(&proc_mutex); printk("%s: Invalid scn context\n", __func__); ASSERT(0); return -EINVAL; @@ -294,6 +302,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, pl_dev = get_pl_handle((struct ol_softc *)scn); if (!pl_dev) { + mutex_unlock(&proc_mutex); printk("%s: Invalid pktlog handle\n", __func__); ASSERT(0); return -ENODEV; @@ -318,6 +327,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ctl->data = NULL; ctl->maxlen = 0; + mutex_unlock(&proc_mutex); return ret; } From e35fc78d6dde3cd2ae9bd24c0bfb3ebed9a2abc6 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 21 Dec 2017 16:27:03 +0530 Subject: [PATCH 50/78] qcacld-2.0: Fix buffer overwrite due to ssid_len in WMA handlers In multiple WMA event handler functions, ssid_len is used to copy ssid from FW buffer to local buffer and ssid_len value is received from the FW. If the ssid_len value exceeds SIR_MAC_MAX_SSID_LENGTH then a buffer overwrite would occur. Add sanity check for ssid_len against SIR_MAC_MAX_SSID_LENGTH in multiple WMA handler functions Bug: 72956801 Change-Id: I9e4b1f88c275093b4912496cdb936cf54a8880a2 CRs-Fixed: 2162678 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 1b755e01de69e..d4be4bc23f3ce 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -4006,6 +4006,11 @@ static int wma_extscan_hotlist_match_event_handler(void *handle, dest_ap->ieLength = src_hotlist-> ie_length; WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, dest_ap->bssid); + if (src_hotlist->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGE("%s Invalid SSID len %d, truncating", + __func__, src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + } vos_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, src_hotlist->ssid.ssid_len); dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; @@ -4180,6 +4185,13 @@ static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, ap->bssid); + if (src_hotlist->ssid.ssid_len > + SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGD("%s Invalid SSID len %d, truncating", + __func__, src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = + SIR_MAC_MAX_SSID_LENGTH; + } vos_mem_copy(ap->ssid, src_hotlist->ssid.ssid, src_hotlist->ssid.ssid_len); ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; @@ -4488,9 +4500,13 @@ static int wma_passpoint_match_event_handler(void *handle, WMA_SVC_MSG_MAX_SIZE) { WMA_LOGE("IE Length: %d or ANQP Length: %d is huge", event->ie_length, event->anqp_length); - VOS_ASSERT(0); return -EINVAL; } + if (event->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGD("%s: Invalid ssid len %d, truncating", + __func__, event->ssid.ssid_len); + event->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + } dest_match = vos_mem_malloc(sizeof(*dest_match) + event->ie_length + event->anqp_length); if (!dest_match) { From 174ee8671dd4d9afbbe523bc77e0d156f29ea4a7 Mon Sep 17 00:00:00 2001 From: "Padma, Santhosh Kumar" Date: Fri, 8 Dec 2017 17:48:10 +0530 Subject: [PATCH 51/78] qcacld-2.0: Avoid buffer overflow qcacld-3.0 to qcacld-2.0 propagation Add max check for probe request length against max length of probe request buffer to avoid buffer overflow. Bug: 72957234 Change-Id: Ie0fad7443b2c749c66bb9ad662625a16d3a840c3 CRs-Fixed: 2155808 Signed-off-by: Ahmed ElArabawy Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c index 4cef79044b99d..b6bb3ee09404f 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c @@ -742,6 +742,10 @@ limSendSmeProbeReqInd(tpAniSirGlobal pMac, MTRACE(macTrace(pMac, TRACE_CODE_TX_SME_MSG, psessionEntry->peSessionId, msgQ.type)); + + if (ProbeReqIELen > sizeof(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE)) + ProbeReqIELen = sizeof(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE); + pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIELen = (tANI_U16)ProbeReqIELen; vos_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE, pProbeReqIE, ProbeReqIELen); From 3a81df52a23b9f10a5541048331a44fda26ec98a Mon Sep 17 00:00:00 2001 From: Tiger Yu Date: Wed, 6 Dec 2017 15:24:55 +0800 Subject: [PATCH 52/78] qcacld-2.0: Fix potential buffer overflow for TX_COMPL_IND Check for the validity of num_msdus when received the htt message of HTT_T2H_MSG_TYPE_TX_COMPL_IND or HTT_T2H_MSG_TYPE_TX_INSPECT_IND from firmware to ensure the buffer overflow does not happen. Bug: 72957505 Change-Id: Ic6ce75f34c5e2705d174eda014350e6ef0391388 CRs-Fixed: 2146869 Signed-off-by: Ahmed ElArabawy Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h | 3 ++ .../qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h index c608cf59413af..129443fe84b29 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt.h @@ -6315,6 +6315,9 @@ PREPACK struct htt_txq_group { #define HTT_TX_COMPL_IND_APPEND_GET(_info) \ (((_info) & HTT_TX_COMPL_IND_APPEND_M) >> HTT_TX_COMPL_IND_APPEND_S) +#define HTT_TX_COMPL_HEAD_SZ 4 +#define HTT_TX_COMPL_BYTES_PER_MSDU_ID 2 + #define HTT_TX_COMPL_CTXT_SZ sizeof(A_UINT16) #define HTT_TX_COMPL_CTXT_NUM(_bytes) ((_bytes) >> 1) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c index f20152b1783d5..9b2a2f12a6b1d 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c @@ -646,10 +646,26 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { { int num_msdus; enum htt_tx_status status; + int msg_len = adf_nbuf_len(htt_t2h_msg); /* status - no enum translation needed */ status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + adf_os_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + if (num_msdus & 0x1) { struct htt_tx_compl_ind_base *compl = (void *)msg_word; @@ -718,8 +734,23 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: { int num_msdus; + int msg_len = adf_nbuf_len(htt_t2h_msg); num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + adf_os_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d,inspect\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + if (num_msdus & 0x1) { struct htt_tx_compl_ind_base *compl = (void *)msg_word; From 1306eda7edef4b52a21fc01217a415c758c81745 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Wed, 29 Nov 2017 14:04:38 +0530 Subject: [PATCH 53/78] qcacld-2.0: Avoid possible stack overflow in hdd_ProcessGENIE API There is no check for the return value of dot11fUnpackIeRSN API in hdd_ProcessGENIE API, which may cause stack overflow if pmkid_count is returned as more than the PMKIDCache size. Add a check for return value of dot11fUnpackIeRSN to avoid possible stack overflow. Bug: 72957507 Change-Id: I56424c706de121b18b8d3f2c4a35089ec0434452 CRs-Fixed: 2149187 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- .../staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c index 28fb6b23e96e2..d2543592861e7 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_assoc.c @@ -4418,6 +4418,7 @@ static tANI_S32 hdd_ProcessGENIE(hdd_adapter_t *pAdapter, tDot11fIERSN dot11RSNIE; tDot11fIEWPA dot11WPAIE; tANI_U32 i; + tANI_U32 status; tANI_U8 *pRsnIe; tANI_U16 RSNIeLen; tPmkidCacheInfo PMKIDCache[4]; // Local transfer memory @@ -4443,10 +4444,17 @@ static tANI_S32 hdd_ProcessGENIE(hdd_adapter_t *pAdapter, pRsnIe = gen_ie + 2; RSNIeLen = gen_ie_len - 2; // Unpack the RSN IE - dot11fUnpackIeRSN((tpAniSirGlobal) halHandle, + status = dot11fUnpackIeRSN((tpAniSirGlobal) halHandle, pRsnIe, RSNIeLen, &dot11RSNIE); + if (DOT11F_FAILED(status)) + { + hddLog(LOGE, + FL("Parse failure in hdd_ProcessGENIE (0x%08x)"), + status); + return -EINVAL; + } // Copy out the encryption and authentication types hddLog(LOG1, FL("%s: pairwise cipher suite count: %d"), __func__, dot11RSNIE.pwise_cipher_suite_count ); From 5790063ae4a06849cc90950a192f8a975a50d3b7 Mon Sep 17 00:00:00 2001 From: Tiger Yu Date: Tue, 2 Jan 2018 14:09:23 +0800 Subject: [PATCH 54/78] qcacld-2.0: Fix memory leak for txrx_fw_stats cmd The txrx_fw_stats cmd will allocate a req object before sending the cmd to the firmware, this memory is only freed when get response from firmware. The memory leak will appear if the firmware doesn't response in time before the driver unloading. This fix will add a pending queue to trace this req object in the pdev. when pdev is detaching, it will clean up this queue to avoid memory leak. Bug: 72957257 Change-Id: I35f6216d35befbab978bba161252b305488bd34c CRs-Fixed: 2113219 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c | 65 +++++++++++++++---- .../CORE/CLD_TXRX/TXRX/ol_txrx_types.h | 4 ++ .../CORE/SERVICES/COMMON/ol_txrx_dbg.h | 7 ++ 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c index 7cd0917fc95d8..606209a9ac0be 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c @@ -376,6 +376,9 @@ ol_txrx_pdev_attach( TXRX_STATS_INIT(pdev); TAILQ_INIT(&pdev->vdev_list); + TAILQ_INIT(&pdev->req_list); + pdev->req_list_depth = 0; + adf_os_spinlock_init(&pdev->req_list_spinlock); /* do initial set up of the peer ID -> peer object lookup map */ if (ol_txrx_peer_find_attach(pdev)) { @@ -887,6 +890,8 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) { int i; + unsigned int page_idx; + struct ol_txrx_stats_req_internal *req; /*checking to ensure txrx pdev structure is not NULL */ if (!pdev) { @@ -899,6 +904,16 @@ ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) /* check that the pdev has no vdevs allocated */ TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list)); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(req, &pdev->req_list, req_list_elem) { + TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); + pdev->req_list_depth--; + adf_os_mem_free(req); + } + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + + adf_os_spinlock_destroy(&pdev->req_list_spinlock); + OL_RX_REORDER_TIMEOUT_CLEANUP(pdev); if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) { @@ -1961,12 +1976,6 @@ void ol_txrx_print_level_set(unsigned level) #endif } -struct ol_txrx_stats_req_internal { - struct ol_txrx_stats_req base; - int serviced; /* state of this request */ - int offset; -}; - static inline u_int64_t OL_TXRX_STATS_PTR_TO_U64(struct ol_txrx_stats_req_internal *req) { @@ -2028,6 +2037,11 @@ ol_txrx_fw_stats_get( /* use the non-volatile request object's address as the cookie */ cookie = OL_TXRX_STATS_PTR_TO_U64(non_volatile_req); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_INSERT_TAIL(&pdev->req_list, non_volatile_req, req_list_elem); + pdev->req_list_depth++; + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + if (htt_h2t_dbg_stats_get( pdev->htt_pdev, req->stats_type_upload_mask, @@ -2035,14 +2049,15 @@ ol_txrx_fw_stats_get( HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID, 0, cookie)) { + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_REMOVE(&pdev->req_list, non_volatile_req, req_list_elem); + pdev->req_list_depth--; + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + adf_os_mem_free(non_volatile_req); return A_ERROR; } - if (req->wait.blocking) { - while (adf_os_mutex_acquire(pdev->osdev, req->wait.sem_ptr)) {} - } - return A_OK; } #endif @@ -2056,11 +2071,27 @@ ol_txrx_fw_stats_handler( enum htt_dbg_stats_status status; int length; u_int8_t *stats_data; - struct ol_txrx_stats_req_internal *req; + struct ol_txrx_stats_req_internal *req, *tmp; int more = 0; + int found = 0; req = OL_TXRX_U64_TO_STATS_PTR(cookie); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { + if (req == tmp) { + found = 1; + break; + } + } + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); + + if (!found) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "req(%p) from firmware can't be found in the list\n", req); + return; + } + do { htt_t2h_dbg_stats_hdr_parse( stats_info_list, &type, &status, &length, &stats_data); @@ -2184,10 +2215,16 @@ ol_txrx_fw_stats_handler( } while (1); if (! more) { - if (req->base.wait.blocking) { - adf_os_mutex_release(pdev->osdev, req->base.wait.sem_ptr); + adf_os_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { + if (req == tmp) { + TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); + pdev->req_list_depth--; + adf_os_mem_free(req); + break; + } } - adf_os_mem_free(req); + adf_os_spin_unlock_bh(&pdev->req_list_spinlock); } } diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h index ff889caff7c04..2873e9d3c3215 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h @@ -544,6 +544,10 @@ struct ol_txrx_pdev_t { /* ol_txrx_vdev list */ TAILQ_HEAD(, ol_txrx_vdev_t) vdev_list; + TAILQ_HEAD(, ol_txrx_stats_req_internal) req_list; + int req_list_depth; + adf_os_spinlock_t req_list_spinlock; + /* peer ID to peer object map (array of pointers to peer objects) */ struct ol_txrx_peer_t **peer_id_to_obj_map; diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h index 7309db33dc865..517bf5f4b3175 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_dbg.h @@ -76,6 +76,13 @@ struct ol_txrx_stats_req { } wait; }; +struct ol_txrx_stats_req_internal { + struct ol_txrx_stats_req base; + TAILQ_ENTRY(ol_txrx_stats_req_internal) req_list_elem; + int serviced; /* state of this request */ + int offset; +}; + #ifndef TXRX_DEBUG_LEVEL #define TXRX_DEBUG_LEVEL 0 /* no debug info */ #endif From 7e5e4acb47e69d2f6452fef98d5d9d6fc13e7a93 Mon Sep 17 00:00:00 2001 From: tfyu Date: Tue, 26 Sep 2017 14:42:31 +0800 Subject: [PATCH 55/78] qcacld-2.0: Dump the txrx stat req if the queue is not empty Dump the txrx stat req if the queue is not empty when detatch the pdev. Bug: 72957257 Change-Id: Ic38e01668efd28baf55acb04f448e236cc224c79 CRs-Fixed: 2113219 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c index 606209a9ac0be..98961ca06d3a3 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c @@ -889,7 +889,7 @@ A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev) void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) { - int i; + int i = 0; unsigned int page_idx; struct ol_txrx_stats_req_internal *req; @@ -905,9 +905,23 @@ ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list)); adf_os_spin_lock_bh(&pdev->req_list_spinlock); + if (pdev->req_list_depth > 0) + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Warning: the txrx req list is not empty, depth=%d\n", + pdev->req_list_depth + ); TAILQ_FOREACH(req, &pdev->req_list, req_list_elem) { TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); pdev->req_list_depth--; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%d: %p,verbose(%d), concise(%d), up_m(0x%x), reset_m(0x%x)\n", + i++, + req, + req->base.print.verbose, + req->base.print.concise, + req->base.stats_type_upload_mask, + req->base.stats_type_reset_mask + ); adf_os_mem_free(req); } adf_os_spin_unlock_bh(&pdev->req_list_spinlock); From 9eb19b077ccbcf00a4d5132dca3cefc393995002 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 6 Dec 2017 12:30:30 +0530 Subject: [PATCH 56/78] qcacld-2.0: Fix potential buffer overwrite In function wma_unified_link_iface_stats_event_handler, num_ac is received from the firmware and is used in the loop to populate values into results. However, the memory for results is allocated only for WIFI_AC_MAX and a buffer overflow will occur if num_ac is greater than or equal to WIFI_AC_MAX. Add checks to make sure num_ac is not greater than to WIFI_AC_MAX. Note: This CL has been updated to fix the check to only return error on num_ac > WIFI_AC_MAX since an equal value is a valid value. This is to fix b/73597588. Bug: 70237689 Change-Id: Ie2056017aae641236efb118889e2919795b60f18 CRs-Fixed: 2154226 Signed-off-by: Ahmed ElArabawy Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index d4be4bc23f3ce..8ebf327671c3d 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -4598,6 +4598,11 @@ static int wma_unified_link_iface_stats_event_handler(void *handle, WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__); return -EINVAL; } + if (link_stats->num_ac > WIFI_AC_MAX) { + WMA_LOGE("%s: Excess data received from firmware num_ac %d", + __func__, link_stats->num_ac); + return -EINVAL; + } link_stats_size = sizeof(tSirWifiIfaceStat); iface_info_size = sizeof(tSirWifiInterfaceInfo); From f9dd3a415e61cdcc1e7b88a7fd276e98236df54b Mon Sep 17 00:00:00 2001 From: Vignesh Viswanathan Date: Tue, 12 Dec 2017 15:33:34 +0530 Subject: [PATCH 57/78] qcacld-2.0: Fix potential buffer overwrite in wma_vdev_start_rsp_ind In function wma_vdev_start_rsp_ind, vdev_id is received from the FW and is used to access wma_handle->interfaces without validating the upper limit. If the value of vdev_id received from the FW is not less than max_bssid, then a buffer overwrite will occur in the function wma_vdev_start_rsp_ind. Add sanity check to make sure vdev_id is less than max_bssid. Bug: 72957725 Change-Id: I83e1b797ca50a7fb58519f66dde26b035a2393ce CRs-Fixed: 2150359 Signed-off-by: Ahmed ElArabawy Signed-off-by: anupritaisno1 --- .../qcacld-2.0/CORE/SERVICES/WMA/wma.c | 30 +++++++++++-------- .../CORE/SERVICES/WMA/wma_nan_datapath.c | 2 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 8ebf327671c3d..f6965b4b0ada8 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -498,7 +498,7 @@ static bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, u_int8_t vdev_id) { struct wma_txrx_node *intf = wma->interfaces; - if (vdev_id > wma->max_bssid) { + if (vdev_id >= wma->max_bssid) { WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); VOS_ASSERT(0); return false; @@ -524,7 +524,7 @@ static bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, u_int8_t vdev_id) { struct wma_txrx_node *intf = wma->interfaces; - if (vdev_id > wma->max_bssid) { + if (vdev_id >= wma->max_bssid) { WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); VOS_ASSERT(0); return false; @@ -1300,9 +1300,15 @@ static int wma_vdev_start_rsp_ind(tp_wma_handle wma, u_int8_t *buf) return -EINVAL; } + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + iface = &wma->interfaces[resp_event->vdev_id]; - if ((resp_event->vdev_id <= wma->max_bssid) && + if ((resp_event->vdev_id < wma->max_bssid) && (adf_os_atomic_read( &wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) && (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == true)) { @@ -1903,7 +1909,7 @@ static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) ol_txrx_vdev_handle vdev; ol_txrx_peer_handle peer, temp; - if (!wma || vdev_id > wma->max_bssid) + if (!wma || vdev_id >= wma->max_bssid) return; vdev = wma->interfaces[vdev_id].handle; @@ -1945,7 +1951,7 @@ static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id) ol_txrx_vdev_handle vdev; ol_txrx_peer_handle peer, temp; - if (!wma || vdev_id > wma->max_bssid) + if (!wma || vdev_id >= wma->max_bssid) return; vdev = wma->interfaces[vdev_id].handle; @@ -2143,7 +2149,7 @@ static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf) resp_event = (wmi_vdev_stopped_event_fixed_param *)buf; - if ((resp_event->vdev_id <= wma->max_bssid) && + if ((resp_event->vdev_id < wma->max_bssid) && (adf_os_atomic_read(&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) && ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && (wma->interfaces[resp_event->vdev_id].sub_type == 0))) { @@ -2182,7 +2188,7 @@ static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf) tpDeleteBssParams params = (tpDeleteBssParams)req_msg->user_data; struct beacon_info *bcn; - if (resp_event->vdev_id > wma->max_bssid) { + if (resp_event->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: Invalid vdev_id %d", __func__, resp_event->vdev_id); vos_mem_free(params); @@ -9804,7 +9810,7 @@ VOS_STATUS wma_start_scan(tp_wma_handle wma_handle, int len; tSirScanOffloadEvent *scan_event; - if (scan_req->sessionId > wma_handle->max_bssid) { + if (scan_req->sessionId >= wma_handle->max_bssid) { WMA_LOGE("%s: Invalid vdev_id %d, msg_type : 0x%x", __func__, scan_req->sessionId, msg_type); goto error1; @@ -12775,7 +12781,7 @@ void wma_vdev_resp_timer(void *data) struct beacon_info *bcn; struct wma_txrx_node *iface; - if (tgt_req->vdev_id > wma->max_bssid) { + if (tgt_req->vdev_id >= wma->max_bssid) { WMA_LOGE("%s: Invalid vdev_id %d", __func__, tgt_req->vdev_id); vos_mem_free(params); @@ -23244,7 +23250,7 @@ static VOS_STATUS wma_wow_enter(tp_wma_handle wma, WMA_LOGD("wow enable req received for vdev id: %d", info->sessionId); - if (info->sessionId > wma->max_bssid) { + if (info->sessionId >= wma->max_bssid) { WMA_LOGE("Invalid vdev id (%d)", info->sessionId); vos_mem_free(info); return VOS_STATUS_E_INVAL; @@ -23271,7 +23277,7 @@ static VOS_STATUS wma_wow_exit(tp_wma_handle wma, WMA_LOGD("wow disable req received for vdev id: %d", info->sessionId); - if (info->sessionId > wma->max_bssid) { + if (info->sessionId >= wma->max_bssid) { WMA_LOGE("Invalid vdev id (%d)", info->sessionId); vos_mem_free(info); return VOS_STATUS_E_INVAL; @@ -23304,7 +23310,7 @@ static VOS_STATUS wma_suspend_req(tp_wma_handle wma, tpSirWlanSuspendParam info) wma->no_of_suspend_ind++; - if (info->sessionId > wma->max_bssid) { + if (info->sessionId >= wma->max_bssid) { WMA_LOGE("Invalid vdev id (%d)", info->sessionId); vos_mem_free(info); return VOS_STATUS_E_INVAL; diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c index 2d2909e6b3912..f5ea7ac92498f 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma_nan_datapath.c @@ -1138,7 +1138,7 @@ void wma_delete_all_nan_remote_peers(tp_wma_handle wma, uint32_t vdev_id) ol_txrx_vdev_handle vdev; ol_txrx_peer_handle peer, temp; - if (!wma || vdev_id > wma->max_bssid) + if (!wma || vdev_id >= wma->max_bssid) return; vdev = wma->interfaces[vdev_id].handle; From 7eb57160492b25f7a229dd9b488f2f117386f204 Mon Sep 17 00:00:00 2001 From: Zhang Qian Date: Mon, 4 Dec 2017 19:07:32 +0800 Subject: [PATCH 58/78] qcacld-2.0: Fix potential buffer overflow Fragment count will be larger than the upper limit of cvg_nbuf_cb->extra_flag.num which would lead to an overread of fragment length. Upper limit check for fragment count is added in this change. Change-Id: Icc078b2efee554ac84377b5edd90d0a5c7a61f98 CRs-Fixed: 2129566 Bug: 72957387 Signed-off-by: Ecco Park Signed-off-by: anupritaisno1 --- .../CORE/SERVICES/HIF/USB/hif_usb.c | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c index a6a88bf2754c8..caae8f0e3c2a5 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/HIF/USB/hif_usb.c @@ -245,7 +245,8 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, int usb_status; int i; struct HIFSendContext *pSendContext; - int frag_count = 0, head_data_len, tmp_frag_count = 0; + uint8_t frag_count; + uint32_t head_data_len, tmp_frag_count = 0; unsigned char *pData; AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_OUT, ("+%s pipe : %d, buf:0x%p\n", @@ -254,8 +255,15 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, a_mem_trace(buf); frag_count = adf_nbuf_get_num_frags(buf); - if (frag_count > 1) { /* means have extra fragment buf in skb */ - /* header data length should be total sending length substract + if (frag_count == 1) { + /* + * | HIFSendContext | netbuf->data + */ + head_data_len = sizeof(struct HIFSendContext); + } else if ((frag_count - 1) <= CVG_NBUF_MAX_EXTRA_FRAGS) { + /* + * means have extra fragment buf in skb + * header data length should be total sending length substract * internal data length of netbuf * | HIFSendContext | fragments except internal buffer | * netbuf->data @@ -268,10 +276,12 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, tmp_frag_count = tmp_frag_count + 1; } } else { - /* - * | HIFSendContext | netbuf->data - */ - head_data_len = sizeof(struct HIFSendContext); + /* Extra fragments overflow */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( + "%s Extra fragments count overflow : %d\n", + __func__, frag_count)); + status = A_ERROR; + goto exit; } /* Check whether head room is enough to save extra head data */ @@ -366,6 +376,7 @@ static A_STATUS HIFSend_internal(HIF_DEVICE *hifDevice, a_uint8_t PipeID, } while (FALSE); +exit: if (A_FAILED(status) && (status != A_NO_RESOURCE)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb send failed %d\n", status)); From d30046405893e18677261307e73d82ad6e874c0c Mon Sep 17 00:00:00 2001 From: tinlin Date: Thu, 11 Jan 2018 15:45:27 +0800 Subject: [PATCH 59/78] qcacld-2.0: Add data_len check to avoid OOB access Add data_len check in wma_nan_rsp_event_handler() to avoid OOB access. Bug: 74237168 Change-Id: Iff42da84567381a4b64bc07e69ff1a0cd4b5a543 CRs-Fixed: 2170630 Signed-off-by: anupritaisno1 --- drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index f6965b4b0ada8..11aeea337a431 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -6335,7 +6335,8 @@ static int wma_nan_rsp_event_handler(void *handle, u_int8_t *event_buf, alloc_len = sizeof(tSirNanEvent); alloc_len += nan_rsp_event_hdr->data_len; if (nan_rsp_event_hdr->data_len > ((WMA_SVC_MSG_MAX_SIZE - - sizeof(*nan_rsp_event_hdr)) / sizeof(u_int8_t))) { + sizeof(*nan_rsp_event_hdr)) / sizeof(u_int8_t)) || + nan_rsp_event_hdr->data_len > param_buf->num_data) { WMA_LOGE("excess data length:%d", nan_rsp_event_hdr->data_len); VOS_ASSERT(0); return -EINVAL; From 4f0494d0e3572b4cc44e611c03cfb59650ebb8e0 Mon Sep 17 00:00:00 2001 From: Lianjun Huang Date: Sat, 16 Jun 2018 22:59:46 +0800 Subject: [PATCH 60/78] ANDROID: sdcardfs: fix potential crash when reserved_mb is not zero sdcardfs_mkdir() calls check_min_free_space(). When reserved_mb is not zero, a negative dentry will be passed to ext4_statfs() at last and ext4_statfs() will crash. The parent dentry is positive. So we use the parent dentry to check free space. Change-Id: I80ab9623fe59ba911f4cc9f0e029a1c6f7ee421b Signed-off-by: Lianjun Huang Signed-off-by: anupritaisno1 --- fs/sdcardfs/inode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index ccca427679deb..7386e1b49d759 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -270,6 +270,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct dentry *lower_dentry; struct vfsmount *lower_mnt; struct dentry *lower_parent_dentry = NULL; + struct dentry *parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; @@ -289,11 +290,14 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* check disk space */ - if (!check_min_free_space(dentry, 0, 1)) { + parent_dentry = dget_parent(dentry); + if (!check_min_free_space(parent_dentry, 0, 1)) { pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; + dput(parent_dentry); goto out_revert; } + dput(parent_dentry); /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); From 009730f4c7ba59843a0bc8a37876818cec30990d Mon Sep 17 00:00:00 2001 From: Karthikeyan Mani Date: Thu, 28 Sep 2017 10:54:21 -0700 Subject: [PATCH 61/78] ALSA: pcm: add locks for accessing runtime resource Add spin lock to resolve race conditions while accessing substream runtime resource CRs-fixed: 2112713 Change-Id: I8db743303ceb50205d62adfc02caf6ecab635d47 Signed-off-by: Karthikeyan Mani Signed-off-by: anupritaisno1 --- include/sound/pcm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 42d830afcf672..4c0e95b47213f 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -397,6 +397,7 @@ struct snd_pcm_substream { struct snd_pcm_ops *ops; /* -- runtime information -- */ struct snd_pcm_runtime *runtime; + spinlock_t runtime_lock; /* -- timer section -- */ struct snd_timer *timer; /* timer */ unsigned timer_running: 1; /* time is running */ From 2fc793d4986508694b89de52f5517c6abd2a36ea Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 21 Dec 2017 16:24:31 +0530 Subject: [PATCH 62/78] oc: qcom: rpm-smd-debug: Fix potential memory leaks Fix memory leak due to rpm request not freed during error conditions. Change-Id: I440a58bf452e76c8886f7bcd8f89b24698a301e9 Signed-off-by: Raghavendra Kakarla Signed-off-by: anupritaisno1 --- drivers/soc/qcom/rpm-smd-debug.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/rpm-smd-debug.c b/drivers/soc/qcom/rpm-smd-debug.c index 1c0a05c87edaf..8194fe0cda5b6 100644 --- a/drivers/soc/qcom/rpm-smd-debug.c +++ b/drivers/soc/qcom/rpm-smd-debug.c @@ -99,23 +99,23 @@ static ssize_t rsc_ops_write(struct file *fp, const char __user *user_buffer, cmp += pos; if (sscanf(cmp, "%5s %n", key_str, &pos) != 1) { pr_err("Invalid number of arguments passed\n"); - goto err; + goto err_request; } if (strlen(key_str) > 4) { pr_err("Key value cannot be more than 4 charecters"); - goto err; + goto err_request; } key = string_to_uint(key_str); if (!key) { pr_err("Key values entered incorrectly\n"); - goto err; + goto err_request; } cmp += pos; if (sscanf(cmp, "%u %n", &data, &pos) != 1) { pr_err("Invalid number of arguments passed\n"); - goto err; + goto err_request; } if (msm_rpm_add_kvp_data(req, key, From 8d5ef616c0e0b5b5060463d7c6b894f6520144e4 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Wed, 25 Oct 2017 16:16:36 +0530 Subject: [PATCH 63/78] soc: qcom: pil: Fix error handling during PIL driver probe During probe function of the Linux PIL kernel driver Initialization of various resources are done. This fix is for acquired resource cleanup, in case of error. CRs-Fixed: 2129451 Change-Id: I0b3511cff7e2917fe83bddfc15086e939f5c2abc Signed-off-by: Jitendra Sharma Signed-off-by: Swetha Chikkaboraiah Signed-off-by: anupritaisno1 --- drivers/soc/qcom/subsys-pil-tz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index 001cc25bd4e3a..cd44f5ae6db99 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -969,6 +969,7 @@ static int pil_tz_driver_probe(struct platform_device *pdev) destroy_ramdump_device(d->ramdump_dev); err_ramdump: pil_desc_release(&d->desc); + platform_set_drvdata(pdev, NULL); return rc; } From a406fd06ee40daffaccd7e95db8bd7321b998f1a Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Fri, 25 Nov 2016 14:24:35 +0530 Subject: [PATCH 64/78] qseecom: Add new ioctl to export qsee version Export new ioctl to user space to know the qsee version, which is required for QSEECOM listener services. Change-Id: Idd80ce0a3153d669d5f6fb748f73f7aaedefb3a5 Signed-off-by: Neeraj Soni Signed-off-by: anupritaisno1 --- drivers/misc/qseecom.c | 27 ++++++++++++++++++++++++++- include/uapi/linux/qseecom.h | 9 +++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 01732976d44f6..1d38f4d7e41aa 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,6 +1,6 @@ /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3448,6 +3448,23 @@ static int qseecom_get_qseos_version(struct qseecom_dev_handle *data, return 0; } +static int qseecom_get_qsee_version(struct qseecom_dev_handle *data, + void __user *argp) +{ + struct qseecom_qsee_version_req req; + + if (copy_from_user(&req, argp, sizeof(req))) { + pr_err("copy_from_user failed\n"); + return -EINVAL; + } + req.qsee_version = qseecom.qsee_version; + if (copy_to_user(argp, &req, sizeof(req))) { + pr_err("copy_to_user failed\n"); + return -EINVAL; + } + return 0; +} + static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce) { int rc = 0; @@ -5312,6 +5329,14 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) atomic_dec(&data->ioctl_count); break; } + case QSEECOM_IOCTL_GET_QSEE_VERSION_REQ: { + atomic_inc(&data->ioctl_count); + ret = qseecom_get_qsee_version(data, argp); + if (ret) + pr_err("qseecom_get_qseos_version: %d\n", ret); + atomic_dec(&data->ioctl_count); + break; + } case QSEECOM_IOCTL_PERF_ENABLE_REQ:{ if ((data->type != QSEECOM_GENERIC) && (data->type != QSEECOM_CLIENT_APP)) { diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index aac13eef45830..fae2e05552280 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -107,6 +107,13 @@ struct qseecom_qseos_version_req { unsigned int qseos_version; /* in */ }; +/* + * struct qseecom_qsee_version_req - get qsee version + * @qsee_version - version number + */ +struct qseecom_qsee_version_req { + unsigned int qsee_version; +}; /* * struct qseecom_qseos_app_load_query - verify if app is loaded in qsee * @app_name[MAX_APP_NAME_SIZE]- name of the app. @@ -293,4 +300,6 @@ extern long qseecom_ioctl(struct file *file, #define QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 33, struct qseecom_qteec_modfd_req) +#define QSEECOM_IOCTL_GET_QSEE_VERSION_REQ \ + _IOWR(QSEECOM_IOC_MAGIC, 37, struct qseecom_qsee_version_req) #endif /* _UAPI_QSEECOM_H_ */ From 834ca453cca9dab83c607b3c532af1d0b1ea4ceb Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Tue, 16 Jan 2018 14:51:15 +0530 Subject: [PATCH 65/78] dwc3: debugfs: Add check for length before copy data from userspace Add boundary check before copying data from userspace buffer to dwc3 local buffer. The third parameter passed to copy_from_user() should be minimum of the two values between userpsace buffer size count and (local_buffer size - 1). The last one byte in local_buffer should be reserved for null terminator. Change-Id: I9b2e3db4d5ad6b5f14515cadafa6264f9e8b786c Signed-off-by: Vijayavardhan Vennapusa Signed-off-by: anupritaisno1 --- drivers/usb/dwc3/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 04851ab4796a4..f0df6eee63ca0 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -653,7 +653,7 @@ static ssize_t dwc3_store_ep_num(struct file *file, const char __user *ubuf, unsigned int num, dir, temp; unsigned long flags; - if (copy_from_user(kbuf, ubuf, count > 10 ? 10 : count)) + if (copy_from_user(kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) return -EFAULT; if (sscanf(kbuf, "%u %u", &num, &dir) != 2) From 6c247ca5c1aebe61d91192acffcdb15d8bd48b45 Mon Sep 17 00:00:00 2001 From: Xiaoyu Ye Date: Mon, 15 Jan 2018 16:10:30 -0800 Subject: [PATCH 66/78] ASoC: wcd_cpe_core: add size check for WDSP ELF files Add size check to make sure the data sizes from WDSP ELF metadata and the split firmware ELF are the same. Change-Id: Ic2f7dc04dfc95608302cba23461c519378619db0 Signed-off-by: Xiaoyu Ye Signed-off-by: anupritaisno1 --- sound/soc/codecs/wcd_cpe_core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 965caf8d4e8a1..a433bd2b18dcd 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -290,6 +290,14 @@ static int wcd_cpe_load_each_segment(struct wcd_cpe_core *core, goto done; } + if (phdr->p_filesz != split_fw->size) { + dev_err(core->dev, + "%s: %s size mismatch, phdr_size: 0x%x fw_size: 0x%zx", + __func__, split_fname, phdr->p_filesz, split_fw->size); + ret = -EINVAL; + goto done; + } + segment->cpe_addr = phdr->p_paddr; segment->size = phdr->p_filesz; segment->data = (u8 *) split_fw->data; From 998445c76c42de5e71e62468dc07a4d17c7a63b5 Mon Sep 17 00:00:00 2001 From: smanag Date: Tue, 14 Nov 2017 14:57:57 +0530 Subject: [PATCH 67/78] drivers: soc: Synchronize apr callback and voice svc release Issue is seen when apr callback is received while voice_svc_release is in process of freeing the driver private data. Avoid invalid access of private data pointer by putting the callback and release functions in the same locked context. Change-Id: I93af13cab0a3c7e653a9bc9fa7f4f86bfa0502df Signed-off-by: smanag Signed-off-by: anupritaisno1 --- drivers/soc/qcom/qdsp6v2/voice_svc.c | 40 ++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index fe54589744061..e05230255d6f0 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,11 @@ static void *dummy_q6_mvm; static void *dummy_q6_cvs; dev_t device_num; +spinlock_t voicesvc_lock; +static bool is_released; static int voice_svc_dummy_reg(void); +static int voice_svc_dummy_dereg(void); + static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data, void *priv); @@ -82,10 +87,16 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) return -EINVAL; } + spin_lock(&voicesvc_lock); + if (is_released) { + spin_unlock(&voicesvc_lock); + return 0; + } prtd = (struct voice_svc_prvt *)priv; if (prtd == NULL) { pr_err("%s: private data is NULL\n", __func__); + spin_unlock(&voicesvc_lock); return -EINVAL; } @@ -128,6 +139,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) spin_unlock_irqrestore(&prtd->response_lock, spin_flags); + spin_unlock(&voicesvc_lock); return -ENOMEM; } @@ -156,6 +168,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) __func__); } + spin_unlock(&voicesvc_lock); return 0; } @@ -614,6 +627,21 @@ static int voice_svc_dummy_reg() return -EINVAL; } +static int voice_svc_dummy_dereg(void) +{ + pr_debug("%s\n", __func__); + if (dummy_q6_mvm != NULL) { + apr_deregister(dummy_q6_mvm); + dummy_q6_mvm = NULL; + } + + if (dummy_q6_cvs != NULL) { + apr_deregister(dummy_q6_cvs); + dummy_q6_cvs = NULL; + } + return 0; +} + static int voice_svc_open(struct inode *inode, struct file *file) { struct voice_svc_prvt *prtd = NULL; @@ -637,6 +665,7 @@ static int voice_svc_open(struct inode *inode, struct file *file) mutex_init(&prtd->response_mutex_lock); file->private_data = (void *)prtd; + is_released = 0; /* Current APR implementation doesn't support session based * multiple service registrations. The apr_deregister() * function sets the destination and client IDs to zero, if @@ -669,6 +698,11 @@ static int voice_svc_release(struct inode *inode, struct file *file) goto done; } + mutex_lock(&prtd->response_mutex_lock); + if (reg_dummy_sess) { + voice_svc_dummy_dereg(); + reg_dummy_sess = 0; + } if (prtd->apr_q6_cvs != NULL) { svc_name = VOICE_SVC_MVM_STR; handle = &prtd->apr_q6_cvs; @@ -685,7 +719,6 @@ static int voice_svc_release(struct inode *inode, struct file *file) pr_err("%s: Failed to dereg MVM %d\n", __func__, ret); } - mutex_lock(&prtd->response_mutex_lock); spin_lock_irqsave(&prtd->response_lock, spin_flags); while (!list_empty(&prtd->response_queue)) { @@ -703,9 +736,11 @@ static int voice_svc_release(struct inode *inode, struct file *file) mutex_destroy(&prtd->response_mutex_lock); + spin_lock(&voicesvc_lock); kfree(file->private_data); file->private_data = NULL; - + is_released = 1; + spin_unlock(&voicesvc_lock); done: return ret; } @@ -774,6 +809,7 @@ static int voice_svc_probe(struct platform_device *pdev) goto add_err; } pr_debug("%s: Device created\n", __func__); + spin_lock_init(&voicesvc_lock); goto done; add_err: From 70a29898693ed951ad4d3d123c6c5a8a284d3242 Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Thu, 18 Jan 2018 00:41:48 -0800 Subject: [PATCH 68/78] ASoC: msm: qdspv2: add spin lock to protect ac ac could get freed during the execution of q6asm_callback. And kernel panic happens. Add spinlock to protect ac to avoid kernel panic. Change-Id: Ie49c8a3979231552ba7d5f207aab0d95ffdc2a72 Signed-off-by: Meng Wang Signed-off-by: anupritaisno1 --- sound/soc/msm/qdsp6v2/q6asm.c | 139 +++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 34 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index fa27343fd2d20..c3d3814272b5b 100755 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -60,8 +60,13 @@ struct asm_mmap { }; static struct asm_mmap this_mmap; + +struct audio_session { + struct audio_client *ac; + spinlock_t session_lock; +}; /* session id: 0 reserved */ -static struct audio_client *session[SESSION_MAX+1]; +static struct audio_session session[SESSION_MAX + 1]; struct asm_no_wait_node { struct list_head list; @@ -408,8 +413,8 @@ static int q6asm_session_alloc(struct audio_client *ac) { int n; for (n = 1; n <= SESSION_MAX; n++) { - if (!session[n]) { - session[n] = ac; + if (!session[n].ac) { + session[n].ac = ac; return n; } } @@ -417,34 +422,41 @@ static int q6asm_session_alloc(struct audio_client *ac) return -ENOMEM; } -static bool q6asm_is_valid_audio_client(struct audio_client *ac) +static unsigned int q6asm_get_session_id_from_audio_client( + struct audio_client *ac) { - int n; + unsigned int n; + for (n = 1; n <= SESSION_MAX; n++) { - if (session[n] == ac) - return 1; + if (session[n].ac == ac) + return n; } return 0; } +static bool q6asm_is_valid_audio_client(struct audio_client *ac) +{ + return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0; +} + static void q6asm_session_free(struct audio_client *ac) { - struct list_head *ptr, *next; - struct asm_no_wait_node *node; + int session_id; + unsigned long flags; pr_debug("%s: sessionid[%d]\n", __func__, ac->session); + session_id = ac->session; rtac_remove_popp_from_adm_devices(ac->session); - session[ac->session] = 0; + spin_lock_irqsave(&(session[session_id].session_lock), flags); + session[ac->session].ac = NULL; ac->session = 0; ac->perf_mode = LEGACY_PCM_MODE; ac->fptr_cache_ops = NULL; + ac->cb = NULL; + ac->priv = NULL; - list_for_each_safe(ptr, next, &ac->no_wait_que) { - node = list_entry(ptr, struct asm_no_wait_node, list); - list_del(&node->list); - kfree(node); - } - list_del(&ac->no_wait_que); + kfree(ac); + spin_unlock_irqrestore(&(session[session_id].session_lock), flags); return; } @@ -990,8 +1002,6 @@ void q6asm_audio_client_free(struct audio_client *ac) pr_debug("%s: APR De-Register\n", __func__); /*done:*/ - kfree(ac); - ac = NULL; mutex_unlock(&session_lock); return; @@ -1060,6 +1070,7 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) if (n <= 0) { pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n); mutex_unlock(&session_lock); + kfree(ac); goto fail_session; } ac->session = n; @@ -1137,7 +1148,6 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) fail_apr1: q6asm_session_free(ac); fail_session: - kfree(ac); return NULL; } @@ -1152,11 +1162,11 @@ struct audio_client *q6asm_get_audio_client(int session_id) goto err; } - if (!session[session_id]) { + if (!(session[session_id].ac)) { pr_err("%s: session not active: %d\n", __func__, session_id); goto err; } - return session[session_id]; + return session[session_id].ac; err: return NULL; } @@ -1361,6 +1371,7 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) uint32_t i = IN; uint32_t *payload; unsigned long dsp_flags; + unsigned long flags; struct asm_buffer_node *buf_node = NULL; struct list_head *ptr, *next; @@ -1409,9 +1420,16 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) return 0; } sid = (data->token >> 8) & 0x0F; + if ((sid > 0 && sid <= SESSION_MAX)) + spin_lock_irqsave(&(session[sid].session_lock), flags); + ac = q6asm_get_audio_client(sid); if (!ac) { pr_debug("%s: session[%d] already freed\n", __func__, sid); + if ((sid > 0 && + sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); return 0; } @@ -1461,6 +1479,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + if ((sid > 0 && + sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); return 0; } @@ -1496,6 +1518,10 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); + if ((sid > 0 && sid <= SESSION_MAX)) + spin_unlock_irqrestore( + &(session[sid].session_lock), flags); + return 0; } @@ -1522,7 +1548,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) uint32_t *payload; uint32_t wakeup_flag = 1; int32_t ret = 0; - + unsigned long flags; + int session_id; if (ac == NULL) { pr_err("%s: ac NULL\n", __func__); @@ -1532,15 +1559,21 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) pr_err("%s: data NULL\n", __func__); return -EINVAL; } - if (!q6asm_is_valid_audio_client(ac)) { - pr_err("%s: audio client pointer is invalid, ac = %pK\n", - __func__, ac); + + session_id = q6asm_get_session_id_from_audio_client(ac); + if (session_id <= 0) { + pr_err("%s: Session ID is invalid, session = %d\n", __func__, + session_id); return -EINVAL; } - if (ac->session <= 0 || ac->session > 8) { - pr_err("%s: Session ID is invalid, session = %d\n", __func__, - ac->session); + spin_lock_irqsave(&(session[session_id].session_lock), flags); + + if (!q6asm_is_valid_audio_client(ac)) { + pr_err("%s: audio client pointer is invalid, ac = %pK\n", + __func__, ac); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return -EINVAL; } @@ -1555,7 +1588,6 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) } if (data->opcode == RESET_EVENTS) { - mutex_lock(&ac->cmd_lock); atomic_set(&ac->reset, 1); if (ac->apr == NULL) ac->apr = ac->apr2; @@ -1571,7 +1603,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->cmd_state, 0); wake_up(&ac->time_wait); wake_up(&ac->cmd_wait); - mutex_unlock(&ac->cmd_lock); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1582,9 +1615,16 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->dest_port); if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) && (data->opcode != ASM_DATA_EVENT_EOS) && - (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) + (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) { + if (payload == NULL) { + pr_err("%s: payload is null\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); + return -EINVAL; + } dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n", __func__, payload[0], payload[1], data->opcode); + } if (data->opcode == APR_BASIC_RSP_RESULT) { token = data->token; switch (payload[0]) { @@ -1606,6 +1646,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) ret = q6asm_is_valid_session(data, priv); if (ret != 0) { pr_err("%s: session invalid %d\n", __func__, ret); + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return ret; } case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2: @@ -1633,6 +1675,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->cmd_state, -payload[1]); wake_up(&ac->cmd_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->cmd_state) && wakeup_flag) { @@ -1653,6 +1698,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) atomic_set(&ac->mem_state, -payload[1]); wake_up(&ac->mem_wait); } + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return 0; } if (atomic_read(&ac->mem_state) && wakeup_flag) { @@ -1689,6 +1737,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0]); break; } + + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1702,6 +1753,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -1715,6 +1769,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) __func__, payload[0], payload[1]); spin_unlock_irqrestore(&port->dsp_lock, dsp_flags); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } token = data->token; @@ -1786,6 +1843,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->io_mode & SYNC_IO_MODE) { if (port->buf == NULL) { pr_err("%s: Unexpected Write Done\n", __func__); + spin_unlock_irqrestore( + &(session[session_id].session_lock), + flags); return -EINVAL; } spin_lock_irqsave(&port->dsp_lock, dsp_flags); @@ -1854,7 +1914,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->cb) ac->cb(data->opcode, data->token, data->payload, ac->priv); - + spin_unlock_irqrestore( + &(session[session_id].session_lock), flags); return 0; } @@ -1996,11 +2057,16 @@ int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac) static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id) { + unsigned long flags; + dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n", __func__, pkt_size, cmd_flg, ac->session, stream_id); mutex_lock(&ac->cmd_lock); + spin_lock_irqsave(&(session[ac->session].session_lock), flags); if (ac->apr == NULL) { pr_err("%s: AC APR handle NULL", __func__); + spin_unlock_irqrestore( + &(session[ac->session].session_lock), flags); mutex_unlock(&ac->cmd_lock); return; } @@ -2018,6 +2084,8 @@ static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, hdr->token = ac->session; } hdr->pkt_size = pkt_size; + spin_unlock_irqrestore( + &(session[ac->session].session_lock), flags); mutex_unlock(&ac->cmd_lock); return; } @@ -6510,7 +6578,7 @@ int q6asm_get_apr_service_id(int session_id) return -EINVAL; } - return ((struct apr_svc *)session[session_id]->apr)->id; + return ((struct apr_svc *)(session[session_id].ac)->apr)->id; } int q6asm_get_asm_topology(void) @@ -6728,7 +6796,10 @@ static int __init q6asm_init(void) int lcnt, ret; pr_debug("%s:\n", __func__); - memset(session, 0, sizeof(session)); + memset(session, 0, sizeof(struct audio_session) * + (SESSION_MAX + 1)); + for (lcnt = 0; lcnt <= SESSION_MAX; lcnt++) + spin_lock_init(&(session[lcnt].session_lock)); set_custom_topology = 1; /*setup common client used for cal mem map */ From e273c78974d46b161abb45d8a5399eb56aa9a276 Mon Sep 17 00:00:00 2001 From: David Dai Date: Mon, 25 Sep 2017 15:16:23 -0700 Subject: [PATCH 69/78] dev_freq: devfreq_spdm: add null terminator to prevent OOB access Add null terminator to end of buffered copied from user to prevent over reading. Change-Id: I80cfcb087ea2c335fd65d8fcdaf372c7d34a533d Signed-off-by: David Dai Signed-off-by: anupritaisno1 --- drivers/devfreq/devfreq_spdm_debugfs.c | 62 ++++++++++++++++++++------ 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/drivers/devfreq/devfreq_spdm_debugfs.c b/drivers/devfreq/devfreq_spdm_debugfs.c index 94e94f3bbc1c7..1d6a581341a5f 100644 --- a/drivers/devfreq/devfreq_spdm_debugfs.c +++ b/drivers/devfreq/devfreq_spdm_debugfs.c @@ -34,7 +34,7 @@ static ssize_t enable_write(struct file *file, const char __user *data, int i; int next_idx; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { @@ -42,6 +42,8 @@ static ssize_t enable_write(struct file *file, const char __user *data, size = -EINVAL; } + buf[size] = '\0'; + if (sscanf(buf, "%u\n", &i) != 1) { size = -EINVAL; goto err; @@ -105,7 +107,7 @@ static ssize_t pl_write(struct file *file, const char __user *data, int ext_status = 0; int i; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { @@ -113,6 +115,8 @@ static ssize_t pl_write(struct file *file, const char __user *data, goto out; } + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.pl_freqs[0], &spdm_data->config_data.pl_freqs[1]) != 2) { size = -EINVAL; @@ -164,7 +168,7 @@ static ssize_t rejrate_low_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { @@ -172,6 +176,8 @@ static ssize_t rejrate_low_write(struct file *file, const char __user *data, goto out; } + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[0], &spdm_data->config_data.reject_rate[1]) != 2) { size = -EINVAL; @@ -224,13 +230,16 @@ static ssize_t rejrate_med_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[2], &spdm_data->config_data.reject_rate[3]) != 2) { size = -EINVAL; @@ -282,13 +291,16 @@ static ssize_t rejrate_high_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[4], &spdm_data->config_data.reject_rate[5]) != 2) { size = -EINVAL; @@ -340,13 +352,16 @@ static ssize_t resptime_low_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[0], &spdm_data->config_data.response_time_us[1]) != 2) { size = -EINVAL; @@ -398,13 +413,16 @@ static ssize_t resptime_med_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[2], &spdm_data->config_data.response_time_us[3]) != 2) { size = -EINVAL; @@ -456,13 +474,16 @@ static ssize_t resptime_high_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[4], &spdm_data->config_data.response_time_us[5]) != 2) { size = -EINVAL; @@ -515,13 +536,16 @@ static ssize_t cciresptime_low_write(struct file *file, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[0], &spdm_data->config_data.cci_response_time_us[1]) != 2) { @@ -575,13 +599,16 @@ static ssize_t cciresptime_med_write(struct file *file, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[2], &spdm_data->config_data.cci_response_time_us[3]) != 2) { @@ -635,13 +662,16 @@ static ssize_t cciresptime_high_write(struct file *file, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[4], &spdm_data->config_data.cci_response_time_us[5]) != 2){ @@ -694,13 +724,16 @@ static ssize_t cci_max_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u\n", &spdm_data->config_data.max_cci_freq) != 1) { size = -EINVAL; goto out; @@ -748,13 +781,16 @@ static ssize_t vote_cfg_write(struct file *file, const char __user *data, struct spdm_args desc = { { 0 } }; int ext_status = 0; - if (size > sizeof(buf)) + if (size > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, data, size)) { size = -EINVAL; goto out; } + + buf[size] = '\0'; + if (sscanf(buf, "%u %u %u %u\n", &spdm_data->config_data.upstep, &spdm_data->config_data.downstep, &spdm_data->config_data.max_vote, From 47fabcacba91e242e929846a0f53020ab2cff4fc Mon Sep 17 00:00:00 2001 From: Santhosh Kumar Thimmanna Bhattar Date: Tue, 13 Feb 2018 14:05:20 +0530 Subject: [PATCH 70/78] msm: thermal: Pass correct size of voltage table to IOCTL Fix issue in msm_thermal_process_voltage_table_request. For voltage tables bigger than 16 it is not correclty passing the partial table size to user space. The full size is passed instead of the partial size. For example if reading a table of 18 values the first read returns 16, and the partial read returns 18 but it should return 2. Change-Id: I75943e94341388cca772ee45bc1275fb5d2091d2 Signed-off-by: Jeff Bernard Signed-off-by: Santhosh Kumar Thimmanna Bhattar Signed-off-by: anupritaisno1 --- drivers/thermal/msm_thermal-dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index eb0490a9cad81..ead9765666c84 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -268,6 +268,7 @@ static long msm_thermal_process_voltage_table_req( voltage->voltage_table[idx] = voltage_table_ptr[cluster_id][table_idx]; } + voltage->voltage_table_len = idx; copy_and_return: ret = copy_to_user((void __user *)(*arg), query, From 23ba138e31e0d613bfa392c467e50e45efd13199 Mon Sep 17 00:00:00 2001 From: Sriharsha P V Date: Wed, 31 Jan 2018 17:45:01 +0530 Subject: [PATCH 71/78] msm: kgsl: Increase memstore size Increase the memstore size to increase the number of the kgsl context that can be supported simultaneously. Signed-off-by: Sriharsha P V Change-Id: I295dfd057cf5869a77b265262b38b41fca3cf3ba Signed-off-by: anupritaisno1 --- drivers/gpu/msm/kgsl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 0711c43c31783..20de789fbd05e 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -30,7 +30,7 @@ /* The number of memstore arrays limits the number of contexts allowed. * If more contexts are needed, update multiple for MEMSTORE_SIZE */ -#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 2)) +#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 8)) #define KGSL_MEMSTORE_GLOBAL (0) #define KGSL_PRIORITY_MAX_RB_LEVELS 4 #define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \ From bcf1a0de18e2af6d914c8081e564c34c707d9b82 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Wed, 31 Jan 2018 14:49:37 +0200 Subject: [PATCH 72/78] msm: ipa: Prevent deletion of the default route rule The first APPS default routing table rule is installed at the IPA driver initialization. To prevent routing exception, this rule cannot be deleted by user application. This change prevents deleting this rule. Change-Id: Ia27434fd24a15fea5956018a1271b11bbe227df7 CRs-fixed: 2165859 Signed-off-by: Ghanim Fodi Signed-off-by: anupritaisno1 --- drivers/platform/msm/ipa/ipa_rt.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c index 9d2f1df371030..db3c469cb83f2 100644 --- a/drivers/platform/msm/ipa/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_rt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1072,6 +1072,15 @@ int __ipa_del_rt_rule(u32 rule_hdl) return -EINVAL; } + if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) { + IPADBG("Deleting rule from default rt table idx=%u\n", + entry->tbl->idx); + if (entry->tbl->rule_cnt == 1) { + IPAERR("Default tbl last rule cannot be deleted\n"); + return -EINVAL; + } + } + if (entry->hdr) __ipa_release_hdr(entry->hdr->id); else if (entry->proc_ctx) From 644afc899705c267efd7b1a189414b175cf0330e Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Wed, 17 Jan 2018 21:03:52 +0530 Subject: [PATCH 73/78] diag: Validate copying length against source buffer length There a possibility of out-of-bound read because of not validating source buffer length against length that about to be copied. The patch adds proper check for validating length before copying data CRs-Fixed: 2163793 Change-Id: I7c93839d0c4d83024ce23a0ce494d09dd08567a9 Signed-off-by: Hardik Arya Signed-off-by: Bharat Pawar Signed-off-by: anupritaisno1 --- drivers/char/diag/diag_dci.c | 91 ++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 57b43001caec6..444e79849799a 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1099,18 +1099,31 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; - length = *(uint16_t *)(buf + 1); /* total length of event series */ - if (length == 0) { - pr_err("diag: Incoming dci event length is invalid\n"); + if (!buf) { + pr_err("diag: In %s buffer is NULL\n", __func__); return; } - /* Move directly to the start of the event series. 1 byte for - * event code and 2 bytes for the length field. - */ - /* The length field indicates the total length removing the cmd_code + /* + * 1 byte for event code and 2 bytes for the length field. + * The length field indicates the total length removing the cmd_code * and the lenght field. The event parsing in that case should happen * till the end. */ + if (len < 3) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); + return; + } + length = *(uint16_t *)(buf + 1); /* total length of event series */ + if ((length == 0) || (len != (length + 3))) { + pr_err("diag: Incoming dci event length: %d is invalid\n", + length); + return; + } + /* + * Move directly to the start of the event series. + * The event parsing should happen from start of event + * series till the end. + */ temp_len = 3; while (temp_len < length) { event_id_packet = *(uint16_t *)(buf + temp_len); @@ -1127,30 +1140,60 @@ void extract_dci_events(unsigned char *buf, int len, int data_source, int token) * necessary. */ timestamp_len = 8; - memcpy(timestamp, buf + temp_len + 2, timestamp_len); + if ((temp_len + timestamp_len + 2) <= len) + memcpy(timestamp, buf + temp_len + 2, + timestamp_len); + else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } } /* 13th and 14th bit represent the payload length */ if (((event_id_packet & 0x6000) >> 13) == 3) { payload_len_field = 1; - payload_len = *(uint8_t *) + if ((temp_len + timestamp_len + 3) <= len) { + payload_len = *(uint8_t *) (buf + temp_len + 2 + timestamp_len); - if (payload_len < (MAX_EVENT_SIZE - 13)) { - /* copy the payload length and the payload */ + } else { + pr_err("diag: Invalid length in %s, len: %d, temp_len: %d", + __func__, len, temp_len); + return; + } + if ((payload_len < (MAX_EVENT_SIZE - 13)) && + ((temp_len + timestamp_len + payload_len + 3) <= len)) { + /* + * Copy the payload length and the payload + * after skipping temp_len bytes for already + * parsed packet, timestamp_len for timestamp + * buffer, 2 bytes for event_id_packet. + */ memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, 1); memcpy(event_data + 13, buf + temp_len + 2 + timestamp_len + 1, payload_len); } else { - pr_err("diag: event > %d, payload_len = %d\n", - (MAX_EVENT_SIZE - 13), payload_len); + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 13), payload_len, temp_len); return; } } else { payload_len_field = 0; payload_len = (event_id_packet & 0x6000) >> 13; - /* copy the payload */ - memcpy(event_data + 12, buf + temp_len + 2 + + /* + * Copy the payload after skipping temp_len bytes + * for already parsed packet, timestamp_len for + * timestamp buffer, 2 bytes for event_id_packet. + */ + if ((payload_len < (MAX_EVENT_SIZE - 12)) && + ((temp_len + timestamp_len + payload_len + 2) <= len)) + memcpy(event_data + 12, buf + temp_len + 2 + timestamp_len, payload_len); + else { + pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n", + (MAX_EVENT_SIZE - 12), payload_len, temp_len); + return; + } } /* Before copying the data to userspace, check if we are still @@ -1266,19 +1309,19 @@ void extract_dci_log(unsigned char *buf, int len, int data_source, int token) pr_err("diag: In %s buffer is NULL\n", __func__); return; } - - /* The first six bytes for the incoming log packet contains - * Command code (2), the length of the packet (2) and the length - * of the log (2) + /* + * The first eight bytes for the incoming log packet contains + * Command code (2), the length of the packet (2), the length + * of the log (2) and log code (2) */ - log_code = *(uint16_t *)(buf + 6); - read_bytes += sizeof(uint16_t) + 6; - if (read_bytes > len) { - pr_err("diag: Invalid length in %s, len: %d, read: %d", - __func__, len, read_bytes); + if (len < 8) { + pr_err("diag: In %s invalid len: %d\n", __func__, len); return; } + log_code = *(uint16_t *)(buf + 6); + read_bytes += sizeof(uint16_t) + 6; + /* parse through log mask table of each client and check mask */ list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); From ecefb80412cd0d611ac2e562d28d19ca20f67100 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Thu, 15 Mar 2018 12:08:54 +0530 Subject: [PATCH 74/78] usb: dwc3: dbm: Fix double free in msm_dbm_probe Memory allocated with devm_kzalloc is automatically released by the kernel if the probe function fails with an error code. Therefore, using kfree is unsafe since it can lead to the Double-Free security issue. This change removes kfree from msm_dbm_probe function to avoid double free for dbm_data. Change-Id: I512284d021ba89d5d04a6d498aa17489e37bff2e Signed-off-by: Pratham Pratap Signed-off-by: anupritaisno1 --- drivers/usb/dwc3/dbm-1_4.c | 27 ++++----------------------- drivers/usb/dwc3/dbm-1_5.c | 27 ++++----------------------- 2 files changed, 8 insertions(+), 46 deletions(-) diff --git a/drivers/usb/dwc3/dbm-1_4.c b/drivers/usb/dwc3/dbm-1_4.c index 661a938e055c5..1caf7983f60f4 100644 --- a/drivers/usb/dwc3/dbm-1_4.c +++ b/drivers/usb/dwc3/dbm-1_4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -372,7 +372,6 @@ static int msm_dbm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dbm *dbm; struct resource *res; - int ret = 0; dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL); if (!dbm_data) @@ -382,24 +381,21 @@ static int msm_dbm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory base resource\n"); - ret = -ENODEV; - goto free_dbm_data; + return -ENODEV; } dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!dbm_data->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL); if (!dbm) { dev_err(&pdev->dev, "not enough memory\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm->dev = dev; @@ -418,20 +414,6 @@ static int msm_dbm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dbm); return usb_add_dbm(dbm); - -free_dbm_data: - kfree(dbm_data); - return ret; -} - -static int msm_dbm_remove(struct platform_device *pdev) -{ - struct dbm *dbm = platform_get_drvdata(pdev); - - kfree(dbm); - kfree(dbm_data); - - return 0; } static const struct of_device_id msm_dbm_1_4_id_table[] = { @@ -444,7 +426,6 @@ MODULE_DEVICE_TABLE(of, msm_dbm_1_4_id_table); static struct platform_driver msm_dbm_driver = { .probe = msm_dbm_probe, - .remove = msm_dbm_remove, .driver = { .name = "msm-usb-dbm-1-4", .of_match_table = of_match_ptr(msm_dbm_1_4_id_table), diff --git a/drivers/usb/dwc3/dbm-1_5.c b/drivers/usb/dwc3/dbm-1_5.c index 2a3609ef6ffb6..7f6c5f0bfe15d 100644 --- a/drivers/usb/dwc3/dbm-1_5.c +++ b/drivers/usb/dwc3/dbm-1_5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -387,7 +387,6 @@ static int msm_dbm_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct dbm *dbm; struct resource *res; - int ret = 0; dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL); if (!dbm_data) @@ -397,24 +396,21 @@ static int msm_dbm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory base resource\n"); - ret = -ENODEV; - goto free_dbm_data; + return -ENODEV; } dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!dbm_data->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL); if (!dbm) { dev_err(&pdev->dev, "not enough memory\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm_data->dbm_reset_ep_after_lpm = of_property_read_bool(node, @@ -437,20 +433,6 @@ static int msm_dbm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dbm); return usb_add_dbm(dbm); - -free_dbm_data: - kfree(dbm_data); - return ret; -} - -static int msm_dbm_remove(struct platform_device *pdev) -{ - struct dbm *dbm = platform_get_drvdata(pdev); - - kfree(dbm); - kfree(dbm_data); - - return 0; } static const struct of_device_id msm_dbm_1_5_id_table[] = { @@ -463,7 +445,6 @@ MODULE_DEVICE_TABLE(of, msm_dbm_1_5_id_table); static struct platform_driver msm_dbm_driver = { .probe = msm_dbm_probe, - .remove = msm_dbm_remove, .driver = { .name = "msm-usb-dbm-1-5", .of_match_table = of_match_ptr(msm_dbm_1_5_id_table), From 0a2a70425d81f05bf8b8cacec85bcb120c69e6ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 29 Apr 2014 23:40:14 -0400 Subject: [PATCH 75/78] new helper: dentry_free() The part of old d_free() is that dealt with actual freeing of dentry. Taken out of dentry_kill() into a separate function. Git-repo: https://github.com/torvalds/linux.git Git-commit: b4f0354e968f5fabd39bc85b99fedae4a97589fe Change-Id: I4b16554b6f6acc558d299ca3282eebf93612d8a9 Signed-off-by: Al Viro Signed-off-by: Ankit Jain Signed-off-by: anupritaisno1 --- fs/dcache.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index dcb875bdd1ab3..cdfe02554c786 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -220,6 +220,15 @@ static void __d_free(struct rcu_head *head) kmem_cache_free(dentry_cache, dentry); } +static void dentry_free(struct dentry *dentry) +{ + /* if dentry was never visible to RCU, immediate free is OK */ + if (!(dentry->d_flags & DCACHE_RCUACCESS)) + __d_free(&dentry->d_u.d_rcu); + else + call_rcu(&dentry->d_u.d_rcu, __d_free); +} + /* * no locks, please. */ @@ -231,11 +240,7 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - /* if dentry was never visible to RCU, immediate free is OK */ - if (!(dentry->d_flags & DCACHE_RCUACCESS)) - __d_free(&dentry->d_u.d_rcu); - else - call_rcu(&dentry->d_u.d_rcu, __d_free); + dentry_free(dentry); } void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) From aa115c0d84829a122bd13a98f7ec99ae9a1d5f1a Mon Sep 17 00:00:00 2001 From: "Mugata, Sreenivasa Rao" Date: Sun, 11 Mar 2018 12:37:30 +0530 Subject: [PATCH 76/78] Allow sharing external names after __d_move() * external dentry names get a small structure prepended to them (struct external_name). * it contains an atomic refcount, matching the number of struct dentry instances that have ->d_name.name pointing to that external name. The first thing free_dentry() does is decrementing refcount of external name, so the instances that are between the call of free_dentry() and RCU-delayed actual freeing do not contribute. * __d_move(x, y, false) makes the name of x equal to the name of y, external or not. If y has an external name, extra reference is grabbed and put into x->d_name.name. If x used to have an external name, the reference to the old name is dropped and, should it reach zero, freeing is scheduled via kfree_rcu(). * free_dentry() in dentry with external name decrements the refcount of that name and, should it reach zero, does RCU-delayed call that will free both the dentry and external name. Otherwise it does what it used to do, except that __d_free() doesn't even look at ->d_name.name; it simply frees the dentry. All non-RCU accesses to dentry external name are safe wrt freeing since they all should happen before free_dentry() is called. RCU accesses might run into a dentry seen by free_dentry() or into an old name that got already dropped by __d_move(); however, in both cases dentry must have been alive and refer to that name at some point after we'd done rcu_read_lock(), which means that any freeing must be still pending. Git-repo: https://github.com/torvalds/linux.git Git-commit: 8d85b4845a668d9a72649005c5aa932657311bd4 Change-Id: I1fa645f0e2eba6e8485daa8593600f933a5342c9 Signed-off-by: Al Viro Signed-off-by: Ankit Jain Signed-off-by: Mugata, Sreenivasa Rao Signed-off-by: anupritaisno1 --- fs/dcache.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index cdfe02554c786..aa42c7930c14d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -211,17 +211,42 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c return dentry_string_cmp(cs, ct, tcount); } +struct external_name { + union { + atomic_t count; + struct rcu_head head; + } u; + unsigned char name[]; +}; + +static inline struct external_name *external_name(struct dentry *dentry) +{ + return container_of(dentry->d_name.name, struct external_name, name[0]); +} + static void __d_free(struct rcu_head *head) { struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); - if (dname_external(dentry)) - kfree(dentry->d_name.name); kmem_cache_free(dentry_cache, dentry); } +static void __d_free_external(struct rcu_head *head) +{ + struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); + kfree(external_name(dentry)); + kmem_cache_free(dentry_cache, dentry); +} + static void dentry_free(struct dentry *dentry) { + if (unlikely(dname_external(dentry))) { + struct external_name *p = external_name(dentry); + if (likely(atomic_dec_and_test(&p->u.count))) { + call_rcu(&dentry->d_u.d_rcu, __d_free_external); + return; + } + } /* if dentry was never visible to RCU, immediate free is OK */ if (!(dentry->d_flags & DCACHE_RCUACCESS)) __d_free(&dentry->d_u.d_rcu); @@ -1300,11 +1325,14 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) */ dentry->d_iname[DNAME_INLINE_LEN-1] = 0; if (name->len > DNAME_INLINE_LEN-1) { - dname = kmalloc(name->len + 1, GFP_KERNEL); - if (!dname) { + size_t size = offsetof(struct external_name, name[1]); + struct external_name *p = kmalloc(size + name->len, GFP_KERNEL); + if (!p) { kmem_cache_free(dentry_cache, dentry); return NULL; } + atomic_set(&p->u.count, 1); + dname = p->name; } else { dname = dentry->d_iname; } @@ -2196,8 +2224,8 @@ EXPORT_SYMBOL(dentry_update_name_case); static void switch_names(struct dentry *dentry, struct dentry *target) { - if (dname_external(target)) { - if (dname_external(dentry)) { + if (unlikely(dname_external(target))) { + if (unlikely(dname_external(dentry))) { /* * Both external: swap the pointers */ @@ -2213,7 +2241,7 @@ static void switch_names(struct dentry *dentry, struct dentry *target) target->d_name.name = target->d_iname; } } else { - if (dname_external(dentry)) { + if (unlikely(dname_external(dentry))) { /* * dentry:external, target:internal. Give dentry's * storage to target and make dentry internal @@ -2235,6 +2263,25 @@ static void switch_names(struct dentry *dentry, struct dentry *target) swap(dentry->d_name.len, target->d_name.len); } +static void copy_name(struct dentry *dentry, struct dentry *target) +{ + struct external_name *old_name = NULL; + if (unlikely(dname_external(dentry))) + old_name = external_name(dentry); + if (unlikely(dname_external(target))) { + atomic_inc(&external_name(target)->u.count); + dentry->d_name = target->d_name; + } else { + memcpy(dentry->d_iname, target->d_name.name, + target->d_name.len + 1); + dentry->d_name.name = dentry->d_iname; + dentry->d_name.len = target->d_name.len; + } + if (old_name && likely(atomic_dec_and_test(&old_name->u.count))) + kfree_rcu(old_name, u.head); +} + + static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) { /* @@ -2321,7 +2368,7 @@ static void __d_move(struct dentry * dentry, struct dentry * target) list_del(&target->d_child); /* Switch the names.. */ - switch_names(dentry, target); + copy_name(dentry, target); swap(dentry->d_name.hash, target->d_name.hash); /* ... and switch the parents */ From 18965a21c94961963bb902080afb466b64ced561 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Thu, 9 Oct 2014 15:29:38 -0700 Subject: [PATCH 77/78] fs/buffer.c: increase the buffer-head per-CPU LRU size Increase the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will access multiple buffer heads and will overflow the LRU at the default 8-block LRU size: * parent directory inode table block (ctime, nlinks for subdirs) * new inode bitmap * inode table block * 2 quota blocks * directory leaf block (not reused, but pollutes one cache entry) * 2 levels htree blocks (only one is reused, other pollutes cache) * 2 levels indirect/index blocks (only one is reused) The buffer-head per-CPU LRU size is raised to 16, as it shows in metadata performance benchmarks up to 10% gain for create, 4% for lookup and 7% for destroy. Change-Id: Ia8e4c430886b29fca32b7d4319365088cc2ca9d1 Signed-off-by: Liang Zhen Signed-off-by: Andreas Dilger Signed-off-by: Sebastien Buisson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: anupritaisno1 --- fs/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/buffer.c b/fs/buffer.c index 963b348199007..c36b69324ada5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1263,7 +1263,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh) * a local interrupt disable for that. */ -#define BH_LRU_SIZE 8 +#define BH_LRU_SIZE 16 struct bh_lru { struct buffer_head *bhs[BH_LRU_SIZE]; From b4dfa526c7f5b3627666d8d5eebe6fad6b05a1cb Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 12 Dec 2013 09:53:51 -0800 Subject: [PATCH 78/78] futex: move user address verification up to common code When debugging the read-only hugepage case, I was confused by the fact that get_futex_key() did an access_ok() only for the non-shared futex case, since the user address checking really isn't in any way specific to the private key handling. Now, it turns out that the shared key handling does effectively do the equivalent checks inside get_user_pages_fast() (it doesn't actually check the address range on x86, but does check the page protections for being a user page). So it wasn't actually a bug, but the fact that we treat the address differently for private and shared futexes threw me for a loop. Just move the check up, so that it gets done for both cases. Also, use the 'rw' parameter for the type, even if it doesn't actually matter any more (it's a historical artifact of the old racy i386 "page faults from kernel space don't check write protections"). Change-Id: I70a366e4e392e917dce1ac19d66dfaea8984939b Cc: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: anupritaisno1 --- kernel/futex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 191a280d1275e..800994c0b388f 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -254,6 +254,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) return -EINVAL; address -= key->both.offset; + if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) + return -EFAULT; + /* * PROCESS_PRIVATE futexes are fast. * As the mm cannot disappear under us and the 'key' only needs @@ -262,8 +265,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) * but access_ok() should be faster than find_vma() */ if (!fshared) { - if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) - return -EFAULT; key->private.mm = mm; key->private.address = address; get_futex_key_refs(key);