Merge "Merge 5.15.88 into android14-5.15" into android14-5.15

This commit is contained in:
Treehugger Robot
2023-01-18 14:33:30 +00:00
20 changed files with 273 additions and 57 deletions

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
VERSION = 5 VERSION = 5
PATCHLEVEL = 15 PATCHLEVEL = 15
SUBLEVEL = 87 SUBLEVEL = 88
EXTRAVERSION = EXTRAVERSION =
NAME = Trick or Treat NAME = Trick or Treat

View File

@@ -49,31 +49,30 @@
#define MADV_DONTFORK 10 /* don't inherit across fork */ #define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */ #define MADV_DOFORK 11 /* do inherit across fork */
#define MADV_MERGEABLE 12 /* KSM may merge identical pages */
#define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages */
#define MADV_HUGEPAGE 14 /* Worth backing with hugepages */
#define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */
#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump,
overrides the coredump filter bits */
#define MADV_DODUMP 17 /* Clear the MADV_NODUMP flag */
#define MADV_WIPEONFORK 18 /* Zero memory on fork, child only */
#define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK */
#define MADV_COLD 20 /* deactivate these pages */ #define MADV_COLD 20 /* deactivate these pages */
#define MADV_PAGEOUT 21 /* reclaim these pages */ #define MADV_PAGEOUT 21 /* reclaim these pages */
#define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ #define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */
#define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ #define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */
#define MADV_MERGEABLE 65 /* KSM may merge identical pages */
#define MADV_UNMERGEABLE 66 /* KSM may not merge identical pages */
#define MADV_HUGEPAGE 67 /* Worth backing with hugepages */
#define MADV_NOHUGEPAGE 68 /* Not worth backing with hugepages */
#define MADV_DONTDUMP 69 /* Explicity exclude from the core dump,
overrides the coredump filter bits */
#define MADV_DODUMP 70 /* Clear the MADV_NODUMP flag */
#define MADV_WIPEONFORK 71 /* Zero memory on fork, child only */
#define MADV_KEEPONFORK 72 /* Undo MADV_WIPEONFORK */
#define MADV_HWPOISON 100 /* poison a page for testing */ #define MADV_HWPOISON 100 /* poison a page for testing */
#define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ #define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */
/* compatibility flags */ /* compatibility flags */
#define MAP_FILE 0 #define MAP_FILE 0
#define MAP_VARIABLE 0
#define PKEY_DISABLE_ACCESS 0x1 #define PKEY_DISABLE_ACCESS 0x1
#define PKEY_DISABLE_WRITE 0x2 #define PKEY_DISABLE_WRITE 0x2

View File

@@ -463,3 +463,30 @@ asmlinkage long parisc_inotify_init1(int flags)
flags = FIX_O_NONBLOCK(flags); flags = FIX_O_NONBLOCK(flags);
return sys_inotify_init1(flags); return sys_inotify_init1(flags);
} }
/*
* madvise() wrapper
*
* Up to kernel v6.1 parisc has different values than all other
* platforms for the MADV_xxx flags listed below.
* To keep binary compatibility with existing userspace programs
* translate the former values to the new values.
*
* XXX: Remove this wrapper in year 2025 (or later)
*/
asmlinkage notrace long parisc_madvise(unsigned long start, size_t len_in, int behavior)
{
switch (behavior) {
case 65: behavior = MADV_MERGEABLE; break;
case 66: behavior = MADV_UNMERGEABLE; break;
case 67: behavior = MADV_HUGEPAGE; break;
case 68: behavior = MADV_NOHUGEPAGE; break;
case 69: behavior = MADV_DONTDUMP; break;
case 70: behavior = MADV_DODUMP; break;
case 71: behavior = MADV_WIPEONFORK; break;
case 72: behavior = MADV_KEEPONFORK; break;
}
return sys_madvise(start, len_in, behavior);
}

View File

@@ -131,7 +131,7 @@
116 common sysinfo sys_sysinfo compat_sys_sysinfo 116 common sysinfo sys_sysinfo compat_sys_sysinfo
117 common shutdown sys_shutdown 117 common shutdown sys_shutdown
118 common fsync sys_fsync 118 common fsync sys_fsync
119 common madvise sys_madvise 119 common madvise parisc_madvise
120 common clone sys_clone_wrapper 120 common clone sys_clone_wrapper
121 common setdomainname sys_setdomainname 121 common setdomainname sys_setdomainname
122 common sendfile sys_sendfile compat_sys_sendfile 122 common sendfile sys_sendfile compat_sys_sendfile

