mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-24 05:29:04 -04:00
Linux 5.4-rc1
-----BEGIN PGP SIGNATURE----- iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAl2SPPkeHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiG3dcH/2iCaNvD0Ify+Ke/ d0Ncf7KhBejfW1pjGjfpfbAQkdaY/gSLsWPJmQ2HT00SmnTJ4y3zvr/HmEE8mIBA fMzY4TFHMRNNEOrCugoNxzjU5ycgIMq5doontDdHeS7Pfa8mgDLLwH/dzoORA0+b T1ZZT3yDsQ92/jW97LEhTv7UcKqgBdVT5PauU/pe6LHpqmzn8XwdiKaNTM1uY8vw U9rIrYnfxCuLfxyK7xUp6bRUlqluZrY4U+pqEnGOVlFYX1xMjjPIE9sDHJ/z5WvY JSH4/aOqVxRII2oU0+uITsO658tS912iUsa8++F6Z5R1gZSqQD1FqrvW7Z0S58Ay vjXIX3Q= =epsM -----END PGP SIGNATURE----- Merge 5.4-rc1 into android-mainline Linux 5.4-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I15eec52df70f829acf81ff614a1c2a5fb443a4e0
This commit is contained in:
commit
cb33d78781
435 changed files with 8519 additions and 3590 deletions
|
|
@ -58,6 +58,7 @@ endif
|
|||
obj-$(CONFIG_UID16) += uid16.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_MODULE_SIG) += module_signing.o
|
||||
obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
|
||||
obj-$(CONFIG_KALLSYMS) += kallsyms.o
|
||||
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
|
||||
obj-$(CONFIG_CRASH_CORE) += crash_core.o
|
||||
|
|
|
|||
|
|
@ -2332,7 +2332,7 @@ static int btf_enum_check_kflag_member(struct btf_verifier_env *env,
|
|||
if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Member is not byte aligned");
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nr_bits = int_bitsize;
|
||||
|
|
@ -2377,9 +2377,8 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->size != sizeof(int)) {
|
||||
btf_verifier_log_type(env, t, "Expected size:%zu",
|
||||
sizeof(int));
|
||||
if (t->size > 8 || !is_power_of_2(t->size)) {
|
||||
btf_verifier_log_type(env, t, "Unexpected size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ static struct xsk_map_node *xsk_map_node_alloc(struct xsk_map *map,
|
|||
|
||||
node = kzalloc(sizeof(*node), GFP_ATOMIC | __GFP_NOWARN);
|
||||
if (!node)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = xsk_map_inc(map);
|
||||
if (err) {
|
||||
|
|
|
|||
|
|
@ -10925,6 +10925,13 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
err = security_locked_down(LOCKDOWN_PERF);
|
||||
if (err && (attr.sample_type & PERF_SAMPLE_REGS_INTR))
|
||||
/* REGS_INTR can leak data, lockdown must prevent this */
|
||||
return err;
|
||||
|
||||
err = 0;
|
||||
|
||||
/*
|
||||
* In cgroup mode, the pid argument is used to pass the fd
|
||||
* opened to the cgroup directory in cgroupfs. The cpu argument
|
||||
|
|
|
|||
|
|
@ -182,6 +182,11 @@ static void delayed_put_task_struct(struct rcu_head *rhp)
|
|||
put_task_struct(tsk);
|
||||
}
|
||||
|
||||
void put_task_struct_rcu_user(struct task_struct *task)
|
||||
{
|
||||
if (refcount_dec_and_test(&task->rcu_users))
|
||||
call_rcu(&task->rcu, delayed_put_task_struct);
|
||||
}
|
||||
|
||||
void release_task(struct task_struct *p)
|
||||
{
|
||||
|
|
@ -222,76 +227,13 @@ repeat:
|
|||
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
release_thread(p);
|
||||
call_rcu(&p->rcu, delayed_put_task_struct);
|
||||
put_task_struct_rcu_user(p);
|
||||
|
||||
p = leader;
|
||||
if (unlikely(zap_leader))
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that if this function returns a valid task_struct pointer (!NULL)
|
||||
* task->usage must remain >0 for the duration of the RCU critical section.
|
||||
*/
|
||||
struct task_struct *task_rcu_dereference(struct task_struct **ptask)
|
||||
{
|
||||
struct sighand_struct *sighand;
|
||||
struct task_struct *task;
|
||||
|
||||
/*
|
||||
* We need to verify that release_task() was not called and thus
|
||||
* delayed_put_task_struct() can't run and drop the last reference
|
||||
* before rcu_read_unlock(). We check task->sighand != NULL,
|
||||
* but we can read the already freed and reused memory.
|
||||
*/
|
||||
retry:
|
||||
task = rcu_dereference(*ptask);
|
||||
if (!task)
|
||||
return NULL;
|
||||
|
||||
probe_kernel_address(&task->sighand, sighand);
|
||||
|
||||
/*
|
||||
* Pairs with atomic_dec_and_test() in put_task_struct(). If this task
|
||||
* was already freed we can not miss the preceding update of this
|
||||
* pointer.
|
||||
*/
|
||||
smp_rmb();
|
||||
if (unlikely(task != READ_ONCE(*ptask)))
|
||||
goto retry;
|
||||
|
||||
/*
|
||||
* We've re-checked that "task == *ptask", now we have two different
|
||||
* cases:
|
||||
*
|
||||
* 1. This is actually the same task/task_struct. In this case
|
||||
* sighand != NULL tells us it is still alive.
|
||||
*
|
||||
* 2. This is another task which got the same memory for task_struct.
|
||||
* We can't know this of course, and we can not trust
|
||||
* sighand != NULL.
|
||||
*
|
||||
* In this case we actually return a random value, but this is
|
||||
* correct.
|
||||
*
|
||||
* If we return NULL - we can pretend that we actually noticed that
|
||||
* *ptask was updated when the previous task has exited. Or pretend
|
||||
* that probe_slab_address(&sighand) reads NULL.
|
||||
*
|
||||
* If we return the new task (because sighand is not NULL for any
|
||||
* reason) - this is fine too. This (new) task can't go away before
|
||||
* another gp pass.
|
||||
*
|
||||
* And note: We could even eliminate the false positive if re-read
|
||||
* task->sighand once again to avoid the falsely NULL. But this case
|
||||
* is very unlikely so we don't care.
|
||||
*/
|
||||
if (!sighand)
|
||||
return NULL;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
void rcuwait_wake_up(struct rcuwait *w)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
|
@ -311,10 +253,6 @@ void rcuwait_wake_up(struct rcuwait *w)
|
|||
*/
|
||||
smp_mb(); /* (B) */
|
||||
|
||||
/*
|
||||
* Avoid using task_rcu_dereference() magic as long as we are careful,
|
||||
* see comment in rcuwait_wait_event() regarding ->exit_state.
|
||||
*/
|
||||
task = rcu_dereference(w->task);
|
||||
if (task)
|
||||
wake_up_process(task);
|
||||
|
|
|
|||
|
|
@ -918,10 +918,12 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
|
|||
tsk->cpus_ptr = &tsk->cpus_mask;
|
||||
|
||||
/*
|
||||
* One for us, one for whoever does the "release_task()" (usually
|
||||
* parent)
|
||||
* One for the user space visible state that goes away when reaped.
|
||||
* One for the scheduler.
|
||||
*/
|
||||
refcount_set(&tsk->usage, 2);
|
||||
refcount_set(&tsk->rcu_users, 2);
|
||||
/* One for the rcu users */
|
||||
refcount_set(&tsk->usage, 1);
|
||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||
tsk->btrace_seq = 0;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -205,6 +205,14 @@ static inline int kexec_load_check(unsigned long nr_segments,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* kexec can be used to circumvent module loading restrictions, so
|
||||
* prevent loading in that case
|
||||
*/
|
||||
result = security_locked_down(LOCKDOWN_KEXEC);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* Verify we have a legal set of flags
|
||||
* This leaves us room for future extensions.
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ int __weak arch_kimage_file_post_load_cleanup(struct kimage *image)
|
|||
return kexec_image_post_load_cleanup_default(image);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
||||
#ifdef CONFIG_KEXEC_SIG
|
||||
static int kexec_image_verify_sig_default(struct kimage *image, void *buf,
|
||||
unsigned long buf_len)
|
||||
{
|
||||
|
|
@ -177,6 +177,59 @@ void kimage_file_post_load_cleanup(struct kimage *image)
|
|||
image->image_loader_data = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KEXEC_SIG
|
||||
static int
|
||||
kimage_validate_signature(struct kimage *image)
|
||||
{
|
||||
const char *reason;
|
||||
int ret;
|
||||
|
||||
ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,
|
||||
image->kernel_buf_len);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
/* Certain verification errors are non-fatal if we're not
|
||||
* checking errors, provided we aren't mandating that there
|
||||
* must be a valid signature.
|
||||
*/
|
||||
case -ENODATA:
|
||||
reason = "kexec of unsigned image";
|
||||
goto decide;
|
||||
case -ENOPKG:
|
||||
reason = "kexec of image with unsupported crypto";
|
||||
goto decide;
|
||||
case -ENOKEY:
|
||||
reason = "kexec of image with unavailable key";
|
||||
decide:
|
||||
if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)) {
|
||||
pr_notice("%s rejected\n", reason);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If IMA is guaranteed to appraise a signature on the kexec
|
||||
* image, permit it even if the kernel is otherwise locked
|
||||
* down.
|
||||
*/
|
||||
if (!ima_appraise_signature(READING_KEXEC_IMAGE) &&
|
||||
security_locked_down(LOCKDOWN_KEXEC))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
|
||||
/* All other errors are fatal, including nomem, unparseable
|
||||
* signatures and signature check failures - even if signatures
|
||||
* aren't required.
|
||||
*/
|
||||
default:
|
||||
pr_notice("kernel signature verification failed (%d).\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In file mode list of segments is prepared by kernel. Copy relevant
|
||||
* data from user space, do error checking, prepare segment list
|
||||
|
|
@ -186,7 +239,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
|||
const char __user *cmdline_ptr,
|
||||
unsigned long cmdline_len, unsigned flags)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
void *ldata;
|
||||
loff_t size;
|
||||
|
||||
|
|
@ -202,14 +255,11 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
||||
ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,
|
||||
image->kernel_buf_len);
|
||||
if (ret) {
|
||||
pr_debug("kernel signature verification failed.\n");
|
||||
#ifdef CONFIG_KEXEC_SIG
|
||||
ret = kimage_validate_signature(image);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
pr_debug("kernel signature verification successful.\n");
|
||||
#endif
|
||||
/* It is possible that there no initramfs is being loaded */
|
||||
if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/extable.h>
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/module_signature.h>
|
||||
#include <linux/trace_events.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kallsyms.h>
|
||||
|
|
@ -2838,8 +2839,9 @@ static inline void kmemleak_load_module(const struct module *mod,
|
|||
#ifdef CONFIG_MODULE_SIG
|
||||
static int module_sig_check(struct load_info *info, int flags)
|
||||
{
|
||||
int err = -ENOKEY;
|
||||
int err = -ENODATA;
|
||||
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
|
||||
const char *reason;
|
||||
const void *mod = info->hdr;
|
||||
|
||||
/*
|
||||
|
|
@ -2854,16 +2856,38 @@ static int module_sig_check(struct load_info *info, int flags)
|
|||
err = mod_verify_sig(mod, info);
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
switch (err) {
|
||||
case 0:
|
||||
info->sig_ok = true;
|
||||
return 0;
|
||||
|
||||
/* We don't permit modules to be loaded into trusted kernels
|
||||
* without a valid signature on them, but if we're not
|
||||
* enforcing, certain errors are non-fatal.
|
||||
*/
|
||||
case -ENODATA:
|
||||
reason = "Loading of unsigned module";
|
||||
goto decide;
|
||||
case -ENOPKG:
|
||||
reason = "Loading of module with unsupported crypto";
|
||||
goto decide;
|
||||
case -ENOKEY:
|
||||
reason = "Loading of module with unavailable key";
|
||||
decide:
|
||||
if (is_module_sig_enforced()) {
|
||||
pr_notice("%s is rejected\n", reason);
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
|
||||
|
||||
/* All other errors are fatal, including nomem, unparseable
|
||||
* signatures and signature check failures - even if signatures
|
||||
* aren't required.
|
||||
*/
|
||||
default:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Not having a signature is only an error if we're strict. */
|
||||
if (err == -ENOKEY && !is_module_sig_enforced())
|
||||
err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
#else /* !CONFIG_MODULE_SIG */
|
||||
static int module_sig_check(struct load_info *info, int flags)
|
||||
|
|
|
|||
46
kernel/module_signature.c
Normal file
46
kernel/module_signature.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Module signature checker
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/module_signature.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/**
|
||||
* mod_check_sig - check that the given signature is sane
|
||||
*
|
||||
* @ms: Signature to check.
|
||||
* @file_len: Size of the file to which @ms is appended.
|
||||
* @name: What is being checked. Used for error messages.
|
||||
*/
|
||||
int mod_check_sig(const struct module_signature *ms, size_t file_len,
|
||||
const char *name)
|
||||
{
|
||||
if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms))
|
||||
return -EBADMSG;
|
||||
|
||||
if (ms->id_type != PKEY_ID_PKCS7) {
|
||||
pr_err("%s: Module is not signed with expected PKCS#7 message\n",
|
||||
name);
|
||||
return -ENOPKG;
|
||||
}
|
||||
|
||||
if (ms->algo != 0 ||
|
||||
ms->hash != 0 ||
|
||||
ms->signer_len != 0 ||
|
||||
ms->key_id_len != 0 ||
|
||||
ms->__pad[0] != 0 ||
|
||||
ms->__pad[1] != 0 ||
|
||||
ms->__pad[2] != 0) {
|
||||
pr_err("%s: PKCS#7 signature info has unexpected non-zero params\n",
|
||||
name);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -7,37 +7,13 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/module_signature.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/verification.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
enum pkey_id_type {
|
||||
PKEY_ID_PGP, /* OpenPGP generated key ID */
|
||||
PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
|
||||
PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
|
||||
};
|
||||
|
||||
/*
|
||||
* Module signature information block.
|
||||
*
|
||||
* The constituents of the signature section are, in order:
|
||||
*
|
||||
* - Signer's name
|
||||
* - Key identifier
|
||||
* - Signature data
|
||||
* - Information block
|
||||
*/
|
||||
struct module_signature {
|
||||
u8 algo; /* Public-key crypto algorithm [0] */
|
||||
u8 hash; /* Digest algorithm [0] */
|
||||
u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
||||
u8 signer_len; /* Length of signer's name [0] */
|
||||
u8 key_id_len; /* Length of key identifier [0] */
|
||||
u8 __pad[3];
|
||||
__be32 sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
/*
|
||||
* Verify the signature on a module.
|
||||
*/
|
||||
|
|
@ -45,6 +21,7 @@ int mod_verify_sig(const void *mod, struct load_info *info)
|
|||
{
|
||||
struct module_signature ms;
|
||||
size_t sig_len, modlen = info->len;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s(,%zu)\n", __func__, modlen);
|
||||
|
||||
|
|
@ -52,32 +29,15 @@ int mod_verify_sig(const void *mod, struct load_info *info)
|
|||
return -EBADMSG;
|
||||
|
||||
memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
|
||||
modlen -= sizeof(ms);
|
||||
|
||||
ret = mod_check_sig(&ms, modlen, info->name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sig_len = be32_to_cpu(ms.sig_len);
|
||||
if (sig_len >= modlen)
|
||||
return -EBADMSG;
|
||||
modlen -= sig_len;
|
||||
modlen -= sig_len + sizeof(ms);
|
||||
info->len = modlen;
|
||||
|
||||
if (ms.id_type != PKEY_ID_PKCS7) {
|
||||
pr_err("%s: Module is not signed with expected PKCS#7 message\n",
|
||||
info->name);
|
||||
return -ENOPKG;
|
||||
}
|
||||
|
||||
if (ms.algo != 0 ||
|
||||
ms.hash != 0 ||
|
||||
ms.signer_len != 0 ||
|
||||
ms.key_id_len != 0 ||
|
||||
ms.__pad[0] != 0 ||
|
||||
ms.__pad[1] != 0 ||
|
||||
ms.__pad[2] != 0) {
|
||||
pr_err("%s: PKCS#7 signature info has unexpected non-zero params\n",
|
||||
info->name);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
|
||||
VERIFY_USE_SECONDARY_KEYRING,
|
||||
VERIFYING_MODULE_SIGNATURE,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
/* Protects all built-in parameters, modules use their own param_lock */
|
||||
|
|
@ -96,13 +97,19 @@ bool parameq(const char *a, const char *b)
|
|||
return parameqn(a, b, strlen(a)+1);
|
||||
}
|
||||
|
||||
static void param_check_unsafe(const struct kernel_param *kp)
|
||||
static bool param_check_unsafe(const struct kernel_param *kp)
|
||||
{
|
||||
if (kp->flags & KERNEL_PARAM_FL_HWPARAM &&
|
||||
security_locked_down(LOCKDOWN_MODULE_PARAMETERS))
|
||||
return false;
|
||||
|
||||
if (kp->flags & KERNEL_PARAM_FL_UNSAFE) {
|
||||
pr_notice("Setting dangerous option %s - tainting kernel\n",
|
||||
kp->name);
|
||||
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int parse_one(char *param,
|
||||
|
|
@ -132,8 +139,10 @@ static int parse_one(char *param,
|
|||
pr_debug("handling %s with %p\n", param,
|
||||
params[i].ops->set);
|
||||
kernel_param_lock(params[i].mod);
|
||||
param_check_unsafe(¶ms[i]);
|
||||
err = params[i].ops->set(val, ¶ms[i]);
|
||||
if (param_check_unsafe(¶ms[i]))
|
||||
err = params[i].ops->set(val, ¶ms[i]);
|
||||
else
|
||||
err = -EPERM;
|
||||
kernel_param_unlock(params[i].mod);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -553,8 +562,10 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
|
|||
return -EPERM;
|
||||
|
||||
kernel_param_lock(mk->mod);
|
||||
param_check_unsafe(attribute->param);
|
||||
err = attribute->param->ops->set(buf, attribute->param);
|
||||
if (param_check_unsafe(attribute->param))
|
||||
err = attribute->param->ops->set(buf, attribute->param);
|
||||
else
|
||||
err = -EPERM;
|
||||
kernel_param_unlock(mk->mod);
|
||||
if (!err)
|
||||
return len;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/ctype.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/security.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "power.h"
|
||||
|
|
@ -68,7 +69,7 @@ static const struct platform_hibernation_ops *hibernation_ops;
|
|||
|
||||
bool hibernation_available(void)
|
||||
{
|
||||
return (nohibernate == 0);
|
||||
return nohibernate == 0 && !security_locked_down(LOCKDOWN_HIBERNATION);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1656,7 +1656,8 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,
|
|||
if (cpumask_equal(p->cpus_ptr, new_mask))
|
||||
goto out;
|
||||
|
||||
if (!cpumask_intersects(new_mask, cpu_valid_mask)) {
|
||||
dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask);
|
||||
if (dest_cpu >= nr_cpu_ids) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1677,7 +1678,6 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,
|
|||
if (cpumask_test_cpu(task_cpu(p), new_mask))
|
||||
goto out;
|
||||
|
||||
dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask);
|
||||
if (task_running(rq, p) || p->state == TASK_WAKING) {
|
||||
struct migration_arg arg = { p, dest_cpu };
|
||||
/* Need help from migration thread: drop lock and wait. */
|
||||
|
|
@ -3254,7 +3254,7 @@ static struct rq *finish_task_switch(struct task_struct *prev)
|
|||
/* Task is done with its stack. */
|
||||
put_task_stack(prev);
|
||||
|
||||
put_task_struct(prev);
|
||||
put_task_struct_rcu_user(prev);
|
||||
}
|
||||
|
||||
tick_nohz_task_switch();
|
||||
|
|
@ -3358,15 +3358,15 @@ context_switch(struct rq *rq, struct task_struct *prev,
|
|||
else
|
||||
prev->active_mm = NULL;
|
||||
} else { // to user
|
||||
membarrier_switch_mm(rq, prev->active_mm, next->mm);
|
||||
/*
|
||||
* sys_membarrier() requires an smp_mb() between setting
|
||||
* rq->curr and returning to userspace.
|
||||
* rq->curr / membarrier_switch_mm() and returning to userspace.
|
||||
*
|
||||
* The below provides this either through switch_mm(), or in
|
||||
* case 'prev->active_mm == next->mm' through
|
||||
* finish_task_switch()'s mmdrop().
|
||||
*/
|
||||
|
||||
switch_mm_irqs_off(prev->active_mm, next->mm, next);
|
||||
|
||||
if (!prev->mm) { // from kernel
|
||||
|
|
@ -4042,7 +4042,11 @@ static void __sched notrace __schedule(bool preempt)
|
|||
|
||||
if (likely(prev != next)) {
|
||||
rq->nr_switches++;
|
||||
rq->curr = next;
|
||||
/*
|
||||
* RCU users of rcu_dereference(rq->curr) may not see
|
||||
* changes to task_struct made by pick_next_task().
|
||||
*/
|
||||
RCU_INIT_POINTER(rq->curr, next);
|
||||
/*
|
||||
* The membarrier system call requires each architecture
|
||||
* to have a full memory barrier after updating
|
||||
|
|
@ -4223,9 +4227,8 @@ static void __sched notrace preempt_schedule_common(void)
|
|||
|
||||
#ifdef CONFIG_PREEMPTION
|
||||
/*
|
||||
* this is the entry point to schedule() from in-kernel preemption
|
||||
* off of preempt_enable. Kernel preemptions off return from interrupt
|
||||
* occur there and call schedule directly.
|
||||
* This is the entry point to schedule() from in-kernel preemption
|
||||
* off of preempt_enable.
|
||||
*/
|
||||
asmlinkage __visible void __sched notrace preempt_schedule(void)
|
||||
{
|
||||
|
|
@ -4296,7 +4299,7 @@ EXPORT_SYMBOL_GPL(preempt_schedule_notrace);
|
|||
#endif /* CONFIG_PREEMPTION */
|
||||
|
||||
/*
|
||||
* this is the entry point to schedule() from kernel preemption
|
||||
* This is the entry point to schedule() from kernel preemption
|
||||
* off of irq context.
|
||||
* Note, that this is called and return with irqs disabled. This will
|
||||
* protect us against recursive calling from irq.
|
||||
|
|
@ -6069,7 +6072,8 @@ void init_idle(struct task_struct *idle, int cpu)
|
|||
__set_task_cpu(idle, cpu);
|
||||
rcu_read_unlock();
|
||||
|
||||
rq->curr = rq->idle = idle;
|
||||
rq->idle = idle;
|
||||
rcu_assign_pointer(rq->curr, idle);
|
||||
idle->on_rq = TASK_ON_RQ_QUEUED;
|
||||
#ifdef CONFIG_SMP
|
||||
idle->on_cpu = 1;
|
||||
|
|
@ -6430,8 +6434,6 @@ int sched_cpu_activate(unsigned int cpu)
|
|||
}
|
||||
rq_unlock_irqrestore(rq, &rf);
|
||||
|
||||
update_max_interval();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -749,7 +749,6 @@ void init_entity_runnable_average(struct sched_entity *se)
|
|||
/* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
|
||||
}
|
||||
|
||||
static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq);
|
||||
static void attach_entity_cfs_rq(struct sched_entity *se);
|
||||
|
||||
/*
|
||||
|
|
@ -1603,7 +1602,7 @@ static void task_numa_compare(struct task_numa_env *env,
|
|||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
cur = task_rcu_dereference(&dst_rq->curr);
|
||||
cur = rcu_dereference(dst_rq->curr);
|
||||
if (cur && ((cur->flags & PF_EXITING) || is_idle_task(cur)))
|
||||
cur = NULL;
|
||||
|
||||
|
|
@ -4354,21 +4353,16 @@ static inline u64 sched_cfs_bandwidth_slice(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Replenish runtime according to assigned quota and update expiration time.
|
||||
* We use sched_clock_cpu directly instead of rq->clock to avoid adding
|
||||
* additional synchronization around rq->lock.
|
||||
* Replenish runtime according to assigned quota. We use sched_clock_cpu
|
||||
* directly instead of rq->clock to avoid adding additional synchronization
|
||||
* around rq->lock.
|
||||
*
|
||||
* requires cfs_b->lock
|
||||
*/
|
||||
void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
|
||||
{
|
||||
u64 now;
|
||||
|
||||
if (cfs_b->quota == RUNTIME_INF)
|
||||
return;
|
||||
|
||||
now = sched_clock_cpu(smp_processor_id());
|
||||
cfs_b->runtime = cfs_b->quota;
|
||||
if (cfs_b->quota != RUNTIME_INF)
|
||||
cfs_b->runtime = cfs_b->quota;
|
||||
}
|
||||
|
||||
static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
|
||||
|
|
@ -4376,15 +4370,6 @@ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
|
|||
return &tg->cfs_bandwidth;
|
||||
}
|
||||
|
||||
/* rq->task_clock normalized against any time this cfs_rq has spent throttled */
|
||||
static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
|
||||
{
|
||||
if (unlikely(cfs_rq->throttle_count))
|
||||
return cfs_rq->throttled_clock_task - cfs_rq->throttled_clock_task_time;
|
||||
|
||||
return rq_clock_task(rq_of(cfs_rq)) - cfs_rq->throttled_clock_task_time;
|
||||
}
|
||||
|
||||
/* returns 0 on failure to allocate runtime */
|
||||
static int assign_cfs_rq_runtime(struct cfs_rq *cfs_rq)
|
||||
{
|
||||
|
|
@ -4476,7 +4461,6 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
|
|||
|
||||
cfs_rq->throttle_count--;
|
||||
if (!cfs_rq->throttle_count) {
|
||||
/* adjust cfs_rq_clock_task() */
|
||||
cfs_rq->throttled_clock_task_time += rq_clock_task(rq) -
|
||||
cfs_rq->throttled_clock_task;
|
||||
|
||||
|
|
@ -4994,15 +4978,13 @@ static void init_cfs_rq_runtime(struct cfs_rq *cfs_rq)
|
|||
|
||||
void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
|
||||
{
|
||||
u64 overrun;
|
||||
|
||||
lockdep_assert_held(&cfs_b->lock);
|
||||
|
||||
if (cfs_b->period_active)
|
||||
return;
|
||||
|
||||
cfs_b->period_active = 1;
|
||||
overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
|
||||
hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
|
||||
hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED);
|
||||
}
|
||||
|
||||
|
|
@ -5080,11 +5062,6 @@ static inline bool cfs_bandwidth_used(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
|
||||
{
|
||||
return rq_clock_task(rq_of(cfs_rq));
|
||||
}
|
||||
|
||||
static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {}
|
||||
static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) { return false; }
|
||||
static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {}
|
||||
|
|
@ -6412,7 +6389,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
|
|||
}
|
||||
|
||||
/* Evaluate the energy impact of using this CPU. */
|
||||
if (max_spare_cap_cpu >= 0) {
|
||||
if (max_spare_cap_cpu >= 0 && max_spare_cap_cpu != prev_cpu) {
|
||||
cur_delta = compute_energy(p, max_spare_cap_cpu, pd);
|
||||
cur_delta -= base_energy_pd;
|
||||
if (cur_delta < best_delta) {
|
||||
|
|
|
|||
|
|
@ -30,10 +30,42 @@ static void ipi_mb(void *info)
|
|||
smp_mb(); /* IPIs should be serializing but paranoid. */
|
||||
}
|
||||
|
||||
static void ipi_sync_rq_state(void *info)
|
||||
{
|
||||
struct mm_struct *mm = (struct mm_struct *) info;
|
||||
|
||||
if (current->mm != mm)
|
||||
return;
|
||||
this_cpu_write(runqueues.membarrier_state,
|
||||
atomic_read(&mm->membarrier_state));
|
||||
/*
|
||||
* Issue a memory barrier after setting
|
||||
* MEMBARRIER_STATE_GLOBAL_EXPEDITED in the current runqueue to
|
||||
* guarantee that no memory access following registration is reordered
|
||||
* before registration.
|
||||
*/
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
void membarrier_exec_mmap(struct mm_struct *mm)
|
||||
{
|
||||
/*
|
||||
* Issue a memory barrier before clearing membarrier_state to
|
||||
* guarantee that no memory access prior to exec is reordered after
|
||||
* clearing this state.
|
||||
*/
|
||||
smp_mb();
|
||||
atomic_set(&mm->membarrier_state, 0);
|
||||
/*
|
||||
* Keep the runqueue membarrier_state in sync with this mm
|
||||
* membarrier_state.
|
||||
*/
|
||||
this_cpu_write(runqueues.membarrier_state, 0);
|
||||
}
|
||||
|
||||
static int membarrier_global_expedited(void)
|
||||
{
|
||||
int cpu;
|
||||
bool fallback = false;
|
||||
cpumask_var_t tmpmask;
|
||||
|
||||
if (num_online_cpus() == 1)
|
||||
|
|
@ -45,17 +77,11 @@ static int membarrier_global_expedited(void)
|
|||
*/
|
||||
smp_mb(); /* system call entry is not a mb. */
|
||||
|
||||
/*
|
||||
* Expedited membarrier commands guarantee that they won't
|
||||
* block, hence the GFP_NOWAIT allocation flag and fallback
|
||||
* implementation.
|
||||
*/
|
||||
if (!zalloc_cpumask_var(&tmpmask, GFP_NOWAIT)) {
|
||||
/* Fallback for OOM. */
|
||||
fallback = true;
|
||||
}
|
||||
if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
cpus_read_lock();
|
||||
rcu_read_lock();
|
||||
for_each_online_cpu(cpu) {
|
||||
struct task_struct *p;
|
||||
|
||||
|
|
@ -70,23 +96,28 @@ static int membarrier_global_expedited(void)
|
|||
if (cpu == raw_smp_processor_id())
|
||||
continue;
|
||||
|
||||
rcu_read_lock();
|
||||
p = task_rcu_dereference(&cpu_rq(cpu)->curr);
|
||||
if (p && p->mm && (atomic_read(&p->mm->membarrier_state) &
|
||||
MEMBARRIER_STATE_GLOBAL_EXPEDITED)) {
|
||||
if (!fallback)
|
||||
__cpumask_set_cpu(cpu, tmpmask);
|
||||
else
|
||||
smp_call_function_single(cpu, ipi_mb, NULL, 1);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
if (!fallback) {
|
||||
preempt_disable();
|
||||
smp_call_function_many(tmpmask, ipi_mb, NULL, 1);
|
||||
preempt_enable();
|
||||
free_cpumask_var(tmpmask);
|
||||
if (!(READ_ONCE(cpu_rq(cpu)->membarrier_state) &
|
||||
MEMBARRIER_STATE_GLOBAL_EXPEDITED))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Skip the CPU if it runs a kernel thread. The scheduler
|
||||
* leaves the prior task mm in place as an optimization when
|
||||
* scheduling a kthread.
|
||||
*/
|
||||
p = rcu_dereference(cpu_rq(cpu)->curr);
|
||||
if (p->flags & PF_KTHREAD)
|
||||
continue;
|
||||
|
||||
__cpumask_set_cpu(cpu, tmpmask);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
preempt_disable();
|
||||
smp_call_function_many(tmpmask, ipi_mb, NULL, 1);
|
||||
preempt_enable();
|
||||
|
||||
free_cpumask_var(tmpmask);
|
||||
cpus_read_unlock();
|
||||
|
||||
/*
|
||||
|
|
@ -101,22 +132,22 @@ static int membarrier_global_expedited(void)
|
|||
static int membarrier_private_expedited(int flags)
|
||||
{
|
||||
int cpu;
|
||||
bool fallback = false;
|
||||
cpumask_var_t tmpmask;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
if (flags & MEMBARRIER_FLAG_SYNC_CORE) {
|
||||
if (!IS_ENABLED(CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE))
|
||||
return -EINVAL;
|
||||
if (!(atomic_read(¤t->mm->membarrier_state) &
|
||||
if (!(atomic_read(&mm->membarrier_state) &
|
||||
MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY))
|
||||
return -EPERM;
|
||||
} else {
|
||||
if (!(atomic_read(¤t->mm->membarrier_state) &
|
||||
if (!(atomic_read(&mm->membarrier_state) &
|
||||
MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (num_online_cpus() == 1)
|
||||
if (atomic_read(&mm->mm_users) == 1 || num_online_cpus() == 1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
|
@ -125,17 +156,11 @@ static int membarrier_private_expedited(int flags)
|
|||
*/
|
||||
smp_mb(); /* system call entry is not a mb. */
|
||||
|
||||
/*
|
||||
* Expedited membarrier commands guarantee that they won't
|
||||
* block, hence the GFP_NOWAIT allocation flag and fallback
|
||||
* implementation.
|
||||
*/
|
||||
if (!zalloc_cpumask_var(&tmpmask, GFP_NOWAIT)) {
|
||||
/* Fallback for OOM. */
|
||||
fallback = true;
|
||||
}
|
||||
if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
cpus_read_lock();
|
||||
rcu_read_lock();
|
||||
for_each_online_cpu(cpu) {
|
||||
struct task_struct *p;
|
||||
|
||||
|
|
@ -150,21 +175,17 @@ static int membarrier_private_expedited(int flags)
|
|||
if (cpu == raw_smp_processor_id())
|
||||
continue;
|
||||
rcu_read_lock();
|
||||
p = task_rcu_dereference(&cpu_rq(cpu)->curr);
|
||||
if (p && p->mm == current->mm) {
|
||||
if (!fallback)
|
||||
__cpumask_set_cpu(cpu, tmpmask);
|
||||
else
|
||||
smp_call_function_single(cpu, ipi_mb, NULL, 1);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
if (!fallback) {
|
||||
preempt_disable();
|
||||
smp_call_function_many(tmpmask, ipi_mb, NULL, 1);
|
||||
preempt_enable();
|
||||
free_cpumask_var(tmpmask);
|
||||
p = rcu_dereference(cpu_rq(cpu)->curr);
|
||||
if (p && p->mm == mm)
|
||||
__cpumask_set_cpu(cpu, tmpmask);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
preempt_disable();
|
||||
smp_call_function_many(tmpmask, ipi_mb, NULL, 1);
|
||||
preempt_enable();
|
||||
|
||||
free_cpumask_var(tmpmask);
|
||||
cpus_read_unlock();
|
||||
|
||||
/*
|
||||
|
|
@ -177,32 +198,78 @@ static int membarrier_private_expedited(int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sync_runqueues_membarrier_state(struct mm_struct *mm)
|
||||
{
|
||||
int membarrier_state = atomic_read(&mm->membarrier_state);
|
||||
cpumask_var_t tmpmask;
|
||||
int cpu;
|
||||
|
||||
if (atomic_read(&mm->mm_users) == 1 || num_online_cpus() == 1) {
|
||||
this_cpu_write(runqueues.membarrier_state, membarrier_state);
|
||||
|
||||
/*
|
||||
* For single mm user, we can simply issue a memory barrier
|
||||
* after setting MEMBARRIER_STATE_GLOBAL_EXPEDITED in the
|
||||
* mm and in the current runqueue to guarantee that no memory
|
||||
* access following registration is reordered before
|
||||
* registration.
|
||||
*/
|
||||
smp_mb();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* For mm with multiple users, we need to ensure all future
|
||||
* scheduler executions will observe @mm's new membarrier
|
||||
* state.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
|
||||
/*
|
||||
* For each cpu runqueue, if the task's mm match @mm, ensure that all
|
||||
* @mm's membarrier state set bits are also set in in the runqueue's
|
||||
* membarrier state. This ensures that a runqueue scheduling
|
||||
* between threads which are users of @mm has its membarrier state
|
||||
* updated.
|
||||
*/
|
||||
cpus_read_lock();
|
||||
rcu_read_lock();
|
||||
for_each_online_cpu(cpu) {
|
||||
struct rq *rq = cpu_rq(cpu);
|
||||
struct task_struct *p;
|
||||
|
||||
p = rcu_dereference(rq->curr);
|
||||
if (p && p->mm == mm)
|
||||
__cpumask_set_cpu(cpu, tmpmask);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
preempt_disable();
|
||||
smp_call_function_many(tmpmask, ipi_sync_rq_state, mm, 1);
|
||||
preempt_enable();
|
||||
|
||||
free_cpumask_var(tmpmask);
|
||||
cpus_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int membarrier_register_global_expedited(void)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
struct mm_struct *mm = p->mm;
|
||||
int ret;
|
||||
|
||||
if (atomic_read(&mm->membarrier_state) &
|
||||
MEMBARRIER_STATE_GLOBAL_EXPEDITED_READY)
|
||||
return 0;
|
||||
atomic_or(MEMBARRIER_STATE_GLOBAL_EXPEDITED, &mm->membarrier_state);
|
||||
if (atomic_read(&mm->mm_users) == 1 && get_nr_threads(p) == 1) {
|
||||
/*
|
||||
* For single mm user, single threaded process, we can
|
||||
* simply issue a memory barrier after setting
|
||||
* MEMBARRIER_STATE_GLOBAL_EXPEDITED to guarantee that
|
||||
* no memory access following registration is reordered
|
||||
* before registration.
|
||||
*/
|
||||
smp_mb();
|
||||
} else {
|
||||
/*
|
||||
* For multi-mm user threads, we need to ensure all
|
||||
* future scheduler executions will observe the new
|
||||
* thread flag state for this mm.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
}
|
||||
ret = sync_runqueues_membarrier_state(mm);
|
||||
if (ret)
|
||||
return ret;
|
||||
atomic_or(MEMBARRIER_STATE_GLOBAL_EXPEDITED_READY,
|
||||
&mm->membarrier_state);
|
||||
|
||||
|
|
@ -213,12 +280,15 @@ static int membarrier_register_private_expedited(int flags)
|
|||
{
|
||||
struct task_struct *p = current;
|
||||
struct mm_struct *mm = p->mm;
|
||||
int state = MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY;
|
||||
int ready_state = MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY,
|
||||
set_state = MEMBARRIER_STATE_PRIVATE_EXPEDITED,
|
||||
ret;
|
||||
|
||||
if (flags & MEMBARRIER_FLAG_SYNC_CORE) {
|
||||
if (!IS_ENABLED(CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE))
|
||||
return -EINVAL;
|
||||
state = MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY;
|
||||
ready_state =
|
||||
MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -226,20 +296,15 @@ static int membarrier_register_private_expedited(int flags)
|
|||
* groups, which use the same mm. (CLONE_VM but not
|
||||
* CLONE_THREAD).
|
||||
*/
|
||||
if (atomic_read(&mm->membarrier_state) & state)
|
||||
if ((atomic_read(&mm->membarrier_state) & ready_state) == ready_state)
|
||||
return 0;
|
||||
atomic_or(MEMBARRIER_STATE_PRIVATE_EXPEDITED, &mm->membarrier_state);
|
||||
if (flags & MEMBARRIER_FLAG_SYNC_CORE)
|
||||
atomic_or(MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE,
|
||||
&mm->membarrier_state);
|
||||
if (!(atomic_read(&mm->mm_users) == 1 && get_nr_threads(p) == 1)) {
|
||||
/*
|
||||
* Ensure all future scheduler executions will observe the
|
||||
* new thread flag state for this process.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
}
|
||||
atomic_or(state, &mm->membarrier_state);
|
||||
set_state |= MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE;
|
||||
atomic_or(set_state, &mm->membarrier_state);
|
||||
ret = sync_runqueues_membarrier_state(mm);
|
||||
if (ret)
|
||||
return ret;
|
||||
atomic_or(ready_state, &mm->membarrier_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -253,8 +318,10 @@ static int membarrier_register_private_expedited(int flags)
|
|||
* command specified does not exist, not available on the running
|
||||
* kernel, or if the command argument is invalid, this system call
|
||||
* returns -EINVAL. For a given command, with flags argument set to 0,
|
||||
* this system call is guaranteed to always return the same value until
|
||||
* reboot.
|
||||
* if this system call returns -ENOSYS or -EINVAL, it is guaranteed to
|
||||
* always return the same value until reboot. In addition, it can return
|
||||
* -ENOMEM if there is not enough memory available to perform the system
|
||||
* call.
|
||||
*
|
||||
* All memory accesses performed in program order from each targeted thread
|
||||
* is guaranteed to be ordered with respect to sys_membarrier(). If we use
|
||||
|
|
|
|||
|
|
@ -911,6 +911,10 @@ struct rq {
|
|||
|
||||
atomic_t nr_iowait;
|
||||
|
||||
#ifdef CONFIG_MEMBARRIER
|
||||
int membarrier_state;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
struct root_domain *rd;
|
||||
struct sched_domain __rcu *sd;
|
||||
|
|
@ -2438,3 +2442,33 @@ static inline bool sched_energy_enabled(void)
|
|||
static inline bool sched_energy_enabled(void) { return false; }
|
||||
|
||||
#endif /* CONFIG_ENERGY_MODEL && CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
|
||||
|
||||
#ifdef CONFIG_MEMBARRIER
|
||||
/*
|
||||
* The scheduler provides memory barriers required by membarrier between:
|
||||
* - prior user-space memory accesses and store to rq->membarrier_state,
|
||||
* - store to rq->membarrier_state and following user-space memory accesses.
|
||||
* In the same way it provides those guarantees around store to rq->curr.
|
||||
*/
|
||||
static inline void membarrier_switch_mm(struct rq *rq,
|
||||
struct mm_struct *prev_mm,
|
||||
struct mm_struct *next_mm)
|
||||
{
|
||||
int membarrier_state;
|
||||
|
||||
if (prev_mm == next_mm)
|
||||
return;
|
||||
|
||||
membarrier_state = atomic_read(&next_mm->membarrier_state);
|
||||
if (READ_ONCE(rq->membarrier_state) == membarrier_state)
|
||||
return;
|
||||
|
||||
WRITE_ONCE(rq->membarrier_state, membarrier_state);
|
||||
}
|
||||
#else
|
||||
static inline void membarrier_switch_mm(struct rq *rq,
|
||||
struct mm_struct *prev_mm,
|
||||
struct mm_struct *next_mm)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -142,8 +142,13 @@ BPF_CALL_3(bpf_probe_read, void *, dst, u32, size, const void *, unsafe_ptr)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = security_locked_down(LOCKDOWN_BPF_READ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = probe_kernel_read(dst, unsafe_ptr, size);
|
||||
if (unlikely(ret < 0))
|
||||
out:
|
||||
memset(dst, 0, size);
|
||||
|
||||
return ret;
|
||||
|
|
@ -500,14 +505,17 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {
|
|||
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct pt_regs, bpf_pt_regs);
|
||||
static DEFINE_PER_CPU(struct perf_sample_data, bpf_misc_sd);
|
||||
static DEFINE_PER_CPU(int, bpf_event_output_nest_level);
|
||||
struct bpf_nested_pt_regs {
|
||||
struct pt_regs regs[3];
|
||||
};
|
||||
static DEFINE_PER_CPU(struct bpf_nested_pt_regs, bpf_pt_regs);
|
||||
static DEFINE_PER_CPU(struct bpf_trace_sample_data, bpf_misc_sds);
|
||||
|
||||
u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
|
||||
void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy)
|
||||
{
|
||||
struct perf_sample_data *sd = this_cpu_ptr(&bpf_misc_sd);
|
||||
struct pt_regs *regs = this_cpu_ptr(&bpf_pt_regs);
|
||||
int nest_level = this_cpu_inc_return(bpf_event_output_nest_level);
|
||||
struct perf_raw_frag frag = {
|
||||
.copy = ctx_copy,
|
||||
.size = ctx_size,
|
||||
|
|
@ -522,12 +530,25 @@ u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
|
|||
.data = meta,
|
||||
},
|
||||
};
|
||||
struct perf_sample_data *sd;
|
||||
struct pt_regs *regs;
|
||||
u64 ret;
|
||||
|
||||
if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(bpf_misc_sds.sds))) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
sd = this_cpu_ptr(&bpf_misc_sds.sds[nest_level - 1]);
|
||||
regs = this_cpu_ptr(&bpf_pt_regs.regs[nest_level - 1]);
|
||||
|
||||
perf_fetch_caller_regs(regs);
|
||||
perf_sample_data_init(sd, 0, 0);
|
||||
sd->raw = &raw;
|
||||
|
||||
return __bpf_perf_event_output(regs, map, flags, sd);
|
||||
ret = __bpf_perf_event_output(regs, map, flags, sd);
|
||||
out:
|
||||
this_cpu_dec(bpf_event_output_nest_level);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BPF_CALL_0(bpf_get_current_task)
|
||||
|
|
@ -569,6 +590,10 @@ BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = security_locked_down(LOCKDOWN_BPF_READ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* The strncpy_from_unsafe() call will likely not fill the entire
|
||||
* buffer, but that's okay in this circumstance as we're probing
|
||||
|
|
@ -580,6 +605,7 @@ BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size,
|
|||
*/
|
||||
ret = strncpy_from_unsafe(dst, unsafe_ptr, size);
|
||||
if (unlikely(ret < 0))
|
||||
out:
|
||||
memset(dst, 0, size);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -365,11 +365,11 @@ static inline struct trace_array *top_trace_array(void)
|
|||
__builtin_types_compatible_p(typeof(var), type *)
|
||||
|
||||
#undef IF_ASSIGN
|
||||
#define IF_ASSIGN(var, entry, etype, id) \
|
||||
if (FTRACE_CMP_TYPE(var, etype)) { \
|
||||
var = (typeof(var))(entry); \
|
||||
WARN_ON(id && (entry)->type != id); \
|
||||
break; \
|
||||
#define IF_ASSIGN(var, entry, etype, id) \
|
||||
if (FTRACE_CMP_TYPE(var, etype)) { \
|
||||
var = (typeof(var))(entry); \
|
||||
WARN_ON(id != 0 && (entry)->type != id); \
|
||||
break; \
|
||||
}
|
||||
|
||||
/* Will cause compile errors if type is not found. */
|
||||
|
|
|
|||
|
|
@ -452,8 +452,10 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
|
|||
|
||||
switch (*next) {
|
||||
case '(': /* #2 */
|
||||
if (top - op_stack > nr_parens)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (top - op_stack > nr_parens) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
*(++top) = invert;
|
||||
continue;
|
||||
case '!': /* #3 */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/error-injection.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
|
||||
|
||||
|
|
@ -460,6 +461,10 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
|
|||
{
|
||||
int i, ret;
|
||||
|
||||
ret = security_locked_down(LOCKDOWN_KPROBES);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (trace_kprobe_is_registered(tk))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -178,6 +178,16 @@ void __trace_probe_log_err(int offset, int err_type)
|
|||
if (!command)
|
||||
return;
|
||||
|
||||
if (trace_probe_log.index >= trace_probe_log.argc) {
|
||||
/**
|
||||
* Set the error position is next to the last arg + space.
|
||||
* Note that len includes the terminal null and the cursor
|
||||
* appaers at pos + 1.
|
||||
*/
|
||||
pos = len;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/* And make a command string from argv array */
|
||||
p = command;
|
||||
for (i = 0; i < trace_probe_log.argc; i++) {
|
||||
|
|
@ -1084,6 +1094,12 @@ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)
|
|||
{
|
||||
int i;
|
||||
|
||||
/* In case of more arguments */
|
||||
if (a->nr_args < b->nr_args)
|
||||
return a->nr_args + 1;
|
||||
if (a->nr_args > b->nr_args)
|
||||
return b->nr_args + 1;
|
||||
|
||||
for (i = 0; i < a->nr_args; i++) {
|
||||
if ((b->nr_args <= i) ||
|
||||
((a->args[i].type != b->args[i].type) ||
|
||||
|
|
|
|||
Loading…
Reference in a new issue