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:
commit
b46b1587e9
|
@ -14,3 +14,10 @@ filesystem.
|
||||||
efivarfs is typically mounted like this,
|
efivarfs is typically mounted like this,
|
||||||
|
|
||||||
mount -t efivarfs none /sys/firmware/efi/efivars
|
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.
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
||||||
VERSION = 3
|
VERSION = 3
|
||||||
PATCHLEVEL = 10
|
PATCHLEVEL = 10
|
||||||
SUBLEVEL = 100
|
SUBLEVEL = 101
|
||||||
EXTRAVERSION =
|
EXTRAVERSION =
|
||||||
NAME = TOSSUG Baby Fish
|
NAME = TOSSUG Baby Fish
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
|
||||||
if (syms[i].st_shndx == SHN_UNDEF) {
|
if (syms[i].st_shndx == SHN_UNDEF) {
|
||||||
char *name = strtab + syms[i].st_name;
|
char *name = strtab + syms[i].st_name;
|
||||||
if (name[0] == '.')
|
if (name[0] == '.')
|
||||||
memmove(name, name+1, strlen(name));
|
syms[i].st_name++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1487,6 +1487,13 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
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)
|
for (i = 0; i < m->nr; ++i)
|
||||||
|
|
|
@ -1941,6 +1941,8 @@ static void accumulate_steal_time(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static void record_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))
|
if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2074,12 +2076,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||||
if (!(data & KVM_MSR_ENABLED))
|
if (!(data & KVM_MSR_ENABLED))
|
||||||
break;
|
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);
|
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -2758,7 +2754,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||||
vcpu->cpu = cpu;
|
vcpu->cpu = cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulate_steal_time(vcpu);
|
|
||||||
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
|
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,23 +125,6 @@ int af_alg_release(struct socket *sock)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(af_alg_release);
|
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)
|
static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
{
|
{
|
||||||
struct sock *sk = sock->sk;
|
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;
|
struct sockaddr_alg *sa = (void *)uaddr;
|
||||||
const struct af_alg_type *type;
|
const struct af_alg_type *type;
|
||||||
void *private;
|
void *private;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (sock->state == SS_CONNECTED)
|
if (sock->state == SS_CONNECTED)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -175,22 +157,16 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
return PTR_ERR(private);
|
return PTR_ERR(private);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -EBUSY;
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
if (ask->refcnt)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
swap(ask->type, type);
|
swap(ask->type, type);
|
||||||
swap(ask->private, private);
|
swap(ask->private, private);
|
||||||
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
unlock:
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
|
||||||
alg_do_release(type, private);
|
alg_do_release(type, private);
|
||||||
|
|
||||||
return err;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alg_setkey(struct sock *sk, char __user *ukey,
|
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 sock *sk = sock->sk;
|
||||||
struct alg_sock *ask = alg_sk(sk);
|
struct alg_sock *ask = alg_sk(sk);
|
||||||
const struct af_alg_type *type;
|
const struct af_alg_type *type;
|
||||||
int err = -EBUSY;
|
int err = -ENOPROTOOPT;
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
if (ask->refcnt)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
type = ask->type;
|
type = ask->type;
|
||||||
|
|
||||||
err = -ENOPROTOOPT;
|
|
||||||
if (level != SOL_ALG || !type)
|
if (level != SOL_ALG || !type)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
|
@ -280,8 +252,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
|
||||||
|
|
||||||
sk2->sk_family = PF_ALG;
|
sk2->sk_family = PF_ALG;
|
||||||
|
|
||||||
if (!ask->refcnt++)
|
sock_hold(sk);
|
||||||
sock_hold(sk);
|
|
||||||
alg_sk(sk2)->parent = sk;
|
alg_sk(sk2)->parent = sk;
|
||||||
alg_sk(sk2)->type = type;
|
alg_sk(sk2)->type = type;
|
||||||
|
|
||||||
|
|
|
@ -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 ||
|
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");
|
printk(KERN_ERR "efivars: Malformed variable content\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -334,7 +335,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
|
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");
|
printk(KERN_ERR "efivars: Malformed variable content\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -405,35 +407,27 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
|
||||||
{
|
{
|
||||||
int i, short_name_size;
|
int i, short_name_size;
|
||||||
char *short_name;
|
char *short_name;
|
||||||
unsigned long variable_name_size;
|
unsigned long utf8_name_size;
|
||||||
efi_char16_t *variable_name;
|
efi_char16_t *variable_name = new_var->var.VariableName;
|
||||||
|
|
||||||
variable_name = new_var->var.VariableName;
|
|
||||||
variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* plus the GUID, plus trailing NUL
|
||||||
*/
|
*/
|
||||||
short_name_size = variable_name_size / sizeof(efi_char16_t)
|
utf8_name_size = ucs2_utf8size(variable_name);
|
||||||
+ 1 + EFI_VARIABLE_GUID_LEN + 1;
|
short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
|
||||||
|
|
||||||
short_name = kzalloc(short_name_size, GFP_KERNEL);
|
|
||||||
|
|
||||||
|
short_name = kmalloc(short_name_size, GFP_KERNEL);
|
||||||
if (!short_name)
|
if (!short_name)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Convert Unicode to normal chars (assume top bits are 0),
|
ucs2_as_utf8(short_name, variable_name, short_name_size);
|
||||||
ala UTF-8 */
|
|
||||||
for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
|
|
||||||
short_name[i] = variable_name[i] & 0xFF;
|
|
||||||
}
|
|
||||||
/* This is ugly, but necessary to separate one vendor's
|
/* This is ugly, but necessary to separate one vendor's
|
||||||
private variables from another's. */
|
private variables from another's. */
|
||||||
|
short_name[utf8_name_size] = '-';
|
||||||
*(short_name + strlen(short_name)) = '-';
|
|
||||||
efi_guid_unparse(&new_var->var.VendorGuid,
|
efi_guid_unparse(&new_var->var.VendorGuid,
|
||||||
short_name + strlen(short_name));
|
short_name + utf8_name_size + 1);
|
||||||
|
|
||||||
new_var->kobj.kset = efivars_kset;
|
new_var->kobj.kset = efivars_kset;
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL);
|
||||||
EXPORT_SYMBOL_GPL(efivar_work);
|
EXPORT_SYMBOL_GPL(efivar_work);
|
||||||
|
|
||||||
static bool
|
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)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
struct efi_generic_dev_path *node;
|
struct efi_generic_dev_path *node;
|
||||||
|
@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
/* An array of 16-bit integers */
|
/* An array of 16-bit integers */
|
||||||
|
@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
u16 filepathlength;
|
u16 filepathlength;
|
||||||
int i, desclength = 0, namelen;
|
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 */
|
/* Either "Boot" or "Driver" followed by four digits of hex */
|
||||||
for (i = match; i < match+4; i++) {
|
for (i = match; i < match+4; i++) {
|
||||||
if (var->VariableName[i] > 127 ||
|
if (var_name[i] > 127 ||
|
||||||
hex_to_bin(var->VariableName[i] & 0xff) < 0)
|
hex_to_bin(var_name[i] & 0xff) < 0)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
|
||||||
/*
|
/*
|
||||||
* And, finally, check the filepath
|
* 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);
|
filepathlength);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
/* A single 16-bit integer */
|
/* A single 16-bit integer */
|
||||||
|
@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -165,67 +165,133 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct variable_validate {
|
struct variable_validate {
|
||||||
|
efi_guid_t vendor;
|
||||||
char *name;
|
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);
|
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[] = {
|
static const struct variable_validate variable_validate[] = {
|
||||||
{ "BootNext", validate_uint16 },
|
{ EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
|
||||||
{ "BootOrder", validate_boot_order },
|
{ EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
|
||||||
{ "DriverOrder", validate_boot_order },
|
{ EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
|
||||||
{ "Boot*", validate_load_option },
|
{ EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
|
||||||
{ "Driver*", validate_load_option },
|
{ EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
|
||||||
{ "ConIn", validate_device_path },
|
{ EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
|
||||||
{ "ConInDev", validate_device_path },
|
{ EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
|
||||||
{ "ConOut", validate_device_path },
|
{ EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
|
||||||
{ "ConOutDev", validate_device_path },
|
{ EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
|
||||||
{ "ErrOut", validate_device_path },
|
{ EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
|
||||||
{ "ErrOutDev", validate_device_path },
|
{ EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
|
||||||
{ "Timeout", validate_uint16 },
|
{ EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
|
||||||
{ "Lang", validate_ascii_string },
|
{ EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
|
||||||
{ "PlatformLang", validate_ascii_string },
|
{ EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
|
||||||
{ "", NULL },
|
{ 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
|
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;
|
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;
|
const char *name = variable_validate[i].name;
|
||||||
int match;
|
int match = 0;
|
||||||
|
|
||||||
for (match = 0; ; match++) {
|
if (efi_guidcmp(vendor, variable_validate[i].vendor))
|
||||||
char c = name[match];
|
continue;
|
||||||
u16 u = unicode_name[match];
|
|
||||||
|
|
||||||
/* All special variables are plain ascii */
|
if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
|
||||||
if (u > 127)
|
if (variable_validate[i].validate == NULL)
|
||||||
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)
|
|
||||||
break;
|
break;
|
||||||
|
kfree(utf8_name);
|
||||||
/* Reached the end of the string while matching */
|
return variable_validate[i].validate(var_name, match,
|
||||||
if (!c)
|
data, data_size);
|
||||||
return variable_validate[i].validate(var,
|
|
||||||
match, data, len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kfree(utf8_name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(efivar_validate);
|
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
|
static efi_status_t
|
||||||
check_var_size(u32 attributes, unsigned long size)
|
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;
|
*set = false;
|
||||||
|
|
||||||
if (efivar_validate(&entry->var, data, *size) == false)
|
if (efivar_validate(*vendor, name, data, *size) == false)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/efi.h>
|
#include <linux/efi.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
@ -108,9 +109,79 @@ out_free:
|
||||||
return size;
|
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 = {
|
const struct file_operations efivarfs_file_operations = {
|
||||||
.open = simple_open,
|
.open = simple_open,
|
||||||
.read = efivarfs_file_read,
|
.read = efivarfs_file_read,
|
||||||
.write = efivarfs_file_write,
|
.write = efivarfs_file_write,
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
|
.unlocked_ioctl = efivarfs_file_ioctl,
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
struct inode *efivarfs_get_inode(struct super_block *sb,
|
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);
|
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_ino = get_next_ino();
|
||||||
inode->i_mode = mode;
|
inode->i_mode = mode;
|
||||||
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||||
|
inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
|
||||||
switch (mode & S_IFMT) {
|
switch (mode & S_IFMT) {
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
inode->i_fop = &efivarfs_file_operations;
|
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,
|
static int efivarfs_create(struct inode *dir, struct dentry *dentry,
|
||||||
umode_t mode, bool excl)
|
umode_t mode, bool excl)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode = NULL;
|
||||||
struct efivar_entry *var;
|
struct efivar_entry *var;
|
||||||
int namelen, i = 0, err = 0;
|
int namelen, i = 0, err = 0;
|
||||||
|
bool is_removable = false;
|
||||||
|
|
||||||
if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
|
if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
|
|
||||||
if (!inode)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
|
var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
|
||||||
if (!var) {
|
if (!var)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* length of the variable name itself: remove GUID and separator */
|
/* length of the variable name itself: remove GUID and separator */
|
||||||
namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
|
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,
|
efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
|
||||||
&var->var.VendorGuid);
|
&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++)
|
for (i = 0; i < namelen; i++)
|
||||||
var->var.VariableName[i] = dentry->d_name.name[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:
|
out:
|
||||||
if (err) {
|
if (err) {
|
||||||
kfree(var);
|
kfree(var);
|
||||||
iput(inode);
|
if (inode)
|
||||||
|
iput(inode);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations;
|
||||||
extern const struct inode_operations efivarfs_dir_inode_operations;
|
extern const struct inode_operations efivarfs_dir_inode_operations;
|
||||||
extern bool efivarfs_valid_name(const char *str, int len);
|
extern bool efivarfs_valid_name(const char *str, int len);
|
||||||
extern struct inode *efivarfs_get_inode(struct super_block *sb,
|
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;
|
extern struct list_head efivarfs_list;
|
||||||
|
|
||||||
|
|
|
@ -128,8 +128,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
|
||||||
struct dentry *dentry, *root = sb->s_root;
|
struct dentry *dentry, *root = sb->s_root;
|
||||||
unsigned long size = 0;
|
unsigned long size = 0;
|
||||||
char *name;
|
char *name;
|
||||||
int len, i;
|
int len;
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
|
bool is_removable = false;
|
||||||
|
|
||||||
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
||||||
if (!entry)
|
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.VariableName, name16, name_size);
|
||||||
memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
|
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, plus '-', plus GUID, plus NUL*/
|
||||||
name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
|
name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
|
||||||
if (!name)
|
if (!name)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
ucs2_as_utf8(name, entry->var.VariableName, len);
|
||||||
name[i] = entry->var.VariableName[i] & 0xFF;
|
|
||||||
|
if (efivar_variable_is_removable(entry->var.VendorGuid, name, len))
|
||||||
|
is_removable = true;
|
||||||
|
|
||||||
name[len] = '-';
|
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';
|
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)
|
if (!inode)
|
||||||
goto fail_name;
|
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_d_op = &efivarfs_d_ops;
|
||||||
sb->s_time_gran = 1;
|
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)
|
if (!inode)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
inode->i_op = &efivarfs_dir_inode_operations;
|
inode->i_op = &efivarfs_dir_inode_operations;
|
||||||
|
|
|
@ -30,8 +30,6 @@ struct alg_sock {
|
||||||
|
|
||||||
struct sock *parent;
|
struct sock *parent;
|
||||||
|
|
||||||
unsigned int refcnt;
|
|
||||||
|
|
||||||
const struct af_alg_type *type;
|
const struct af_alg_type *type;
|
||||||
void *private;
|
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_unregister_type(const struct af_alg_type *type);
|
||||||
|
|
||||||
int af_alg_release(struct socket *sock);
|
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_accept(struct sock *sk, struct socket *newsock);
|
||||||
|
|
||||||
int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len,
|
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;
|
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)
|
static inline void af_alg_init_completion(struct af_alg_completion *completion)
|
||||||
{
|
{
|
||||||
init_completion(&completion->completion);
|
init_completion(&completion->completion);
|
||||||
|
|
|
@ -811,8 +811,10 @@ struct efivars {
|
||||||
* and we use a page for reading/writing.
|
* and we use a page for reading/writing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define EFI_VAR_NAME_LEN 1024
|
||||||
|
|
||||||
struct efi_variable {
|
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;
|
efi_guid_t VendorGuid;
|
||||||
unsigned long DataSize;
|
unsigned long DataSize;
|
||||||
__u8 Data[1024];
|
__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 efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
|
||||||
struct list_head *head, bool remove);
|
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;
|
extern struct work_struct efivar_work;
|
||||||
void efivar_run_worker(void);
|
void efivar_run_worker(void);
|
||||||
|
|
|
@ -226,6 +226,12 @@ struct module_ref {
|
||||||
unsigned long decs;
|
unsigned long decs;
|
||||||
} __attribute((aligned(2 * sizeof(unsigned long))));
|
} __attribute((aligned(2 * sizeof(unsigned long))));
|
||||||
|
|
||||||
|
struct mod_kallsyms {
|
||||||
|
Elf_Sym *symtab;
|
||||||
|
unsigned int num_symtab;
|
||||||
|
char *strtab;
|
||||||
|
};
|
||||||
|
|
||||||
struct module
|
struct module
|
||||||
{
|
{
|
||||||
enum module_state state;
|
enum module_state state;
|
||||||
|
@ -314,14 +320,9 @@ struct module
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
/*
|
/* Protected by RCU and/or module_mutex: use rcu_dereference() */
|
||||||
* We keep the symbol and string tables for kallsyms.
|
struct mod_kallsyms *kallsyms;
|
||||||
* The core_* fields below are temporary, loader-only (they
|
struct mod_kallsyms core_kallsyms;
|
||||||
* could really be discarded after module init).
|
|
||||||
*/
|
|
||||||
Elf_Sym *symtab, *core_symtab;
|
|
||||||
unsigned int num_symtab, core_num_syms;
|
|
||||||
char *strtab, *core_strtab;
|
|
||||||
|
|
||||||
/* Section attributes */
|
/* Section attributes */
|
||||||
struct module_sect_attrs *sect_attrs;
|
struct module_sect_attrs *sect_attrs;
|
||||||
|
|
|
@ -129,9 +129,6 @@ static inline void tracepoint_synchronize_unregister(void)
|
||||||
void *it_func; \
|
void *it_func; \
|
||||||
void *__data; \
|
void *__data; \
|
||||||
\
|
\
|
||||||
if (!cpu_online(raw_smp_processor_id())) \
|
|
||||||
return; \
|
|
||||||
\
|
|
||||||
if (!(cond)) \
|
if (!(cond)) \
|
||||||
return; \
|
return; \
|
||||||
prercu; \
|
prercu; \
|
||||||
|
@ -275,15 +272,19 @@ static inline void tracepoint_synchronize_unregister(void)
|
||||||
* "void *__data, proto" as the callback prototype.
|
* "void *__data, proto" as the callback prototype.
|
||||||
*/
|
*/
|
||||||
#define DECLARE_TRACE_NOARGS(name) \
|
#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) \
|
#define DECLARE_TRACE(name, proto, args) \
|
||||||
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1, \
|
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \
|
||||||
PARAMS(void *__data, proto), \
|
cpu_online(raw_smp_processor_id()), \
|
||||||
PARAMS(__data, args))
|
PARAMS(void *__data, proto), \
|
||||||
|
PARAMS(__data, args))
|
||||||
|
|
||||||
#define DECLARE_TRACE_CONDITION(name, proto, args, cond) \
|
#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(void *__data, proto), \
|
||||||
PARAMS(__data, args))
|
PARAMS(__data, args))
|
||||||
|
|
||||||
|
|
|
@ -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);
|
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);
|
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_ */
|
#endif /* _LINUX_UCS2_STRING_H_ */
|
||||||
|
|
109
kernel/module.c
109
kernel/module.c
|
@ -261,6 +261,9 @@ struct load_info {
|
||||||
struct _ddebug *debug;
|
struct _ddebug *debug;
|
||||||
unsigned int num_debug;
|
unsigned int num_debug;
|
||||||
bool sig_ok;
|
bool sig_ok;
|
||||||
|
#ifdef CONFIG_KALLSYMS
|
||||||
|
unsigned long mod_kallsyms_init_off;
|
||||||
|
#endif
|
||||||
struct {
|
struct {
|
||||||
unsigned int sym, str, mod, vers, info, pcpu;
|
unsigned int sym, str, mod, vers, info, pcpu;
|
||||||
} index;
|
} 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,
|
strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
|
||||||
info->index.str) | INIT_OFFSET_MASK;
|
info->index.str) | INIT_OFFSET_MASK;
|
||||||
pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
|
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)
|
static void add_kallsyms(struct module *mod, const struct load_info *info)
|
||||||
{
|
{
|
||||||
unsigned int i, ndst;
|
unsigned int i, ndst;
|
||||||
|
@ -2438,28 +2453,33 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
|
||||||
char *s;
|
char *s;
|
||||||
Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
|
Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
|
||||||
|
|
||||||
mod->symtab = (void *)symsec->sh_addr;
|
/* Set up to point into init section. */
|
||||||
mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
|
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. */
|
/* 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. */
|
/* Set types up while we still have access to sections. */
|
||||||
for (i = 0; i < mod->num_symtab; i++)
|
for (i = 0; i < mod->kallsyms->num_symtab; i++)
|
||||||
mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
|
mod->kallsyms->symtab[i].st_info
|
||||||
|
= elf_type(&mod->kallsyms->symtab[i], info);
|
||||||
|
|
||||||
mod->core_symtab = dst = mod->module_core + info->symoffs;
|
/* Now populate the cut down core kallsyms for after init. */
|
||||||
mod->core_strtab = s = mod->module_core + info->stroffs;
|
mod->core_kallsyms.symtab = dst = mod->module_core + info->symoffs;
|
||||||
src = mod->symtab;
|
mod->core_kallsyms.strtab = s = mod->module_core + info->stroffs;
|
||||||
for (ndst = i = 0; i < mod->num_symtab; i++) {
|
src = mod->kallsyms->symtab;
|
||||||
|
for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
|
||||||
if (i == 0 ||
|
if (i == 0 ||
|
||||||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
||||||
dst[ndst] = src[i];
|
dst[ndst] = src[i];
|
||||||
dst[ndst++].st_name = s - mod->core_strtab;
|
dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
|
||||||
s += strlcpy(s, &mod->strtab[src[i].st_name],
|
s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
|
||||||
KSYM_NAME_LEN) + 1;
|
KSYM_NAME_LEN) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod->core_num_syms = ndst;
|
mod->core_kallsyms.num_symtab = ndst;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void layout_symtab(struct module *mod, struct load_info *info)
|
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);
|
module_put(mod);
|
||||||
trim_init_extable(mod);
|
trim_init_extable(mod);
|
||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
mod->num_symtab = mod->core_num_syms;
|
/* Switch to core kallsyms now init is done: kallsyms may be walking! */
|
||||||
mod->symtab = mod->core_symtab;
|
rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
|
||||||
mod->strtab = mod->core_strtab;
|
|
||||||
#endif
|
#endif
|
||||||
unset_module_init_ro_nx(mod);
|
unset_module_init_ro_nx(mod);
|
||||||
module_free(mod, mod->module_init);
|
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] == '.');
|
&& (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,
|
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 int i, best = 0;
|
||||||
unsigned long nextval;
|
unsigned long nextval;
|
||||||
|
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
|
||||||
|
|
||||||
/* At worse, next value is at end of module */
|
/* At worse, next value is at end of module */
|
||||||
if (within_module_init(addr, mod))
|
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
|
/* Scan for closest preceding symbol, and next symbol. (ELF
|
||||||
starts real symbols at 1). */
|
starts real symbols at 1). */
|
||||||
for (i = 1; i < mod->num_symtab; i++) {
|
for (i = 1; i < kallsyms->num_symtab; i++) {
|
||||||
if (mod->symtab[i].st_shndx == SHN_UNDEF)
|
if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* We ignore unnamed symbols: they're uninformative
|
/* We ignore unnamed symbols: they're uninformative
|
||||||
* and inserted at a whim. */
|
* and inserted at a whim. */
|
||||||
if (*symname(mod, i) == '\0'
|
if (*symname(kallsyms, i) == '\0'
|
||||||
|| is_arm_mapping_symbol(symname(mod, i)))
|
|| is_arm_mapping_symbol(symname(kallsyms, i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mod->symtab[i].st_value <= addr
|
if (kallsyms->symtab[i].st_value <= addr
|
||||||
&& mod->symtab[i].st_value > mod->symtab[best].st_value)
|
&& kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
|
||||||
best = i;
|
best = i;
|
||||||
if (mod->symtab[i].st_value > addr
|
if (kallsyms->symtab[i].st_value > addr
|
||||||
&& mod->symtab[i].st_value < nextval)
|
&& kallsyms->symtab[i].st_value < nextval)
|
||||||
nextval = mod->symtab[i].st_value;
|
nextval = kallsyms->symtab[i].st_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!best)
|
if (!best)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
*size = nextval - mod->symtab[best].st_value;
|
*size = nextval - kallsyms->symtab[best].st_value;
|
||||||
if (offset)
|
if (offset)
|
||||||
*offset = addr - mod->symtab[best].st_value;
|
*offset = addr - kallsyms->symtab[best].st_value;
|
||||||
return symname(mod, best);
|
return symname(kallsyms, best);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For kallsyms to ask for address resolution. NULL means not found. Careful
|
/* 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();
|
preempt_disable();
|
||||||
list_for_each_entry_rcu(mod, &modules, list) {
|
list_for_each_entry_rcu(mod, &modules, list) {
|
||||||
|
struct mod_kallsyms *kallsyms;
|
||||||
|
|
||||||
if (mod->state == MODULE_STATE_UNFORMED)
|
if (mod->state == MODULE_STATE_UNFORMED)
|
||||||
continue;
|
continue;
|
||||||
if (symnum < mod->num_symtab) {
|
kallsyms = rcu_dereference_sched(mod->kallsyms);
|
||||||
*value = mod->symtab[symnum].st_value;
|
if (symnum < kallsyms->num_symtab) {
|
||||||
*type = mod->symtab[symnum].st_info;
|
*value = kallsyms->symtab[symnum].st_value;
|
||||||
strlcpy(name, symname(mod, symnum), KSYM_NAME_LEN);
|
*type = kallsyms->symtab[symnum].st_info;
|
||||||
|
strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN);
|
||||||
strlcpy(module_name, mod->name, MODULE_NAME_LEN);
|
strlcpy(module_name, mod->name, MODULE_NAME_LEN);
|
||||||
*exported = is_exported(name, *value, mod);
|
*exported = is_exported(name, *value, mod);
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
symnum -= mod->num_symtab;
|
symnum -= kallsyms->num_symtab;
|
||||||
}
|
}
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
return -ERANGE;
|
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)
|
static unsigned long mod_find_symname(struct module *mod, const char *name)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
|
||||||
|
|
||||||
for (i = 0; i < mod->num_symtab; i++)
|
for (i = 0; i < kallsyms->num_symtab; i++)
|
||||||
if (strcmp(name, symname(mod, i)) == 0 &&
|
if (strcmp(name, symname(kallsyms, i)) == 0 &&
|
||||||
mod->symtab[i].st_info != 'U')
|
kallsyms->symtab[i].st_info != 'U')
|
||||||
return mod->symtab[i].st_value;
|
return kallsyms->symtab[i].st_value;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4076,11 +4100,14 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(mod, &modules, list) {
|
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)
|
if (mod->state == MODULE_STATE_UNFORMED)
|
||||||
continue;
|
continue;
|
||||||
for (i = 0; i < mod->num_symtab; i++) {
|
for (i = 0; i < kallsyms->num_symtab; i++) {
|
||||||
ret = fn(data, symname(mod, i),
|
ret = fn(data, symname(kallsyms, i),
|
||||||
mod, mod->symtab[i].st_value);
|
mod, kallsyms->symtab[i].st_value);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ucs2_strncmp);
|
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);
|
||||||
|
|
|
@ -290,7 +290,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare A-MPDU MLME for Rx aggregation */
|
/* 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)
|
if (!tid_agg_rx)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
|
|
|
@ -454,7 +454,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
|
||||||
if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
|
if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ieee80211_start_tx_ba_session(pubsta, tid, 5000);
|
ieee80211_start_tx_ba_session(pubsta, tid, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -342,6 +342,39 @@ static const int compat_event_type_size[] = {
|
||||||
|
|
||||||
/* IW event code */
|
/* 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)
|
static int __net_init wext_pernet_init(struct net *net)
|
||||||
{
|
{
|
||||||
skb_queue_head_init(&net->wext_nlevents);
|
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)
|
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);
|
subsys_initcall(wireless_nlevent_init);
|
||||||
|
@ -368,17 +406,8 @@ subsys_initcall(wireless_nlevent_init);
|
||||||
/* Process events generated by the wireless layer or the driver. */
|
/* Process events generated by the wireless layer or the driver. */
|
||||||
static void wireless_nlevent_process(struct work_struct *work)
|
static void wireless_nlevent_process(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
|
||||||
struct net *net;
|
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
wireless_nlevent_flush();
|
||||||
for_each_net(net) {
|
|
||||||
while ((skb = skb_dequeue(&net->wext_nlevents)))
|
|
||||||
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
|
|
||||||
GFP_KERNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||||
struct wm8994 *control = wm8994->wm8994;
|
struct wm8994 *control = wm8994->wm8994;
|
||||||
int value = ucontrol->value.integer.value[0];
|
int value = ucontrol->value.enumerated.item[0];
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
/* Don't allow on the fly reconfiguration */
|
/* 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 snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||||
struct wm8994 *control = wm8994->wm8994;
|
struct wm8994 *control = wm8994->wm8994;
|
||||||
int value = ucontrol->value.integer.value[0];
|
int value = ucontrol->value.enumerated.item[0];
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
/* Don't allow on the fly reconfiguration */
|
/* 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 snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||||
struct wm8994 *control = wm8994->wm8994;
|
struct wm8994 *control = wm8994->wm8994;
|
||||||
int value = ucontrol->value.integer.value[0];
|
int value = ucontrol->value.enumerated.item[0];
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
/* Don't allow on the fly reconfiguration */
|
/* 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 snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||||
struct wm8994 *control = wm8994->wm8994;
|
struct wm8994 *control = wm8994->wm8994;
|
||||||
int value = ucontrol->value.integer.value[0];
|
int value = ucontrol->value.enumerated.item[0];
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
/* Don't allow on the fly reconfiguration */
|
/* Don't allow on the fly reconfiguration */
|
||||||
|
|
|
@ -361,7 +361,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
|
||||||
struct wm8994 *control = wm8994->wm8994;
|
struct wm8994 *control = wm8994->wm8994;
|
||||||
struct wm8994_pdata *pdata = &control->pdata;
|
struct wm8994_pdata *pdata = &control->pdata;
|
||||||
int drc = wm8994_get_drc(kcontrol->id.name);
|
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)
|
if (drc < 0)
|
||||||
return drc;
|
return drc;
|
||||||
|
@ -468,7 +468,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
|
||||||
struct wm8994 *control = wm8994->wm8994;
|
struct wm8994 *control = wm8994->wm8994;
|
||||||
struct wm8994_pdata *pdata = &control->pdata;
|
struct wm8994_pdata *pdata = &control->pdata;
|
||||||
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
|
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)
|
if (block < 0)
|
||||||
return block;
|
return block;
|
||||||
|
|
|
@ -88,7 +88,11 @@ test_delete()
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm $file
|
rm $file 2>/dev/null
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
chattr -i $file
|
||||||
|
rm $file
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -e $file ]; then
|
if [ -e $file ]; then
|
||||||
echo "$file couldn't be deleted" >&2
|
echo "$file couldn't be deleted" >&2
|
||||||
|
@ -111,6 +115,7 @@ test_zero_size_delete()
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
chattr -i $file
|
||||||
printf "$attrs" > $file
|
printf "$attrs" > $file
|
||||||
|
|
||||||
if [ -e $file ]; then
|
if [ -e $file ]; then
|
||||||
|
@ -141,7 +146,11 @@ test_valid_filenames()
|
||||||
echo "$file could not be created" >&2
|
echo "$file could not be created" >&2
|
||||||
ret=1
|
ret=1
|
||||||
else
|
else
|
||||||
rm $file
|
rm $file 2>/dev/null
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
chattr -i $file
|
||||||
|
rm $file
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -174,7 +183,11 @@ test_invalid_filenames()
|
||||||
|
|
||||||
if [ -e $file ]; then
|
if [ -e $file ]; then
|
||||||
echo "Creating $file should have failed" >&2
|
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
|
ret=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -1,10 +1,68 @@
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +85,7 @@ int main(int argc, char **argv)
|
||||||
buf[4] = 0;
|
buf[4] = 0;
|
||||||
|
|
||||||
/* create a test variable */
|
/* create a test variable */
|
||||||
fd = open(path, O_WRONLY | O_CREAT);
|
fd = open(path, O_WRONLY | O_CREAT, 0600);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("open(O_WRONLY)");
|
perror("open(O_WRONLY)");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -41,6 +99,18 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
close(fd);
|
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);
|
fd = open(path, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("open");
|
perror("open");
|
||||||
|
|
Loading…
Reference in New Issue