View File

@@ -136,8 +136,8 @@ extern void __init update_regset_xstate_info(unsigned int size,
void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr);
int xfeature_size(int xfeature_nr); int xfeature_size(int xfeature_nr);
int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf); int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf, u32 *pkru);
int copy_sigframe_from_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf); int copy_sigframe_from_user_to_xstate(struct task_struct *tsk, const void __user *ubuf);
void xsaves(struct xregs_state *xsave, u64 mask); void xsaves(struct xregs_state *xsave, u64 mask);
void xrstors(struct xregs_state *xsave, u64 mask); void xrstors(struct xregs_state *xsave, u64 mask);

View File

@@ -163,7 +163,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
} }
fpu_force_restore(fpu); fpu_force_restore(fpu);
ret = copy_uabi_from_kernel_to_xstate(&fpu->state.xsave, kbuf ?: tmpbuf); ret = copy_uabi_from_kernel_to_xstate(&fpu->state.xsave, kbuf ?: tmpbuf, &target->thread.pkru);
out: out:
vfree(tmpbuf); vfree(tmpbuf);

View File

@@ -370,7 +370,7 @@ static int __fpu_restore_sig(void __user *buf, void __user *buf_fx,
fpregs_unlock(); fpregs_unlock();
if (use_xsave() && !fx_only) { if (use_xsave() && !fx_only) {
ret = copy_sigframe_from_user_to_xstate(&fpu->state.xsave, buf_fx); ret = copy_sigframe_from_user_to_xstate(tsk, buf_fx);
if (ret) if (ret)
return ret; return ret;
} else { } else {

View File

@@ -1091,8 +1091,31 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
} }
/**
* copy_uabi_to_xstate - Copy a UABI format buffer to the kernel xstate
* @fpstate: The fpstate buffer to copy to
* @kbuf: The UABI format buffer, if it comes from the kernel
* @ubuf: The UABI format buffer, if it comes from userspace
* @pkru: The location to write the PKRU value to
*
* Converts from the UABI format into the kernel internal hardware
* dependent format.
*
* This function ultimately has two different callers with distinct PKRU
* behavior.
* 1. When called from sigreturn the PKRU register will be restored from
* @fpstate via an XRSTOR. Correctly copying the UABI format buffer to
* @fpstate is sufficient to cover this case, but the caller will also
* pass a pointer to the thread_struct's pkru field in @pkru and updating
* it is harmless.
* 2. When called from ptrace the PKRU register will be restored from the
* thread_struct's pkru field. A pointer to that is passed in @pkru.
* The kernel will restore it manually, so the XRSTOR behavior that resets
* the PKRU register to the hardware init value (0) if the corresponding
* xfeatures bit is not set is emulated here.
*/
static int copy_uabi_to_xstate(struct xregs_state *xsave, const void *kbuf, static int copy_uabi_to_xstate(struct xregs_state *xsave, const void *kbuf,
const void __user *ubuf) const void __user *ubuf, u32 *pkru)
{ {
unsigned int offset, size; unsigned int offset, size;
struct xstate_header hdr; struct xstate_header hdr;
@@ -1140,6 +1163,14 @@ static int copy_uabi_to_xstate(struct xregs_state *xsave, const void *kbuf,
} }
} }
if (hdr.xfeatures & XFEATURE_MASK_PKRU) {
struct pkru_state *xpkru;
xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU);
*pkru = xpkru->pkru;
} else
*pkru = 0;
/* /*
* The state that came in from userspace was user-state only. * The state that came in from userspace was user-state only.
* Mask all the user states out of 'xfeatures': * Mask all the user states out of 'xfeatures':
@@ -1159,9 +1190,9 @@ static int copy_uabi_to_xstate(struct xregs_state *xsave, const void *kbuf,
* format and copy to the target thread. This is called from * format and copy to the target thread. This is called from
* xstateregs_set(). * xstateregs_set().
*/ */
int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf) int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf, u32 *pkru)
{ {
return copy_uabi_to_xstate(xsave, kbuf, NULL); return copy_uabi_to_xstate(xsave, kbuf, NULL, pkru);
} }
/* /*
@@ -1169,10 +1200,10 @@ int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf)
* XSAVE[S] format and copy to the target thread. This is called from the * XSAVE[S] format and copy to the target thread. This is called from the
* sigreturn() and rt_sigreturn() system calls. * sigreturn() and rt_sigreturn() system calls.
*/ */
int copy_sigframe_from_user_to_xstate(struct xregs_state *xsave, int copy_sigframe_from_user_to_xstate(struct task_struct *tsk,
const void __user *ubuf) const void __user *ubuf)
{ {
return copy_uabi_to_xstate(xsave, NULL, ubuf); return copy_uabi_to_xstate(&tsk->thread.fpu.state.xsave, NULL, ubuf, &tsk->thread.pkru);
} }
static bool validate_xsaves_xrstors(u64 mask) static bool validate_xsaves_xrstors(u64 mask)

