Merge branch 'akpm' (patches from Andrew)

Merge more updates from Andrew Morton:
 "VM:
   - z3fold fixes and enhancements by Henry Burns and Vitaly Wool

   - more accurate reclaimed slab caches calculations by Yafang Shao

   - fix MAP_UNINITIALIZED UAPI symbol to not depend on config, by
     Christoph Hellwig

   - !CONFIG_MMU fixes by Christoph Hellwig

   - new novmcoredd parameter to omit device dumps from vmcore, by
     Kairui Song

   - new test_meminit module for testing heap and pagealloc
     initialization, by Alexander Potapenko

   - ioremap improvements for huge mappings, by Anshuman Khandual

   - generalize kprobe page fault handling, by Anshuman Khandual

   - device-dax hotplug fixes and improvements, by Pavel Tatashin

   - enable synchronous DAX fault on powerpc, by Aneesh Kumar K.V

   - add pte_devmap() support for arm64, by Robin Murphy

   - unify locked_vm accounting with a helper, by Daniel Jordan

   - several misc fixes

  core/lib:
   - new typeof_member() macro including some users, by Alexey Dobriyan

   - make BIT() and GENMASK() available in asm, by Masahiro Yamada

   - changed LIST_POISON2 on x86_64 to 0xdead000000000122 for better
     code generation, by Alexey Dobriyan

   - rbtree code size optimizations, by Michel Lespinasse

   - convert struct pid count to refcount_t, by Joel Fernandes

  get_maintainer.pl:
   - add --no-moderated switch to skip moderated ML's, by Joe Perches

  misc:
   - ptrace PTRACE_GET_SYSCALL_INFO interface

   - coda updates

   - gdb scripts, various"

[ Using merge message suggestion from Vlastimil Babka, with some editing - Linus ]

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (100 commits)
  fs/select.c: use struct_size() in kmalloc()
  mm: add account_locked_vm utility function
  arm64: mm: implement pte_devmap support
  mm: introduce ARCH_HAS_PTE_DEVMAP
  mm: clean up is_device_*_page() definitions
  mm/mmap: move common defines to mman-common.h
  mm: move MAP_SYNC to asm-generic/mman-common.h
  device-dax: "Hotremove" persistent memory that is used like normal RAM
  mm/hotplug: make remove_memory() interface usable
  device-dax: fix memory and resource leak if hotplug fails
  include/linux/lz4.h: fix spelling and copy-paste errors in documentation
  ipc/mqueue.c: only perform resource calculation if user valid
  include/asm-generic/bug.h: fix "cut here" for WARN_ON for __WARN_TAINT architectures
  scripts/gdb: add helpers to find and list devices
  scripts/gdb: add lx-genpd-summary command
  drivers/pps/pps.c: clear offset flags in PPS_SETPARAMS ioctl
  kernel/pid.c: convert struct pid count to refcount_t
  drivers/rapidio/devices/rio_mport_cdev.c: NUL terminate some strings
  select: shift restore_saved_sigmask_unless() into poll_select_copy_remaining()
  select: change do_poll() to return -ERESTARTNOHAND rather than -EINTR
  ...
This commit is contained in:
Linus Torvalds
2019-07-17 08:58:04 -07:00
151 changed files with 2672 additions and 1223 deletions

View File

@@ -12,4 +12,5 @@
/read
/self
/setns-dcache
/setns-sysvipc
/thread-self

View File

@@ -17,6 +17,7 @@ TEST_GEN_PROGS += proc-uptime-002
TEST_GEN_PROGS += read
TEST_GEN_PROGS += self
TEST_GEN_PROGS += setns-dcache
TEST_GEN_PROGS += setns-sysvipc
TEST_GEN_PROGS += thread-self
include ../lib.mk

View File

