[PATCH 3/6] Protectable Memory

2018-04-13 Thread Igor Stoppa
The MMU available in many systems running Linux can often provide R/O
protection to the memory pages it handles.

However, the MMU-based protection works efficiently only when said pages
contain exclusively data that will not need further modifications.

Statically allocated variables can be segregated into a dedicated
section (that's how __ro_after_init works), but this does not sit very
well with dynamically allocated ones.

Dynamic allocation does not provide, currently, any means for grouping
variables in memory pages that would contain exclusively data suitable
for conversion to read only access mode.

The allocator here provided (pmalloc - protectable memory allocator)
introduces the concept of pools of protectable memory.

A module can instantiate a pool, and then refer any allocation request to
the pool handler it has received.

A pool is organized ias list of areas of virtually contiguous memory.
Whenever the protection functionality is invoked on a pool, all the
areas it contains that are not yet read-only are write-protected.

The process of growing and protecting the pool can be iterated at will.
Each iteration will prevent further allocation from the memory area
currently active, turn it into read-only mode and then proceed to
secure whatever other area might still be unprotected.

Write-protcting some part of a pool before completing all the
allocations can be wasteful, however it will guarrantee the minimum
window of vulnerability, sice the data can be allocated, initialized
and protected in a single sweep.

There are pros and cons, depending on the allocation patterns, the size
of the areas being allocated, the time intervals between initialization
and protection.

Dstroying a pool is the only way to claim back the associated memory.
It is up to its user to avoid any further references to the memory that
was allocated, once the destruction is invoked.

An example where it is desirable to destroy a pool and claim back its
memory is when unloading a kernel module.

A module can have as many pools as needed.

Since pmalloc memory is obtained from vmalloc, an attacker that has
gained access to the physical mapping, still has to identify where the
target of the attack (in virtually contiguous mapping) is located.

Compared to plain vmalloc, pmalloc does not generate as much TLB
trashing, since it can host multiple allocations in the same page,
where present.

Signed-off-by: Igor Stoppa 
---
 include/linux/pmalloc.h | 166 ++
 include/linux/vmalloc.h |   3 +
 mm/Kconfig  |   6 ++
 mm/Makefile |   1 +
 mm/pmalloc.c| 265 
 mm/usercopy.c   |  33 ++
 mm/vmalloc.c|   2 +-
 7 files changed, 475 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pmalloc.h
 create mode 100644 mm/pmalloc.c

diff --git a/include/linux/pmalloc.h b/include/linux/pmalloc.h
new file mode 100644
index ..1c24067eb167
--- /dev/null
+++ b/include/linux/pmalloc.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * pmalloc.h: Header for Protectable Memory Allocator
+ *
+ * (C) Copyright 2017-18 Huawei Technologies Co. Ltd.
+ * Author: Igor Stoppa 
+ */
+
+#ifndef _LINUX_PMALLOC_H
+#define _LINUX_PMALLOC_H
+
+
+#include 
+#include 
+
+/*
+ * Library for dynamic allocation of pools of protectable memory.
+ * A pool is a single linked list of vmap_area structures.
+ * Whenever a pool is protected, all the areas it contain at that point
+ * are write protected.
+ * More areas can be added and protected, in the same way.
+ * Memory in a pool cannot be individually unprotected, but the pool can
+ * be destroyed.
+ * Upon destruction of a certain pool, all the related memory is released,
+ * including its metadata.
+ *
+ * Pmalloc memory is intended to complement __read_only_after_init.
+ * It can be used, for example, where there is a write-once variable, for
+ * which it is not possible to know the initialization value before init
+ * is completed (which is what __read_only_after_init requires).
+ *
+ * It can be useful also where the amount of data to protect is not known
+ * at compile time and the memory can only be allocated dynamically.
+ *
+ * Finally, it can be useful also when it is desirable to control
+ * dynamically (for example throguh the command line) if something ought
+ * to be protected or not, without having to rebuild the kernel (like in
+ * the build used for a linux distro).
+ */
+
+
+#define PMALLOC_REFILL_DEFAULT (0)
+#define PMALLOC_ALIGN_DEFAULT ARCH_KMALLOC_MINALIGN
+
+struct pmalloc_pool *pmalloc_create_custom_pool(size_t refill,
+   unsigned short align_order);
+
+/**
+ * pmalloc_create_pool() - create a protectable memory pool
+ *
+ * Shorthand for pmalloc_create_custom_pool() with default argument:
+ * * refill is set to PMALLOC_REFILL_DEFAULT
+ * 

[PATCH 3/6] Protectable Memory

2018-04-13 Thread Igor Stoppa
The MMU available in many systems running Linux can often provide R/O
protection to the memory pages it handles.

However, the MMU-based protection works efficiently only when said pages
contain exclusively data that will not need further modifications.

Statically allocated variables can be segregated into a dedicated
section (that's how __ro_after_init works), but this does not sit very
well with dynamically allocated ones.

Dynamic allocation does not provide, currently, any means for grouping
variables in memory pages that would contain exclusively data suitable
for conversion to read only access mode.

The allocator here provided (pmalloc - protectable memory allocator)
introduces the concept of pools of protectable memory.

A module can instantiate a pool, and then refer any allocation request to
the pool handler it has received.

A pool is organized ias list of areas of virtually contiguous memory.
Whenever the protection functionality is invoked on a pool, all the
areas it contains that are not yet read-only are write-protected.

The process of growing and protecting the pool can be iterated at will.
Each iteration will prevent further allocation from the memory area
currently active, turn it into read-only mode and then proceed to
secure whatever other area might still be unprotected.

Write-protcting some part of a pool before completing all the
allocations can be wasteful, however it will guarrantee the minimum
window of vulnerability, sice the data can be allocated, initialized
and protected in a single sweep.

There are pros and cons, depending on the allocation patterns, the size
of the areas being allocated, the time intervals between initialization
and protection.

Dstroying a pool is the only way to claim back the associated memory.
It is up to its user to avoid any further references to the memory that
was allocated, once the destruction is invoked.

An example where it is desirable to destroy a pool and claim back its
memory is when unloading a kernel module.

A module can have as many pools as needed.

Since pmalloc memory is obtained from vmalloc, an attacker that has
gained access to the physical mapping, still has to identify where the
target of the attack (in virtually contiguous mapping) is located.

Compared to plain vmalloc, pmalloc does not generate as much TLB
trashing, since it can host multiple allocations in the same page,
where present.

Signed-off-by: Igor Stoppa 
---
 include/linux/pmalloc.h | 166 ++
 include/linux/vmalloc.h |   3 +
 mm/Kconfig  |   6 ++
 mm/Makefile |   1 +
 mm/pmalloc.c| 265 
 mm/usercopy.c   |  33 ++
 mm/vmalloc.c|   2 +-
 7 files changed, 475 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pmalloc.h
 create mode 100644 mm/pmalloc.c

diff --git a/include/linux/pmalloc.h b/include/linux/pmalloc.h
new file mode 100644
index ..1c24067eb167
--- /dev/null
+++ b/include/linux/pmalloc.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * pmalloc.h: Header for Protectable Memory Allocator
+ *
+ * (C) Copyright 2017-18 Huawei Technologies Co. Ltd.
+ * Author: Igor Stoppa 
+ */
+
+#ifndef _LINUX_PMALLOC_H
+#define _LINUX_PMALLOC_H
+
+
+#include 
+#include 
+
+/*
+ * Library for dynamic allocation of pools of protectable memory.
+ * A pool is a single linked list of vmap_area structures.
+ * Whenever a pool is protected, all the areas it contain at that point
+ * are write protected.
+ * More areas can be added and protected, in the same way.
+ * Memory in a pool cannot be individually unprotected, but the pool can
+ * be destroyed.
+ * Upon destruction of a certain pool, all the related memory is released,
+ * including its metadata.
+ *
+ * Pmalloc memory is intended to complement __read_only_after_init.
+ * It can be used, for example, where there is a write-once variable, for
+ * which it is not possible to know the initialization value before init
+ * is completed (which is what __read_only_after_init requires).
+ *
+ * It can be useful also where the amount of data to protect is not known
+ * at compile time and the memory can only be allocated dynamically.
+ *
+ * Finally, it can be useful also when it is desirable to control
+ * dynamically (for example throguh the command line) if something ought
+ * to be protected or not, without having to rebuild the kernel (like in
+ * the build used for a linux distro).
+ */
+
+
+#define PMALLOC_REFILL_DEFAULT (0)
+#define PMALLOC_ALIGN_DEFAULT ARCH_KMALLOC_MINALIGN
+
+struct pmalloc_pool *pmalloc_create_custom_pool(size_t refill,
+   unsigned short align_order);
+
+/**
+ * pmalloc_create_pool() - create a protectable memory pool
+ *
+ * Shorthand for pmalloc_create_custom_pool() with default argument:
+ * * refill is set to PMALLOC_REFILL_DEFAULT
+ * * align_order is set to PMALLOC_ALIGN_DEFAULT
+ 

Re: [PATCH 3/6] Protectable Memory

2018-03-27 Thread kbuild test robot
Hi Igor,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v4.16-rc7 next-20180327]
[cannot apply to mmotm/master]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Igor-Stoppa/mm-security-ro-protection-for-dynamic-data/20180328-041541
config: i386-randconfig-x073-201812 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386 

All warnings (new ones prefixed by >>):

   In file included from include/asm-generic/bug.h:18:0,
from arch/x86/include/asm/bug.h:83,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/mm.h:9,
from mm/pmalloc.c:11:
   mm/pmalloc.c: In function 'grow':
   include/linux/kernel.h:809:16: warning: comparison of distinct pointer types 
lacks a cast
 (void) ( == );   \
   ^
   include/linux/kernel.h:818:2: note: in expansion of macro '__max'
 __max(typeof(x), typeof(y),   \
 ^
>> mm/pmalloc.c:155:17: note: in expansion of macro 'max'
 addr = vmalloc(max(size, pool->refill));
^~~

vim +/max +155 mm/pmalloc.c

  > 11  #include 
12  #include 
13  #include 
14  #include 
15  #include 
16  #include 
17  #include 
18  #include 
19  #include 
20  #include 
21  #include 
22  
23  #include 
24  
25  #define MAX_ALIGN_ORDER (ilog2(sizeof(void *)))
26  struct pmalloc_pool {
27  struct mutex mutex;
28  struct list_head pool_node;
29  struct llist_head vm_areas;
30  unsigned long refill;
31  unsigned long offset;
32  unsigned long align;
33  };
34  
35  static LIST_HEAD(pools_list);
36  static DEFINE_MUTEX(pools_mutex);
37  
38  static inline void tag_area(struct vmap_area *area)
39  {
40  area->vm->flags |= VM_PMALLOC;
41  }
42  
43  static inline void untag_area(struct vmap_area *area)
44  {
45  area->vm->flags &= ~VM_PMALLOC;
46  }
47  
48  static inline struct vmap_area *current_area(struct pmalloc_pool *pool)
49  {
50  return llist_entry(pool->vm_areas.first, struct vmap_area,
51 area_list);
52  }
53  
54  static inline bool is_area_protected(struct vmap_area *area)
55  {
56  return area->vm->flags & VM_PMALLOC_PROTECTED;
57  }
58  
59  static inline bool protect_area(struct vmap_area *area)
60  {
61  if (unlikely(is_area_protected(area)))
62  return false;
63  set_memory_ro(area->va_start, area->vm->nr_pages);
64  area->vm->flags |= VM_PMALLOC_PROTECTED;
65  return true;
66  }
67  
68  static inline void destroy_area(struct vmap_area *area)
69  {
70  WARN(!is_area_protected(area), "Destroying unprotected area.");
71  set_memory_rw(area->va_start, area->vm->nr_pages);
72  vfree((void *)area->va_start);
73  }
74  
75  static inline bool empty(struct pmalloc_pool *pool)
76  {
77  return unlikely(llist_empty(>vm_areas));
78  }
79  
80  static inline bool protected(struct pmalloc_pool *pool)
81  {
82  return is_area_protected(current_area(pool));
83  }
84  
85  static inline unsigned long get_align(struct pmalloc_pool *pool,
86short int align_order)
87  {
88  if (likely(align_order < 0))
89  return pool->align;
90  return 1UL << align_order;
91  }
92  
93  static inline bool exhausted(struct pmalloc_pool *pool, size_t size,
94   short int align_order)
95  {
96  unsigned long align = get_align(pool, align_order);
97  unsigned long space_before = round_down(pool->offset, align);
98  unsigned long space_after = pool->offset - space_before;
99  
   100  return unlikely(space_after < size && space_before < size);
   101  }
   102  
   103  static inline bool space_needed(struct pmalloc_pool *pool, size_t size,
   104  short int align_order)
   105  {
   106  return empty(pool) || protected(pool) ||
   107  exhausted(pool, size, align_order);
   108  }
   109  
   110  #define DEFAULT_REFILL_SIZE PAGE_SIZE
   111  /**
   112   * pmalloc_create_custom_pool() - create a new protectable memory pool
   113   * @refill: the minimum size to allocate when in need of more memory.
   114   *  It will be rounded up to a multiple of 

Re: [PATCH 3/6] Protectable Memory

2018-03-27 Thread kbuild test robot
Hi Igor,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v4.16-rc7 next-20180327]
[cannot apply to mmotm/master]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Igor-Stoppa/mm-security-ro-protection-for-dynamic-data/20180328-041541
config: i386-randconfig-x073-201812 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386 

All warnings (new ones prefixed by >>):

   In file included from include/asm-generic/bug.h:18:0,
from arch/x86/include/asm/bug.h:83,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/mm.h:9,
from mm/pmalloc.c:11:
   mm/pmalloc.c: In function 'grow':
   include/linux/kernel.h:809:16: warning: comparison of distinct pointer types 
lacks a cast
 (void) ( == );   \
   ^
   include/linux/kernel.h:818:2: note: in expansion of macro '__max'
 __max(typeof(x), typeof(y),   \
 ^
>> mm/pmalloc.c:155:17: note: in expansion of macro 'max'
 addr = vmalloc(max(size, pool->refill));
^~~

vim +/max +155 mm/pmalloc.c

  > 11  #include 
12  #include 
13  #include 
14  #include 
15  #include 
16  #include 
17  #include 
18  #include 
19  #include 
20  #include 
21  #include 
22  
23  #include 
24  
25  #define MAX_ALIGN_ORDER (ilog2(sizeof(void *)))
26  struct pmalloc_pool {
27  struct mutex mutex;
28  struct list_head pool_node;
29  struct llist_head vm_areas;
30  unsigned long refill;
31  unsigned long offset;
32  unsigned long align;
33  };
34  
35  static LIST_HEAD(pools_list);
36  static DEFINE_MUTEX(pools_mutex);
37  
38  static inline void tag_area(struct vmap_area *area)
39  {
40  area->vm->flags |= VM_PMALLOC;
41  }
42  
43  static inline void untag_area(struct vmap_area *area)
44  {
45  area->vm->flags &= ~VM_PMALLOC;
46  }
47  
48  static inline struct vmap_area *current_area(struct pmalloc_pool *pool)
49  {
50  return llist_entry(pool->vm_areas.first, struct vmap_area,
51 area_list);
52  }
53  
54  static inline bool is_area_protected(struct vmap_area *area)
55  {
56  return area->vm->flags & VM_PMALLOC_PROTECTED;
57  }
58  
59  static inline bool protect_area(struct vmap_area *area)
60  {
61  if (unlikely(is_area_protected(area)))
62  return false;
63  set_memory_ro(area->va_start, area->vm->nr_pages);
64  area->vm->flags |= VM_PMALLOC_PROTECTED;
65  return true;
66  }
67  
68  static inline void destroy_area(struct vmap_area *area)
69  {
70  WARN(!is_area_protected(area), "Destroying unprotected area.");
71  set_memory_rw(area->va_start, area->vm->nr_pages);
72  vfree((void *)area->va_start);
73  }
74  
75  static inline bool empty(struct pmalloc_pool *pool)
76  {
77  return unlikely(llist_empty(>vm_areas));
78  }
79  
80  static inline bool protected(struct pmalloc_pool *pool)
81  {
82  return is_area_protected(current_area(pool));
83  }
84  
85  static inline unsigned long get_align(struct pmalloc_pool *pool,
86short int align_order)
87  {
88  if (likely(align_order < 0))
89  return pool->align;
90  return 1UL << align_order;
91  }
92  
93  static inline bool exhausted(struct pmalloc_pool *pool, size_t size,
94   short int align_order)
95  {
96  unsigned long align = get_align(pool, align_order);
97  unsigned long space_before = round_down(pool->offset, align);
98  unsigned long space_after = pool->offset - space_before;
99  
   100  return unlikely(space_after < size && space_before < size);
   101  }
   102  
   103  static inline bool space_needed(struct pmalloc_pool *pool, size_t size,
   104  short int align_order)
   105  {
   106  return empty(pool) || protected(pool) ||
   107  exhausted(pool, size, align_order);
   108  }
   109  
   110  #define DEFAULT_REFILL_SIZE PAGE_SIZE
   111  /**
   112   * pmalloc_create_custom_pool() - create a new protectable memory pool
   113   * @refill: the minimum size to allocate when in need of more memory.
   114   *  It will be rounded up to a multiple of 

[PATCH 3/6] Protectable Memory

2018-03-27 Thread Igor Stoppa
The MMU available in many systems running Linux can often provide R/O
protection to the memory pages it handles.

However, the MMU-based protection works efficiently only when said pages
contain exclusively data that will not need further modifications.

Statically allocated variables can be segregated into a dedicated
section (that's how __ro_after_init works), but this does not sit very
well with dynamically allocated ones.

Dynamic allocation does not provide, currently, any means for grouping
variables in memory pages that would contain exclusively data suitable
for conversion to read only access mode.

The allocator here provided (pmalloc - protectable memory allocator)
introduces the concept of pools of protectable memory.

A module can instantiate a pool, and then refer any allocation request to
the pool handler it has received.

A pool is organized ias list of areas of virtually contiguous memory.
Whenever the protection functionality is invoked on a pool, all the
areas it contains that are not yet read-only are write-protected.

The process of growing and protecting the pool can be iterated at will.
Each iteration will prevent further allocation from the memory area
currently active, turn it into read-only mode and then proceed to
secure whatever other area might still be unprotected.

Write-protcting some part of a pool before completing all the
allocations can be wasteful, however it will guarrantee the minimum
window of vulnerability, sice the data can be allocated, initialized
and protected in a single sweep.

There are pros and cons, depending on the allocation patterns, the size
of the areas being allocated, the time intervals between initialization
and protection.

Dstroying a pool is the only way to claim back the associated memory.
It is up to its user to avoid any further references to the memory that
was allocated, once the destruction is invoked.

An example where it is desirable to destroy a pool and claim back its
memory is when unloading a kernel module.

A module can have as many pools as needed.

Since pmalloc memory is obtained from vmalloc, an attacker that has
gained access to the physical mapping, still has to identify where the
target of the attack (in virtually contiguous mapping) is located.

Compared to plain vmalloc, pmalloc does not generate as much TLB
trashing, since it can host multiple allocations in the same page,
where present.

Signed-off-by: Igor Stoppa 
---
 include/linux/pmalloc.h | 166 ++
 include/linux/vmalloc.h |   3 +
 mm/Kconfig  |   6 ++
 mm/Makefile |   1 +
 mm/pmalloc.c| 264 
 mm/usercopy.c   |  33 ++
 mm/vmalloc.c|   2 +-
 7 files changed, 474 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pmalloc.h
 create mode 100644 mm/pmalloc.c

diff --git a/include/linux/pmalloc.h b/include/linux/pmalloc.h
new file mode 100644
index ..07d7838f7877
--- /dev/null
+++ b/include/linux/pmalloc.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * pmalloc.h: Header for Protectable Memory Allocator
+ *
+ * (C) Copyright 2017-18 Huawei Technologies Co. Ltd.
+ * Author: Igor Stoppa 
+ */
+
+#ifndef _LINUX_PMALLOC_H
+#define _LINUX_PMALLOC_H
+
+
+#include 
+#include 
+
+/*
+ * Library for dynamic allocation of pools of protectable memory.
+ * A pool is a single linked list of vmap_area structures.
+ * Whenever a pool is protected, all the areas it contain at that point
+ * are write protected.
+ * More areas can be added and protected, in the same way.
+ * Memory in a pool cannot be individually unprotected, but the pool can
+ * be destroyed.
+ * Upon destruction of a certain pool, all the related memory is released,
+ * including its metadata.
+ *
+ * Pmalloc memory is intended to complement __read_only_after_init.
+ * It can be used, for example, where there is a write-once variable, for
+ * which it is not possible to know the initialization value before init
+ * is completed (which is what __read_only_after_init requires).
+ *
+ * It can be useful also where the amount of data to protect is not known
+ * at compile time and the memory can only be allocated dynamically.
+ *
+ * Finally, it can be useful also when it is desirable to control
+ * dynamically (for example throguh the command line) if something ought
+ * to be protected or not, without having to rebuild the kernel (like in
+ * the build used for a linux distro).
+ */
+
+
+#define PMALLOC_REFILL_DEFAULT (0)
+#define PMALLOC_ALIGN_DEFAULT ARCH_KMALLOC_MINALIGN
+
+struct pmalloc_pool *pmalloc_create_custom_pool(unsigned long int refill,
+   unsigned short align_order);
+
+/**
+ * pmalloc_create_pool() - create a protectable memory pool
+ *
+ * Shorthand for pmalloc_create_custom_pool() with default argument:
+ * * refill is set to 

[PATCH 3/6] Protectable Memory

2018-03-27 Thread Igor Stoppa
The MMU available in many systems running Linux can often provide R/O
protection to the memory pages it handles.

However, the MMU-based protection works efficiently only when said pages
contain exclusively data that will not need further modifications.

Statically allocated variables can be segregated into a dedicated
section (that's how __ro_after_init works), but this does not sit very
well with dynamically allocated ones.

Dynamic allocation does not provide, currently, any means for grouping
variables in memory pages that would contain exclusively data suitable
for conversion to read only access mode.

The allocator here provided (pmalloc - protectable memory allocator)
introduces the concept of pools of protectable memory.

A module can instantiate a pool, and then refer any allocation request to
the pool handler it has received.

A pool is organized ias list of areas of virtually contiguous memory.
Whenever the protection functionality is invoked on a pool, all the
areas it contains that are not yet read-only are write-protected.

The process of growing and protecting the pool can be iterated at will.
Each iteration will prevent further allocation from the memory area
currently active, turn it into read-only mode and then proceed to
secure whatever other area might still be unprotected.

Write-protcting some part of a pool before completing all the
allocations can be wasteful, however it will guarrantee the minimum
window of vulnerability, sice the data can be allocated, initialized
and protected in a single sweep.

There are pros and cons, depending on the allocation patterns, the size
of the areas being allocated, the time intervals between initialization
and protection.

Dstroying a pool is the only way to claim back the associated memory.
It is up to its user to avoid any further references to the memory that
was allocated, once the destruction is invoked.

An example where it is desirable to destroy a pool and claim back its
memory is when unloading a kernel module.

A module can have as many pools as needed.

Since pmalloc memory is obtained from vmalloc, an attacker that has
gained access to the physical mapping, still has to identify where the
target of the attack (in virtually contiguous mapping) is located.

Compared to plain vmalloc, pmalloc does not generate as much TLB
trashing, since it can host multiple allocations in the same page,
where present.

Signed-off-by: Igor Stoppa 
---
 include/linux/pmalloc.h | 166 ++
 include/linux/vmalloc.h |   3 +
 mm/Kconfig  |   6 ++
 mm/Makefile |   1 +
 mm/pmalloc.c| 264 
 mm/usercopy.c   |  33 ++
 mm/vmalloc.c|   2 +-
 7 files changed, 474 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pmalloc.h
 create mode 100644 mm/pmalloc.c

diff --git a/include/linux/pmalloc.h b/include/linux/pmalloc.h
new file mode 100644
index ..07d7838f7877
--- /dev/null
+++ b/include/linux/pmalloc.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * pmalloc.h: Header for Protectable Memory Allocator
+ *
+ * (C) Copyright 2017-18 Huawei Technologies Co. Ltd.
+ * Author: Igor Stoppa 
+ */
+
+#ifndef _LINUX_PMALLOC_H
+#define _LINUX_PMALLOC_H
+
+
+#include 
+#include 
+
+/*
+ * Library for dynamic allocation of pools of protectable memory.
+ * A pool is a single linked list of vmap_area structures.
+ * Whenever a pool is protected, all the areas it contain at that point
+ * are write protected.
+ * More areas can be added and protected, in the same way.
+ * Memory in a pool cannot be individually unprotected, but the pool can
+ * be destroyed.
+ * Upon destruction of a certain pool, all the related memory is released,
+ * including its metadata.
+ *
+ * Pmalloc memory is intended to complement __read_only_after_init.
+ * It can be used, for example, where there is a write-once variable, for
+ * which it is not possible to know the initialization value before init
+ * is completed (which is what __read_only_after_init requires).
+ *
+ * It can be useful also where the amount of data to protect is not known
+ * at compile time and the memory can only be allocated dynamically.
+ *
+ * Finally, it can be useful also when it is desirable to control
+ * dynamically (for example throguh the command line) if something ought
+ * to be protected or not, without having to rebuild the kernel (like in
+ * the build used for a linux distro).
+ */
+
+
+#define PMALLOC_REFILL_DEFAULT (0)
+#define PMALLOC_ALIGN_DEFAULT ARCH_KMALLOC_MINALIGN
+
+struct pmalloc_pool *pmalloc_create_custom_pool(unsigned long int refill,
+   unsigned short align_order);
+
+/**
+ * pmalloc_create_pool() - create a protectable memory pool
+ *
+ * Shorthand for pmalloc_create_custom_pool() with default argument:
+ * * refill is set to PMALLOC_REFILL_DEFAULT
+ * * align_order is set to 

Re: [PATCH 3/6] Protectable Memory

2018-03-27 Thread Igor Stoppa


On 27/03/18 05:31, Matthew Wilcox wrote:
> On Tue, Mar 27, 2018 at 04:55:21AM +0300, Igor Stoppa wrote:
>> +static inline void *pmalloc_array_align(struct pmalloc_pool *pool,
>> +size_t n, size_t size,
>> +short int align_order)
>> +{
> 
> You're missing:
> 
> if (size != 0 && n > SIZE_MAX / size)
> return NULL;


ACK

>> +return pmalloc_align(pool, n * size, align_order);
>> +}
> 
>> +static inline void *pcalloc_align(struct pmalloc_pool *pool, size_t n,
>> +  size_t size, short int align_order)
>> +{
>> +return pzalloc_align(pool, n * size, align_order);
>> +}
> 
> Ditto.

ok

>> +static inline void *pcalloc(struct pmalloc_pool *pool, size_t n,
>> +size_t size)
>> +{
>> +return pzalloc_align(pool, n * size, PMALLOC_ALIGN_DEFAULT);
>> +}
> 
> If you make this one:
> 
>   return pcalloc_align(pool, n, size, PMALLOC_ALIGN_DEFAULT)

ok

> then you don't need the check in this function.
> 
> Also, do we really need 'align' as a parameter to the allocator functions
> rather than to the pool?

I actually wrote it first without, but then I wondered how to deal if
one needs to allocate both small fry structures and then something
larger that is page aligned.

However it's just speculation, I do not have any real example.

> I'd just reuse ARCH_KMALLOC_MINALIGN from slab.h as the alignment, and
> then add the special alignment options when we have a real user for them.

ok

--
thanks, igor


Re: [PATCH 3/6] Protectable Memory

2018-03-27 Thread Igor Stoppa


On 27/03/18 05:31, Matthew Wilcox wrote:
> On Tue, Mar 27, 2018 at 04:55:21AM +0300, Igor Stoppa wrote:
>> +static inline void *pmalloc_array_align(struct pmalloc_pool *pool,
>> +size_t n, size_t size,
>> +short int align_order)
>> +{
> 
> You're missing:
> 
> if (size != 0 && n > SIZE_MAX / size)
> return NULL;


ACK

>> +return pmalloc_align(pool, n * size, align_order);
>> +}
> 
>> +static inline void *pcalloc_align(struct pmalloc_pool *pool, size_t n,
>> +  size_t size, short int align_order)
>> +{
>> +return pzalloc_align(pool, n * size, align_order);
>> +}
> 
> Ditto.

ok

>> +static inline void *pcalloc(struct pmalloc_pool *pool, size_t n,
>> +size_t size)
>> +{
>> +return pzalloc_align(pool, n * size, PMALLOC_ALIGN_DEFAULT);
>> +}
> 
> If you make this one:
> 
>   return pcalloc_align(pool, n, size, PMALLOC_ALIGN_DEFAULT)

ok

> then you don't need the check in this function.
> 
> Also, do we really need 'align' as a parameter to the allocator functions
> rather than to the pool?

I actually wrote it first without, but then I wondered how to deal if
one needs to allocate both small fry structures and then something
larger that is page aligned.

However it's just speculation, I do not have any real example.

> I'd just reuse ARCH_KMALLOC_MINALIGN from slab.h as the alignment, and
> then add the special alignment options when we have a real user for them.

ok

--
thanks, igor


Re: [PATCH 3/6] Protectable Memory

2018-03-26 Thread Matthew Wilcox
On Tue, Mar 27, 2018 at 04:55:21AM +0300, Igor Stoppa wrote:
> +static inline void *pmalloc_array_align(struct pmalloc_pool *pool,
> + size_t n, size_t size,
> + short int align_order)
> +{

You're missing:

if (size != 0 && n > SIZE_MAX / size)
return NULL;

> + return pmalloc_align(pool, n * size, align_order);
> +}

> +static inline void *pcalloc_align(struct pmalloc_pool *pool, size_t n,
> +   size_t size, short int align_order)
> +{
> + return pzalloc_align(pool, n * size, align_order);
> +}

Ditto.

> +static inline void *pcalloc(struct pmalloc_pool *pool, size_t n,
> + size_t size)
> +{
> + return pzalloc_align(pool, n * size, PMALLOC_ALIGN_DEFAULT);
> +}

If you make this one:

return pcalloc_align(pool, n, size, PMALLOC_ALIGN_DEFAULT)

then you don't need the check in this function.

Also, do we really need 'align' as a parameter to the allocator functions
rather than to the pool?

I'd just reuse ARCH_KMALLOC_MINALIGN from slab.h as the alignment, and
then add the special alignment options when we have a real user for them.



Re: [PATCH 3/6] Protectable Memory

2018-03-26 Thread Matthew Wilcox
On Tue, Mar 27, 2018 at 04:55:21AM +0300, Igor Stoppa wrote:
> +static inline void *pmalloc_array_align(struct pmalloc_pool *pool,
> + size_t n, size_t size,
> + short int align_order)
> +{

You're missing:

if (size != 0 && n > SIZE_MAX / size)
return NULL;

> + return pmalloc_align(pool, n * size, align_order);
> +}

> +static inline void *pcalloc_align(struct pmalloc_pool *pool, size_t n,
> +   size_t size, short int align_order)
> +{
> + return pzalloc_align(pool, n * size, align_order);
> +}

Ditto.

> +static inline void *pcalloc(struct pmalloc_pool *pool, size_t n,
> + size_t size)
> +{
> + return pzalloc_align(pool, n * size, PMALLOC_ALIGN_DEFAULT);
> +}

If you make this one:

return pcalloc_align(pool, n, size, PMALLOC_ALIGN_DEFAULT)

then you don't need the check in this function.

Also, do we really need 'align' as a parameter to the allocator functions
rather than to the pool?

I'd just reuse ARCH_KMALLOC_MINALIGN from slab.h as the alignment, and
then add the special alignment options when we have a real user for them.



[PATCH 3/6] Protectable Memory

2018-03-26 Thread Igor Stoppa
The MMU available in many systems running Linux can often provide R/O
protection to the memory pages it handles.

However, the MMU-based protection works efficiently only when said pages
contain exclusively data that will not need further modifications.

Statically allocated variables can be segregated into a dedicated
section, but this does not sit very well with dynamically allocated
ones.

Dynamic allocation does not provide, currently, any means for grouping
variables in memory pages that would contain exclusively data suitable
for conversion to read only access mode.

The allocator here provided (pmalloc - protectable memory allocator)
introduces the concept of pools of protectable memory.

A module can request a pool and then refer any allocation request to the
pool handler it has received.

A pool is organized in areas of virtually contiguous memory.
Whenever the protection functionality is invoked on a pool, all the
areas it contains are marked as read-only.

The process of growing and protecting the pool can be iterated at will.

The pool can only be destroyed (it is up to its user to avoid any further
references to the memory from the pool, after the destruction is invoked).

The latter case is mainly meant for releasing memory, when a module is
unloaded.

A module can have as many pools as needed, for example to support the
protection of data that is initialized in sufficiently distinct phases.

Since pmalloc memory is obtained from vmalloc, an attacker that has
gained access to the physical mapping, still has to identify where the
target of the attack is actually located.

At the same time, being also based on genalloc, pmalloc does not
generate as much trashing of the TLB as it would be caused by only using
directly vmalloc.

Signed-off-by: Igor Stoppa 
---
 include/linux/pmalloc.h | 281 ++
 include/linux/vmalloc.h |   3 +
 mm/Kconfig  |   6 +
 mm/Makefile |   1 +
 mm/pmalloc.c| 321 
 mm/usercopy.c   |  33 +
 mm/vmalloc.c|   2 +-
 7 files changed, 646 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pmalloc.h
 create mode 100644 mm/pmalloc.c

diff --git a/include/linux/pmalloc.h b/include/linux/pmalloc.h
new file mode 100644
index ..1d71fb73bb5b
--- /dev/null
+++ b/include/linux/pmalloc.h
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * pmalloc.h: Header for Protectable Memory Allocator
+ *
+ * (C) Copyright 2017-18 Huawei Technologies Co. Ltd.
+ * Author: Igor Stoppa 
+ */
+
+#ifndef _LINUX_PMALLOC_H
+#define _LINUX_PMALLOC_H
+
+
+#include 
+
+/*
+ * Library for dynamic allocation of pools of protectable memory.
+ * A pool is a single linked list of vmap_area structures.
+ * Whenever a pool is protected, all the areas it contain at that point
+ * are write protected.
+ * More areas can be added and protected, in the same way.
+ * Memory in a pool cannot be individually unprotected, but the pool can
+ * be destroyed.
+ * Upon destruction of a certain pool, all the related memory is released,
+ * including its metadata.
+ *
+ * Pmalloc memory is intended to complement __read_only_after_init.
+ * It can be used, for example, where there is a write-once variable, for
+ * which it is not possible to know the initialization value before init
+ * is completed (which is what __read_only_after_init requires).
+ *
+ * It can be useful also where the amount of data to protect is not known
+ * at compile time and the memory can only be allocated dynamically.
+ *
+ * Finally, it can be useful also when it is desirable to control
+ * dynamically (for example throguh the command line) if something ought
+ * to be protected or not, without having to rebuild the kernel (like in
+ * the build used for a linux distro).
+ */
+
+
+#define PMALLOC_REFILL_DEFAULT (0)
+#define PMALLOC_ALIGN_DEFAULT (-1)
+
+struct pmalloc_pool *pmalloc_create_custom_pool(unsigned long int refill,
+   short int align_order);
+
+/**
+ * pmalloc_create_pool() - create a protectable memory pool
+ *
+ * Shorthand for pmalloc_create_custom_pool() with default arguments:
+ * * refill is set to PMALLOC_REFILL_DEFAULT, which is one memory page
+ * * align_order is set to PMALLOC_ALIGN_DEFAULT, which is size_of(size_t)
+ *
+ * Return:
+ * * pointer to the new pool   - success
+ * * NULL  - error
+ */
+static inline struct pmalloc_pool *pmalloc_create_pool(void)
+{
+   return pmalloc_create_custom_pool(PMALLOC_REFILL_DEFAULT,
+ PMALLOC_ALIGN_DEFAULT);
+}
+
+
+//bool pmalloc_expand_pool(struct gen_pool *pool, size_t size);
+
+
+void *pmalloc_align(struct pmalloc_pool *pool, size_t size,
+   short int align_order);
+
+
+/**
+ * pmalloc() - allocates protectable memory from a pool
+ * 

[PATCH 3/6] Protectable Memory

2018-03-26 Thread Igor Stoppa
The MMU available in many systems running Linux can often provide R/O
protection to the memory pages it handles.

However, the MMU-based protection works efficiently only when said pages
contain exclusively data that will not need further modifications.

Statically allocated variables can be segregated into a dedicated
section, but this does not sit very well with dynamically allocated
ones.

Dynamic allocation does not provide, currently, any means for grouping
variables in memory pages that would contain exclusively data suitable
for conversion to read only access mode.

The allocator here provided (pmalloc - protectable memory allocator)
introduces the concept of pools of protectable memory.

A module can request a pool and then refer any allocation request to the
pool handler it has received.

A pool is organized in areas of virtually contiguous memory.
Whenever the protection functionality is invoked on a pool, all the
areas it contains are marked as read-only.

The process of growing and protecting the pool can be iterated at will.

The pool can only be destroyed (it is up to its user to avoid any further
references to the memory from the pool, after the destruction is invoked).

The latter case is mainly meant for releasing memory, when a module is
unloaded.

A module can have as many pools as needed, for example to support the
protection of data that is initialized in sufficiently distinct phases.

Since pmalloc memory is obtained from vmalloc, an attacker that has
gained access to the physical mapping, still has to identify where the
target of the attack is actually located.

At the same time, being also based on genalloc, pmalloc does not
generate as much trashing of the TLB as it would be caused by only using
directly vmalloc.

Signed-off-by: Igor Stoppa 
---
 include/linux/pmalloc.h | 281 ++
 include/linux/vmalloc.h |   3 +
 mm/Kconfig  |   6 +
 mm/Makefile |   1 +
 mm/pmalloc.c| 321 
 mm/usercopy.c   |  33 +
 mm/vmalloc.c|   2 +-
 7 files changed, 646 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pmalloc.h
 create mode 100644 mm/pmalloc.c

diff --git a/include/linux/pmalloc.h b/include/linux/pmalloc.h
new file mode 100644
index ..1d71fb73bb5b
--- /dev/null
+++ b/include/linux/pmalloc.h
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * pmalloc.h: Header for Protectable Memory Allocator
+ *
+ * (C) Copyright 2017-18 Huawei Technologies Co. Ltd.
+ * Author: Igor Stoppa 
+ */
+
+#ifndef _LINUX_PMALLOC_H
+#define _LINUX_PMALLOC_H
+
+
+#include 
+
+/*
+ * Library for dynamic allocation of pools of protectable memory.
+ * A pool is a single linked list of vmap_area structures.
+ * Whenever a pool is protected, all the areas it contain at that point
+ * are write protected.
+ * More areas can be added and protected, in the same way.
+ * Memory in a pool cannot be individually unprotected, but the pool can
+ * be destroyed.
+ * Upon destruction of a certain pool, all the related memory is released,
+ * including its metadata.
+ *
+ * Pmalloc memory is intended to complement __read_only_after_init.
+ * It can be used, for example, where there is a write-once variable, for
+ * which it is not possible to know the initialization value before init
+ * is completed (which is what __read_only_after_init requires).
+ *
+ * It can be useful also where the amount of data to protect is not known
+ * at compile time and the memory can only be allocated dynamically.
+ *
+ * Finally, it can be useful also when it is desirable to control
+ * dynamically (for example throguh the command line) if something ought
+ * to be protected or not, without having to rebuild the kernel (like in
+ * the build used for a linux distro).
+ */
+
+
+#define PMALLOC_REFILL_DEFAULT (0)
+#define PMALLOC_ALIGN_DEFAULT (-1)
+
+struct pmalloc_pool *pmalloc_create_custom_pool(unsigned long int refill,
+   short int align_order);
+
+/**
+ * pmalloc_create_pool() - create a protectable memory pool
+ *
+ * Shorthand for pmalloc_create_custom_pool() with default arguments:
+ * * refill is set to PMALLOC_REFILL_DEFAULT, which is one memory page
+ * * align_order is set to PMALLOC_ALIGN_DEFAULT, which is size_of(size_t)
+ *
+ * Return:
+ * * pointer to the new pool   - success
+ * * NULL  - error
+ */
+static inline struct pmalloc_pool *pmalloc_create_pool(void)
+{
+   return pmalloc_create_custom_pool(PMALLOC_REFILL_DEFAULT,
+ PMALLOC_ALIGN_DEFAULT);
+}
+
+
+//bool pmalloc_expand_pool(struct gen_pool *pool, size_t size);
+
+
+void *pmalloc_align(struct pmalloc_pool *pool, size_t size,
+   short int align_order);
+
+
+/**
+ * pmalloc() - allocates protectable memory from a pool
+ * @pool: handle to the pool to be used for memory