View File

@@ -2784,9 +2784,9 @@ static int lpuart_probe(struct platform_device *pdev)
return 0; return 0;
failed_irq_request: failed_irq_request:
failed_get_rs485:
uart_remove_one_port(&lpuart_reg, &sport->port); uart_remove_one_port(&lpuart_reg, &sport->port);
failed_attach_port: failed_attach_port:
failed_get_rs485:
failed_reset: failed_reset:
lpuart_disable_clks(sport); lpuart_disable_clks(sport);
return ret; return ret;

View File

@@ -2225,6 +2225,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
spin_lock_irq(&uport->lock); spin_lock_irq(&uport->lock);
ops->stop_tx(uport); ops->stop_tx(uport);
if (!(uport->rs485.flags & SER_RS485_ENABLED))
ops->set_mctrl(uport, 0); ops->set_mctrl(uport, 0);
ops->stop_rx(uport); ops->stop_rx(uport);
spin_unlock_irq(&uport->lock); spin_unlock_irq(&uport->lock);

View File

@@ -1040,11 +1040,25 @@ void inet_csk_prepare_forced_close(struct sock *sk)
} }
EXPORT_SYMBOL(inet_csk_prepare_forced_close); EXPORT_SYMBOL(inet_csk_prepare_forced_close);
static int inet_ulp_can_listen(const struct sock *sk)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
if (icsk->icsk_ulp_ops && !icsk->icsk_ulp_ops->clone)
return -EINVAL;
return 0;
}
int inet_csk_listen_start(struct sock *sk, int backlog) int inet_csk_listen_start(struct sock *sk, int backlog)
{ {
struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
int err = -EADDRINUSE; int err;
err = inet_ulp_can_listen(sk);
if (unlikely(err))
return err;
reqsk_queue_alloc(&icsk->icsk_accept_queue); reqsk_queue_alloc(&icsk->icsk_accept_queue);

View File

@@ -136,6 +136,10 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
if (icsk->icsk_ulp_ops) if (icsk->icsk_ulp_ops)
goto out_err; goto out_err;
err = -EINVAL;
if (!ulp_ops->clone && sk->sk_state == TCP_LISTEN)
goto out_err;
err = ulp_ops->init(sk); err = ulp_ops->init(sk);
if (err) if (err)
goto out_err; goto out_err;

View File

@@ -1114,6 +1114,11 @@ skip:
return -ENOENT; return -ENOENT;
} }
if (new && new->ops == &noqueue_qdisc_ops) {
NL_SET_ERR_MSG(extack, "Cannot assign noqueue to a class");
return -EINVAL;
}
err = cops->graft(parent, cl, new, &old, extack); err = cops->graft(parent, cl, new, &old, extack);
if (err) if (err)
return err; return err;

View File

@@ -1178,14 +1178,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
const u32 pattern = 0xdeadbeef; const u32 pattern = 0xdeadbeef;
int ret; int ret;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id); kctl = snd_ctl_find_id(card, &control->id);
if (kctl == NULL) if (kctl == NULL) {
return -ENOENT; ret = -ENOENT;
goto unlock;
}
index_offset = snd_ctl_get_ioff(kctl, &control->id); index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset]; vd = &kctl->vd[index_offset];
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
return -EPERM; ret = -EPERM;
goto unlock;
}
snd_ctl_build_ioff(&control->id, kctl, index_offset); snd_ctl_build_ioff(&control->id, kctl, index_offset);
@@ -1195,7 +1200,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
info.id = control->id; info.id = control->id;
ret = __snd_ctl_elem_info(card, kctl, &info, NULL); ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
if (ret < 0) if (ret < 0)
return ret; goto unlock;
#endif #endif
if (!snd_ctl_skip_validation(&info)) if (!snd_ctl_skip_validation(&info))
@@ -1205,7 +1210,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
ret = kctl->get(kctl, control); ret = kctl->get(kctl, control);
snd_power_unref(card); snd_power_unref(card);
if (ret < 0) if (ret < 0)
return ret; goto unlock;
if (!snd_ctl_skip_validation(&info) && if (!snd_ctl_skip_validation(&info) &&
sanity_check_elem_value(card, control, &info, pattern) < 0) { sanity_check_elem_value(card, control, &info, pattern) < 0) {
dev_err(card->dev, dev_err(card->dev,
@@ -1213,8 +1218,11 @@ static int snd_ctl_elem_read(struct snd_card *card,
control->id.iface, control->id.device, control->id.iface, control->id.device,
control->id.subdevice, control->id.name, control->id.subdevice, control->id.name,
control->id.index); control->id.index);
return -EINVAL; ret = -EINVAL;
goto unlock;
} }
unlock:
up_read(&card->controls_rwsem);
return ret; return ret;
} }
@@ -1228,9 +1236,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
if (IS_ERR(control)) if (IS_ERR(control))
return PTR_ERR(control); return PTR_ERR(control);
down_read(&card->controls_rwsem);
result = snd_ctl_elem_read(card, control); result = snd_ctl_elem_read(card, control);
up_read(&card->controls_rwsem);
if (result < 0) if (result < 0)
goto error; goto error;

