Linux 3.13-rc4
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQEcBAABAgAGBQJSrhGrAAoJEHm+PkMAQRiGsNoH/jIK3CsQ2lbW7yRLXmfgtbzz i2Kep6D4SDvmaLpLYOVC8xNYTiE8jtTbSXHomwP5wMZ63MQDhBfnEWsEWqeZ9+D9 3Q46p0QWuoBgYu2VGkoxTfygkT6hhSpwWIi3SeImbY4fg57OHiUil/+YGhORM4Qc K4549OCTY3sIrgmWL77gzqjRUo+pQ4C73NKqZ3+5nlOmYBZC1yugk8mFwEpQkwhK 4NRNU760Fo+XIht/bINqRiPMddzC15p0mxvJy3cDW8bZa1tFSS9SB7AQUULBbcHL +2dFlFOEb5SV1sNiNPrJ0W+h2qUh2e7kPB0F8epaBppgbwVdyQoC2u4uuLV2ZN0= =lI2r -----END PGP SIGNATURE----- Merge tag 'v3.13-rc4' into core/locking Merge Linux 3.13-rc4, to refresh this rather old tree with the latest fixes. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
bb799d3b98
1709 changed files with 30339 additions and 14394 deletions
1
kernel/.gitignore
vendored
1
kernel/.gitignore
vendored
|
|
@ -5,3 +5,4 @@ config_data.h
|
|||
config_data.gz
|
||||
timeconst.h
|
||||
hz.bc
|
||||
x509_certificate_list
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ ifneq ($(CONFIG_SMP),y)
|
|||
obj-y += up.o
|
||||
endif
|
||||
obj-$(CONFIG_UID16) += uid16.o
|
||||
obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o
|
||||
obj-$(CONFIG_MODULE_SIG) += module_signing.o
|
||||
obj-$(CONFIG_KALLSYMS) += kallsyms.o
|
||||
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
|
||||
obj-$(CONFIG_KEXEC) += kexec.o
|
||||
|
|
@ -122,19 +123,52 @@ targets += timeconst.h
|
|||
$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
|
||||
$(call if_changed,bc)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Roll all the X.509 certificates that we can find together and pull them into
|
||||
# the kernel so that they get loaded into the system trusted keyring during
|
||||
# boot.
|
||||
#
|
||||
# We look in the source root and the build root for all files whose name ends
|
||||
# in ".x509". Unfortunately, this will generate duplicate filenames, so we
|
||||
# have make canonicalise the pathnames and then sort them to discard the
|
||||
# duplicates.
|
||||
#
|
||||
###############################################################################
|
||||
ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
|
||||
X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
|
||||
X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
|
||||
X509_CERTIFICATES := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \
|
||||
$(or $(realpath $(CERT)),$(CERT))))
|
||||
|
||||
ifeq ($(X509_CERTIFICATES),)
|
||||
$(warning *** No X.509 certificates found ***)
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard $(obj)/.x509.list),)
|
||||
ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES))
|
||||
$(info X.509 certificate list changed)
|
||||
$(shell rm $(obj)/.x509.list)
|
||||
endif
|
||||
endif
|
||||
|
||||
kernel/system_certificates.o: $(obj)/x509_certificate_list
|
||||
|
||||
quiet_cmd_x509certs = CERTS $@
|
||||
cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)")
|
||||
|
||||
targets += $(obj)/x509_certificate_list
|
||||
$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
|
||||
$(call if_changed,x509certs)
|
||||
|
||||
targets += $(obj)/.x509.list
|
||||
$(obj)/.x509.list:
|
||||
@echo $(X509_CERTIFICATES) >$@
|
||||
|
||||
clean-files := x509_certificate_list .x509.list
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MODULE_SIG),y)
|
||||
#
|
||||
# Pull the signing certificate and any extra certificates into the kernel
|
||||
#
|
||||
|
||||
quiet_cmd_touch = TOUCH $@
|
||||
cmd_touch = touch $@
|
||||
|
||||
extra_certificates:
|
||||
$(call cmd,touch)
|
||||
|
||||
kernel/modsign_certificate.o: signing_key.x509 extra_certificates
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# If module signing is requested, say by allyesconfig, but a key has not been
|
||||
|
|
|
|||
153
kernel/audit.c
153
kernel/audit.c
|
|
@ -60,7 +60,6 @@
|
|||
#ifdef CONFIG_SECURITY
|
||||
#include <linux/security.h>
|
||||
#endif
|
||||
#include <net/netlink.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
|
|
@ -140,6 +139,17 @@ static struct task_struct *kauditd_task;
|
|||
static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
|
||||
|
||||
static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION,
|
||||
.mask = -1,
|
||||
.features = 0,
|
||||
.lock = 0,};
|
||||
|
||||
static char *audit_feature_names[2] = {
|
||||
"only_unset_loginuid",
|
||||
"loginuid_immutable",
|
||||
};
|
||||
|
||||
|
||||
/* Serialize requests from userspace. */
|
||||
DEFINE_MUTEX(audit_cmd_mutex);
|
||||
|
||||
|
|
@ -584,6 +594,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
|
|||
return -EOPNOTSUPP;
|
||||
case AUDIT_GET:
|
||||
case AUDIT_SET:
|
||||
case AUDIT_GET_FEATURE:
|
||||
case AUDIT_SET_FEATURE:
|
||||
case AUDIT_LIST_RULES:
|
||||
case AUDIT_ADD_RULE:
|
||||
case AUDIT_DEL_RULE:
|
||||
|
|
@ -613,7 +625,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
|||
int rc = 0;
|
||||
uid_t uid = from_kuid(&init_user_ns, current_uid());
|
||||
|
||||
if (!audit_enabled) {
|
||||
if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
|
||||
*ab = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -628,6 +640,94 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int is_audit_feature_set(int i)
|
||||
{
|
||||
return af.features & AUDIT_FEATURE_TO_MASK(i);
|
||||
}
|
||||
|
||||
|
||||
static int audit_get_feature(struct sk_buff *skb)
|
||||
{
|
||||
u32 seq;
|
||||
|
||||
seq = nlmsg_hdr(skb)->nlmsg_seq;
|
||||
|
||||
audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
|
||||
&af, sizeof(af));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature,
|
||||
u32 old_lock, u32 new_lock, int res)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
|
||||
audit_log_format(ab, "feature=%s new=%d old=%d old_lock=%d new_lock=%d res=%d",
|
||||
audit_feature_names[which], !!old_feature, !!new_feature,
|
||||
!!old_lock, !!new_lock, res);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
static int audit_set_feature(struct sk_buff *skb)
|
||||
{
|
||||
struct audit_features *uaf;
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > sizeof(audit_feature_names)/sizeof(audit_feature_names[0]));
|
||||
uaf = nlmsg_data(nlmsg_hdr(skb));
|
||||
|
||||
/* if there is ever a version 2 we should handle that here */
|
||||
|
||||
for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
|
||||
u32 feature = AUDIT_FEATURE_TO_MASK(i);
|
||||
u32 old_feature, new_feature, old_lock, new_lock;
|
||||
|
||||
/* if we are not changing this feature, move along */
|
||||
if (!(feature & uaf->mask))
|
||||
continue;
|
||||
|
||||
old_feature = af.features & feature;
|
||||
new_feature = uaf->features & feature;
|
||||
new_lock = (uaf->lock | af.lock) & feature;
|
||||
old_lock = af.lock & feature;
|
||||
|
||||
/* are we changing a locked feature? */
|
||||
if ((af.lock & feature) && (new_feature != old_feature)) {
|
||||
audit_log_feature_change(i, old_feature, new_feature,
|
||||
old_lock, new_lock, 0);
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
/* nothing invalid, do the changes */
|
||||
for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
|
||||
u32 feature = AUDIT_FEATURE_TO_MASK(i);
|
||||
u32 old_feature, new_feature, old_lock, new_lock;
|
||||
|
||||
/* if we are not changing this feature, move along */
|
||||
if (!(feature & uaf->mask))
|
||||
continue;
|
||||
|
||||
old_feature = af.features & feature;
|
||||
new_feature = uaf->features & feature;
|
||||
old_lock = af.lock & feature;
|
||||
new_lock = (uaf->lock | af.lock) & feature;
|
||||
|
||||
if (new_feature != old_feature)
|
||||
audit_log_feature_change(i, old_feature, new_feature,
|
||||
old_lock, new_lock, 1);
|
||||
|
||||
if (new_feature)
|
||||
af.features |= feature;
|
||||
else
|
||||
af.features &= ~feature;
|
||||
af.lock |= new_lock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
{
|
||||
u32 seq;
|
||||
|
|
@ -659,6 +759,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
|
||||
switch (msg_type) {
|
||||
case AUDIT_GET:
|
||||
memset(&status_set, 0, sizeof(status_set));
|
||||
status_set.enabled = audit_enabled;
|
||||
status_set.failure = audit_failure;
|
||||
status_set.pid = audit_pid;
|
||||
|
|
@ -670,7 +771,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
&status_set, sizeof(status_set));
|
||||
break;
|
||||
case AUDIT_SET:
|
||||
if (nlh->nlmsg_len < sizeof(struct audit_status))
|
||||
if (nlmsg_len(nlh) < sizeof(struct audit_status))
|
||||
return -EINVAL;
|
||||
status_get = (struct audit_status *)data;
|
||||
if (status_get->mask & AUDIT_STATUS_ENABLED) {
|
||||
|
|
@ -699,6 +800,16 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
|
||||
err = audit_set_backlog_limit(status_get->backlog_limit);
|
||||
break;
|
||||
case AUDIT_GET_FEATURE:
|
||||
err = audit_get_feature(skb);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case AUDIT_SET_FEATURE:
|
||||
err = audit_set_feature(skb);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case AUDIT_USER:
|
||||
case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
|
||||
case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
|
||||
|
|
@ -715,7 +826,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
}
|
||||
audit_log_common_recv_msg(&ab, msg_type);
|
||||
if (msg_type != AUDIT_USER_TTY)
|
||||
audit_log_format(ab, " msg='%.1024s'",
|
||||
audit_log_format(ab, " msg='%.*s'",
|
||||
AUDIT_MESSAGE_TEXT_MAX,
|
||||
(char *)data);
|
||||
else {
|
||||
int size;
|
||||
|
|
@ -818,7 +930,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
struct task_struct *tsk = current;
|
||||
|
||||
spin_lock(&tsk->sighand->siglock);
|
||||
s.enabled = tsk->signal->audit_tty != 0;
|
||||
s.enabled = tsk->signal->audit_tty;
|
||||
s.log_passwd = tsk->signal->audit_tty_log_passwd;
|
||||
spin_unlock(&tsk->sighand->siglock);
|
||||
|
||||
|
|
@ -832,7 +944,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
|
||||
memset(&s, 0, sizeof(s));
|
||||
/* guard against past and future API changes */
|
||||
memcpy(&s, data, min(sizeof(s), (size_t)nlh->nlmsg_len));
|
||||
memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
|
||||
if ((s.enabled != 0 && s.enabled != 1) ||
|
||||
(s.log_passwd != 0 && s.log_passwd != 1))
|
||||
return -EINVAL;
|
||||
|
|
@ -1067,13 +1179,6 @@ static void wait_for_auditd(unsigned long sleep_time)
|
|||
remove_wait_queue(&audit_backlog_wait, &wait);
|
||||
}
|
||||
|
||||
/* Obtain an audit buffer. This routine does locking to obtain the
|
||||
* audit buffer, but then no locking is required for calls to
|
||||
* audit_log_*format. If the tsk is a task that is currently in a
|
||||
* syscall, then the syscall is marked as auditable and an audit record
|
||||
* will be written at syscall exit. If there is no associated task, tsk
|
||||
* should be NULL. */
|
||||
|
||||
/**
|
||||
* audit_log_start - obtain an audit buffer
|
||||
* @ctx: audit_context (may be NULL)
|
||||
|
|
@ -1389,7 +1494,7 @@ void audit_log_session_info(struct audit_buffer *ab)
|
|||
u32 sessionid = audit_get_sessionid(current);
|
||||
uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
|
||||
|
||||
audit_log_format(ab, " auid=%u ses=%u\n", auid, sessionid);
|
||||
audit_log_format(ab, " auid=%u ses=%u", auid, sessionid);
|
||||
}
|
||||
|
||||
void audit_log_key(struct audit_buffer *ab, char *key)
|
||||
|
|
@ -1536,6 +1641,26 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
|
|||
}
|
||||
}
|
||||
|
||||
/* log the audit_names record type */
|
||||
audit_log_format(ab, " nametype=");
|
||||
switch(n->type) {
|
||||
case AUDIT_TYPE_NORMAL:
|
||||
audit_log_format(ab, "NORMAL");
|
||||
break;
|
||||
case AUDIT_TYPE_PARENT:
|
||||
audit_log_format(ab, "PARENT");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_DELETE:
|
||||
audit_log_format(ab, "DELETE");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_CREATE:
|
||||
audit_log_format(ab, "CREATE");
|
||||
break;
|
||||
default:
|
||||
audit_log_format(ab, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
|
||||
audit_log_fcaps(ab, n);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,6 +197,9 @@ struct audit_context {
|
|||
int fd;
|
||||
int flags;
|
||||
} mmap;
|
||||
struct {
|
||||
int argc;
|
||||
} execve;
|
||||
};
|
||||
int fds[2];
|
||||
|
||||
|
|
|
|||
|
|
@ -343,6 +343,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
|
|||
case AUDIT_DEVMINOR:
|
||||
case AUDIT_EXIT:
|
||||
case AUDIT_SUCCESS:
|
||||
case AUDIT_INODE:
|
||||
/* bit ops are only useful on syscall args */
|
||||
if (f->op == Audit_bitmask || f->op == Audit_bittest)
|
||||
return -EINVAL;
|
||||
|
|
@ -423,7 +424,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
|
|||
f->lsm_rule = NULL;
|
||||
|
||||
/* Support legacy tests for a valid loginuid */
|
||||
if ((f->type == AUDIT_LOGINUID) && (f->val == ~0U)) {
|
||||
if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
|
||||
f->type = AUDIT_LOGINUID_SET;
|
||||
f->val = 0;
|
||||
}
|
||||
|
|
|
|||
133
kernel/auditsc.c
133
kernel/auditsc.c
|
|
@ -95,13 +95,6 @@ struct audit_aux_data {
|
|||
/* Number of target pids per aux struct. */
|
||||
#define AUDIT_AUX_PIDS 16
|
||||
|
||||
struct audit_aux_data_execve {
|
||||
struct audit_aux_data d;
|
||||
int argc;
|
||||
int envc;
|
||||
struct mm_struct *mm;
|
||||
};
|
||||
|
||||
struct audit_aux_data_pids {
|
||||
struct audit_aux_data d;
|
||||
pid_t target_pid[AUDIT_AUX_PIDS];
|
||||
|
|
@ -121,12 +114,6 @@ struct audit_aux_data_bprm_fcaps {
|
|||
struct audit_cap_data new_pcap;
|
||||
};
|
||||
|
||||
struct audit_aux_data_capset {
|
||||
struct audit_aux_data d;
|
||||
pid_t pid;
|
||||
struct audit_cap_data cap;
|
||||
};
|
||||
|
||||
struct audit_tree_refs {
|
||||
struct audit_tree_refs *next;
|
||||
struct audit_chunk *c[31];
|
||||
|
|
@ -566,7 +553,7 @@ static int audit_filter_rules(struct task_struct *tsk,
|
|||
break;
|
||||
case AUDIT_INODE:
|
||||
if (name)
|
||||
result = (name->ino == f->val);
|
||||
result = audit_comparator(name->ino, f->op, f->val);
|
||||
else if (ctx) {
|
||||
list_for_each_entry(n, &ctx->names_list, list) {
|
||||
if (audit_comparator(n->ino, f->op, f->val)) {
|
||||
|
|
@ -943,8 +930,10 @@ int audit_alloc(struct task_struct *tsk)
|
|||
return 0; /* Return if not auditing. */
|
||||
|
||||
state = audit_filter_task(tsk, &key);
|
||||
if (state == AUDIT_DISABLED)
|
||||
if (state == AUDIT_DISABLED) {
|
||||
clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(context = audit_alloc_context(state))) {
|
||||
kfree(key);
|
||||
|
|
@ -1149,20 +1138,16 @@ static int audit_log_single_execve_arg(struct audit_context *context,
|
|||
}
|
||||
|
||||
static void audit_log_execve_info(struct audit_context *context,
|
||||
struct audit_buffer **ab,
|
||||
struct audit_aux_data_execve *axi)
|
||||
struct audit_buffer **ab)
|
||||
{
|
||||
int i, len;
|
||||
size_t len_sent = 0;
|
||||
const char __user *p;
|
||||
char *buf;
|
||||
|
||||
if (axi->mm != current->mm)
|
||||
return; /* execve failed, no additional info */
|
||||
p = (const char __user *)current->mm->arg_start;
|
||||
|
||||
p = (const char __user *)axi->mm->arg_start;
|
||||
|
||||
audit_log_format(*ab, "argc=%d", axi->argc);
|
||||
audit_log_format(*ab, "argc=%d", context->execve.argc);
|
||||
|
||||
/*
|
||||
* we need some kernel buffer to hold the userspace args. Just
|
||||
|
|
@ -1176,7 +1161,7 @@ static void audit_log_execve_info(struct audit_context *context,
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < axi->argc; i++) {
|
||||
for (i = 0; i < context->execve.argc; i++) {
|
||||
len = audit_log_single_execve_arg(context, ab, i,
|
||||
&len_sent, p, buf);
|
||||
if (len <= 0)
|
||||
|
|
@ -1279,6 +1264,9 @@ static void show_special(struct audit_context *context, int *call_panic)
|
|||
audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
|
||||
context->mmap.flags);
|
||||
break; }
|
||||
case AUDIT_EXECVE: {
|
||||
audit_log_execve_info(context, &ab);
|
||||
break; }
|
||||
}
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
|
@ -1325,11 +1313,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
|
|||
|
||||
switch (aux->type) {
|
||||
|
||||
case AUDIT_EXECVE: {
|
||||
struct audit_aux_data_execve *axi = (void *)aux;
|
||||
audit_log_execve_info(context, &ab, axi);
|
||||
break; }
|
||||
|
||||
case AUDIT_BPRM_FCAPS: {
|
||||
struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
|
||||
audit_log_format(ab, "fver=%x", axs->fcap_ver);
|
||||
|
|
@ -1964,6 +1947,43 @@ int auditsc_get_stamp(struct audit_context *ctx,
|
|||
/* global counter which is incremented every time something logs in */
|
||||
static atomic_t session_id = ATOMIC_INIT(0);
|
||||
|
||||
static int audit_set_loginuid_perm(kuid_t loginuid)
|
||||
{
|
||||
/* if we are unset, we don't need privs */
|
||||
if (!audit_loginuid_set(current))
|
||||
return 0;
|
||||
/* if AUDIT_FEATURE_LOGINUID_IMMUTABLE means never ever allow a change*/
|
||||
if (is_audit_feature_set(AUDIT_FEATURE_LOGINUID_IMMUTABLE))
|
||||
return -EPERM;
|
||||
/* it is set, you need permission */
|
||||
if (!capable(CAP_AUDIT_CONTROL))
|
||||
return -EPERM;
|
||||
/* reject if this is not an unset and we don't allow that */
|
||||
if (is_audit_feature_set(AUDIT_FEATURE_ONLY_UNSET_LOGINUID) && uid_valid(loginuid))
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
|
||||
unsigned int oldsessionid, unsigned int sessionid,
|
||||
int rc)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
uid_t uid, ologinuid, nloginuid;
|
||||
|
||||
uid = from_kuid(&init_user_ns, task_uid(current));
|
||||
ologinuid = from_kuid(&init_user_ns, koldloginuid);
|
||||
nloginuid = from_kuid(&init_user_ns, kloginuid),
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
|
||||
if (!ab)
|
||||
return;
|
||||
audit_log_format(ab, "pid=%d uid=%u old auid=%u new auid=%u old "
|
||||
"ses=%u new ses=%u res=%d", current->pid, uid, ologinuid,
|
||||
nloginuid, oldsessionid, sessionid, !rc);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_set_loginuid - set current task's audit_context loginuid
|
||||
* @loginuid: loginuid value
|
||||
|
|
@ -1975,37 +1995,26 @@ static atomic_t session_id = ATOMIC_INIT(0);
|
|||
int audit_set_loginuid(kuid_t loginuid)
|
||||
{
|
||||
struct task_struct *task = current;
|
||||
struct audit_context *context = task->audit_context;
|
||||
unsigned int sessionid;
|
||||
unsigned int oldsessionid, sessionid = (unsigned int)-1;
|
||||
kuid_t oldloginuid;
|
||||
int rc;
|
||||
|
||||
#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
|
||||
if (audit_loginuid_set(task))
|
||||
return -EPERM;
|
||||
#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
|
||||
if (!capable(CAP_AUDIT_CONTROL))
|
||||
return -EPERM;
|
||||
#endif /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
|
||||
oldloginuid = audit_get_loginuid(current);
|
||||
oldsessionid = audit_get_sessionid(current);
|
||||
|
||||
sessionid = atomic_inc_return(&session_id);
|
||||
if (context && context->in_syscall) {
|
||||
struct audit_buffer *ab;
|
||||
rc = audit_set_loginuid_perm(loginuid);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* are we setting or clearing? */
|
||||
if (uid_valid(loginuid))
|
||||
sessionid = atomic_inc_return(&session_id);
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
|
||||
if (ab) {
|
||||
audit_log_format(ab, "login pid=%d uid=%u "
|
||||
"old auid=%u new auid=%u"
|
||||
" old ses=%u new ses=%u",
|
||||
task->pid,
|
||||
from_kuid(&init_user_ns, task_uid(task)),
|
||||
from_kuid(&init_user_ns, task->loginuid),
|
||||
from_kuid(&init_user_ns, loginuid),
|
||||
task->sessionid, sessionid);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
}
|
||||
task->sessionid = sessionid;
|
||||
task->loginuid = loginuid;
|
||||
return 0;
|
||||
out:
|
||||
audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2126,22 +2135,12 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo
|
|||
context->ipc.has_perm = 1;
|
||||
}
|
||||
|
||||
int __audit_bprm(struct linux_binprm *bprm)
|
||||
void __audit_bprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct audit_aux_data_execve *ax;
|
||||
struct audit_context *context = current->audit_context;
|
||||
|
||||
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
|
||||
if (!ax)
|
||||
return -ENOMEM;
|
||||
|
||||
ax->argc = bprm->argc;
|
||||
ax->envc = bprm->envc;
|
||||
ax->mm = bprm->mm;
|
||||
ax->d.type = AUDIT_EXECVE;
|
||||
ax->d.next = context->aux;
|
||||
context->aux = (void *)ax;
|
||||
return 0;
|
||||
context->type = AUDIT_EXECVE;
|
||||
context->execve.argc = bprm->argc;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,14 @@ static DEFINE_MUTEX(cgroup_mutex);
|
|||
|
||||
static DEFINE_MUTEX(cgroup_root_mutex);
|
||||
|
||||
/*
|
||||
* cgroup destruction makes heavy use of work items and there can be a lot
|
||||
* of concurrent destructions. Use a separate workqueue so that cgroup
|
||||
* destruction work items don't end up filling up max_active of system_wq
|
||||
* which may lead to deadlock.
|
||||
*/
|
||||
static struct workqueue_struct *cgroup_destroy_wq;
|
||||
|
||||
/*
|
||||
* Generate an array of cgroup subsystem pointers. At boot time, this is
|
||||
* populated with the built in subsystems, and modular subsystems are
|
||||
|
|
@ -191,6 +199,7 @@ static void cgroup_destroy_css_killed(struct cgroup *cgrp);
|
|||
static int cgroup_destroy_locked(struct cgroup *cgrp);
|
||||
static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[],
|
||||
bool is_add);
|
||||
static int cgroup_file_release(struct inode *inode, struct file *file);
|
||||
|
||||
/**
|
||||
* cgroup_css - obtain a cgroup's css for the specified subsystem
|
||||
|
|
@ -871,7 +880,7 @@ static void cgroup_free_rcu(struct rcu_head *head)
|
|||
struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head);
|
||||
|
||||
INIT_WORK(&cgrp->destroy_work, cgroup_free_fn);
|
||||
schedule_work(&cgrp->destroy_work);
|
||||
queue_work(cgroup_destroy_wq, &cgrp->destroy_work);
|
||||
}
|
||||
|
||||
static void cgroup_diput(struct dentry *dentry, struct inode *inode)
|
||||
|
|
@ -895,11 +904,6 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
|
|||
iput(inode);
|
||||
}
|
||||
|
||||
static int cgroup_delete(const struct dentry *d)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void remove_dir(struct dentry *d)
|
||||
{
|
||||
struct dentry *parent = dget(d->d_parent);
|
||||
|
|
@ -1486,7 +1490,7 @@ static int cgroup_get_rootdir(struct super_block *sb)
|
|||
{
|
||||
static const struct dentry_operations cgroup_dops = {
|
||||
.d_iput = cgroup_diput,
|
||||
.d_delete = cgroup_delete,
|
||||
.d_delete = always_delete_dentry,
|
||||
};
|
||||
|
||||
struct inode *inode =
|
||||
|
|
@ -2426,7 +2430,7 @@ static const struct file_operations cgroup_seqfile_operations = {
|
|||
.read = seq_read,
|
||||
.write = cgroup_file_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = cgroup_file_release,
|
||||
};
|
||||
|
||||
static int cgroup_file_open(struct inode *inode, struct file *file)
|
||||
|
|
@ -2487,6 +2491,8 @@ static int cgroup_file_release(struct inode *inode, struct file *file)
|
|||
ret = cft->release(inode, file);
|
||||
if (css->ss)
|
||||
css_put(css);
|
||||
if (file->f_op == &cgroup_seqfile_operations)
|
||||
single_release(inode, file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -4254,7 +4260,7 @@ static void css_free_rcu_fn(struct rcu_head *rcu_head)
|
|||
* css_put(). dput() requires process context which we don't have.
|
||||
*/
|
||||
INIT_WORK(&css->destroy_work, css_free_work_fn);
|
||||
schedule_work(&css->destroy_work);
|
||||
queue_work(cgroup_destroy_wq, &css->destroy_work);
|
||||
}
|
||||
|
||||
static void css_release(struct percpu_ref *ref)
|
||||
|
|
@ -4544,7 +4550,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
|
|||
container_of(ref, struct cgroup_subsys_state, refcnt);
|
||||
|
||||
INIT_WORK(&css->destroy_work, css_killed_work_fn);
|
||||
schedule_work(&css->destroy_work);
|
||||
queue_work(cgroup_destroy_wq, &css->destroy_work);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5068,6 +5074,22 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int __init cgroup_wq_init(void)
|
||||
{
|
||||
/*
|
||||
* There isn't much point in executing destruction path in
|
||||
* parallel. Good chunk is serialized with cgroup_mutex anyway.
|
||||
* Use 1 for @max_active.
|
||||
*
|
||||
* We would prefer to do this in cgroup_init() above, but that
|
||||
* is called before init_workqueues(): so leave this until after.
|
||||
*/
|
||||
cgroup_destroy_wq = alloc_workqueue("cgroup_destroy", 0, 1);
|
||||
BUG_ON(!cgroup_destroy_wq);
|
||||
return 0;
|
||||
}
|
||||
core_initcall(cgroup_wq_init);
|
||||
|
||||
/*
|
||||
* proc_cgroup_show()
|
||||
* - Print task's cgroup paths into seq_file, one line for each hierarchy
|
||||
|
|
|
|||
|
|
@ -1033,8 +1033,10 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
|||
need_loop = task_has_mempolicy(tsk) ||
|
||||
!nodes_intersects(*newmems, tsk->mems_allowed);
|
||||
|
||||
if (need_loop)
|
||||
if (need_loop) {
|
||||
local_irq_disable();
|
||||
write_seqcount_begin(&tsk->mems_allowed_seq);
|
||||
}
|
||||
|
||||
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
|
||||
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
|
||||
|
|
@ -1042,8 +1044,10 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
|||
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2);
|
||||
tsk->mems_allowed = *newmems;
|
||||
|
||||
if (need_loop)
|
||||
if (need_loop) {
|
||||
write_seqcount_end(&tsk->mems_allowed_seq);
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
task_unlock(tsk);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5680,11 +5680,6 @@ static void swevent_hlist_put(struct perf_event *event)
|
|||
{
|
||||
int cpu;
|
||||
|
||||
if (event->cpu != -1) {
|
||||
swevent_hlist_put_cpu(event, event->cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
swevent_hlist_put_cpu(event, cpu);
|
||||
}
|
||||
|
|
@ -5718,9 +5713,6 @@ static int swevent_hlist_get(struct perf_event *event)
|
|||
int err;
|
||||
int cpu, failed_cpu;
|
||||
|
||||
if (event->cpu != -1)
|
||||
return swevent_hlist_get_cpu(event, event->cpu);
|
||||
|
||||
get_online_cpus();
|
||||
for_each_possible_cpu(cpu) {
|
||||
err = swevent_hlist_get_cpu(event, cpu);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr)
|
|||
static inline int init_kernel_text(unsigned long addr)
|
||||
{
|
||||
if (addr >= (unsigned long)_sinittext &&
|
||||
addr <= (unsigned long)_einittext)
|
||||
addr < (unsigned long)_einittext)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ static inline int init_kernel_text(unsigned long addr)
|
|||
int core_kernel_text(unsigned long addr)
|
||||
{
|
||||
if (addr >= (unsigned long)_stext &&
|
||||
addr <= (unsigned long)_etext)
|
||||
addr < (unsigned long)_etext)
|
||||
return 1;
|
||||
|
||||
if (system_state == SYSTEM_BOOTING &&
|
||||
|
|
|
|||
|
|
@ -251,6 +251,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
|
|||
return -EINVAL;
|
||||
address -= key->both.offset;
|
||||
|
||||
if (unlikely(!access_ok(rw, uaddr, sizeof(u32))))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* PROCESS_PRIVATE futexes are fast.
|
||||
* As the mm cannot disappear under us and the 'key' only needs
|
||||
|
|
@ -259,8 +262,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
|
|||
* but access_ok() should be faster than find_vma()
|
||||
*/
|
||||
if (!fshared) {
|
||||
if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
|
||||
return -EFAULT;
|
||||
key->private.mm = mm;
|
||||
key->private.address = address;
|
||||
get_futex_key_refs(key);
|
||||
|
|
@ -288,7 +289,7 @@ again:
|
|||
put_page(page);
|
||||
/* serialize against __split_huge_page_splitting() */
|
||||
local_irq_disable();
|
||||
if (likely(__get_user_pages_fast(address, 1, 1, &page) == 1)) {
|
||||
if (likely(__get_user_pages_fast(address, 1, !ro, &page) == 1)) {
|
||||
page_head = compound_head(page);
|
||||
/*
|
||||
* page_head is valid pointer but we must pin
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ static void resume_irqs(bool want_early)
|
|||
bool is_early = desc->action &&
|
||||
desc->action->flags & IRQF_EARLY_RESUME;
|
||||
|
||||
if (is_early != want_early)
|
||||
if (!is_early && want_early)
|
||||
continue;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
|
|||
size_t vmcoreinfo_size;
|
||||
size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
|
||||
|
||||
/* Flag to indicate we are going to kexec a new kernel */
|
||||
bool kexec_in_progress = false;
|
||||
|
||||
/* Location of the reserved area for the crash kernel */
|
||||
struct resource crashk_res = {
|
||||
.name = "Crash kernel",
|
||||
|
|
@ -1675,6 +1678,7 @@ int kernel_kexec(void)
|
|||
} else
|
||||
#endif
|
||||
{
|
||||
kexec_in_progress = true;
|
||||
kernel_restart_prepare(NULL);
|
||||
printk(KERN_EMERG "Starting new kernel\n");
|
||||
machine_shutdown();
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
#include <linux/export.h>
|
||||
|
||||
#define GLOBAL(name) \
|
||||
.globl VMLINUX_SYMBOL(name); \
|
||||
VMLINUX_SYMBOL(name):
|
||||
|
||||
.section ".init.data","aw"
|
||||
|
||||
GLOBAL(modsign_certificate_list)
|
||||
.incbin "signing_key.x509"
|
||||
.incbin "extra_certificates"
|
||||
GLOBAL(modsign_certificate_list_end)
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/* Public keys for module signature verification
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/err.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
struct key *modsign_keyring;
|
||||
|
||||
extern __initconst const u8 modsign_certificate_list[];
|
||||
extern __initconst const u8 modsign_certificate_list_end[];
|
||||
|
||||
/*
|
||||
* We need to make sure ccache doesn't cache the .o file as it doesn't notice
|
||||
* if modsign.pub changes.
|
||||
*/
|
||||
static __initconst const char annoy_ccache[] = __TIME__ "foo";
|
||||
|
||||
/*
|
||||
* Load the compiled-in keys
|
||||
*/
|
||||
static __init int module_verify_init(void)
|
||||
{
|
||||
pr_notice("Initialise module verification\n");
|
||||
|
||||
modsign_keyring = keyring_alloc(".module_sign",
|
||||
KUIDT_INIT(0), KGIDT_INIT(0),
|
||||
current_cred(),
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ),
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
if (IS_ERR(modsign_keyring))
|
||||
panic("Can't allocate module signing keyring\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be initialised before we try and load the keys into the keyring.
|
||||
*/
|
||||
device_initcall(module_verify_init);
|
||||
|
||||
/*
|
||||
* Load the compiled-in keys
|
||||
*/
|
||||
static __init int load_module_signing_keys(void)
|
||||
{
|
||||
key_ref_t key;
|
||||
const u8 *p, *end;
|
||||
size_t plen;
|
||||
|
||||
pr_notice("Loading module verification certificates\n");
|
||||
|
||||
end = modsign_certificate_list_end;
|
||||
p = modsign_certificate_list;
|
||||
while (p < end) {
|
||||
/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
||||
* than 256 bytes in size.
|
||||
*/
|
||||
if (end - p < 4)
|
||||
goto dodgy_cert;
|
||||
if (p[0] != 0x30 &&
|
||||
p[1] != 0x82)
|
||||
goto dodgy_cert;
|
||||
plen = (p[2] << 8) | p[3];
|
||||
plen += 4;
|
||||
if (plen > end - p)
|
||||
goto dodgy_cert;
|
||||
|
||||
key = key_create_or_update(make_key_ref(modsign_keyring, 1),
|
||||
"asymmetric",
|
||||
NULL,
|
||||
p,
|
||||
plen,
|
||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
if (IS_ERR(key))
|
||||
pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
|
||||
PTR_ERR(key));
|
||||
else
|
||||
pr_notice("MODSIGN: Loaded cert '%s'\n",
|
||||
key_ref_to_ptr(key)->description);
|
||||
p += plen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dodgy_cert:
|
||||
pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
|
||||
return 0;
|
||||
}
|
||||
late_initcall(load_module_signing_keys);
|
||||
|
|
@ -9,6 +9,4 @@
|
|||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
extern struct key *modsign_keyring;
|
||||
|
||||
extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <crypto/public_key.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include <keys/system_keyring.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
/*
|
||||
|
|
@ -28,7 +29,7 @@
|
|||
*/
|
||||
struct module_signature {
|
||||
u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */
|
||||
u8 hash; /* Digest algorithm [enum pkey_hash_algo] */
|
||||
u8 hash; /* Digest algorithm [enum hash_algo] */
|
||||
u8 id_type; /* Key identifier type [enum pkey_id_type] */
|
||||
u8 signer_len; /* Length of signer's name */
|
||||
u8 key_id_len; /* Length of key identifier */
|
||||
|
|
@ -39,7 +40,7 @@ struct module_signature {
|
|||
/*
|
||||
* Digest the module contents.
|
||||
*/
|
||||
static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
|
||||
static struct public_key_signature *mod_make_digest(enum hash_algo hash,
|
||||
const void *mod,
|
||||
unsigned long modlen)
|
||||
{
|
||||
|
|
@ -54,7 +55,7 @@ static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
|
|||
/* Allocate the hashing algorithm we're going to need and find out how
|
||||
* big the hash operational data will be.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0);
|
||||
tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
|
||||
|
||||
|
|
@ -157,7 +158,7 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
|
|||
|
||||
pr_debug("Look up: \"%s\"\n", id);
|
||||
|
||||
key = keyring_search(make_key_ref(modsign_keyring, 1),
|
||||
key = keyring_search(make_key_ref(system_trusted_keyring, 1),
|
||||
&key_type_asymmetric, id);
|
||||
if (IS_ERR(key))
|
||||
pr_warn("Request for unknown module key '%s' err %ld\n",
|
||||
|
|
@ -217,7 +218,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
|
|||
return -ENOPKG;
|
||||
|
||||
if (ms.hash >= PKEY_HASH__LAST ||
|
||||
!pkey_hash_algo[ms.hash])
|
||||
!hash_algo_name[ms.hash])
|
||||
return -ENOPKG;
|
||||
|
||||
key = request_asymmetric_key(sig, ms.signer_len,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
|
|||
|
||||
static int padata_cpu_hash(struct parallel_data *pd)
|
||||
{
|
||||
unsigned int seq_nr;
|
||||
int cpu_index;
|
||||
|
||||
/*
|
||||
|
|
@ -53,10 +54,8 @@ static int padata_cpu_hash(struct parallel_data *pd)
|
|||
* seq_nr mod. number of cpus in use.
|
||||
*/
|
||||
|
||||
spin_lock(&pd->seq_lock);
|
||||
cpu_index = pd->seq_nr % cpumask_weight(pd->cpumask.pcpu);
|
||||
pd->seq_nr++;
|
||||
spin_unlock(&pd->seq_lock);
|
||||
seq_nr = atomic_inc_return(&pd->seq_nr);
|
||||
cpu_index = seq_nr % cpumask_weight(pd->cpumask.pcpu);
|
||||
|
||||
return padata_index_to_cpu(pd, cpu_index);
|
||||
}
|
||||
|
|
@ -429,7 +428,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
|
|||
padata_init_pqueues(pd);
|
||||
padata_init_squeues(pd);
|
||||
setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
|
||||
pd->seq_nr = 0;
|
||||
atomic_set(&pd->seq_nr, -1);
|
||||
atomic_set(&pd->reorder_objects, 0);
|
||||
atomic_set(&pd->refcnt, 0);
|
||||
pd->pinst = pinst;
|
||||
|
|
|
|||
|
|
@ -792,7 +792,8 @@ void free_basic_memory_bitmaps(void)
|
|||
{
|
||||
struct memory_bitmap *bm1, *bm2;
|
||||
|
||||
BUG_ON(!(forbidden_pages_map && free_pages_map));
|
||||
if (WARN_ON(!(forbidden_pages_map && free_pages_map)))
|
||||
return;
|
||||
|
||||
bm1 = forbidden_pages_map;
|
||||
bm2 = free_pages_map;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
|
|||
data->swap = swsusp_resume_device ?
|
||||
swap_type_of(swsusp_resume_device, 0, NULL) : -1;
|
||||
data->mode = O_RDONLY;
|
||||
data->free_bitmaps = false;
|
||||
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
|
||||
if (error)
|
||||
pm_notifier_call_chain(PM_POST_HIBERNATION);
|
||||
|
|
|
|||
|
|
@ -1643,7 +1643,7 @@ module_param(rcu_idle_gp_delay, int, 0644);
|
|||
static int rcu_idle_lazy_gp_delay = RCU_IDLE_LAZY_GP_DELAY;
|
||||
module_param(rcu_idle_lazy_gp_delay, int, 0644);
|
||||
|
||||
extern int tick_nohz_enabled;
|
||||
extern int tick_nohz_active;
|
||||
|
||||
/*
|
||||
* Try to advance callbacks for all flavors of RCU on the current CPU, but
|
||||
|
|
@ -1740,7 +1740,7 @@ static void rcu_prepare_for_idle(int cpu)
|
|||
int tne;
|
||||
|
||||
/* Handle nohz enablement switches conservatively. */
|
||||
tne = ACCESS_ONCE(tick_nohz_enabled);
|
||||
tne = ACCESS_ONCE(tick_nohz_active);
|
||||
if (tne != rdtp->tick_nohz_enabled_snap) {
|
||||
if (rcu_cpu_has_callbacks(cpu, NULL))
|
||||
invoke_rcu_core(); /* force nohz to see update. */
|
||||
|
|
|
|||
|
|
@ -2660,6 +2660,7 @@ asmlinkage void __sched notrace preempt_schedule(void)
|
|||
} while (need_resched());
|
||||
}
|
||||
EXPORT_SYMBOL(preempt_schedule);
|
||||
#endif /* CONFIG_PREEMPT */
|
||||
|
||||
/*
|
||||
* this is the entry point to schedule() from kernel preemption
|
||||
|
|
@ -2693,8 +2694,6 @@ asmlinkage void __sched preempt_schedule_irq(void)
|
|||
exception_exit(prev_state);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PREEMPT */
|
||||
|
||||
int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
|
||||
void *key)
|
||||
{
|
||||
|
|
@ -4762,7 +4761,7 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
|
|||
cpumask_clear_cpu(rq->cpu, old_rd->span);
|
||||
|
||||
/*
|
||||
* If we dont want to free the old_rt yet then
|
||||
* If we dont want to free the old_rd yet then
|
||||
* set old_rd to NULL to skip the freeing later
|
||||
* in this function:
|
||||
*/
|
||||
|
|
@ -4910,8 +4909,9 @@ static void update_top_cache_domain(int cpu)
|
|||
if (sd) {
|
||||
id = cpumask_first(sched_domain_span(sd));
|
||||
size = cpumask_weight(sched_domain_span(sd));
|
||||
rcu_assign_pointer(per_cpu(sd_busy, cpu), sd->parent);
|
||||
sd = sd->parent; /* sd_busy */
|
||||
}
|
||||
rcu_assign_pointer(per_cpu(sd_busy, cpu), sd);
|
||||
|
||||
rcu_assign_pointer(per_cpu(sd_llc, cpu), sd);
|
||||
per_cpu(sd_llc_size, cpu) = size;
|
||||
|
|
|
|||
|
|
@ -5379,10 +5379,31 @@ void update_group_power(struct sched_domain *sd, int cpu)
|
|||
*/
|
||||
|
||||
for_each_cpu(cpu, sched_group_cpus(sdg)) {
|
||||
struct sched_group *sg = cpu_rq(cpu)->sd->groups;
|
||||
struct sched_group_power *sgp;
|
||||
struct rq *rq = cpu_rq(cpu);
|
||||
|
||||
power_orig += sg->sgp->power_orig;
|
||||
power += sg->sgp->power;
|
||||
/*
|
||||
* build_sched_domains() -> init_sched_groups_power()
|
||||
* gets here before we've attached the domains to the
|
||||
* runqueues.
|
||||
*
|
||||
* Use power_of(), which is set irrespective of domains
|
||||
* in update_cpu_power().
|
||||
*
|
||||
* This avoids power/power_orig from being 0 and
|
||||
* causing divide-by-zero issues on boot.
|
||||
*
|
||||
* Runtime updates will correct power_orig.
|
||||
*/
|
||||
if (unlikely(!rq->sd)) {
|
||||
power_orig += power_of(cpu);
|
||||
power += power_of(cpu);
|
||||
continue;
|
||||
}
|
||||
|
||||
sgp = rq->sd->groups->sgp;
|
||||
power_orig += sgp->power_orig;
|
||||
power += sgp->power;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
|
|
|||
20
kernel/system_certificates.S
Normal file
20
kernel/system_certificates.S
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
__INITRODATA
|
||||
|
||||
.align 8
|
||||
.globl VMLINUX_SYMBOL(system_certificate_list)
|
||||
VMLINUX_SYMBOL(system_certificate_list):
|
||||
__cert_list_start:
|
||||
.incbin "kernel/x509_certificate_list"
|
||||
__cert_list_end:
|
||||
|
||||
.align 8
|
||||
.globl VMLINUX_SYMBOL(system_certificate_list_size)
|
||||
VMLINUX_SYMBOL(system_certificate_list_size):
|
||||
#ifdef CONFIG_64BIT
|
||||
.quad __cert_list_end - __cert_list_start
|
||||
#else
|
||||
.long __cert_list_end - __cert_list_start
|
||||
#endif
|
||||
105
kernel/system_keyring.c
Normal file
105
kernel/system_keyring.c
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/* System trusted keyring for trusted public keys
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/err.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include <keys/system_keyring.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
struct key *system_trusted_keyring;
|
||||
EXPORT_SYMBOL_GPL(system_trusted_keyring);
|
||||
|
||||
extern __initconst const u8 system_certificate_list[];
|
||||
extern __initconst const unsigned long system_certificate_list_size;
|
||||
|
||||
/*
|
||||
* Load the compiled-in keys
|
||||
*/
|
||||
static __init int system_trusted_keyring_init(void)
|
||||
{
|
||||
pr_notice("Initialise system trusted keyring\n");
|
||||
|
||||
system_trusted_keyring =
|
||||
keyring_alloc(".system_keyring",
|
||||
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
if (IS_ERR(system_trusted_keyring))
|
||||
panic("Can't allocate system trusted keyring\n");
|
||||
|
||||
set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be initialised before we try and load the keys into the keyring.
|
||||
*/
|
||||
device_initcall(system_trusted_keyring_init);
|
||||
|
||||
/*
|
||||
* Load the compiled-in list of X.509 certificates.
|
||||
*/
|
||||
static __init int load_system_certificate_list(void)
|
||||
{
|
||||
key_ref_t key;
|
||||
const u8 *p, *end;
|
||||
size_t plen;
|
||||
|
||||
pr_notice("Loading compiled-in X.509 certificates\n");
|
||||
|
||||
p = system_certificate_list;
|
||||
end = p + system_certificate_list_size;
|
||||
while (p < end) {
|
||||
/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
||||
* than 256 bytes in size.
|
||||
*/
|
||||
if (end - p < 4)
|
||||
goto dodgy_cert;
|
||||
if (p[0] != 0x30 &&
|
||||
p[1] != 0x82)
|
||||
goto dodgy_cert;
|
||||
plen = (p[2] << 8) | p[3];
|
||||
plen += 4;
|
||||
if (plen > end - p)
|
||||
goto dodgy_cert;
|
||||
|
||||
key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
|
||||
"asymmetric",
|
||||
NULL,
|
||||
p,
|
||||
plen,
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ),
|
||||
KEY_ALLOC_NOT_IN_QUOTA |
|
||||
KEY_ALLOC_TRUSTED);
|
||||
if (IS_ERR(key)) {
|
||||
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
|
||||
PTR_ERR(key));
|
||||
} else {
|
||||
pr_notice("Loaded X.509 cert '%s'\n",
|
||||
key_ref_to_ptr(key)->description);
|
||||
key_ref_put(key);
|
||||
}
|
||||
p += plen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dodgy_cert:
|
||||
pr_err("Problem parsing in-kernel X.509 certificate list\n");
|
||||
return 0;
|
||||
}
|
||||
late_initcall(load_system_certificate_list);
|
||||
|
|
@ -33,6 +33,21 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
|
|||
*/
|
||||
ktime_t tick_next_period;
|
||||
ktime_t tick_period;
|
||||
|
||||
/*
|
||||
* tick_do_timer_cpu is a timer core internal variable which holds the CPU NR
|
||||
* which is responsible for calling do_timer(), i.e. the timekeeping stuff. This
|
||||
* variable has two functions:
|
||||
*
|
||||
* 1) Prevent a thundering herd issue of a gazillion of CPUs trying to grab the
|
||||
* timekeeping lock all at once. Only the CPU which is assigned to do the
|
||||
* update is handling it.
|
||||
*
|
||||
* 2) Hand off the duty in the NOHZ idle case by setting the value to
|
||||
* TICK_DO_TIMER_NONE, i.e. a non existing CPU. So the next cpu which looks
|
||||
* at it will take over and keep the time keeping alive. The handover
|
||||
* procedure also covers cpu hotplug.
|
||||
*/
|
||||
int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -361,8 +361,8 @@ void __init tick_nohz_init(void)
|
|||
/*
|
||||
* NO HZ enabled ?
|
||||
*/
|
||||
int tick_nohz_enabled __read_mostly = 1;
|
||||
|
||||
static int tick_nohz_enabled __read_mostly = 1;
|
||||
int tick_nohz_active __read_mostly;
|
||||
/*
|
||||
* Enable / Disable tickless mode
|
||||
*/
|
||||
|
|
@ -465,7 +465,7 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
|
|||
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
||||
ktime_t now, idle;
|
||||
|
||||
if (!tick_nohz_enabled)
|
||||
if (!tick_nohz_active)
|
||||
return -1;
|
||||
|
||||
now = ktime_get();
|
||||
|
|
@ -506,7 +506,7 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
|
|||
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
|
||||
ktime_t now, iowait;
|
||||
|
||||
if (!tick_nohz_enabled)
|
||||
if (!tick_nohz_active)
|
||||
return -1;
|
||||
|
||||
now = ktime_get();
|
||||
|
|
@ -711,8 +711,10 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
|
||||
if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) {
|
||||
ts->sleep_length = (ktime_t) { .tv64 = NSEC_PER_SEC/HZ };
|
||||
return false;
|
||||
}
|
||||
|
||||
if (need_resched())
|
||||
return false;
|
||||
|
|
@ -799,11 +801,6 @@ void tick_nohz_idle_enter(void)
|
|||
local_irq_disable();
|
||||
|
||||
ts = &__get_cpu_var(tick_cpu_sched);
|
||||
/*
|
||||
* set ts->inidle unconditionally. even if the system did not
|
||||
* switch to nohz mode the cpu frequency governers rely on the
|
||||
* update of the idle time accounting in tick_nohz_start_idle().
|
||||
*/
|
||||
ts->inidle = 1;
|
||||
__tick_nohz_idle_enter(ts);
|
||||
|
||||
|
|
@ -973,7 +970,7 @@ static void tick_nohz_switch_to_nohz(void)
|
|||
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
|
||||
ktime_t next;
|
||||
|
||||
if (!tick_nohz_enabled)
|
||||
if (!tick_nohz_active)
|
||||
return;
|
||||
|
||||
local_irq_disable();
|
||||
|
|
@ -981,7 +978,7 @@ static void tick_nohz_switch_to_nohz(void)
|
|||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
tick_nohz_active = 1;
|
||||
ts->nohz_mode = NOHZ_MODE_LOWRES;
|
||||
|
||||
/*
|
||||
|
|
@ -1139,8 +1136,10 @@ void tick_setup_sched_timer(void)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_NO_HZ_COMMON
|
||||
if (tick_nohz_enabled)
|
||||
if (tick_nohz_enabled) {
|
||||
ts->nohz_mode = NOHZ_MODE_HIGHRES;
|
||||
tick_nohz_active = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* HIGH_RES_TIMERS */
|
||||
|
|
|
|||
|
|
@ -1347,7 +1347,7 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk)
|
|||
tk->xtime_nsec -= remainder;
|
||||
tk->xtime_nsec += 1ULL << tk->shift;
|
||||
tk->ntp_error += remainder << tk->ntp_error_shift;
|
||||
|
||||
tk->ntp_error -= (1ULL << tk->shift) << tk->ntp_error_shift;
|
||||
}
|
||||
#else
|
||||
#define old_vsyscall_fixup(tk)
|
||||
|
|
|
|||
|
|
@ -1518,9 +1518,8 @@ static int init_timers_cpu(int cpu)
|
|||
/*
|
||||
* The APs use this path later in boot
|
||||
*/
|
||||
base = kmalloc_node(sizeof(*base),
|
||||
GFP_KERNEL | __GFP_ZERO,
|
||||
cpu_to_node(cpu));
|
||||
base = kzalloc_node(sizeof(*base), GFP_KERNEL,
|
||||
cpu_to_node(cpu));
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -367,9 +367,6 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
|
|||
|
||||
static int __register_ftrace_function(struct ftrace_ops *ops)
|
||||
{
|
||||
if (unlikely(ftrace_disabled))
|
||||
return -ENODEV;
|
||||
|
||||
if (FTRACE_WARN_ON(ops == &global_ops))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -428,9 +425,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (ftrace_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED)))
|
||||
return -EBUSY;
|
||||
|
||||
|
|
@ -2088,10 +2082,15 @@ static void ftrace_startup_enable(int command)
|
|||
static int ftrace_startup(struct ftrace_ops *ops, int command)
|
||||
{
|
||||
bool hash_enable = true;
|
||||
int ret;
|
||||
|
||||
if (unlikely(ftrace_disabled))
|
||||
return -ENODEV;
|
||||
|
||||
ret = __register_ftrace_function(ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ftrace_start_up++;
|
||||
command |= FTRACE_UPDATE_CALLS;
|
||||
|
||||
|
|
@ -2113,12 +2112,17 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ftrace_shutdown(struct ftrace_ops *ops, int command)
|
||||
static int ftrace_shutdown(struct ftrace_ops *ops, int command)
|
||||
{
|
||||
bool hash_disable = true;
|
||||
int ret;
|
||||
|
||||
if (unlikely(ftrace_disabled))
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
ret = __unregister_ftrace_function(ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ftrace_start_up--;
|
||||
/*
|
||||
|
|
@ -2153,9 +2157,10 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command)
|
|||
}
|
||||
|
||||
if (!command || !ftrace_enabled)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
ftrace_run_update_code(command);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ftrace_startup_sysctl(void)
|
||||
|
|
@ -3060,16 +3065,13 @@ static void __enable_ftrace_function_probe(void)
|
|||
if (i == FTRACE_FUNC_HASHSIZE)
|
||||
return;
|
||||
|
||||
ret = __register_ftrace_function(&trace_probe_ops);
|
||||
if (!ret)
|
||||
ret = ftrace_startup(&trace_probe_ops, 0);
|
||||
ret = ftrace_startup(&trace_probe_ops, 0);
|
||||
|
||||
ftrace_probe_registered = 1;
|
||||
}
|
||||
|
||||
static void __disable_ftrace_function_probe(void)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!ftrace_probe_registered)
|
||||
|
|
@ -3082,9 +3084,7 @@ static void __disable_ftrace_function_probe(void)
|
|||
}
|
||||
|
||||
/* no more funcs left */
|
||||
ret = __unregister_ftrace_function(&trace_probe_ops);
|
||||
if (!ret)
|
||||
ftrace_shutdown(&trace_probe_ops, 0);
|
||||
ftrace_shutdown(&trace_probe_ops, 0);
|
||||
|
||||
ftrace_probe_registered = 0;
|
||||
}
|
||||
|
|
@ -4366,12 +4366,15 @@ core_initcall(ftrace_nodyn_init);
|
|||
static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
|
||||
static inline void ftrace_startup_enable(int command) { }
|
||||
/* Keep as macros so we do not need to define the commands */
|
||||
# define ftrace_startup(ops, command) \
|
||||
({ \
|
||||
(ops)->flags |= FTRACE_OPS_FL_ENABLED; \
|
||||
0; \
|
||||
# define ftrace_startup(ops, command) \
|
||||
({ \
|
||||
int ___ret = __register_ftrace_function(ops); \
|
||||
if (!___ret) \
|
||||
(ops)->flags |= FTRACE_OPS_FL_ENABLED; \
|
||||
___ret; \
|
||||
})
|
||||
# define ftrace_shutdown(ops, command) do { } while (0)
|
||||
# define ftrace_shutdown(ops, command) __unregister_ftrace_function(ops)
|
||||
|
||||
# define ftrace_startup_sysctl() do { } while (0)
|
||||
# define ftrace_shutdown_sysctl() do { } while (0)
|
||||
|
||||
|
|
@ -4780,9 +4783,7 @@ int register_ftrace_function(struct ftrace_ops *ops)
|
|||
|
||||
mutex_lock(&ftrace_lock);
|
||||
|
||||
ret = __register_ftrace_function(ops);
|
||||
if (!ret)
|
||||
ret = ftrace_startup(ops, 0);
|
||||
ret = ftrace_startup(ops, 0);
|
||||
|
||||
mutex_unlock(&ftrace_lock);
|
||||
|
||||
|
|
@ -4801,9 +4802,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops)
|
|||
int ret;
|
||||
|
||||
mutex_lock(&ftrace_lock);
|
||||
ret = __unregister_ftrace_function(ops);
|
||||
if (!ret)
|
||||
ftrace_shutdown(ops, 0);
|
||||
ret = ftrace_shutdown(ops, 0);
|
||||
mutex_unlock(&ftrace_lock);
|
||||
|
||||
return ret;
|
||||
|
|
@ -4997,6 +4996,13 @@ ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state,
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/* Just a place holder for function graph */
|
||||
static struct ftrace_ops fgraph_ops __read_mostly = {
|
||||
.func = ftrace_stub,
|
||||
.flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_GLOBAL |
|
||||
FTRACE_OPS_FL_RECURSION_SAFE,
|
||||
};
|
||||
|
||||
int register_ftrace_graph(trace_func_graph_ret_t retfunc,
|
||||
trace_func_graph_ent_t entryfunc)
|
||||
{
|
||||
|
|
@ -5023,7 +5029,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
|
|||
ftrace_graph_return = retfunc;
|
||||
ftrace_graph_entry = entryfunc;
|
||||
|
||||
ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);
|
||||
ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ftrace_lock);
|
||||
|
|
@ -5040,7 +5046,7 @@ void unregister_ftrace_graph(void)
|
|||
ftrace_graph_active--;
|
||||
ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
|
||||
ftrace_graph_entry = ftrace_graph_entry_stub;
|
||||
ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);
|
||||
ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET);
|
||||
unregister_pm_notifier(&ftrace_suspend_notifier);
|
||||
unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ static int total_ref_count;
|
|||
static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
|
||||
struct perf_event *p_event)
|
||||
{
|
||||
if (tp_event->perf_perm) {
|
||||
int ret = tp_event->perf_perm(tp_event, p_event);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The ftrace function trace is allowed only for root. */
|
||||
if (ftrace_event_is_function(tp_event) &&
|
||||
perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
|
||||
|
|
@ -173,7 +179,7 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event,
|
|||
int perf_trace_init(struct perf_event *p_event)
|
||||
{
|
||||
struct ftrace_event_call *tp_event;
|
||||
int event_id = p_event->attr.config;
|
||||
u64 event_id = p_event->attr.config;
|
||||
int ret = -EINVAL;
|
||||
|
||||
mutex_lock(&event_mutex);
|
||||
|
|
|
|||
|
|
@ -2314,6 +2314,9 @@ int event_trace_del_tracer(struct trace_array *tr)
|
|||
/* Disable any running events */
|
||||
__ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0);
|
||||
|
||||
/* Access to events are within rcu_read_lock_sched() */
|
||||
synchronize_sched();
|
||||
|
||||
down_write(&trace_event_sem);
|
||||
__trace_remove_event_dirs(tr);
|
||||
debugfs_remove_recursive(tr->event_dir);
|
||||
|
|
|
|||
|
|
@ -431,11 +431,6 @@ static void unreg_event_syscall_enter(struct ftrace_event_file *file,
|
|||
if (!tr->sys_refcount_enter)
|
||||
unregister_trace_sys_enter(ftrace_syscall_enter, tr);
|
||||
mutex_unlock(&syscall_trace_lock);
|
||||
/*
|
||||
* Callers expect the event to be completely disabled on
|
||||
* return, so wait for current handlers to finish.
|
||||
*/
|
||||
synchronize_sched();
|
||||
}
|
||||
|
||||
static int reg_event_syscall_exit(struct ftrace_event_file *file,
|
||||
|
|
@ -474,11 +469,6 @@ static void unreg_event_syscall_exit(struct ftrace_event_file *file,
|
|||
if (!tr->sys_refcount_exit)
|
||||
unregister_trace_sys_exit(ftrace_syscall_exit, tr);
|
||||
mutex_unlock(&syscall_trace_lock);
|
||||
/*
|
||||
* Callers expect the event to be completely disabled on
|
||||
* return, so wait for current handlers to finish.
|
||||
*/
|
||||
synchronize_sched();
|
||||
}
|
||||
|
||||
static int __init init_syscall_trace(struct ftrace_event_call *call)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ struct user_namespace init_user_ns = {
|
|||
.owner = GLOBAL_ROOT_UID,
|
||||
.group = GLOBAL_ROOT_GID,
|
||||
.proc_inum = PROC_USER_INIT_INO,
|
||||
#ifdef CONFIG_KEYS_KERBEROS_CACHE
|
||||
.krb_cache_register_sem =
|
||||
__RWSEM_INITIALIZER(init_user_ns.krb_cache_register_sem),
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(init_user_ns);
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ int create_user_ns(struct cred *new)
|
|||
|
||||
set_cred_user_ns(new, ns);
|
||||
|
||||
#ifdef CONFIG_PERSISTENT_KEYRINGS
|
||||
init_rwsem(&ns->persistent_keyring_register_sem);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +133,9 @@ void free_user_ns(struct user_namespace *ns)
|
|||
|
||||
do {
|
||||
parent = ns->parent;
|
||||
#ifdef CONFIG_PERSISTENT_KEYRINGS
|
||||
key_put(ns->persistent_keyring_register);
|
||||
#endif
|
||||
proc_free_inum(ns->proc_inum);
|
||||
kmem_cache_free(user_ns_cachep, ns);
|
||||
ns = parent;
|
||||
|
|
|
|||
|
|
@ -305,6 +305,9 @@ static DEFINE_HASHTABLE(unbound_pool_hash, UNBOUND_POOL_HASH_ORDER);
|
|||
/* I: attributes used when instantiating standard unbound pools on demand */
|
||||
static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS];
|
||||
|
||||
/* I: attributes used when instantiating ordered pools on demand */
|
||||
static struct workqueue_attrs *ordered_wq_attrs[NR_STD_WORKER_POOLS];
|
||||
|
||||
struct workqueue_struct *system_wq __read_mostly;
|
||||
EXPORT_SYMBOL(system_wq);
|
||||
struct workqueue_struct *system_highpri_wq __read_mostly;
|
||||
|
|
@ -518,14 +521,21 @@ static inline void debug_work_activate(struct work_struct *work) { }
|
|||
static inline void debug_work_deactivate(struct work_struct *work) { }
|
||||
#endif
|
||||
|
||||
/* allocate ID and assign it to @pool */
|
||||
/**
|
||||
* worker_pool_assign_id - allocate ID and assing it to @pool
|
||||
* @pool: the pool pointer of interest
|
||||
*
|
||||
* Returns 0 if ID in [0, WORK_OFFQ_POOL_NONE) is allocated and assigned
|
||||
* successfully, -errno on failure.
|
||||
*/
|
||||
static int worker_pool_assign_id(struct worker_pool *pool)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&wq_pool_mutex);
|
||||
|
||||
ret = idr_alloc(&worker_pool_idr, pool, 0, 0, GFP_KERNEL);
|
||||
ret = idr_alloc(&worker_pool_idr, pool, 0, WORK_OFFQ_POOL_NONE,
|
||||
GFP_KERNEL);
|
||||
if (ret >= 0) {
|
||||
pool->id = ret;
|
||||
return 0;
|
||||
|
|
@ -1320,7 +1330,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
|
|||
|
||||
debug_work_activate(work);
|
||||
|
||||
/* if dying, only works from the same workqueue are allowed */
|
||||
/* if draining, only works from the same workqueue are allowed */
|
||||
if (unlikely(wq->flags & __WQ_DRAINING) &&
|
||||
WARN_ON_ONCE(!is_chained_work(wq)))
|
||||
return;
|
||||
|
|
@ -1736,16 +1746,17 @@ static struct worker *create_worker(struct worker_pool *pool)
|
|||
if (IS_ERR(worker->task))
|
||||
goto fail;
|
||||
|
||||
set_user_nice(worker->task, pool->attrs->nice);
|
||||
|
||||
/* prevent userland from meddling with cpumask of workqueue workers */
|
||||
worker->task->flags |= PF_NO_SETAFFINITY;
|
||||
|
||||
/*
|
||||
* set_cpus_allowed_ptr() will fail if the cpumask doesn't have any
|
||||
* online CPUs. It'll be re-applied when any of the CPUs come up.
|
||||
*/
|
||||
set_user_nice(worker->task, pool->attrs->nice);
|
||||
set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
|
||||
|
||||
/* prevent userland from meddling with cpumask of workqueue workers */
|
||||
worker->task->flags |= PF_NO_SETAFFINITY;
|
||||
|
||||
/*
|
||||
* The caller is responsible for ensuring %POOL_DISASSOCIATED
|
||||
* remains stable across this function. See the comments above the
|
||||
|
|
@ -2840,19 +2851,6 @@ already_gone:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool __flush_work(struct work_struct *work)
|
||||
{
|
||||
struct wq_barrier barr;
|
||||
|
||||
if (start_flush_work(work, &barr)) {
|
||||
wait_for_completion(&barr.done);
|
||||
destroy_work_on_stack(&barr.work);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flush_work - wait for a work to finish executing the last queueing instance
|
||||
* @work: the work to flush
|
||||
|
|
@ -2866,10 +2864,18 @@ static bool __flush_work(struct work_struct *work)
|
|||
*/
|
||||
bool flush_work(struct work_struct *work)
|
||||
{
|
||||
struct wq_barrier barr;
|
||||
|
||||
lock_map_acquire(&work->lockdep_map);
|
||||
lock_map_release(&work->lockdep_map);
|
||||
|
||||
return __flush_work(work);
|
||||
if (start_flush_work(work, &barr)) {
|
||||
wait_for_completion(&barr.done);
|
||||
destroy_work_on_stack(&barr.work);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(flush_work);
|
||||
|
||||
|
|
@ -4106,7 +4112,7 @@ out_unlock:
|
|||
static int alloc_and_link_pwqs(struct workqueue_struct *wq)
|
||||
{
|
||||
bool highpri = wq->flags & WQ_HIGHPRI;
|
||||
int cpu;
|
||||
int cpu, ret;
|
||||
|
||||
if (!(wq->flags & WQ_UNBOUND)) {
|
||||
wq->cpu_pwqs = alloc_percpu(struct pool_workqueue);
|
||||
|
|
@ -4126,6 +4132,13 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
|
|||
mutex_unlock(&wq->mutex);
|
||||
}
|
||||
return 0;
|
||||
} else if (wq->flags & __WQ_ORDERED) {
|
||||
ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]);
|
||||
/* there should only be single pwq for ordering guarantee */
|
||||
WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node ||
|
||||
wq->pwqs.prev != &wq->dfl_pwq->pwqs_node),
|
||||
"ordering guarantee broken for workqueue %s\n", wq->name);
|
||||
return ret;
|
||||
} else {
|
||||
return apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]);
|
||||
}
|
||||
|
|
@ -4814,14 +4827,7 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
|
|||
|
||||
INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
|
||||
schedule_work_on(cpu, &wfc.work);
|
||||
|
||||
/*
|
||||
* The work item is on-stack and can't lead to deadlock through
|
||||
* flushing. Use __flush_work() to avoid spurious lockdep warnings
|
||||
* when work_on_cpu()s are nested.
|
||||
*/
|
||||
__flush_work(&wfc.work);
|
||||
|
||||
flush_work(&wfc.work);
|
||||
return wfc.ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(work_on_cpu);
|
||||
|
|
@ -5009,10 +5015,6 @@ static int __init init_workqueues(void)
|
|||
int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
|
||||
int i, cpu;
|
||||
|
||||
/* make sure we have enough bits for OFFQ pool ID */
|
||||
BUILD_BUG_ON((1LU << (BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT)) <
|
||||
WORK_CPU_END * NR_STD_WORKER_POOLS);
|
||||
|
||||
WARN_ON(__alignof__(struct pool_workqueue) < __alignof__(long long));
|
||||
|
||||
pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
|
||||
|
|
@ -5051,13 +5053,23 @@ static int __init init_workqueues(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* create default unbound wq attrs */
|
||||
/* create default unbound and ordered wq attrs */
|
||||
for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
|
||||
struct workqueue_attrs *attrs;
|
||||
|
||||
BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL)));
|
||||
attrs->nice = std_nice[i];
|
||||
unbound_std_wq_attrs[i] = attrs;
|
||||
|
||||
/*
|
||||
* An ordered wq should have only one pwq as ordering is
|
||||
* guaranteed by max_active which is enforced by pwqs.
|
||||
* Turn off NUMA so that dfl_pwq is used for all nodes.
|
||||
*/
|
||||
BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL)));
|
||||
attrs->nice = std_nice[i];
|
||||
attrs->no_numa = true;
|
||||
ordered_wq_attrs[i] = attrs;
|
||||
}
|
||||
|
||||
system_wq = alloc_workqueue("events", 0, 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue