From c3464453126ec309c6a7e93f4f165dc76146858c Mon Sep 17 00:00:00 2001 From: Anan Jaser Date: Sat, 16 Dec 2023 21:15:34 +0400 Subject: [PATCH] N770FXXU9HWI2 * Skip security FIVE/DEFEX/DSMS/MZ/PROCA * Skip sensorhub patch files --- drivers/char/hw_random/exyswd-rng.c | 140 ++++++++++++------ drivers/gpu/arm/bv_r26p0/mali_kbase_mem.c | 22 ++- .../arm/bv_r26p0/mali_kbase_sync_android.c | 15 +- .../gpu/arm/bv_r26p0/tl/mali_kbase_timeline.c | 2 + .../gpu/arm/bv_r26p0/tl/mali_kbase_timeline.h | 2 + .../arm/bv_r26p0/tl/mali_kbase_timeline_io.c | 64 +++++++- drivers/gpu/arm/bv_r32p1/mali_kbase_mem.c | 22 ++- .../arm/bv_r32p1/mali_kbase_sync_android.c | 13 +- .../gpu/arm/bv_r32p1/tl/mali_kbase_timeline.c | 2 + .../gpu/arm/bv_r32p1/tl/mali_kbase_timeline.h | 2 + .../arm/bv_r32p1/tl/mali_kbase_timeline_io.c | 64 +++++++- drivers/gpu/arm/bv_r38p1/mali_kbase_mem.c | 22 ++- .../gpu/arm/bv_r38p1/tl/mali_kbase_timeline.c | 2 + .../gpu/arm/bv_r38p1/tl/mali_kbase_timeline.h | 2 + .../arm/bv_r38p1/tl/mali_kbase_timeline_io.c | 64 +++++++- .../fimc-is2/fimc-is-device-sensor_v2.c | 14 +- fs/f2fs/checkpoint.c | 13 +- fs/f2fs/data.c | 21 +++ fs/f2fs/super.c | 15 +- security/samsung/kumiho/Kconfig | 7 + 20 files changed, 424 insertions(+), 84 deletions(-) create mode 100644 security/samsung/kumiho/Kconfig diff --git a/drivers/char/hw_random/exyswd-rng.c b/drivers/char/hw_random/exyswd-rng.c index 9dbcdc3542c8..d84eb5775d4c 100755 --- a/drivers/char/hw_random/exyswd-rng.c +++ b/drivers/char/hw_random/exyswd-rng.c @@ -43,6 +43,12 @@ static int hwrng_disabled; #endif static int start_up_test; +atomic_t hwrng_suspend_flag; +atomic_t hwrng_running_flag; + +/* Protects exyswd read functions */ +static DEFINE_SPINLOCK(rng_running_lock); + #ifdef CONFIG_EXYRNG_DEBUG #define exyrng_debug(args...) printk(KERN_INFO args) #else @@ -64,8 +70,33 @@ void exynos_swd_test_fail(void) #endif } +static int exynos_cm_smc(uint64_t *arg0, uint64_t *arg1, + uint64_t *arg2, uint64_t *arg3) +{ + register uint64_t reg0 __asm__("x0") = *arg0; + register uint64_t reg1 __asm__("x1") = *arg1; + register uint64_t reg2 __asm__("x2") = *arg2; + register uint64_t reg3 __asm__("x3") = *arg3; + + __asm__ volatile ( + "smc 0\n" + : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) + ); + + *arg0 = reg0; + *arg1 = reg1; + *arg2 = reg2; + *arg3 = reg3; + + return *arg0; +} + static int exynos_swd_startup_test(void) { + uint64_t reg0; + uint64_t reg1; + uint64_t reg2; + uint64_t reg3; uint32_t start_up_size; uint32_t retry_cnt; uint32_t test_cnt; @@ -76,7 +107,12 @@ static int exynos_swd_startup_test(void) retry_cnt = 0; test_cnt = 1; while (start_up_size) { - ret = exynos_smc(SMC_CMD_RANDOM, HWRNG_GET_DATA, 1, 0); + reg0 = SMC_CMD_RANDOM; + reg1 = HWRNG_GET_DATA; + reg2 = 1; + reg3 = 0; + + ret = exynos_cm_smc(®0, ®1, ®2, ®3); if (ret == HWRNG_RET_RETRY_ERROR) { if (retry_cnt++ > EXYRNG_RETRY_MAX_COUNT) { printk("[ExyRNG] exceed retry in start-up test\n"); @@ -128,33 +164,42 @@ static int exynos_swd_startup_test(void) static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait) { + uint64_t reg0; + uint64_t reg1; + uint64_t reg2; + uint64_t reg3; uint32_t *read_buf = data; uint32_t read_size = max; - uint32_t r_data[2]; unsigned long flag; + unsigned long running_flag; uint32_t retry_cnt; int ret = HWRNG_RET_OK; - register u64 reg0 __asm__("x0"); - register u64 reg1 __asm__("x1"); - register u64 reg2 __asm__("x2"); - register u64 reg3 __asm__("x3"); - #if defined(CONFIG_EXYRNG_FAIL_POLICY_DISABLE) if (hwrng_disabled) return -EPERM; #endif + spin_lock_irqsave(&rng_running_lock, running_flag); + if (atomic_read(&hwrng_suspend_flag) == 1) { + atomic_set(&hwrng_running_flag, 0); + spin_unlock_irqrestore(&rng_running_lock, running_flag); + printk("[ExyRNG] exynos_swd_read is failed because of suspend flag\n"); + return -EFAULT; + } - reg0 = 0; - reg1 = 0; - reg2 = 0; - reg3 = 0; + atomic_set(&hwrng_running_flag, 1); + spin_unlock_irqrestore(&rng_running_lock, running_flag); retry_cnt = 0; do { spin_lock_irqsave(&hwrandom_lock, flag); if (hwrng_read_flag == 0) { - ret = exynos_smc(SMC_CMD_RANDOM, HWRNG_INIT, 0, 0); + reg0 = SMC_CMD_RANDOM; + reg1 = HWRNG_INIT; + reg2 = 0; + reg3 = 0; + + ret = exynos_cm_smc(®0, ®1, ®2, ®3); if (ret == HWRNG_RET_OK) hwrng_read_flag = 1; spin_unlock_irqrestore(&hwrandom_lock, flag); @@ -177,7 +222,8 @@ static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait) } while (ret == HWRNG_RET_RETRY_ERROR); if (ret != HWRNG_RET_OK) { msleep(1); - return -EFAULT; + ret = -EFAULT; + goto err; } if (start_up_test) { @@ -192,13 +238,14 @@ static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait) retry_cnt = 0; while (read_size) { spin_lock_irqsave(&hwrandom_lock, flag); - ret = __exynos_smc(SMC_CMD_RANDOM, HWRNG_GET_DATA, 0, 0); - __asm__ volatile( - "\t" - : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) - ); - r_data[0] = (uint32_t)reg2; - r_data[1] = (uint32_t)reg3; + + reg0 = SMC_CMD_RANDOM; + reg1 = HWRNG_GET_DATA; + reg2 = 0; + reg3 = 0; + + ret = exynos_cm_smc(®0, ®1, ®2, ®3); + spin_unlock_irqrestore(&hwrandom_lock, flag); if (ret == HWRNG_RET_RETRY_ERROR) { @@ -222,8 +269,8 @@ static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait) goto out; } - *(uint32_t*)(read_buf++) = r_data[0]; - *(uint32_t*)(read_buf++) = r_data[1]; + *(uint32_t*)(read_buf++) = (uint32_t)reg2; + *(uint32_t*)(read_buf++) = (uint32_t)reg3; read_size -= 8; retry_cnt = 0; @@ -235,7 +282,13 @@ static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait) retry_cnt = 0; do { spin_lock_irqsave(&hwrandom_lock, flag); - if (!exynos_smc(SMC_CMD_RANDOM, HWRNG_EXIT, 0, 0)) { + + reg0 = SMC_CMD_RANDOM; + reg1 = HWRNG_EXIT; + reg2 = 0; + reg3 = 0; + + if (!exynos_cm_smc(®0, ®1, ®2, ®3)) { hwrng_read_flag = 0; spin_unlock_irqrestore(&hwrandom_lock, flag); break; @@ -249,6 +302,11 @@ static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait) usleep_range(50, 100); } while(1); +err: + spin_lock_irqsave(&rng_running_lock, running_flag); + atomic_set(&hwrng_running_flag, 0); + spin_unlock_irqrestore(&rng_running_lock, running_flag); + return ret; } @@ -265,6 +323,9 @@ static int exyswd_rng_probe(struct platform_device *pdev) start_up_test = 1; #endif + atomic_set(&hwrng_suspend_flag, 0); + atomic_set(&hwrng_running_flag, 0); + ret = hwrng_register(&rng); if (ret) return ret; @@ -287,13 +348,16 @@ static int exyswd_rng_suspend(struct device *dev) unsigned long flag; int ret = HWRNG_RET_OK; - spin_lock_irqsave(&hwrandom_lock, flag); - if (hwrng_read_flag) { - ret = exynos_smc(SMC_CMD_RANDOM, HWRNG_EXIT, 0, 0); - if (ret != HWRNG_RET_OK) - printk("[ExyRNG] failed to enter suspend with %d\n", ret); + spin_lock_irqsave(&rng_running_lock, flag); + if (atomic_read(&hwrng_running_flag) == 1) { + printk("[ExyRNG] exyswd_rng_suspend: hwrng_running_flag is 1.\n"); + ret = -EFAULT; + goto out; } - spin_unlock_irqrestore(&hwrandom_lock, flag); + + atomic_set(&hwrng_suspend_flag, 1); +out: + spin_unlock_irqrestore(&rng_running_lock, flag); return ret; } @@ -301,22 +365,12 @@ static int exyswd_rng_suspend(struct device *dev) static int exyswd_rng_resume(struct device *dev) { unsigned long flag; - int ret = HWRNG_RET_OK; - spin_lock_irqsave(&hwrandom_lock, flag); -#if defined(CONFIG_EXYRNG_FIPS_COMPLIANCE) - ret = exynos_smc(SMC_CMD_RANDOM, HWRNG_RESUME, 0, 0); - if (ret != HWRNG_RET_OK) - printk("[ExyRNG] failed to resume with %d\n", ret); -#endif - if (hwrng_read_flag) { - ret = exynos_smc(SMC_CMD_RANDOM, HWRNG_INIT, 0, 0); - if (ret != HWRNG_RET_OK) - printk("[ExyRNG] failed to resume with %d\n", ret); - } - spin_unlock_irqrestore(&hwrandom_lock, flag); + spin_lock_irqsave(&rng_running_lock, flag); + atomic_set(&hwrng_suspend_flag, 0); + spin_unlock_irqrestore(&rng_running_lock, flag); - return ret; + return HWRNG_RET_OK; } #endif diff --git a/drivers/gpu/arm/bv_r26p0/mali_kbase_mem.c b/drivers/gpu/arm/bv_r26p0/mali_kbase_mem.c index f42121c8a62b..6d5622082fc5 100755 --- a/drivers/gpu/arm/bv_r26p0/mali_kbase_mem.c +++ b/drivers/gpu/arm/bv_r26p0/mali_kbase_mem.c @@ -362,6 +362,7 @@ int kbase_remove_va_region(struct kbase_va_region *reg) struct rb_node *rbnext; struct kbase_va_region *next = NULL; struct rb_root *reg_rbtree = NULL; + struct kbase_va_region *orig_reg = reg; int merged_front = 0; int merged_back = 0; @@ -422,6 +423,12 @@ int kbase_remove_va_region(struct kbase_va_region *reg) } rb_replace_node(&(reg->rblink), &(free_reg->rblink), reg_rbtree); } + /* This operation is always safe because the function never frees + * the region. If the region has been merged to both front and back, + * then it's the previous region that is supposed to be freed. + */ + orig_reg->start_pfn = 0; + out: return err; @@ -1453,7 +1460,7 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, kctx->as_nr, group_id, mmu_sync_info); if (err) - goto bad_insert; + goto bad_aliased_insert; /* Note: mapping count is tracked at alias * creation time @@ -1468,7 +1475,7 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, if (err) - goto bad_insert; + goto bad_aliased_insert; } } } else { @@ -1512,9 +1519,16 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, return err; +bad_aliased_insert: + while (i-- > 0) { + + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, + reg->nr_pages, kctx->as_nr); + + } + + bad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, - reg->nr_pages, kctx->as_nr); kbase_remove_va_region(reg); diff --git a/drivers/gpu/arm/bv_r26p0/mali_kbase_sync_android.c b/drivers/gpu/arm/bv_r26p0/mali_kbase_sync_android.c index 75940fb08a05..b8575dba4e96 100755 --- a/drivers/gpu/arm/bv_r26p0/mali_kbase_sync_android.c +++ b/drivers/gpu/arm/bv_r26p0/mali_kbase_sync_android.c @@ -263,12 +263,14 @@ int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int tl_fd) fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC); if (fd < 0) { sync_fence_put(fence); + katom->fence = NULL; goto out; } #else fd = get_unused_fd(); if (fd < 0) { sync_fence_put(fence); + katom->fence = NULL; goto out; } @@ -283,13 +285,18 @@ int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int tl_fd) spin_unlock(&files->file_lock); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) */ + /* Take an extra reference count on the created fence file */ + get_file(fence->file); /* bind fence to the new fd */ sync_fence_install(fence, fd); - katom->fence = sync_fence_fdget(fd); - if (katom->fence == NULL) { - /* The only way the fence can be NULL is if userspace closed it - * for us, so we don't need to clear it up */ + /* Drop the extra reference count */ + fput(fence->file); + + if (katom->fence != fence) { + if (katom->fence) + sync_fence_put(katom->fence); + katom->fence = NULL; fd = -EINVAL; goto out; } diff --git a/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.c b/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.c index 88fba83840af..96f821a8801b 100755 --- a/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.c +++ b/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.c @@ -181,6 +181,8 @@ int kbase_timeline_io_acquire(struct kbase_device *kbdev, u32 flags) if (!atomic_cmpxchg(timeline->timeline_flags, 0, timeline_flags)) { int rcode; + if (!timeline_is_permitted()) + return -EPERM; ret = anon_inode_getfd( "[mali_tlstream]", diff --git a/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.h b/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.h index cd48411b45cf..c565ea783e30 100755 --- a/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.h +++ b/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline.h @@ -118,4 +118,6 @@ void kbase_timeline_test( void kbase_timeline_stats(struct kbase_timeline *timeline, u32 *bytes_collected, u32 *bytes_generated); #endif /* MALI_UNIT_TEST */ +bool timeline_is_permitted(void); + #endif /* _KBASE_TIMELINE_H */ diff --git a/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline_io.c b/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline_io.c index cdde928bbab9..b5da504f4ec2 100755 --- a/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline_io.c +++ b/drivers/gpu/arm/bv_r26p0/tl/mali_kbase_timeline_io.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -26,6 +26,59 @@ #include +#ifndef MALI_STRIP_KBASE_DEVELOPMENT +/* Development builds need to test instrumentation and enable unprivileged + * processes to acquire timeline streams, in order to avoid complications + * with configurations across multiple platforms and systems. + * + * Release builds, instead, shall deny access to unprivileged processes + * because there are no use cases where they are allowed to acquire timeline + * streams, unless they're given special permissions by a privileged process. + */ +static int kbase_unprivileged_global_profiling = 1; +#else +static int kbase_unprivileged_global_profiling; +#endif + +/** + * kbase_unprivileged_global_profiling_set - set permissions for unprivileged processes + * + * @val: String containing value to set. Only strings representing positive + * integers are accepted as valid; any non-positive integer (including 0) + * is rejected. + * @kp: Module parameter associated with this method. + * + * This method can only be used to enable permissions for unprivileged processes, + * if they are disabled: for this reason, the only values which are accepted are + * strings representing positive integers. Since it's impossible to disable + * permissions once they're set, any integer which is non-positive is rejected, + * including 0. + * + * Return: 0 if success, otherwise error code. + */ +static int kbase_unprivileged_global_profiling_set(const char *val, const struct kernel_param *kp) +{ + int new_val; + int ret = kstrtoint(val, 0, &new_val); + + if (ret == 0) { + if (new_val < 1) + return -EINVAL; + + kbase_unprivileged_global_profiling = 1; + } + + return ret; +} + +static const struct kernel_param_ops kbase_global_unprivileged_profiling_ops = { + .get = param_get_int, + .set = kbase_unprivileged_global_profiling_set, +}; + +module_param_cb(kbase_unprivileged_global_profiling, &kbase_global_unprivileged_profiling_ops, + &kbase_unprivileged_global_profiling, 0600); + /* The timeline stream file operations functions. */ static ssize_t kbasep_timeline_io_read( struct file *filp, @@ -43,6 +96,15 @@ const struct file_operations kbasep_tlstream_fops = { .poll = kbasep_timeline_io_poll, }; +bool timeline_is_permitted(void) +{ +#if KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE + return kbase_unprivileged_global_profiling || perfmon_capable(); +#else + return kbase_unprivileged_global_profiling || capable(CAP_SYS_ADMIN); +#endif +} + /** * kbasep_timeline_io_packet_pending - check timeline streams for pending packets * @timeline: Timeline instance diff --git a/drivers/gpu/arm/bv_r32p1/mali_kbase_mem.c b/drivers/gpu/arm/bv_r32p1/mali_kbase_mem.c index cc2a5f58df9f..17a86b2ad284 100755 --- a/drivers/gpu/arm/bv_r32p1/mali_kbase_mem.c +++ b/drivers/gpu/arm/bv_r32p1/mali_kbase_mem.c @@ -367,6 +367,7 @@ void kbase_remove_va_region(struct kbase_device *kbdev, struct rb_node *rbnext; struct kbase_va_region *next = NULL; struct rb_root *reg_rbtree = NULL; + struct kbase_va_region *orig_reg = reg; int merged_front = 0; int merged_back = 0; @@ -464,6 +465,12 @@ void kbase_remove_va_region(struct kbase_device *kbdev, rb_replace_node(&(reg->rblink), &(free_reg->rblink), reg_rbtree); } + /* This operation is always safe because the function never frees + * the region. If the region has been merged to both front and back, + * then it's the previous region that is supposed to be freed. + */ + orig_reg->start_pfn = 0; + out: return; } @@ -1551,7 +1558,7 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, kctx->as_nr, group_id, mmu_sync_info); if (err) - goto bad_insert; + goto bad_aliased_insert; /* Note: mapping count is tracked at alias * creation time @@ -1565,7 +1572,7 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, group_id, mmu_sync_info); if (err) - goto bad_insert; + goto bad_aliased_insert; } } } else { @@ -1609,9 +1616,16 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, return err; +bad_aliased_insert: + while (i-- > 0) { + + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, + reg->nr_pages, kctx->as_nr); + + } + + bad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, - reg->nr_pages, kctx->as_nr); kbase_remove_va_region(kctx->kbdev, reg); diff --git a/drivers/gpu/arm/bv_r32p1/mali_kbase_sync_android.c b/drivers/gpu/arm/bv_r32p1/mali_kbase_sync_android.c index 8af2584cdc18..ead42c800ba7 100755 --- a/drivers/gpu/arm/bv_r32p1/mali_kbase_sync_android.c +++ b/drivers/gpu/arm/bv_r32p1/mali_kbase_sync_android.c @@ -249,17 +249,22 @@ int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int tl_fd) fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC); if (fd < 0) { sync_fence_put(fence); + katom->fence = NULL; goto out; } + /* Take an extra reference count on the created fence file */ + get_file(fence->file); /* bind fence to the new fd */ sync_fence_install(fence, fd); katom->fence = sync_fence_fdget(fd); - if (katom->fence == NULL) { - /* The only way the fence can be NULL is if userspace closed it - * for us, so we don't need to clear it up - */ + /* Drop the extra reference count */ + fput(fence->file); + if (katom->fence != fence) { + if (katom->fence) + sync_fence_put(katom->fence); + katom->fence = NULL; fd = -EINVAL; goto out; } diff --git a/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.c b/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.c index 09818a590da0..ed4128968c01 100755 --- a/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.c +++ b/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.c @@ -192,6 +192,8 @@ int kbase_timeline_io_acquire(struct kbase_device *kbdev, u32 flags) if (!atomic_cmpxchg(timeline->timeline_flags, 0, timeline_flags)) { int rcode; + if (!timeline_is_permitted()) + return -EPERM; #if MALI_USE_CSF if (flags & BASE_TLSTREAM_ENABLE_CSFFW_TRACEPOINTS) { diff --git a/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.h b/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.h index 63926ebc63a5..36b2ebafe606 100755 --- a/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.h +++ b/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline.h @@ -117,4 +117,6 @@ void kbase_timeline_post_kbase_context_destroy(struct kbase_context *kctx); void kbase_timeline_stats(struct kbase_timeline *timeline, u32 *bytes_collected, u32 *bytes_generated); #endif /* MALI_UNIT_TEST */ +bool timeline_is_permitted(void); + #endif /* _KBASE_TIMELINE_H */ diff --git a/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline_io.c b/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline_io.c index 23e42adc1264..6996faa27040 100755 --- a/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline_io.c +++ b/drivers/gpu/arm/bv_r32p1/tl/mali_kbase_timeline_io.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -27,6 +27,59 @@ #include #include +#ifndef MALI_STRIP_KBASE_DEVELOPMENT +/* Development builds need to test instrumentation and enable unprivileged + * processes to acquire timeline streams, in order to avoid complications + * with configurations across multiple platforms and systems. + * + * Release builds, instead, shall deny access to unprivileged processes + * because there are no use cases where they are allowed to acquire timeline + * streams, unless they're given special permissions by a privileged process. + */ +static int kbase_unprivileged_global_profiling = 1; +#else +static int kbase_unprivileged_global_profiling; +#endif + +/** + * kbase_unprivileged_global_profiling_set - set permissions for unprivileged processes + * + * @val: String containing value to set. Only strings representing positive + * integers are accepted as valid; any non-positive integer (including 0) + * is rejected. + * @kp: Module parameter associated with this method. + * + * This method can only be used to enable permissions for unprivileged processes, + * if they are disabled: for this reason, the only values which are accepted are + * strings representing positive integers. Since it's impossible to disable + * permissions once they're set, any integer which is non-positive is rejected, + * including 0. + * + * Return: 0 if success, otherwise error code. + */ +static int kbase_unprivileged_global_profiling_set(const char *val, const struct kernel_param *kp) +{ + int new_val; + int ret = kstrtoint(val, 0, &new_val); + + if (ret == 0) { + if (new_val < 1) + return -EINVAL; + + kbase_unprivileged_global_profiling = 1; + } + + return ret; +} + +static const struct kernel_param_ops kbase_global_unprivileged_profiling_ops = { + .get = param_get_int, + .set = kbase_unprivileged_global_profiling_set, +}; + +module_param_cb(kbase_unprivileged_global_profiling, &kbase_global_unprivileged_profiling_ops, + &kbase_unprivileged_global_profiling, 0600); + /* The timeline stream file operations functions. */ static ssize_t kbasep_timeline_io_read(struct file *filp, char __user *buffer, size_t size, loff_t *f_pos); @@ -45,6 +98,15 @@ const struct file_operations kbasep_tlstream_fops = { .fsync = kbasep_timeline_io_fsync, }; +bool timeline_is_permitted(void) +{ +#if KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE + return kbase_unprivileged_global_profiling || perfmon_capable(); +#else + return kbase_unprivileged_global_profiling || capable(CAP_SYS_ADMIN); +#endif +} + /** * kbasep_timeline_io_packet_pending - check timeline streams for pending * packets diff --git a/drivers/gpu/arm/bv_r38p1/mali_kbase_mem.c b/drivers/gpu/arm/bv_r38p1/mali_kbase_mem.c index 8a3e73bb8417..45f05efe7b9b 100644 --- a/drivers/gpu/arm/bv_r38p1/mali_kbase_mem.c +++ b/drivers/gpu/arm/bv_r38p1/mali_kbase_mem.c @@ -380,6 +380,7 @@ void kbase_remove_va_region(struct kbase_device *kbdev, struct rb_node *rbnext; struct kbase_va_region *next = NULL; struct rb_root *reg_rbtree = NULL; + struct kbase_va_region *orig_reg = reg; int merged_front = 0; int merged_back = 0; @@ -477,6 +478,12 @@ void kbase_remove_va_region(struct kbase_device *kbdev, rb_replace_node(&(reg->rblink), &(free_reg->rblink), reg_rbtree); } + /* This operation is always safe because the function never frees + * the region. If the region has been merged to both front and back, + * then it's the previous region that is supposed to be freed. + */ + orig_reg->start_pfn = 0; + out: return; } @@ -1750,7 +1757,7 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, reg->flags & gwt_mask, kctx->as_nr, group_id, mmu_sync_info); if (err) - goto bad_insert; + goto bad_aliased_insert; /* Note: mapping count is tracked at alias * creation time @@ -1764,7 +1771,7 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, group_id, mmu_sync_info); if (err) - goto bad_insert; + goto bad_aliased_insert; } } } else { @@ -1805,9 +1812,16 @@ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, return err; +bad_aliased_insert: + while (i-- > 0) { + + kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, + reg->nr_pages, kctx->as_nr); + + } + + bad_insert: - kbase_mmu_teardown_pages(kctx->kbdev, &kctx->mmu, reg->start_pfn, alloc->pages, - reg->nr_pages, kctx->as_nr); kbase_remove_va_region(kctx->kbdev, reg); diff --git a/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.c b/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.c index 9fd463eb6962..f11a6e8a5dcd 100644 --- a/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.c +++ b/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.c @@ -192,6 +192,8 @@ int kbase_timeline_io_acquire(struct kbase_device *kbdev, u32 flags) if (!atomic_cmpxchg(timeline->timeline_flags, 0, timeline_flags)) { int rcode; + if (!timeline_is_permitted()) + return -EPERM; #if MALI_USE_CSF if (flags & BASE_TLSTREAM_ENABLE_CSFFW_TRACEPOINTS) { diff --git a/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.h b/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.h index 96a4b181a285..10f286a45a75 100644 --- a/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.h +++ b/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline.h @@ -117,4 +117,6 @@ void kbase_timeline_post_kbase_context_destroy(struct kbase_context *kctx); void kbase_timeline_stats(struct kbase_timeline *timeline, u32 *bytes_collected, u32 *bytes_generated); #endif /* MALI_UNIT_TEST */ +bool timeline_is_permitted(void); + #endif /* _KBASE_TIMELINE_H */ diff --git a/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline_io.c b/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline_io.c index af8b3d8c8c35..33e4f4fab7a6 100644 --- a/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline_io.c +++ b/drivers/gpu/arm/bv_r38p1/tl/mali_kbase_timeline_io.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2019-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -28,6 +28,59 @@ #include #include +#ifndef MALI_STRIP_KBASE_DEVELOPMENT +/* Development builds need to test instrumentation and enable unprivileged + * processes to acquire timeline streams, in order to avoid complications + * with configurations across multiple platforms and systems. + * + * Release builds, instead, shall deny access to unprivileged processes + * because there are no use cases where they are allowed to acquire timeline + * streams, unless they're given special permissions by a privileged process. + */ +static int kbase_unprivileged_global_profiling = 1; +#else +static int kbase_unprivileged_global_profiling; +#endif + +/** + * kbase_unprivileged_global_profiling_set - set permissions for unprivileged processes + * + * @val: String containing value to set. Only strings representing positive + * integers are accepted as valid; any non-positive integer (including 0) + * is rejected. + * @kp: Module parameter associated with this method. + * + * This method can only be used to enable permissions for unprivileged processes, + * if they are disabled: for this reason, the only values which are accepted are + * strings representing positive integers. Since it's impossible to disable + * permissions once they're set, any integer which is non-positive is rejected, + * including 0. + * + * Return: 0 if success, otherwise error code. + */ +static int kbase_unprivileged_global_profiling_set(const char *val, const struct kernel_param *kp) +{ + int new_val; + int ret = kstrtoint(val, 0, &new_val); + + if (ret == 0) { + if (new_val < 1) + return -EINVAL; + + kbase_unprivileged_global_profiling = 1; + } + + return ret; +} + +static const struct kernel_param_ops kbase_global_unprivileged_profiling_ops = { + .get = param_get_int, + .set = kbase_unprivileged_global_profiling_set, +}; + +module_param_cb(kbase_unprivileged_global_profiling, &kbase_global_unprivileged_profiling_ops, + &kbase_unprivileged_global_profiling, 0600); + /* The timeline stream file operations functions. */ static ssize_t kbasep_timeline_io_read(struct file *filp, char __user *buffer, size_t size, loff_t *f_pos); @@ -45,6 +98,15 @@ const struct file_operations kbasep_tlstream_fops = { .fsync = kbasep_timeline_io_fsync, }; +bool timeline_is_permitted(void) +{ +#if KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE + return kbase_unprivileged_global_profiling || perfmon_capable(); +#else + return kbase_unprivileged_global_profiling || capable(CAP_SYS_ADMIN); +#endif +} + /** * kbasep_timeline_io_packet_pending - check timeline streams for pending * packets diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-sensor_v2.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-sensor_v2.c index 12032cee3329..869293bc247f 100755 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-sensor_v2.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-sensor_v2.c @@ -2494,23 +2494,17 @@ int fimc_is_sensor_s_ctrl(struct fimc_is_device_sensor *device, int fimc_is_sensor_s_ext_ctrls(struct fimc_is_device_sensor *device, struct v4l2_ext_controls *ctrls) { - int ret = 0; - struct v4l2_subdev *subdev_module; + int ret; + struct v4l2_subdev *subdev_module = device->subdev_module; - WARN_ON(!device); - WARN_ON(!device->subdev_module); - WARN_ON(!device->subdev_csi); - WARN_ON(!ctrls); - - subdev_module = device->subdev_module; + FIMC_BUG(!subdev_module); ret = v4l2_subdev_call(subdev_module, core, s_ext_ctrls, ctrls); if (ret) { err("s_ext_ctrls is fail(%d)", ret); - goto p_err; + return ret; } -p_err: return ret; } diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index f518dc0c8a2c..06b0a12b7c22 100755 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -646,6 +646,12 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi) if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) return 0; + if (bdev_read_only(sbi->sb->s_bdev)) { + f2fs_msg(sbi->sb, KERN_INFO, "write access " + "unavailable, skipping orphan cleanup"); + return 0; + } + if (s_flags & MS_RDONLY) { f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs"); sbi->sb->s_flags &= ~MS_RDONLY; @@ -1593,6 +1599,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) unsigned long long ckpt_ver; int err = 0; + if (f2fs_readonly(sbi->sb) || bdev_read_only(sbi->sb->s_bdev)) + return -EROFS; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { if (cpc->reason != CP_PAUSE) return 0; @@ -1609,10 +1618,6 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) err = -EIO; goto out; } - if (f2fs_readonly(sbi->sb)) { - err = -EROFS; - goto out; - } trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 181c028ad96a..6ab83594b731 100755 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -424,6 +424,25 @@ static void __f2fs_submit_read_bio(struct f2fs_sb_info *sbi, __submit_bio(sbi, bio, type); } +/* + * P221011-01695 + * flush_group: Process group in which file's is very important. + * e.g., system_server, keystore, etc. + */ +static void __sec_attach_io_flag(struct f2fs_io_info *fio) +{ + struct f2fs_sb_info *sbi = fio->sbi; + + if (fio->type == DATA && !(fio->op_flags & REQ_FUA) && + in_group_p(F2FS_OPTION(sbi).flush_group)) { + struct inode *inode = fio->page->mapping->host; + + if (f2fs_is_atomic_file(inode) && f2fs_is_commit_atomic_write(inode)) + fio->op_flags |= REQ_FUA; + } + return; +} + static void __submit_merged_bio(struct f2fs_bio_info *io) { struct f2fs_io_info *fio = &io->fio; @@ -431,6 +450,8 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) if (!io->bio) return; + __sec_attach_io_flag(fio); + if (f2fs_bio_disk_encrypted(io->bio->bi_opf)) bio_set_op_attrs(io->bio, fio->op, fio->op_flags | REQ_CRYPT); else diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 127d0456042d..a69c6bb2f3e6 100755 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3593,10 +3593,17 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * mount should be failed, when device has readonly mode, and * previous checkpoint was not done by clean system shutdown. */ - if (bdev_read_only(sb->s_bdev) && - !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { - err = -EROFS; - goto free_meta; + if (bdev_read_only(sb->s_bdev)) { + if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { + err = -EROFS; + f2fs_msg(sb, KERN_ERR, + "Need to recover fsync data, but " + "write access unavailable"); + goto free_meta; + } + f2fs_msg(sbi->sb, KERN_INFO, "write access " + "unavailable, skipping recovery"); + goto reset_checkpoint; } if (need_fsck) diff --git a/security/samsung/kumiho/Kconfig b/security/samsung/kumiho/Kconfig new file mode 100644 index 000000000000..f21779018547 --- /dev/null +++ b/security/samsung/kumiho/Kconfig @@ -0,0 +1,7 @@ +config SECURITY_KUMIHO + bool "Kumiho Support" + depends on SECURITY + default n + help + This selects Kumiho support. + If you are unsure how to answer this question, answer N. \ No newline at end of file