@@ -215,6 +215,11 @@ static const char str_vsyscall[] =
"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
#ifdef __x86_64__
static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
{
_exit(1);
}
/*
* vsyscall page can't be unmapped, probe it with memory load.
*/
@@ -231,11 +236,19 @@ static void vsyscall(void)
if (pid == 0) {
struct rlimit rlim = {0, 0};
(void)setrlimit(RLIMIT_CORE, &rlim);
/* Hide "segfault at ffffffffff600000" messages. */
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sigaction_SIGSEGV;
(void)sigaction(SIGSEGV, &act, NULL);
*(volatile int *)0xffffffffff600000UL;
exit(0);
}
wait(&wstatus);
if (WIFEXITED(wstatus)) {
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
g_vsyscall = true;
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright © 2019 Alexey Dobriyan <adobriyan@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Test that setns(CLONE_NEWIPC) points to new /proc/sysvipc content even
* if old one is in dcache.
*/
#undef NDEBUG
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
static pid_t pid = -1;
static void f(void)
{
if (pid > 0) {
kill(pid, SIGTERM);
}
}
int main(void)
{
int fd[2];
char _ = 0;
int nsfd;
atexit(f);
/* Check for priviledges and syscall availability straight away. */
if (unshare(CLONE_NEWIPC) == -1) {
if (errno == ENOSYS || errno == EPERM) {
return 4;
}
return 1;
}
/* Distinguisher between two otherwise empty IPC namespaces. */
if (shmget(IPC_PRIVATE, 1, IPC_CREAT) == -1) {
return 1;
}
if (pipe(fd) == -1) {
return 1;
}
pid = fork();
if (pid == -1) {
return 1;
}
if (pid == 0) {
if (unshare(CLONE_NEWIPC) == -1) {
return 1;
}
if (write(fd[1], &_, 1) != 1) {
return 1;
}
pause();
return 0;
}
if (read(fd[0], &_, 1) != 1) {
return 1;
}
{
char buf[64];
snprintf(buf, sizeof(buf), "/proc/%u/ns/ipc", pid);
nsfd = open(buf, O_RDONLY);
if (nsfd == -1) {
return 1;
}
}
/* Reliably pin dentry into dcache. */
(void)open("/proc/sysvipc/shm", O_RDONLY);
if (setns(nsfd, CLONE_NEWIPC) == -1) {
return 1;
}
kill(pid, SIGTERM);
pid = 0;
{
char buf[4096];
ssize_t rv;
int fd;
fd = open("/proc/sysvipc/shm", O_RDONLY);
if (fd == -1) {
return 1;
}
#define S32 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n"
#define S64 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n"
rv = read(fd, buf, sizeof(buf));
if (rv == strlen(S32)) {
assert(memcmp(buf, S32, strlen(S32)) == 0);
} else if (rv == strlen(S64)) {
assert(memcmp(buf, S64, strlen(S64)) == 0);
} else {
assert(0);
}
}
return 0;
}

View File

@@ -1 +1,2 @@
get_syscall_info
peeksiginfo

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
CFLAGS += -iquote../../../../include/uapi -Wall
TEST_GEN_PROGS := peeksiginfo
TEST_GEN_PROGS := get_syscall_info peeksiginfo
include ../lib.mk

View File

@@ -0,0 +1,271 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
* All rights reserved.
*
* Check whether PTRACE_GET_SYSCALL_INFO semantics implemented in the kernel
* matches userspace expectations.
*/
#include "../kselftest_harness.h"
#include <err.h>
#include <signal.h>
#include <asm/unistd.h>
#include "linux/ptrace.h"
static int
kill_tracee(pid_t pid)
{
if (!pid)
return 0;
int saved_errno = errno;
int rc = kill(pid, SIGKILL);
errno = saved_errno;
return rc;
}
static long
sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)
{
return syscall(__NR_ptrace, request, pid, addr, data);
}
#define LOG_KILL_TRACEE(fmt, ...) \
do { \
kill_tracee(pid); \
TH_LOG("wait #%d: " fmt, \
ptrace_stop, ##__VA_ARGS__); \
} while (0)
TEST(get_syscall_info)
{
static const unsigned long args[][7] = {
/* a sequence of architecture-agnostic syscalls */
{
__NR_chdir,
(unsigned long) "",
0xbad1fed1,
0xbad2fed2,
0xbad3fed3,
0xbad4fed4,
0xbad5fed5
},
{
__NR_gettid,
0xcaf0bea0,
0xcaf1bea1,
0xcaf2bea2,
0xcaf3bea3,
0xcaf4bea4,
0xcaf5bea5
},
{
__NR_exit_group,
0,
0xfac1c0d1,
0xfac2c0d2,
0xfac3c0d3,
0xfac4c0d4,
0xfac5c0d5
}
};
const unsigned long *exp_args;
pid_t pid = fork();
ASSERT_LE(0, pid) {
TH_LOG("fork: %m");
}
if (pid == 0) {
/* get the pid before PTRACE_TRACEME */
pid = getpid();
ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {
TH_LOG("PTRACE_TRACEME: %m");
}
ASSERT_EQ(0, kill(pid, SIGSTOP)) {
/* cannot happen */
TH_LOG("kill SIGSTOP: %m");
}
for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
syscall(args[i][0],
args[i][1], args[i][2], args[i][3],
args[i][4], args[i][5], args[i][6]);
}
/* unreachable */
_exit(1);
}
const struct {
unsigned int is_error;
int rval;
} *exp_param, exit_param[] = {
{ 1, -ENOENT }, /* chdir */
{ 0, pid } /* gettid */
};
unsigned int ptrace_stop;
for (ptrace_stop = 0; ; ++ptrace_stop) {
struct ptrace_syscall_info info = {
.op = 0xff /* invalid PTRACE_SYSCALL_INFO_* op */
};
const size_t size = sizeof(info);
const int expected_none_size =
(void *) &info.entry - (void *) &info;
const int expected_entry_size =
(void *) &info.entry.args[6] - (void *) &info;
const int expected_exit_size =
(void *) (&info.exit.is_error + 1) -
(void *) &info;
int status;
long rc;
ASSERT_EQ(pid, wait(&status)) {
/* cannot happen */
LOG_KILL_TRACEE("wait: %m");
}
if (WIFEXITED(status)) {
pid = 0; /* the tracee is no more */
ASSERT_EQ(0, WEXITSTATUS(status));
break;
}
ASSERT_FALSE(WIFSIGNALED(status)) {
pid = 0; /* the tracee is no more */
LOG_KILL_TRACEE("unexpected signal %u",
WTERMSIG(status));
}
ASSERT_TRUE(WIFSTOPPED(status)) {
/* cannot happen */
LOG_KILL_TRACEE("unexpected wait status %#x", status);
}
switch (WSTOPSIG(status)) {
case SIGSTOP:
ASSERT_EQ(0, ptrace_stop) {
LOG_KILL_TRACEE("unexpected signal stop");
}
ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,
PTRACE_O_TRACESYSGOOD)) {
LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
}
ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
pid, size,
(unsigned long) &info))) {
LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
}
ASSERT_EQ(expected_none_size, rc) {
LOG_KILL_TRACEE("signal stop mismatch");
}
ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {
LOG_KILL_TRACEE("signal stop mismatch");
}
ASSERT_TRUE(info.arch) {
LOG_KILL_TRACEE("signal stop mismatch");
}
ASSERT_TRUE(info.instruction_pointer) {
LOG_KILL_TRACEE("signal stop mismatch");
}
ASSERT_TRUE(info.stack_pointer) {
LOG_KILL_TRACEE("signal stop mismatch");
}
break;
case SIGTRAP | 0x80:
ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
pid, size,
(unsigned long) &info))) {
LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
}
switch (ptrace_stop) {
case 1: /* entering chdir */
case 3: /* entering gettid */
case 5: /* entering exit_group */
exp_args = args[ptrace_stop / 2];
ASSERT_EQ(expected_entry_size, rc) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info.op) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_TRUE(info.arch) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_TRUE(info.instruction_pointer) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_TRUE(info.stack_pointer) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[0], info.entry.nr) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[1], info.entry.args[0]) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[2], info.entry.args[1]) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[3], info.entry.args[2]) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[4], info.entry.args[3]) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[5], info.entry.args[4]) {
LOG_KILL_TRACEE("entry stop mismatch");
}
ASSERT_EQ(exp_args[6], info.entry.args[5]) {
LOG_KILL_TRACEE("entry stop mismatch");
}
break;
case 2: /* exiting chdir */
case 4: /* exiting gettid */
exp_param = &exit_param[ptrace_stop / 2 - 1];
ASSERT_EQ(expected_exit_size, rc) {
LOG_KILL_TRACEE("exit stop mismatch");
}
ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info.op) {
LOG_KILL_TRACEE("exit stop mismatch");
}
ASSERT_TRUE(info.arch) {
LOG_KILL_TRACEE("exit stop mismatch");
}
ASSERT_TRUE(info.instruction_pointer) {
LOG_KILL_TRACEE("exit stop mismatch");
}
ASSERT_TRUE(info.stack_pointer) {
LOG_KILL_TRACEE("exit stop mismatch");
}
ASSERT_EQ(exp_param->is_error,
info.exit.is_error) {
LOG_KILL_TRACEE("exit stop mismatch");
}
ASSERT_EQ(exp_param->rval, info.exit.rval) {
LOG_KILL_TRACEE("exit stop mismatch");
}
break;
default:
LOG_KILL_TRACEE("unexpected syscall stop");
abort();
}
break;
default:
LOG_KILL_TRACEE("unexpected stop signal %#x",
WSTOPSIG(status));
abort();
}
ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, pid, 0, 0)) {
LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");
}
}
ASSERT_EQ(ARRAY_SIZE(args) * 2, ptrace_stop);
}
TEST_HARNESS_MAIN

View File

@@ -1775,13 +1775,18 @@ void tracer_ptrace(struct __test_metadata *_metadata, pid_t tracee,
unsigned long msg;
static bool entry;
/* Make sure we got an empty message. */
/*
* The traditional way to tell PTRACE_SYSCALL entry/exit
* is by counting.
*/
entry = !entry;
/* Make sure we got an appropriate message. */
ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg);
EXPECT_EQ(0, ret);
EXPECT_EQ(0, msg);
EXPECT_EQ(entry ? PTRACE_EVENTMSG_SYSCALL_ENTRY
: PTRACE_EVENTMSG_SYSCALL_EXIT, msg);
/* The only way to tell PTRACE_SYSCALL entry/exit is by counting. */
entry = !entry;
if (!entry)
return;