Re: [PATCH v2 8/9] kallsyms: Hide layout

2020-05-21 Thread Kees Cook
On Thu, May 21, 2020 at 09:56:39AM -0700, Kristen Carlson Accardi wrote:
> This patch makes /proc/kallsyms display alphabetically by symbol
> name rather than sorted by address in order to hide the newly
> randomized address layout.
> 
> Signed-off-by: Kristen Carlson Accardi 
> Reviewed-by: Tony Luck 
> Tested-by: Tony Luck 
> ---
>  kernel/kallsyms.c | 138 +-
>  1 file changed, 137 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
> index 16c8c605f4b0..558963b275ec 100644
> --- a/kernel/kallsyms.c
> +++ b/kernel/kallsyms.c
> @@ -25,6 +25,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  /*
>   * These will be re-linked against their real values
> @@ -446,6 +447,11 @@ struct kallsym_iter {
>   int show_value;
>  };
>  
> +struct kallsyms_iter_list {
> + struct kallsym_iter iter;
> + struct list_head next;
> +};
> +
>  int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
>   char *type, char *name)
>  {
> @@ -660,6 +666,121 @@ int kallsyms_show_value(void)
>   }
>  }
>  
> +static int sorted_show(struct seq_file *m, void *p)
> +{
> + struct list_head *list = m->private;
> + struct kallsyms_iter_list *iter;
> + int rc;
> +
> + if (list_empty(list))
> + return 0;
> +
> + iter = list_first_entry(list, struct kallsyms_iter_list, next);
> +
> + m->private = iter;
> + rc = s_show(m, p);
> + m->private = list;
> +
> + list_del(>next);
> + kfree(iter);
> +
> + return rc;
> +}
> +
> +static void *sorted_start(struct seq_file *m, loff_t *pos)
> +{
> + return m->private;
> +}
> +
> +static void *sorted_next(struct seq_file *m, void *p, loff_t *pos)
> +{
> + struct list_head *list = m->private;
> +
> + (*pos)++;
> +
> + if (list_empty(list))
> + return NULL;
> +
> + return p;
> +}
> +
> +static const struct seq_operations kallsyms_sorted_op = {
> + .start = sorted_start,
> + .next = sorted_next,
> + .stop = s_stop,
> + .show = sorted_show
> +};
> +
> +static int kallsyms_list_cmp(void *priv, struct list_head *a,
> +  struct list_head *b)
> +{
> + struct kallsyms_iter_list *iter_a, *iter_b;
> +
> + iter_a = list_entry(a, struct kallsyms_iter_list, next);
> + iter_b = list_entry(b, struct kallsyms_iter_list, next);
> +
> + return strcmp(iter_a->iter.name, iter_b->iter.name);
> +}
> +
> +int get_all_symbol_name(void *data, const char *name, struct module *mod,
> + unsigned long addr)
> +{
> + unsigned long sym_pos;
> + struct kallsyms_iter_list *node, *last;
> + struct list_head *head = (struct list_head *)data;
> +
> + node = kmalloc(sizeof(*node), GFP_KERNEL);
> + if (!node)
> + return -ENOMEM;
> +
> + if (list_empty(head)) {
> + sym_pos = 0;
> + memset(node, 0, sizeof(*node));
> + reset_iter(>iter, 0);
> + node->iter.show_value = kallsyms_show_value();
> + } else {
> + last = list_first_entry(head, struct kallsyms_iter_list, next);
> + memcpy(node, last, sizeof(*node));
> + sym_pos = last->iter.pos;
> + }
> +
> + INIT_LIST_HEAD(>next);
> + list_add(>next, head);
> +
> + /*
> +  * update_iter returns false when at end of file
> +  * which in this case we don't care about and can
> +  * safely ignore. update_iter() will increment
> +  * the value of iter->pos, for ksymbol_core.
> +  */
> + if (sym_pos >= kallsyms_num_syms)
> + sym_pos++;
> +
> + (void)update_iter(>iter, sym_pos);
> +
> + return 0;
> +}
> +
> +static int kallsyms_sorted_open(struct inode *inode, struct file *file)
> +{
> + int ret;
> + struct list_head *list;
> +
> + list = __seq_open_private(file, _sorted_op, sizeof(*list));
> + if (!list)
> + return -ENOMEM;
> +
> + INIT_LIST_HEAD(list);
> +
> + ret = kallsyms_on_each_symbol(get_all_symbol_name, list);
> + if (ret != 0)
> + return ret;
> +
> + list_sort(NULL, list, kallsyms_list_cmp);
> +
> + return 0;
> +}
> +
>  static int kallsyms_open(struct inode *inode, struct file *file)
>  {
>   /*
> @@ -704,9 +825,24 @@ static const struct proc_ops kallsyms_proc_ops = {
>   .proc_release   = seq_release_private,
>  };
>  
> +static const struct proc_ops kallsyms_sorted_proc_ops = {
> + .proc_open = kallsyms_sorted_open,
> + .proc_read = seq_read,
> + .proc_lseek = seq_lseek,
> + .proc_release = seq_release_private,
> +};
> +
>  static int __init kallsyms_init(void)
>  {
> - proc_create("kallsyms", 0444, NULL, _proc_ops);
> + /*
> +  * When fine grained kaslr is enabled, we need to
> +  * print out the symbols sorted by name rather than by
> +  * by address, because this reveals the randomization order.
> +  */
> + 

[PATCH v2 8/9] kallsyms: Hide layout

2020-05-21 Thread Kristen Carlson Accardi
This patch makes /proc/kallsyms display alphabetically by symbol
name rather than sorted by address in order to hide the newly
randomized address layout.

Signed-off-by: Kristen Carlson Accardi 
Reviewed-by: Tony Luck 
Tested-by: Tony Luck 
---
 kernel/kallsyms.c | 138 +-
 1 file changed, 137 insertions(+), 1 deletion(-)

diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 16c8c605f4b0..558963b275ec 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /*
  * These will be re-linked against their real values
@@ -446,6 +447,11 @@ struct kallsym_iter {
int show_value;
 };
 
+struct kallsyms_iter_list {
+   struct kallsym_iter iter;
+   struct list_head next;
+};
+
 int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
char *type, char *name)
 {
@@ -660,6 +666,121 @@ int kallsyms_show_value(void)
}
 }
 
+static int sorted_show(struct seq_file *m, void *p)
+{
+   struct list_head *list = m->private;
+   struct kallsyms_iter_list *iter;
+   int rc;
+
+   if (list_empty(list))
+   return 0;
+
+   iter = list_first_entry(list, struct kallsyms_iter_list, next);
+
+   m->private = iter;
+   rc = s_show(m, p);
+   m->private = list;
+
+   list_del(>next);
+   kfree(iter);
+
+   return rc;
+}
+
+static void *sorted_start(struct seq_file *m, loff_t *pos)
+{
+   return m->private;
+}
+
+static void *sorted_next(struct seq_file *m, void *p, loff_t *pos)
+{
+   struct list_head *list = m->private;
+
+   (*pos)++;
+
+   if (list_empty(list))
+   return NULL;
+
+   return p;
+}
+
+static const struct seq_operations kallsyms_sorted_op = {
+   .start = sorted_start,
+   .next = sorted_next,
+   .stop = s_stop,
+   .show = sorted_show
+};
+
+static int kallsyms_list_cmp(void *priv, struct list_head *a,
+struct list_head *b)
+{
+   struct kallsyms_iter_list *iter_a, *iter_b;
+
+   iter_a = list_entry(a, struct kallsyms_iter_list, next);
+   iter_b = list_entry(b, struct kallsyms_iter_list, next);
+
+   return strcmp(iter_a->iter.name, iter_b->iter.name);
+}
+
+int get_all_symbol_name(void *data, const char *name, struct module *mod,
+   unsigned long addr)
+{
+   unsigned long sym_pos;
+   struct kallsyms_iter_list *node, *last;
+   struct list_head *head = (struct list_head *)data;
+
+   node = kmalloc(sizeof(*node), GFP_KERNEL);
+   if (!node)
+   return -ENOMEM;
+
+   if (list_empty(head)) {
+   sym_pos = 0;
+   memset(node, 0, sizeof(*node));
+   reset_iter(>iter, 0);
+   node->iter.show_value = kallsyms_show_value();
+   } else {
+   last = list_first_entry(head, struct kallsyms_iter_list, next);
+   memcpy(node, last, sizeof(*node));
+   sym_pos = last->iter.pos;
+   }
+
+   INIT_LIST_HEAD(>next);
+   list_add(>next, head);
+
+   /*
+* update_iter returns false when at end of file
+* which in this case we don't care about and can
+* safely ignore. update_iter() will increment
+* the value of iter->pos, for ksymbol_core.
+*/
+   if (sym_pos >= kallsyms_num_syms)
+   sym_pos++;
+
+   (void)update_iter(>iter, sym_pos);
+
+   return 0;
+}
+
+static int kallsyms_sorted_open(struct inode *inode, struct file *file)
+{
+   int ret;
+   struct list_head *list;
+
+   list = __seq_open_private(file, _sorted_op, sizeof(*list));
+   if (!list)
+   return -ENOMEM;
+
+   INIT_LIST_HEAD(list);
+
+   ret = kallsyms_on_each_symbol(get_all_symbol_name, list);
+   if (ret != 0)
+   return ret;
+
+   list_sort(NULL, list, kallsyms_list_cmp);
+
+   return 0;
+}
+
 static int kallsyms_open(struct inode *inode, struct file *file)
 {
/*
@@ -704,9 +825,24 @@ static const struct proc_ops kallsyms_proc_ops = {
.proc_release   = seq_release_private,
 };
 
+static const struct proc_ops kallsyms_sorted_proc_ops = {
+   .proc_open = kallsyms_sorted_open,
+   .proc_read = seq_read,
+   .proc_lseek = seq_lseek,
+   .proc_release = seq_release_private,
+};
+
 static int __init kallsyms_init(void)
 {
-   proc_create("kallsyms", 0444, NULL, _proc_ops);
+   /*
+* When fine grained kaslr is enabled, we need to
+* print out the symbols sorted by name rather than by
+* by address, because this reveals the randomization order.
+*/
+   if (!IS_ENABLED(CONFIG_FG_KASLR))
+   proc_create("kallsyms", 0444, NULL, _proc_ops);
+   else
+   proc_create("kallsyms", 0444, NULL, _sorted_proc_ops);
return 0;
 }
 device_initcall(kallsyms_init);
-- 
2.20.1