This is the 3.10.101 stable release

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJW6X7DAAoJEDjbvchgkmk+RqMP/23oS5ZXheNwIwKzWO8f1tnZ
 Em+1+p5zZ8cFV/mWHz6Jxxt0/3tEteT1m3sWGJLvG3Uzz1kd7alS/omxU0Lf4WEf
 Qzso9R5sg4+SKUtAhRmJlXhLvVwnKc5KiGyrBt4ZBrwViHy+phr6/uPUTI5m6u48
 Xzujf+onqeojNXTfMxAq90r9a/AHmVlTwQ+j6SqPkKKbCrtHp9bjrMEb2JFbk8CN
 dPhJQuKgUjUx0Scfk2KOecS89e0Kr+k8RWFstPtR0eUkvNlfzjcK7SD1WZ5i0yd4
 d89tG/X9T2uTVeO2hTxKmTmOAxgiBS/RAljXgA+3j1VTPBMuOvYjyIVQ8RwROFtp
 UbgkSabwhX2prKj1J0zXNUjSvYyiGQ1mXWcHemZxaJAZKl0rWwHeBuNHPuJCPAWJ
 ZVqFkA0jrKcDbF+pnt9nkWEC1vFkO0kaZAY8hYtUiXkA8ohoC+4rIap09sgGzHiM
 ElN9VZbg8dJOMfSrnFkIO8t8SQzlnLo3lNQsKF8HbtB2UsIODALYasuj61KXlt1s
 xo4bKgKVncRqA0neMdOjVlu4U8qs3f2f8FDFMdX3lAlq/Pcgo/wJCUuhl3y3cr4+
 9FRTaWxbtg7zCfvlV4JmgF9KjNdq+w6CU6ZbtRSDuBhtCx5dpMNGqD9igY6xtV4P
 GN3zWp59z0D40kIU+bLd
 =3YTQ
 -----END PGP SIGNATURE-----

Merge tag 'v3.10.101' into HEAD

This is the 3.10.101 stable release
This commit is contained in:
Luca Stefani 2017-04-18 17:17:55 +02:00
commit b46b1587e9
26 changed files with 552 additions and 214 deletions

View File

@ -14,3 +14,10 @@ filesystem.
efivarfs is typically mounted like this,
mount -t efivarfs none /sys/firmware/efi/efivars
Due to the presence of numerous firmware bugs where removing non-standard
UEFI variables causes the system firmware to fail to POST, efivarfs
files that are not well-known standardized variables are created
as immutable files. This doesn't prevent removal - "chattr -i" will work -
but it does prevent this kind of failure from being accomplished
accidentally.

View File

@ -1,6 +1,6 @@
VERSION = 3
PATCHLEVEL = 10
SUBLEVEL = 100
SUBLEVEL = 101
EXTRAVERSION =
NAME = TOSSUG Baby Fish

View File

@ -192,7 +192,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
if (syms[i].st_shndx == SHN_UNDEF) {
char *name = strtab + syms[i].st_name;
if (name[0] == '.')
memmove(name, name+1, strlen(name));
syms[i].st_name++;
}
}
}

View File

@ -1487,6 +1487,13 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
return;
}
break;
case MSR_IA32_PEBS_ENABLE:
/* PEBS needs a quiescent period after being disabled (to write
* a record). Disabling PEBS through VMX MSR swapping doesn't
* provide that period, so a CPU could write host's record into
* guest's memory.
*/
wrmsrl(MSR_IA32_PEBS_ENABLE, 0);
}
for (i = 0; i < m->nr; ++i)

View File

@ -1941,6 +1941,8 @@ static void accumulate_steal_time(struct kvm_vcpu *vcpu)
static void record_steal_time(struct kvm_vcpu *vcpu)
{
accumulate_steal_time(vcpu);
if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
return;
@ -2074,12 +2076,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (!(data & KVM_MSR_ENABLED))
break;
vcpu->arch.st.last_steal = current->sched_info.run_delay;
preempt_disable();
accumulate_steal_time(vcpu);
preempt_enable();
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
break;
@ -2758,7 +2754,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
vcpu->cpu = cpu;
}
accumulate_steal_time(vcpu);
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
}

View File

