cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

alignment.c (4744B)


      1/*
      2 * Alignment access counters and corresponding user-space interfaces.
      3 *
      4 * Copyright (C) 2009 ST Microelectronics
      5 * Copyright (C) 2009 - 2010 Paul Mundt
      6 *
      7 * This file is subject to the terms and conditions of the GNU General Public
      8 * License.  See the file "COPYING" in the main directory of this archive
      9 * for more details.
     10 */
     11#include <linux/module.h>
     12#include <linux/kernel.h>
     13#include <linux/seq_file.h>
     14#include <linux/proc_fs.h>
     15#include <linux/uaccess.h>
     16#include <linux/ratelimit.h>
     17#include <asm/alignment.h>
     18#include <asm/processor.h>
     19
     20static unsigned long se_user;
     21static unsigned long se_sys;
     22static unsigned long se_half;
     23static unsigned long se_word;
     24static unsigned long se_dword;
     25static unsigned long se_multi;
     26/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
     27   valid! */
     28static int se_usermode = UM_WARN | UM_FIXUP;
     29/* 0: no warning 1: print a warning message, disabled by default */
     30static int se_kernmode_warn;
     31
     32core_param(alignment, se_usermode, int, 0600);
     33
     34void inc_unaligned_byte_access(void)
     35{
     36	se_half++;
     37}
     38
     39void inc_unaligned_word_access(void)
     40{
     41	se_word++;
     42}
     43
     44void inc_unaligned_dword_access(void)
     45{
     46	se_dword++;
     47}
     48
     49void inc_unaligned_multi_access(void)
     50{
     51	se_multi++;
     52}
     53
     54void inc_unaligned_user_access(void)
     55{
     56	se_user++;
     57}
     58
     59void inc_unaligned_kernel_access(void)
     60{
     61	se_sys++;
     62}
     63
     64/*
     65 * This defaults to the global policy which can be set from the command
     66 * line, while processes can overload their preferences via prctl().
     67 */
     68unsigned int unaligned_user_action(void)
     69{
     70	unsigned int action = se_usermode;
     71
     72	if (current->thread.flags & SH_THREAD_UAC_SIGBUS) {
     73		action &= ~UM_FIXUP;
     74		action |= UM_SIGNAL;
     75	}
     76
     77	if (current->thread.flags & SH_THREAD_UAC_NOPRINT)
     78		action &= ~UM_WARN;
     79
     80	return action;
     81}
     82
     83int get_unalign_ctl(struct task_struct *tsk, unsigned long addr)
     84{
     85	return put_user(tsk->thread.flags & SH_THREAD_UAC_MASK,
     86			(unsigned int __user *)addr);
     87}
     88
     89int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
     90{
     91	tsk->thread.flags = (tsk->thread.flags & ~SH_THREAD_UAC_MASK) |
     92			    (val & SH_THREAD_UAC_MASK);
     93	return 0;
     94}
     95
     96void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,
     97			     struct pt_regs *regs)
     98{
     99	if (user_mode(regs) && (se_usermode & UM_WARN))
    100		pr_notice_ratelimited("Fixing up unaligned userspace access "
    101			  "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
    102			  tsk->comm, task_pid_nr(tsk),
    103			  (void *)instruction_pointer(regs), insn);
    104	else if (se_kernmode_warn)
    105		pr_notice_ratelimited("Fixing up unaligned kernel access "
    106			  "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
    107			  tsk->comm, task_pid_nr(tsk),
    108			  (void *)instruction_pointer(regs), insn);
    109}
    110
    111static const char *se_usermode_action[] = {
    112	"ignored",
    113	"warn",
    114	"fixup",
    115	"fixup+warn",
    116	"signal",
    117	"signal+warn"
    118};
    119
    120static int alignment_proc_show(struct seq_file *m, void *v)
    121{
    122	seq_printf(m, "User:\t\t%lu\n", se_user);
    123	seq_printf(m, "System:\t\t%lu\n", se_sys);
    124	seq_printf(m, "Half:\t\t%lu\n", se_half);
    125	seq_printf(m, "Word:\t\t%lu\n", se_word);
    126	seq_printf(m, "DWord:\t\t%lu\n", se_dword);
    127	seq_printf(m, "Multi:\t\t%lu\n", se_multi);
    128	seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
    129			se_usermode_action[se_usermode]);
    130	seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
    131			se_kernmode_warn ? "+warn" : "");
    132	return 0;
    133}
    134
    135static int alignment_proc_open(struct inode *inode, struct file *file)
    136{
    137	return single_open(file, alignment_proc_show, NULL);
    138}
    139
    140static ssize_t alignment_proc_write(struct file *file,
    141		const char __user *buffer, size_t count, loff_t *pos)
    142{
    143	int *data = pde_data(file_inode(file));
    144	char mode;
    145
    146	if (count > 0) {
    147		if (get_user(mode, buffer))
    148			return -EFAULT;
    149		if (mode >= '0' && mode <= '5')
    150			*data = mode - '0';
    151	}
    152	return count;
    153}
    154
    155static const struct proc_ops alignment_proc_ops = {
    156	.proc_open	= alignment_proc_open,
    157	.proc_read	= seq_read,
    158	.proc_lseek	= seq_lseek,
    159	.proc_release	= single_release,
    160	.proc_write	= alignment_proc_write,
    161};
    162
    163/*
    164 * This needs to be done after sysctl_init_bases(), otherwise sys/ will be
    165 * overwritten.  Actually, this shouldn't be in sys/ at all since
    166 * it isn't a sysctl, and it doesn't contain sysctl information.
    167 * We now locate it in /proc/cpu/alignment instead.
    168 */
    169static int __init alignment_init(void)
    170{
    171	struct proc_dir_entry *dir, *res;
    172
    173	dir = proc_mkdir("cpu", NULL);
    174	if (!dir)
    175		return -ENOMEM;
    176
    177	res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
    178			       &alignment_proc_ops, &se_usermode);
    179	if (!res)
    180		return -ENOMEM;
    181
    182        res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
    183			       &alignment_proc_ops, &se_kernmode_warn);
    184        if (!res)
    185                return -ENOMEM;
    186
    187	return 0;
    188}
    189fs_initcall(alignment_init);