View File

@@ -1963,6 +1963,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1), SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1), SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1), SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1), SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
{} {}

View File

@@ -8909,6 +8909,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),

View File

@@ -1,20 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H #ifndef TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H
#define TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H #define TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H
#define MADV_DODUMP 70 #define MADV_DODUMP 17
#define MADV_DOFORK 11 #define MADV_DOFORK 11
#define MADV_DONTDUMP 69 #define MADV_DONTDUMP 16
#define MADV_DONTFORK 10 #define MADV_DONTFORK 10
#define MADV_DONTNEED 4 #define MADV_DONTNEED 4
#define MADV_FREE 8 #define MADV_FREE 8
#define MADV_HUGEPAGE 67 #define MADV_HUGEPAGE 14
#define MADV_MERGEABLE 65 #define MADV_MERGEABLE 12
#define MADV_NOHUGEPAGE 68 #define MADV_NOHUGEPAGE 15
#define MADV_NORMAL 0 #define MADV_NORMAL 0
#define MADV_RANDOM 1 #define MADV_RANDOM 1
#define MADV_REMOVE 9 #define MADV_REMOVE 9
#define MADV_SEQUENTIAL 2 #define MADV_SEQUENTIAL 2
#define MADV_UNMERGEABLE 66 #define MADV_UNMERGEABLE 13
#define MADV_WILLNEED 3 #define MADV_WILLNEED 3
#define MAP_ANONYMOUS 0x10 #define MAP_ANONYMOUS 0x10
#define MAP_DENYWRITE 0x0800 #define MAP_DENYWRITE 0x0800

View File

@@ -10,25 +10,13 @@ extern struct timeval bench__start, bench__end, bench__runtime;
* The madvise transparent hugepage constants were added in glibc * The madvise transparent hugepage constants were added in glibc
* 2.13. For compatibility with older versions of glibc, define these * 2.13. For compatibility with older versions of glibc, define these
* tokens if they are not already defined. * tokens if they are not already defined.
*
* PA-RISC uses different madvise values from other architectures and
* needs to be special-cased.
*/ */
#ifdef __hppa__
# ifndef MADV_HUGEPAGE
# define MADV_HUGEPAGE 67
# endif
# ifndef MADV_NOHUGEPAGE
# define MADV_NOHUGEPAGE 68
# endif
#else
# ifndef MADV_HUGEPAGE # ifndef MADV_HUGEPAGE
# define MADV_HUGEPAGE 14 # define MADV_HUGEPAGE 14
# endif # endif
# ifndef MADV_NOHUGEPAGE # ifndef MADV_NOHUGEPAGE
# define MADV_NOHUGEPAGE 15 # define MADV_NOHUGEPAGE 15
# endif # endif
#endif
int bench_numa(int argc, const char **argv); int bench_numa(int argc, const char **argv);
int bench_sched_messaging(int argc, const char **argv); int bench_sched_messaging(int argc, const char **argv);

View File