@ -125,23 +125,6 @@ int af_alg_release(struct socket *sock)
}
EXPORT_SYMBOL_GPL(af_alg_release);
void af_alg_release_parent(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
bool last;
sk = ask->parent;
ask = alg_sk(sk);
lock_sock(sk);
last = !--ask->refcnt;
release_sock(sk);
if (last)
sock_put(sk);
}
EXPORT_SYMBOL_GPL(af_alg_release_parent);
static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
@ -149,7 +132,6 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sockaddr_alg *sa = (void *)uaddr;
const struct af_alg_type *type;
void *private;
int err;
if (sock->state == SS_CONNECTED)
return -EINVAL;
@ -175,22 +157,16 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return PTR_ERR(private);
}
err = -EBUSY;
lock_sock(sk);
if (ask->refcnt)
goto unlock;
swap(ask->type, type);
swap(ask->private, private);
err = 0;
unlock:
release_sock(sk);
alg_do_release(type, private);
return err;
return 0;
}
static int alg_setkey(struct sock *sk, char __user *ukey,
@ -223,15 +199,11 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
const struct af_alg_type *type;
int err = -EBUSY;
int err = -ENOPROTOOPT;
lock_sock(sk);
if (ask->refcnt)
goto unlock;
type = ask->type;
err = -ENOPROTOOPT;
if (level != SOL_ALG || !type)
goto unlock;
@ -280,8 +252,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
sk2->sk_family = PF_ALG;
if (!ask->refcnt++)
sock_hold(sk);
sock_hold(sk);
alg_sk(sk2)->parent = sk;
alg_sk(sk2)->type = type;

View File

@ -219,7 +219,8 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
}
if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
efivar_validate(new_var->VendorGuid, new_var->VariableName,
new_var->Data, new_var->DataSize) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
@ -334,7 +335,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
return -EACCES;
if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
efivar_validate(new_var->VendorGuid, new_var->VariableName,
new_var->Data, new_var->DataSize) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
@ -405,35 +407,27 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
{
int i, short_name_size;
char *short_name;
unsigned long variable_name_size;
efi_char16_t *variable_name;
variable_name = new_var->var.VariableName;
variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
unsigned long utf8_name_size;
efi_char16_t *variable_name = new_var->var.VariableName;
/*
* Length of the variable bytes in ASCII, plus the '-' separator,
* Length of the variable bytes in UTF8, plus the '-' separator,
* plus the GUID, plus trailing NUL
*/
short_name_size = variable_name_size / sizeof(efi_char16_t)
+ 1 + EFI_VARIABLE_GUID_LEN + 1;
short_name = kzalloc(short_name_size, GFP_KERNEL);
utf8_name_size = ucs2_utf8size(variable_name);
short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
short_name = kmalloc(short_name_size, GFP_KERNEL);
if (!short_name)
return 1;
/* Convert Unicode to normal chars (assume top bits are 0),
ala UTF-8 */
for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
short_name[i] = variable_name[i] & 0xFF;
}
ucs2_as_utf8(short_name, variable_name, short_name_size);
/* This is ugly, but necessary to separate one vendor's
private variables from another's. */
*(short_name + strlen(short_name)) = '-';
short_name[utf8_name_size] = '-';
efi_guid_unparse(&new_var->var.VendorGuid,
short_name + strlen(short_name));
short_name + utf8_name_size + 1);
new_var->kobj.kset = efivars_kset;

View File

