mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
Merge 4.19.204 into android-4.19-stable
Changes in 4.19.204 KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB tracing: Reject string operand in the histogram expression bpf: Inherit expanded/patched seen count from old aux data bpf: Do not mark insn as seen under speculative path verification bpf: Fix leakage under speculation on mispredicted branches bpf, selftests: Adjust few selftest outcomes wrt unreachable code KVM: X86: MMU: Use the correct inherited permissions to get shadow page USB:ehci:fix Kunpeng920 ehci hardware problem ppp: Fix generating ppp unit id when ifname is not specified ovl: prevent private clone if bind mount is not allowed net: xilinx_emaclite: Do not print real IOMEM pointer Linux 4.19.204 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I976cb68d2906fa68add207bca749a1964378c916
This commit is contained in:
@@ -152,8 +152,8 @@ Shadow pages contain the following information:
|
||||
shadow pages) so role.quadrant takes values in the range 0..3. Each
|
||||
quadrant maps 1GB virtual address space.
|
||||
role.access:
|
||||
Inherited guest access permissions in the form uwx. Note execute
|
||||
permission is positive, not negative.
|
||||
Inherited guest access permissions from the parent ptes in the form uwx.
|
||||
Note execute permission is positive, not negative.
|
||||
role.invalid:
|
||||
The page is invalid and should not be used. It is a root page that is
|
||||
currently pinned (by a cpu hardware register pointing to it); once it is
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 19
|
||||
SUBLEVEL = 203
|
||||
SUBLEVEL = 204
|
||||
EXTRAVERSION =
|
||||
NAME = "People's Front"
|
||||
|
||||
|
||||
@@ -93,8 +93,8 @@ struct guest_walker {
|
||||
gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
|
||||
pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS];
|
||||
bool pte_writable[PT_MAX_FULL_LEVELS];
|
||||
unsigned pt_access;
|
||||
unsigned pte_access;
|
||||
unsigned int pt_access[PT_MAX_FULL_LEVELS];
|
||||
unsigned int pte_access;
|
||||
gfn_t gfn;
|
||||
struct x86_exception fault;
|
||||
};
|
||||
@@ -388,13 +388,15 @@ retry_walk:
|
||||
}
|
||||
|
||||
walker->ptes[walker->level - 1] = pte;
|
||||
|
||||
/* Convert to ACC_*_MASK flags for struct guest_walker. */
|
||||
walker->pt_access[walker->level - 1] = FNAME(gpte_access)(pt_access ^ walk_nx_mask);
|
||||
} while (!is_last_gpte(mmu, walker->level, pte));
|
||||
|
||||
pte_pkey = FNAME(gpte_pkeys)(vcpu, pte);
|
||||
accessed_dirty = have_ad ? pte_access & PT_GUEST_ACCESSED_MASK : 0;
|
||||
|
||||
/* Convert to ACC_*_MASK flags for struct guest_walker. */
|
||||
walker->pt_access = FNAME(gpte_access)(pt_access ^ walk_nx_mask);
|
||||
walker->pte_access = FNAME(gpte_access)(pte_access ^ walk_nx_mask);
|
||||
errcode = permission_fault(vcpu, mmu, walker->pte_access, pte_pkey, access);
|
||||
if (unlikely(errcode))
|
||||
@@ -433,7 +435,8 @@ retry_walk:
|
||||
}
|
||||
|
||||
pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
|
||||
__func__, (u64)pte, walker->pte_access, walker->pt_access);
|
||||
__func__, (u64)pte, walker->pte_access,
|
||||
walker->pt_access[walker->level - 1]);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
@@ -602,7 +605,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
|
||||
{
|
||||
struct kvm_mmu_page *sp = NULL;
|
||||
struct kvm_shadow_walk_iterator it;
|
||||
unsigned direct_access, access = gw->pt_access;
|
||||
unsigned int direct_access, access;
|
||||
int top_level, ret;
|
||||
gfn_t gfn, base_gfn;
|
||||
|
||||
@@ -634,6 +637,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
|
||||
sp = NULL;
|
||||
if (!is_shadow_present_pte(*it.sptep)) {
|
||||
table_gfn = gw->table_gfn[it.level - 2];
|
||||
access = gw->pt_access[it.level - 2];
|
||||
sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1,
|
||||
false, access);
|
||||
}
|
||||
|
||||
@@ -1780,7 +1780,7 @@ static void __sev_asid_free(int asid)
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
sd = per_cpu(svm_data, cpu);
|
||||
sd->sev_vmcbs[pos] = NULL;
|
||||
sd->sev_vmcbs[asid] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1177,9 +1177,8 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
|
||||
}
|
||||
|
||||
dev_info(dev,
|
||||
"Xilinx EmacLite at 0x%08X mapped to 0x%08X, irq=%d\n",
|
||||
(unsigned int __force)ndev->mem_start,
|
||||
(unsigned int __force)lp->base_addr, ndev->irq);
|
||||
"Xilinx EmacLite at 0x%08X mapped to 0x%p, irq=%d\n",
|
||||
(unsigned int __force)ndev->mem_start, lp->base_addr, ndev->irq);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
||||
@@ -287,7 +287,7 @@ static struct channel *ppp_find_channel(struct ppp_net *pn, int unit);
|
||||
static int ppp_connect_channel(struct channel *pch, int unit);
|
||||
static int ppp_disconnect_channel(struct channel *pch);
|
||||
static void ppp_destroy_channel(struct channel *pch);
|
||||
static int unit_get(struct idr *p, void *ptr);
|
||||
static int unit_get(struct idr *p, void *ptr, int min);
|
||||
static int unit_set(struct idr *p, void *ptr, int n);
|
||||
static void unit_put(struct idr *p, int n);
|
||||
static void *unit_find(struct idr *p, int n);
|
||||
@@ -963,9 +963,20 @@ static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set)
|
||||
mutex_lock(&pn->all_ppp_mutex);
|
||||
|
||||
if (unit < 0) {
|
||||
ret = unit_get(&pn->units_idr, ppp);
|
||||
ret = unit_get(&pn->units_idr, ppp, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (!ifname_is_set) {
|
||||
while (1) {
|
||||
snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ret);
|
||||
if (!__dev_get_by_name(ppp->ppp_net, ppp->dev->name))
|
||||
break;
|
||||
unit_put(&pn->units_idr, ret);
|
||||
ret = unit_get(&pn->units_idr, ppp, ret + 1);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Caller asked for a specific unit number. Fail with -EEXIST
|
||||
* if unavailable. For backward compatibility, return -EEXIST
|
||||
@@ -3300,9 +3311,9 @@ static int unit_set(struct idr *p, void *ptr, int n)
|
||||
}
|
||||
|
||||
/* get new free unit number and associate pointer with it */
|
||||
static int unit_get(struct idr *p, void *ptr)
|
||||
static int unit_get(struct idr *p, void *ptr, int min)
|
||||
{
|
||||
return idr_alloc(p, ptr, 0, 0, GFP_KERNEL);
|
||||
return idr_alloc(p, ptr, min, 0, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/* put unit number back to a pool */
|
||||
|
||||
@@ -298,6 +298,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
if (pdev->vendor == PCI_VENDOR_ID_STMICRO
|
||||
&& pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
|
||||
; /* ConneXT has no sbrn register */
|
||||
else if (pdev->vendor == PCI_VENDOR_ID_HUAWEI
|
||||
&& pdev->device == 0xa239)
|
||||
; /* HUAWEI Kunpeng920 USB EHCI has no sbrn register */
|
||||
else
|
||||
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
|
||||
|
||||
|
||||
@@ -1817,6 +1817,20 @@ void drop_collected_mounts(struct vfsmount *mnt)
|
||||
namespace_unlock();
|
||||
}
|
||||
|
||||
static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
|
||||
{
|
||||
struct mount *child;
|
||||
|
||||
list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
|
||||
if (!is_subdir(child->mnt_mountpoint, dentry))
|
||||
continue;
|
||||
|
||||
if (child->mnt.mnt_flags & MNT_LOCKED)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* clone_private_mount - create a private clone of a path
|
||||
*
|
||||
@@ -1831,14 +1845,27 @@ struct vfsmount *clone_private_mount(const struct path *path)
|
||||
struct mount *old_mnt = real_mount(path->mnt);
|
||||
struct mount *new_mnt;
|
||||
|
||||
down_read(&namespace_sem);
|
||||
if (IS_MNT_UNBINDABLE(old_mnt))
|
||||
return ERR_PTR(-EINVAL);
|
||||
goto invalid;
|
||||
|
||||
if (!check_mnt(old_mnt))
|
||||
goto invalid;
|
||||
|
||||
if (has_locked_children(old_mnt, path->dentry))
|
||||
goto invalid;
|
||||
|
||||
new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
|
||||
up_read(&namespace_sem);
|
||||
|
||||
if (IS_ERR(new_mnt))
|
||||
return ERR_CAST(new_mnt);
|
||||
|
||||
return &new_mnt->mnt;
|
||||
|
||||
invalid:
|
||||
up_read(&namespace_sem);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clone_private_mount);
|
||||
|
||||
@@ -2154,19 +2181,6 @@ static int do_change_type(struct path *path, int ms_flags)
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
|
||||
{
|
||||
struct mount *child;
|
||||
list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
|
||||
if (!is_subdir(child->mnt_mountpoint, dentry))
|
||||
continue;
|
||||
|
||||
if (child->mnt.mnt_flags & MNT_LOCKED)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* do loopback mount.
|
||||
*/
|
||||
|
||||
@@ -2812,6 +2812,27 @@ struct bpf_sanitize_info {
|
||||
bool mask_to_left;
|
||||
};
|
||||
|
||||
static struct bpf_verifier_state *
|
||||
sanitize_speculative_path(struct bpf_verifier_env *env,
|
||||
const struct bpf_insn *insn,
|
||||
u32 next_idx, u32 curr_idx)
|
||||
{
|
||||
struct bpf_verifier_state *branch;
|
||||
struct bpf_reg_state *regs;
|
||||
|
||||
branch = push_stack(env, next_idx, curr_idx, true);
|
||||
if (branch && insn) {
|
||||
regs = branch->frame[branch->curframe]->regs;
|
||||
if (BPF_SRC(insn->code) == BPF_K) {
|
||||
mark_reg_unknown(env, regs, insn->dst_reg);
|
||||
} else if (BPF_SRC(insn->code) == BPF_X) {
|
||||
mark_reg_unknown(env, regs, insn->dst_reg);
|
||||
mark_reg_unknown(env, regs, insn->src_reg);
|
||||
}
|
||||
}
|
||||
return branch;
|
||||
}
|
||||
|
||||
static int sanitize_ptr_alu(struct bpf_verifier_env *env,
|
||||
struct bpf_insn *insn,
|
||||
const struct bpf_reg_state *ptr_reg,
|
||||
@@ -2895,12 +2916,26 @@ do_sim:
|
||||
tmp = *dst_reg;
|
||||
*dst_reg = *ptr_reg;
|
||||
}
|
||||
ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
|
||||
ret = sanitize_speculative_path(env, NULL, env->insn_idx + 1,
|
||||
env->insn_idx);
|
||||
if (!ptr_is_dst_reg && ret)
|
||||
*dst_reg = tmp;
|
||||
return !ret ? REASON_STACK : 0;
|
||||
}
|
||||
|
||||
static void sanitize_mark_insn_seen(struct bpf_verifier_env *env)
|
||||
{
|
||||
struct bpf_verifier_state *vstate = env->cur_state;
|
||||
|
||||
/* If we simulate paths under speculation, we don't update the
|
||||
* insn as 'seen' such that when we verify unreachable paths in
|
||||
* the non-speculative domain, sanitize_dead_code() can still
|
||||
* rewrite/sanitize them.
|
||||
*/
|
||||
if (!vstate->speculative)
|
||||
env->insn_aux_data[env->insn_idx].seen = true;
|
||||
}
|
||||
|
||||
static int sanitize_err(struct bpf_verifier_env *env,
|
||||
const struct bpf_insn *insn, int reason,
|
||||
const struct bpf_reg_state *off_reg,
|
||||
@@ -4275,14 +4310,28 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
|
||||
tnum_is_const(src_reg->var_off))
|
||||
pred = is_branch_taken(dst_reg, src_reg->var_off.value,
|
||||
opcode);
|
||||
|
||||
if (pred == 1) {
|
||||
/* only follow the goto, ignore fall-through */
|
||||
/* Only follow the goto, ignore fall-through. If needed, push
|
||||
* the fall-through branch for simulation under speculative
|
||||
* execution.
|
||||
*/
|
||||
if (!env->allow_ptr_leaks &&
|
||||
!sanitize_speculative_path(env, insn, *insn_idx + 1,
|
||||
*insn_idx))
|
||||
return -EFAULT;
|
||||
*insn_idx += insn->off;
|
||||
return 0;
|
||||
} else if (pred == 0) {
|
||||
/* only follow fall-through branch, since
|
||||
* that's where the program will go
|
||||
/* Only follow the fall-through branch, since that's where the
|
||||
* program will go. If needed, push the goto branch for
|
||||
* simulation under speculative execution.
|
||||
*/
|
||||
if (!env->allow_ptr_leaks &&
|
||||
!sanitize_speculative_path(env, insn,
|
||||
*insn_idx + insn->off + 1,
|
||||
*insn_idx))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5254,7 +5303,7 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
}
|
||||
|
||||
regs = cur_regs(env);
|
||||
env->insn_aux_data[env->insn_idx].seen = true;
|
||||
sanitize_mark_insn_seen(env);
|
||||
|
||||
if (class == BPF_ALU || class == BPF_ALU64) {
|
||||
err = check_alu_op(env, insn);
|
||||
@@ -5472,7 +5521,7 @@ process_bpf_exit:
|
||||
return err;
|
||||
|
||||
env->insn_idx++;
|
||||
env->insn_aux_data[env->insn_idx].seen = true;
|
||||
sanitize_mark_insn_seen(env);
|
||||
} else {
|
||||
verbose(env, "invalid BPF_LD mode\n");
|
||||
return -EINVAL;
|
||||
@@ -5690,6 +5739,7 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
|
||||
u32 off, u32 cnt)
|
||||
{
|
||||
struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
|
||||
bool old_seen = old_data[off].seen;
|
||||
int i;
|
||||
|
||||
if (cnt == 1)
|
||||
@@ -5701,8 +5751,10 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
|
||||
memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
|
||||
memcpy(new_data + off + cnt - 1, old_data + off,
|
||||
sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
|
||||
for (i = off; i < off + cnt - 1; i++)
|
||||
new_data[i].seen = true;
|
||||
for (i = off; i < off + cnt - 1; i++) {
|
||||
/* Expand insni[off]'s seen count to the patched range. */
|
||||
new_data[i].seen = old_seen;
|
||||
}
|
||||
env->insn_aux_data = new_data;
|
||||
vfree(old_data);
|
||||
return 0;
|
||||
|
||||
@@ -2790,6 +2790,12 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
|
||||
ret = PTR_ERR(operand1);
|
||||
goto free;
|
||||
}
|
||||
if (operand1->flags & HIST_FIELD_FL_STRING) {
|
||||
/* String type can not be the operand of unary operator. */
|
||||
destroy_hist_field(operand1, 0);
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
expr->flags |= operand1->flags &
|
||||
(HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
|
||||
@@ -2890,6 +2896,10 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
|
||||
operand1 = NULL;
|
||||
goto free;
|
||||
}
|
||||
if (operand1->flags & HIST_FIELD_FL_STRING) {
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* rest of string could be another expression e.g. b+c in a+b+c */
|
||||
operand_flags = 0;
|
||||
@@ -2899,6 +2909,10 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
|
||||
operand2 = NULL;
|
||||
goto free;
|
||||
}
|
||||
if (operand2->flags & HIST_FIELD_FL_STRING) {
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
ret = check_expr_operands(operand1, operand2);
|
||||
if (ret)
|
||||
|
||||
@@ -2792,6 +2792,8 @@ static struct bpf_test tests[] = {
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.errstr_unpriv = "R7 invalid mem access 'inv'",
|
||||
.result_unpriv = REJECT,
|
||||
.result = ACCEPT,
|
||||
.retval = 0,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user