Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: sram: Introduce support code for protect-exec sram type

Some platforms, like many ARM SoCs, require the ability to run code from
on-chip memory like SRAM for tasks like reconfiguring the SDRAM
controller or entering low-power sleep modes. In order to do this we
must be able to allocate memory that the code can be copied to but then
change the mapping to be read-only and executable so that no memory is
both writable and executable at the same time to avoid opening any
unneccesary security holes.

By using the existing "pool" partition type that the SRAM driver allows
we can create a memory space that will already be exposed by the
genalloc framework to allow for allocating memory but we must extend
this to meet the executable requirements. By making use of various
set_memory_* APIs we can change the attributes of pages to make them
writable for code upload but then read-only and executable when we want
to actually run code. Because SRAM is a shared resource we need a
centralized manager of these set memory calls. Because the SRAM driver
itself is responsible for allocating the memory we can introduce a
sram_copy_exec API for the driver that works like memcpy but also
manages the page attributes and locking to allow multiple users of the
same SRAM space to all copy their code over independent of other each
before starting execution.

It is maintained in a separate file from the core SRAM driver to allow
it to be selectively built depending on whether or not a platform has
the appropriate set_memory_* APIs. A future patch will integrate it with
the core SRAM driver.

Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dave Gerlach and committed by
Greg Kroah-Hartman
728bbe75 cdd1737c

+150
+105
drivers/misc/sram-exec.c
··· 1 + /* 2 + * SRAM protect-exec region helper functions 3 + * 4 + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ 5 + * Dave Gerlach 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12 + * kind, whether express or implied; without even the implied warranty 13 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #include <linux/device.h> 18 + #include <linux/genalloc.h> 19 + #include <linux/sram.h> 20 + 21 + #include <asm/cacheflush.h> 22 + 23 + #include "sram.h" 24 + 25 + static DEFINE_MUTEX(exec_pool_list_mutex); 26 + static LIST_HEAD(exec_pool_list); 27 + 28 + int sram_check_protect_exec(struct sram_dev *sram, struct sram_reserve *block, 29 + struct sram_partition *part) 30 + { 31 + unsigned long base = (unsigned long)part->base; 32 + unsigned long end = base + block->size; 33 + 34 + if (!PAGE_ALIGNED(base) || !PAGE_ALIGNED(end)) { 35 + dev_err(sram->dev, 36 + "SRAM pool marked with 'protect-exec' is not page aligned and will not be created.\n"); 37 + return -ENOMEM; 38 + } 39 + 40 + return 0; 41 + } 42 + 43 + int sram_add_protect_exec(struct sram_partition *part) 44 + { 45 + mutex_lock(&exec_pool_list_mutex); 46 + list_add_tail(&part->list, &exec_pool_list); 47 + mutex_unlock(&exec_pool_list_mutex); 48 + 49 + return 0; 50 + } 51 + 52 + /** 53 + * sram_exec_copy - copy data to a protected executable region of sram 54 + * 55 + * @pool: struct gen_pool retrieved that is part of this sram 56 + * @dst: Destination address for the copy, that must be inside pool 57 + * @src: Source address for the data to copy 58 + * @size: Size of copy to perform, which starting from dst, must reside in pool 59 + * 60 + * This helper function allows sram driver to act as central control location 61 + * of 'protect-exec' pools which are normal sram pools but are always set 62 + * read-only and executable except when copying data to them, at which point 63 + * they are set to read-write non-executable, to make sure no memory is 64 + * writeable and executable at the same time. This region must be page-aligned 65 + * and is checked during probe, otherwise page attribute manipulation would 66 + * not be possible. 67 + */ 68 + int sram_exec_copy(struct gen_pool *pool, void *dst, void *src, 69 + size_t size) 70 + { 71 + struct sram_partition *part = NULL, *p; 72 + unsigned long base; 73 + int pages; 74 + 75 + mutex_lock(&exec_pool_list_mutex); 76 + list_for_each_entry(p, &exec_pool_list, list) { 77 + if (p->pool == pool) 78 + part = p; 79 + } 80 + mutex_unlock(&exec_pool_list_mutex); 81 + 82 + if (!part) 83 + return -EINVAL; 84 + 85 + if (!addr_in_gen_pool(pool, (unsigned long)dst, size)) 86 + return -EINVAL; 87 + 88 + base = (unsigned long)part->base; 89 + pages = PAGE_ALIGN(size) / PAGE_SIZE; 90 + 91 + mutex_lock(&part->lock); 92 + 93 + set_memory_nx((unsigned long)base, pages); 94 + set_memory_rw((unsigned long)base, pages); 95 + 96 + memcpy(dst, src, size); 97 + 98 + set_memory_ro((unsigned long)base, pages); 99 + set_memory_x((unsigned long)base, pages); 100 + 101 + mutex_unlock(&part->lock); 102 + 103 + return 0; 104 + } 105 + EXPORT_SYMBOL_GPL(sram_exec_copy);
+18
drivers/misc/sram.h
··· 36 36 bool pool; 37 37 const char *label; 38 38 }; 39 + 40 + #ifdef CONFIG_SRAM_EXEC 41 + int sram_check_protect_exec(struct sram_dev *sram, struct sram_reserve *block, 42 + struct sram_partition *part); 43 + int sram_add_protect_exec(struct sram_partition *part); 44 + #else 45 + static inline int sram_check_protect_exec(struct sram_dev *sram, 46 + struct sram_reserve *block, 47 + struct sram_partition *part) 48 + { 49 + return -ENODEV; 50 + } 51 + 52 + static inline int sram_add_protect_exec(struct sram_partition *part) 53 + { 54 + return -ENODEV; 55 + } 56 + #endif /* CONFIG_SRAM_EXEC */ 39 57 #endif /* __SRAM_H */
+27
include/linux/sram.h
··· 1 + /* 2 + * Generic SRAM Driver Interface 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License as 6 + * published by the Free Software Foundation version 2. 7 + * 8 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any 9 + * kind, whether express or implied; without even the implied warranty 10 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + #ifndef __LINUX_SRAM_H__ 14 + #define __LINUX_SRAM_H__ 15 + 16 + struct gen_pool; 17 + 18 + #ifdef CONFIG_SRAM_EXEC 19 + int sram_exec_copy(struct gen_pool *pool, void *dst, void *src, size_t size); 20 + #else 21 + static inline int sram_exec_copy(struct gen_pool *pool, void *dst, void *src, 22 + size_t size) 23 + { 24 + return -ENODEV; 25 + } 26 + #endif /* CONFIG_SRAM_EXEC */ 27 + #endif /* __LINUX_SRAM_H__ */