@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL);
EXPORT_SYMBOL_GPL(efivar_work);
static bool
validate_device_path(struct efi_variable *var, int match, u8 *buffer,
validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
struct efi_generic_dev_path *node;
@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer,
}
static bool
validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
/* An array of 16-bit integers */
@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
}
static bool
validate_load_option(struct efi_variable *var, int match, u8 *buffer,
validate_load_option(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
u16 filepathlength;
int i, desclength = 0, namelen;
namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName));
namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN);
/* Either "Boot" or "Driver" followed by four digits of hex */
for (i = match; i < match+4; i++) {
if (var->VariableName[i] > 127 ||
hex_to_bin(var->VariableName[i] & 0xff) < 0)
if (var_name[i] > 127 ||
hex_to_bin(var_name[i] & 0xff) < 0)
return true;
}
@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
/*
* And, finally, check the filepath
*/
return validate_device_path(var, match, buffer + desclength + 6,
return validate_device_path(var_name, match, buffer + desclength + 6,
filepathlength);
}
static bool
validate_uint16(struct efi_variable *var, int match, u8 *buffer,
validate_uint16(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
/* A single 16-bit integer */
@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer,
}
static bool
validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
int i;
@ -165,67 +165,133 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
}
struct variable_validate {
efi_guid_t vendor;
char *name;
bool (*validate)(struct efi_variable *var, int match, u8 *data,
bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
unsigned long len);
};
/*
* This is the list of variables we need to validate, as well as the
* whitelist for what we think is safe not to default to immutable.
*
* If it has a validate() method that's not NULL, it'll go into the
* validation routine. If not, it is assumed valid, but still used for
* whitelisting.
*
* Note that it's sorted by {vendor,name}, but globbed names must come after
* any other name with the same prefix.
*/
static const struct variable_validate variable_validate[] = {
{ "BootNext", validate_uint16 },
{ "BootOrder", validate_boot_order },
{ "DriverOrder", validate_boot_order },
{ "Boot*", validate_load_option },
{ "Driver*", validate_load_option },
{ "ConIn", validate_device_path },
{ "ConInDev", validate_device_path },
{ "ConOut", validate_device_path },
{ "ConOutDev", validate_device_path },
{ "ErrOut", validate_device_path },
{ "ErrOutDev", validate_device_path },
{ "Timeout", validate_uint16 },
{ "Lang", validate_ascii_string },
{ "PlatformLang", validate_ascii_string },
{ "", NULL },
{ EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
{ EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
{ EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
{ EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
{ EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
{ EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
{ EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
{ EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
{ EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
{ EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
{ EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
{ EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
{ EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
{ EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
{ EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
{ LINUX_EFI_CRASH_GUID, "*", NULL },
{ NULL_GUID, "", NULL },
};
static bool
variable_matches(const char *var_name, size_t len, const char *match_name,
int *match)
{
for (*match = 0; ; (*match)++) {
char c = match_name[*match];
char u = var_name[*match];
/* Wildcard in the matching name means we've matched */
if (c == '*')
return true;
/* Case sensitive match */
if (!c && *match == len)
return true;
if (c != u)
return false;
if (!c)
return true;
}
return true;
}
bool
efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
unsigned long data_size)
{
int i;
u16 *unicode_name = var->VariableName;
unsigned long utf8_size;
u8 *utf8_name;
for (i = 0; variable_validate[i].validate != NULL; i++) {
utf8_size = ucs2_utf8size(var_name);
utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
if (!utf8_name)
return false;
ucs2_as_utf8(utf8_name, var_name, utf8_size);
utf8_name[utf8_size] = '\0';
for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
const char *name = variable_validate[i].name;
int match;
int match = 0;
for (match = 0; ; match++) {
char c = name[match];
u16 u = unicode_name[match];
if (efi_guidcmp(vendor, variable_validate[i].vendor))
continue;
/* All special variables are plain ascii */
if (u > 127)
return true;
/* Wildcard in the matching name means we've matched */
if (c == '*')
return variable_validate[i].validate(var,
match, data, len);
/* Case sensitive match */
if (c != u)
if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
if (variable_validate[i].validate == NULL)
break;
/* Reached the end of the string while matching */
if (!c)
return variable_validate[i].validate(var,
match, data, len);
kfree(utf8_name);
return variable_validate[i].validate(var_name, match,
data, data_size);
}
}
kfree(utf8_name);
return true;
}
EXPORT_SYMBOL_GPL(efivar_validate);
bool
efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
size_t len)
{
int i;
bool found = false;
int match = 0;
/*
* Check if our variable is in the validated variables list
*/
for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
if (efi_guidcmp(variable_validate[i].vendor, vendor))
continue;
if (variable_matches(var_name, len,
variable_validate[i].name, &match)) {
found = true;
break;
}
}
/*
* If it's in our list, it is removable.
*/
return found;
}
EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
static efi_status_t
check_var_size(u32 attributes, unsigned long size)
{
@ -797,7 +863,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
*set = false;
if (efivar_validate(&entry->var, data, *size) == false)
if (efivar_validate(*vendor, name, data, *size) == false)
return -EINVAL;
/*

View File

@ -10,6 +10,7 @@
#include <linux/efi.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/mount.h>
#include "internal.h"
@ -108,9 +109,79 @@ out_free:
return size;
}
static int
efivarfs_ioc_getxflags(struct file *file, void __user *arg)
{
struct inode *inode = file->f_mapping->host;
unsigned int i_flags;
unsigned int flags = 0;
i_flags = inode->i_flags;
if (i_flags & S_IMMUTABLE)
flags |= FS_IMMUTABLE_FL;
if (copy_to_user(arg, &flags, sizeof(flags)))
return -EFAULT;
return 0;
}
static int
efivarfs_ioc_setxflags(struct file *file, void __user *arg)
{
struct inode *inode = file->f_mapping->host;
unsigned int flags;
unsigned int i_flags = 0;
int error;
if (!inode_owner_or_capable(inode))
return -EACCES;
if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT;
if (flags & ~FS_IMMUTABLE_FL)
return -EOPNOTSUPP;
if (!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
if (flags & FS_IMMUTABLE_FL)
i_flags |= S_IMMUTABLE;
error = mnt_want_write_file(file);
if (error)
return error;
mutex_lock(&inode->i_mutex);
inode->i_flags &= ~S_IMMUTABLE;
inode->i_flags |= i_flags;
mutex_unlock(&inode->i_mutex);
mnt_drop_write_file(file);
return 0;
}
long
efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
{
void __user *arg = (void __user *)p;
switch (cmd) {
case FS_IOC_GETFLAGS:
return efivarfs_ioc_getxflags(file, arg);
case FS_IOC_SETFLAGS:
return efivarfs_ioc_setxflags(file, arg);
}
return -ENOTTY;
}
const struct file_operations efivarfs_file_operations = {
.open = simple_open,
.read = efivarfs_file_read,
.write = efivarfs_file_write,
.llseek = no_llseek,
.unlocked_ioctl = efivarfs_file_ioctl,
};

View File

@ -15,7 +15,8 @@
#include "internal.h"
struct inode *efivarfs_get_inode(struct super_block *sb,
const struct inode *dir, int mode, dev_t dev)
const struct inode *dir, int mode,
dev_t dev, bool is_removable)
{
struct inode *inode = new_inode(sb);
@ -23,6 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb,
inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
switch (mode & S_IFMT) {
case S_IFREG:
inode->i_fop = &efivarfs_file_operations;
@ -102,22 +104,17 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
static int efivarfs_create(struct inode *dir, struct dentry *dentry,
umode_t mode, bool excl)
{
struct inode *inode;
struct inode *inode = NULL;
struct efivar_entry *var;
int namelen, i = 0, err = 0;
bool is_removable = false;
if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
return -EINVAL;
inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
if (!inode)
return -ENOMEM;
var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
if (!var) {
err = -ENOMEM;
goto out;
}
if (!var)
return -ENOMEM;
/* length of the variable name itself: remove GUID and separator */
namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
@ -125,6 +122,16 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
&var->var.VendorGuid);
if (efivar_variable_is_removable(var->var.VendorGuid,
dentry->d_name.name, namelen))
is_removable = true;
inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable);
if (!inode) {
err = -ENOMEM;
goto out;
}
for (i = 0; i < namelen; i++)
var->var.VariableName[i] = dentry->d_name.name[i];
@ -138,7 +145,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
out:
if (err) {
kfree(var);
iput(inode);
if (inode)
iput(inode);
}
return err;
}

View File

@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations;
extern const struct inode_operations efivarfs_dir_inode_operations;
extern bool efivarfs_valid_name(const char *str, int len);
extern struct inode *efivarfs_get_inode(struct super_block *sb,
const struct inode *dir, int mode, dev_t dev);
const struct inode *dir, int mode, dev_t dev,
bool is_removable);
extern struct list_head efivarfs_list;

View File

@ -128,8 +128,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
struct dentry *dentry, *root = sb->s_root;
unsigned long size = 0;
char *name;
int len, i;
int len;
int err = -ENOMEM;
bool is_removable = false;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
@ -138,15 +139,17 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
memcpy(entry->var.VariableName, name16, name_size);
memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
len = ucs2_strlen(entry->var.VariableName);
len = ucs2_utf8size(entry->var.VariableName);
/* name, plus '-', plus GUID, plus NUL*/
name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
if (!name)
goto fail;
for (i = 0; i < len; i++)
name[i] = entry->var.VariableName[i] & 0xFF;
ucs2_as_utf8(name, entry->var.VariableName, len);
if (efivar_variable_is_removable(entry->var.VendorGuid, name, len))
is_removable = true;
name[len] = '-';
@ -154,7 +157,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0);
inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0,
is_removable);
if (!inode)
goto fail_name;
@ -210,7 +214,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_d_op = &efivarfs_d_ops;
sb->s_time_gran = 1;
inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true);
if (!inode)
return -ENOMEM;
inode->i_op = &efivarfs_dir_inode_operations;

View File

@ -30,8 +30,6 @@ struct alg_sock {
struct sock *parent;
unsigned int refcnt;
const struct af_alg_type *type;
void *private;
};
@ -66,7 +64,6 @@ int af_alg_register_type(const struct af_alg_type *type);
int af_alg_unregister_type(const struct af_alg_type *type);
int af_alg_release(struct socket *sock);
void af_alg_release_parent(struct sock *sk);
int af_alg_accept(struct sock *sk, struct socket *newsock);
int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len,
@ -83,6 +80,11 @@ static inline struct alg_sock *alg_sk(struct sock *sk)
return (struct alg_sock *)sk;
}
static inline void af_alg_release_parent(struct sock *sk)
{
sock_put(alg_sk(sk)->parent);
}
static inline void af_alg_init_completion(struct af_alg_completion *completion)
{
init_completion(&completion->completion);

View File

@ -811,8 +811,10 @@ struct efivars {
* and we use a page for reading/writing.
*/
#define EFI_VAR_NAME_LEN 1024
struct efi_variable {
efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
efi_guid_t VendorGuid;
unsigned long DataSize;
__u8 Data[1024];
@ -881,7 +883,10 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
struct list_head *head, bool remove);
bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len);
bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
unsigned long data_size);
bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
size_t len);
extern struct work_struct efivar_work;
void efivar_run_worker(void);

View File

@ -226,6 +226,12 @@ struct module_ref {
unsigned long decs;
} __attribute((aligned(2 * sizeof(unsigned long))));
struct mod_kallsyms {
Elf_Sym *symtab;
unsigned int num_symtab;
char *strtab;
};
struct module
{
enum module_state state;
@ -314,14 +320,9 @@ struct module
#endif
#ifdef CONFIG_KALLSYMS
/*
* We keep the symbol and string tables for kallsyms.
* The core_* fields below are temporary, loader-only (they
* could really be discarded after module init).
*/
Elf_Sym *symtab, *core_symtab;
unsigned int num_symtab, core_num_syms;
char *strtab, *core_strtab;
/* Protected by RCU and/or module_mutex: use rcu_dereference() */
struct mod_kallsyms *kallsyms;
struct mod_kallsyms core_kallsyms;
/* Section attributes */
struct module_sect_attrs *sect_attrs;

View File

@ -129,9 +129,6 @@ static inline void tracepoint_synchronize_unregister(void)
void *it_func; \
void *__data; \
\
if (!cpu_online(raw_smp_processor_id())) \
return; \
\
if (!(cond)) \
return; \
prercu; \
@ -275,15 +272,19 @@ static inline void tracepoint_synchronize_unregister(void)
* "void *__data, proto" as the callback prototype.
*/
#define DECLARE_TRACE_NOARGS(name) \
__DECLARE_TRACE(name, void, , 1, void *__data, __data)
__DECLARE_TRACE(name, void, , \
cpu_online(raw_smp_processor_id()), \
void *__data, __data)
#define DECLARE_TRACE(name, proto, args) \
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1, \
PARAMS(void *__data, proto), \
PARAMS(__data, args))
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \
cpu_online(raw_smp_processor_id()), \
PARAMS(void *__data, proto), \
PARAMS(__data, args))
#define DECLARE_TRACE_CONDITION(name, proto, args, cond) \
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), PARAMS(cond), \
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \
cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \
PARAMS(void *__data, proto), \
PARAMS(__data, args))

View File

@ -11,4 +11,8 @@ unsigned long ucs2_strlen(const ucs2_char_t *s);
unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
unsigned long ucs2_utf8size(const ucs2_char_t *src);
unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src,
unsigned long maxlength);
#endif /* _LINUX_UCS2_STRING_H_ */