@@ -119,6 +119,18 @@ static inline int cpu_has_pkeys(void)
return 1; return 1;
} }
static inline int cpu_max_xsave_size(void)
{
unsigned long XSTATE_CPUID = 0xd;
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
__cpuid_count(XSTATE_CPUID, 0, eax, ebx, ecx, edx);
return ecx;
}
static inline u32 pkey_bit_position(int pkey) static inline u32 pkey_bit_position(int pkey)
{ {
return pkey * PKEY_BITS_PER_PKEY; return pkey * PKEY_BITS_PER_PKEY;

View File

@@ -18,12 +18,13 @@
* do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks * do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks
* *
* Compile like this: * Compile like this:
* gcc -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm * gcc -mxsave -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
* gcc -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm * gcc -mxsave -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__ #define __SANE_USERSPACE_TYPES__
#include <errno.h> #include <errno.h>
#include <linux/elf.h>
#include <linux/futex.h> #include <linux/futex.h>
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
@@ -1550,6 +1551,129 @@ void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey)
do_not_expect_pkey_fault("plain read on recently PROT_EXEC area"); do_not_expect_pkey_fault("plain read on recently PROT_EXEC area");
} }
#if defined(__i386__) || defined(__x86_64__)
void test_ptrace_modifies_pkru(int *ptr, u16 pkey)
{
u32 new_pkru;
pid_t child;
int status, ret;
int pkey_offset = pkey_reg_xstate_offset();
size_t xsave_size = cpu_max_xsave_size();
void *xsave;
u32 *pkey_register;
u64 *xstate_bv;
struct iovec iov;
new_pkru = ~read_pkey_reg();
/* Don't make PROT_EXEC mappings inaccessible */
new_pkru &= ~3;
child = fork();
pkey_assert(child >= 0);
dprintf3("[%d] fork() ret: %d\n", getpid(), child);
if (!child) {
ptrace(PTRACE_TRACEME, 0, 0, 0);
/* Stop and allow the tracer to modify PKRU directly */
raise(SIGSTOP);
/*
* need __read_pkey_reg() version so we do not do shadow_pkey_reg
* checking
*/
if (__read_pkey_reg() != new_pkru)
exit(1);
/* Stop and allow the tracer to clear XSTATE_BV for PKRU */
raise(SIGSTOP);
if (__read_pkey_reg() != 0)
exit(1);
/* Stop and allow the tracer to examine PKRU */
raise(SIGSTOP);
exit(0);
}
pkey_assert(child == waitpid(child, &status, 0));
dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
xsave = (void *)malloc(xsave_size);
pkey_assert(xsave > 0);
/* Modify the PKRU register directly */
iov.iov_base = xsave;
iov.iov_len = xsave_size;
ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
pkey_register = (u32 *)(xsave + pkey_offset);
pkey_assert(*pkey_register == read_pkey_reg());
*pkey_register = new_pkru;
ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
/* Test that the modification is visible in ptrace before any execution */
memset(xsave, 0xCC, xsave_size);
ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
pkey_assert(*pkey_register == new_pkru);
/* Execute the tracee */
ret = ptrace(PTRACE_CONT, child, 0, 0);
pkey_assert(ret == 0);
/* Test that the tracee saw the PKRU value change */
pkey_assert(child == waitpid(child, &status, 0));
dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
/* Test that the modification is visible in ptrace after execution */
memset(xsave, 0xCC, xsave_size);
ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
pkey_assert(*pkey_register == new_pkru);
/* Clear the PKRU bit from XSTATE_BV */
xstate_bv = (u64 *)(xsave + 512);
*xstate_bv &= ~(1 << 9);
ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
/* Test that the modification is visible in ptrace before any execution */
memset(xsave, 0xCC, xsave_size);
ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
pkey_assert(*pkey_register == 0);
ret = ptrace(PTRACE_CONT, child, 0, 0);
pkey_assert(ret == 0);
/* Test that the tracee saw the PKRU value go to 0 */
pkey_assert(child == waitpid(child, &status, 0));
dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
/* Test that the modification is visible in ptrace after execution */
memset(xsave, 0xCC, xsave_size);
ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
pkey_assert(ret == 0);
pkey_assert(*pkey_register == 0);
ret = ptrace(PTRACE_CONT, child, 0, 0);
pkey_assert(ret == 0);
pkey_assert(child == waitpid(child, &status, 0));
dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
pkey_assert(WIFEXITED(status));
pkey_assert(WEXITSTATUS(status) == 0);
free(xsave);
}
#endif
void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
{ {
int size = PAGE_SIZE; int size = PAGE_SIZE;
@@ -1585,6 +1709,9 @@ void (*pkey_tests[])(int *ptr, u16 pkey) = {
test_pkey_syscalls_bad_args, test_pkey_syscalls_bad_args,
test_pkey_alloc_exhaust, test_pkey_alloc_exhaust,
test_pkey_alloc_free_attach_pkey0, test_pkey_alloc_free_attach_pkey0,
#if defined(__i386__) || defined(__x86_64__)
test_ptrace_modifies_pkru,
#endif
}; };
void run_tests_once(void) void run_tests_once(void)