View File

@ -261,6 +261,9 @@ struct load_info {
struct _ddebug *debug;
unsigned int num_debug;
bool sig_ok;
#ifdef CONFIG_KALLSYMS
unsigned long mod_kallsyms_init_off;
#endif
struct {
unsigned int sym, str, mod, vers, info, pcpu;
} index;
@ -2428,8 +2431,20 @@ static void layout_symtab(struct module *mod, struct load_info *info)
strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
info->index.str) | INIT_OFFSET_MASK;
pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
/* We'll tack temporary mod_kallsyms on the end. */
mod->init_size = ALIGN(mod->init_size,
__alignof__(struct mod_kallsyms));
info->mod_kallsyms_init_off = mod->init_size;
mod->init_size += sizeof(struct mod_kallsyms);
mod->init_size = debug_align(mod->init_size);
}
/*
* We use the full symtab and strtab which layout_symtab arranged to
* be appended to the init section. Later we switch to the cut-down
* core-only ones.
*/
static void add_kallsyms(struct module *mod, const struct load_info *info)
{
unsigned int i, ndst;
@ -2438,28 +2453,33 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
char *s;
Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
mod->symtab = (void *)symsec->sh_addr;
mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
/* Set up to point into init section. */
mod->kallsyms = mod->module_init + info->mod_kallsyms_init_off;
mod->kallsyms->symtab = (void *)symsec->sh_addr;
mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
/* Make sure we get permanent strtab: don't use info->strtab. */
mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
/* Set types up while we still have access to sections. */
for (i = 0; i < mod->num_symtab; i++)
mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
for (i = 0; i < mod->kallsyms->num_symtab; i++)
mod->kallsyms->symtab[i].st_info
= elf_type(&mod->kallsyms->symtab[i], info);
mod->core_symtab = dst = mod->module_core + info->symoffs;
mod->core_strtab = s = mod->module_core + info->stroffs;
src = mod->symtab;
for (ndst = i = 0; i < mod->num_symtab; i++) {
/* Now populate the cut down core kallsyms for after init. */
mod->core_kallsyms.symtab = dst = mod->module_core + info->symoffs;
mod->core_kallsyms.strtab = s = mod->module_core + info->stroffs;
src = mod->kallsyms->symtab;
for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
if (i == 0 ||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
dst[ndst] = src[i];
dst[ndst++].st_name = s - mod->core_strtab;
s += strlcpy(s, &mod->strtab[src[i].st_name],
dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
KSYM_NAME_LEN) + 1;
}
}
mod->core_num_syms = ndst;
mod->core_kallsyms.num_symtab = ndst;
}
#else
static inline void layout_symtab(struct module *mod, struct load_info *info)
@ -3583,9 +3603,8 @@ static int do_init_module(struct module *mod)
module_put(mod);
trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
mod->num_symtab = mod->core_num_syms;
mod->symtab = mod->core_symtab;
mod->strtab = mod->core_strtab;
/* Switch to core kallsyms now init is done: kallsyms may be walking! */
rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
#endif
unset_module_init_ro_nx(mod);
module_free(mod, mod->module_init);
@ -3871,9 +3890,9 @@ static inline int is_arm_mapping_symbol(const char *str)
&& (str[2] == '\0' || str[2] == '.');
}
static const char *symname(struct module *mod, unsigned int symnum)
static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum)
{
return mod->strtab + mod->symtab[symnum].st_name;
return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
}
static const char *get_ksymbol(struct module *mod,
@ -3883,6 +3902,7 @@ static const char *get_ksymbol(struct module *mod,
{
unsigned int i, best = 0;
unsigned long nextval;
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
/* At worse, next value is at end of module */
if (within_module_init(addr, mod))
@ -3892,32 +3912,32 @@ static const char *get_ksymbol(struct module *mod,
/* Scan for closest preceding symbol, and next symbol. (ELF
starts real symbols at 1). */
for (i = 1; i < mod->num_symtab; i++) {
if (mod->symtab[i].st_shndx == SHN_UNDEF)
for (i = 1; i < kallsyms->num_symtab; i++) {
if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
continue;
/* We ignore unnamed symbols: they're uninformative
* and inserted at a whim. */
if (*symname(mod, i) == '\0'
|| is_arm_mapping_symbol(symname(mod, i)))
if (*symname(kallsyms, i) == '\0'
|| is_arm_mapping_symbol(symname(kallsyms, i)))
continue;
if (mod->symtab[i].st_value <= addr
&& mod->symtab[i].st_value > mod->symtab[best].st_value)
if (kallsyms->symtab[i].st_value <= addr
&& kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
best = i;
if (mod->symtab[i].st_value > addr
&& mod->symtab[i].st_value < nextval)
nextval = mod->symtab[i].st_value;
if (kallsyms->symtab[i].st_value > addr
&& kallsyms->symtab[i].st_value < nextval)
nextval = kallsyms->symtab[i].st_value;
}
if (!best)
return NULL;
if (size)
*size = nextval - mod->symtab[best].st_value;
*size = nextval - kallsyms->symtab[best].st_value;
if (offset)
*offset = addr - mod->symtab[best].st_value;
return symname(mod, best);
*offset = addr - kallsyms->symtab[best].st_value;
return symname(kallsyms, best);
}
/* For kallsyms to ask for address resolution. NULL means not found. Careful
@ -4013,18 +4033,21 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
preempt_disable();
list_for_each_entry_rcu(mod, &modules, list) {
struct mod_kallsyms *kallsyms;
if (mod->state == MODULE_STATE_UNFORMED)
continue;
if (symnum < mod->num_symtab) {
*value = mod->symtab[symnum].st_value;
*type = mod->symtab[symnum].st_info;
strlcpy(name, symname(mod, symnum), KSYM_NAME_LEN);
kallsyms = rcu_dereference_sched(mod->kallsyms);
if (symnum < kallsyms->num_symtab) {
*value = kallsyms->symtab[symnum].st_value;
*type = kallsyms->symtab[symnum].st_info;
strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN);
strlcpy(module_name, mod->name, MODULE_NAME_LEN);
*exported = is_exported(name, *value, mod);
preempt_enable();
return 0;
}
symnum -= mod->num_symtab;
symnum -= kallsyms->num_symtab;
}
preempt_enable();
return -ERANGE;
@ -4033,11 +4056,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
static unsigned long mod_find_symname(struct module *mod, const char *name)
{
unsigned int i;
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
for (i = 0; i < mod->num_symtab; i++)
if (strcmp(name, symname(mod, i)) == 0 &&
mod->symtab[i].st_info != 'U')
return mod->symtab[i].st_value;
for (i = 0; i < kallsyms->num_symtab; i++)
if (strcmp(name, symname(kallsyms, i)) == 0 &&
kallsyms->symtab[i].st_info != 'U')
return kallsyms->symtab[i].st_value;
return 0;
}
@ -4076,11 +4100,14 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
int ret;
list_for_each_entry(mod, &modules, list) {
/* We hold module_mutex: no need for rcu_dereference_sched */
struct mod_kallsyms *kallsyms = mod->kallsyms;
if (mod->state == MODULE_STATE_UNFORMED)
continue;
for (i = 0; i < mod->num_symtab; i++) {
ret = fn(data, symname(mod, i),
mod, mod->symtab[i].st_value);
for (i = 0; i < kallsyms->num_symtab; i++) {
ret = fn(data, symname(kallsyms, i),
mod, kallsyms->symtab[i].st_value);
if (ret != 0)
return ret;
}

View File

@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
}
}
EXPORT_SYMBOL(ucs2_strncmp);
unsigned long
ucs2_utf8size(const ucs2_char_t *src)
{
unsigned long i;
unsigned long j = 0;
for (i = 0; i < ucs2_strlen(src); i++) {
u16 c = src[i];
if (c >= 0x800)
j += 3;
else if (c >= 0x80)
j += 2;
else
j += 1;
}
return j;
}
EXPORT_SYMBOL(ucs2_utf8size);
/*
* copy at most maxlength bytes of whole utf8 characters to dest from the
* ucs2 string src.
*
* The return value is the number of characters copied, not including the
* final NUL character.
*/
unsigned long
ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
{
unsigned int i;
unsigned long j = 0;
unsigned long limit = ucs2_strnlen(src, maxlength);
for (i = 0; maxlength && i < limit; i++) {
u16 c = src[i];
if (c >= 0x800) {
if (maxlength < 3)
break;
maxlength -= 3;
dest[j++] = 0xe0 | (c & 0xf000) >> 12;
dest[j++] = 0x80 | (c & 0x0fc0) >> 6;
dest[j++] = 0x80 | (c & 0x003f);
} else if (c >= 0x80) {
if (maxlength < 2)
break;
maxlength -= 2;
dest[j++] = 0xc0 | (c & 0x7c0) >> 6;
dest[j++] = 0x80 | (c & 0x03f);
} else {
maxlength -= 1;
dest[j++] = c & 0x7f;
}
}
if (maxlength)
dest[j] = '\0';
return j;
}
EXPORT_SYMBOL(ucs2_as_utf8);

View File

@ -290,7 +290,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
}
/* prepare A-MPDU MLME for Rx aggregation */
tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
if (!tid_agg_rx)
goto end;

View File

@ -454,7 +454,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
return;
ieee80211_start_tx_ba_session(pubsta, tid, 5000);
ieee80211_start_tx_ba_session(pubsta, tid, 0);
}
static void

View File

@ -342,6 +342,39 @@ static const int compat_event_type_size[] = {
/* IW event code */
static void wireless_nlevent_flush(void)
{
struct sk_buff *skb;
struct net *net;
ASSERT_RTNL();
for_each_net(net) {
while ((skb = skb_dequeue(&net->wext_nlevents)))
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
GFP_KERNEL);
}
}
static int wext_netdev_notifier_call(struct notifier_block *nb,
unsigned long state, void *ptr)
{
/*
* When a netdev changes state in any way, flush all pending messages
* to avoid them going out in a strange order, e.g. RTM_NEWLINK after
* RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close()
* or similar - all of which could otherwise happen due to delays from
* schedule_work().
*/
wireless_nlevent_flush();
return NOTIFY_OK;
}
static struct notifier_block wext_netdev_notifier = {
.notifier_call = wext_netdev_notifier_call,
};
static int __net_init wext_pernet_init(struct net *net)
{
skb_queue_head_init(&net->wext_nlevents);
@ -360,7 +393,12 @@ static struct pernet_operations wext_pernet_ops = {
static int __init wireless_nlevent_init(void)
{
return register_pernet_subsys(&wext_pernet_ops);
int err = register_pernet_subsys(&wext_pernet_ops);
if (err)
return err;
return register_netdevice_notifier(&wext_netdev_notifier);
}
subsys_initcall(wireless_nlevent_init);
@ -368,17 +406,8 @@ subsys_initcall(wireless_nlevent_init);
/* Process events generated by the wireless layer or the driver. */
static void wireless_nlevent_process(struct work_struct *work)
{
struct sk_buff *skb;
struct net *net;
rtnl_lock();
for_each_net(net) {
while ((skb = skb_dequeue(&net->wext_nlevents)))
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
GFP_KERNEL);
}
wireless_nlevent_flush();
rtnl_unlock();
}

View File

@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
@ -549,7 +549,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
@ -582,7 +582,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
@ -749,7 +749,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */

View File

@ -361,7 +361,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int drc = wm8994_get_drc(kcontrol->id.name);
int value = ucontrol->value.integer.value[0];
int value = ucontrol->value.enumerated.item[0];
if (drc < 0)
return drc;
@ -468,7 +468,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
int value = ucontrol->value.integer.value[0];
int value = ucontrol->value.enumerated.item[0];
if (block < 0)
return block;

View File

@ -88,7 +88,11 @@ test_delete()
exit 1
fi
rm $file
rm $file 2>/dev/null
if [ $? -ne 0 ]; then
chattr -i $file
rm $file
fi
if [ -e $file ]; then
echo "$file couldn't be deleted" >&2
@ -111,6 +115,7 @@ test_zero_size_delete()
exit 1
fi
chattr -i $file
printf "$attrs" > $file
if [ -e $file ]; then
@ -141,7 +146,11 @@ test_valid_filenames()
echo "$file could not be created" >&2
ret=1
else
rm $file
rm $file 2>/dev/null
if [ $? -ne 0 ]; then
chattr -i $file
rm $file
fi
fi
done
@ -174,7 +183,11 @@ test_invalid_filenames()
if [ -e $file ]; then
echo "Creating $file should have failed" >&2
rm $file
rm $file 2>/dev/null
if [ $? -ne 0 ]; then
chattr -i $file
rm $file
fi
ret=1
fi
done

View File

@ -1,10 +1,68 @@
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fs.h>
static int set_immutable(const char *path, int immutable)
{
unsigned int flags;
int fd;
int rc;
int error;
fd = open(path, O_RDONLY);
if (fd < 0)
return fd;
rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
if (rc < 0) {
error = errno;
close(fd);
errno = error;
return rc;
}
if (immutable)
flags |= FS_IMMUTABLE_FL;
else
flags &= ~FS_IMMUTABLE_FL;
rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
error = errno;
close(fd);
errno = error;
return rc;
}
static int get_immutable(const char *path)
{
unsigned int flags;
int fd;
int rc;
int error;
fd = open(path, O_RDONLY);
if (fd < 0)
return fd;
rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
if (rc < 0) {
error = errno;
close(fd);
errno = error;
return rc;
}
close(fd);
if (flags & FS_IMMUTABLE_FL)
return 1;
return 0;
}
int main(int argc, char **argv)
{
@ -27,7 +85,7 @@ int main(int argc, char **argv)
buf[4] = 0;
/* create a test variable */
fd = open(path, O_WRONLY | O_CREAT);
fd = open(path, O_WRONLY | O_CREAT, 0600);
if (fd < 0) {
perror("open(O_WRONLY)");
return EXIT_FAILURE;
@ -41,6 +99,18 @@ int main(int argc, char **argv)
close(fd);
rc = get_immutable(path);
if (rc < 0) {
perror("ioctl(FS_IOC_GETFLAGS)");
return EXIT_FAILURE;
} else if (rc) {
rc = set_immutable(path, 0);
if (rc < 0) {
perror("ioctl(FS_IOC_SETFLAGS)");
return EXIT_FAILURE;
}
}
fd = open(path, O_RDONLY);
if (fd < 0) {
perror("open");