Merge android-4.4.112 (5f6325b
) into msm-4.4
* refs/heads/tmp-5f6325b Linux 4.4.112 selftests/x86: Add test_vsyscall x86/alternatives: Add missing '\n' at end of ALTERNATIVE inline asm x86/alternatives: Fix optimize_nops() checking sysfs/cpu: Fix typos in vulnerability documentation x86/cpu: Implement CPU vulnerabilites sysfs functions sysfs/cpu: Add vulnerability folder x86/cpu: Merge bugs.c and bugs_64.c x86/cpufeatures: Add X86_BUG_SPECTRE_V[12] x86/pti: Rename BUG_CPU_INSECURE to BUG_CPU_MELTDOWN x86/cpufeatures: Add X86_BUG_CPU_INSECURE x86/cpufeatures: Make CPU bugs sticky x86/cpu: Factor out application of forced CPU caps x86/Documentation: Add PTI description e1000e: Fix e1000_check_for_copper_link_ich8lan return value. uas: ignore UAS for Norelsys NS1068(X) chips Bluetooth: Prevent stack info leak from the EFS element. staging: android: ashmem: fix a race condition in ASHMEM_SET_SIZE ioctl usbip: remove kernel addresses from usb device and urb debug msgs USB: fix usbmon BUG trigger usb: misc: usb3503: make sure reset is low for at least 100us USB: serial: cp210x: add new device ID ELV ALC 8xxx USB: serial: cp210x: add IDs for LifeScan OneTouch Verio IQ target: Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK iscsi-target: Make TASK_REASSIGN use proper se_cmd->cmd_kref bpf, array: fix overflow in max_entries and undefined behavior in index_mask bpf: prevent out-of-bounds speculation bpf: adjust insn_aux_data when patching insns bpf: refactor fixup_bpf_calls() bpf: move fixup_bpf_calls() function bpf: don't (ab)use instructions to store state bpf: add bpf_patch_insn_single helper kaiser: Set _PAGE_NX only if supported drm/vmwgfx: Potential off by one in vmw_view_add() KVM: x86: Add memory barrier on vmcs field lookup x86/microcode/intel: Extend BDW late-loading with a revision check rbd: set max_segments to USHRT_MAX crypto: algapi - fix NULL dereference in crypto_remove_spawns() ipv6: fix possible mem leaks in ipv6_make_skb() net: stmmac: enable EEE in MII, GMII or RGMII only sh_eth: fix SH7757 GEther initialization sh_eth: fix TSU resource handling RDS: null pointer dereference in rds_atomic_free_op RDS: Heap OOB write in rds_message_alloc_sgs() net: core: fix module type in sock_diag_bind ip6_tunnel: disable dst caching if tunnel is dual-stack 8021q: fix a memory leak for VLAN 0 device x86/pti/efi: broken conversion from efi to kernel page table Revert "userfaultfd: selftest: vm: allow to build in vm/ directory" xhci: Fix ring leak in failure path of xhci_alloc_virt_device() sysrq: Fix warning in sysrq generated crash. hwrng: core - sleep interruptible in read x86/mm/pat, /dev/mem: Remove superfluous error message cx82310_eth: use skb_cow_head() to deal with cloned skbs smsc75xx: use skb_cow_head() to deal with cloned skbs sr9700: use skb_cow_head() to deal with cloned skbs lan78xx: use skb_cow_head() to deal with cloned skbs r8152: adjust ALDPS function r8152: use test_and_clear_bit r8152: fix the wake event usb: musb: ux500: Fix NULL pointer dereference at system PM usbvision fix overflow of interfaces array locking/mutex: Allow next waiter lockless wakeup futex: Replace barrier() in unqueue_me() with READ_ONCE() locks: don't check for race with close when setting OFD lock zswap: don't param_set_charp while holding spinlock mm/zswap: use workqueue to destroy pool mm/page-writeback: fix dirty_ratelimit calculation mm/compaction: pass only pageblock aligned range to pageblock_pfn_to_page mm/compaction: fix invalid free_pfn and compact_cached_free_pfn x86/acpi: Reduce code duplication in mp_override_legacy_irq() ALSA: aloop: Fix racy hw constraints adjustment ALSA: aloop: Fix inconsistent format due to incomplete rule ALSA: aloop: Release cable upon open error path ALSA: pcm: Allow aborting mutex lock at OSS read/write loops ALSA: pcm: Abort properly at pending signal in OSS read/write loops ALSA: pcm: Add missing error checks in OSS emulation plugin builder ALSA: pcm: Remove incorrect snd_BUG_ON() usages iommu/arm-smmu-v3: Don't free page table ops twice x86/acpi: Handle SCI interrupts above legacy space gracefully x86/vsdo: Fix build on PARAVIRT_CLOCK=y, KVM_GUEST=n kvm: vmx: Scrub hardware GPRs at VM-exit net/mac80211/debugfs.c: prevent build failure with CONFIG_UBSAN=y MIPS: Disallow outsized PTRACE_SETREGSET NT_PRFPREG regset accesses MIPS: Also verify sizeof `elf_fpreg_t' with PTRACE_SETREGSET MIPS: Fix an FCSR access API regression with NT_PRFPREG and MSA MIPS: Consistently handle buffer counter with PTRACE_SETREGSET MIPS: Guard against any partial write attempt with PTRACE_SETREGSET MIPS: Factor out NT_PRFPREG regset access helpers MIPS: Validate PR_SET_FP_MODE prctl(2) requests against the ABI of the task IB/srpt: Disable RDMA access by the initiator can: gs_usb: fix return value of the "set_bittiming" callback KVM: Fix stack-out-of-bounds read in write_mmio dm bufio: fix shrinker scans when (nr_to_scan < retain_target) fscrypt: updates on 4.15-rc4 ANDROID: uid_sys_stats: fix the comment BACKPORT: optee: fix invalid of_node_put() in optee_driver_init() BACKPORT: tee: optee: sync with new naming of interrupts BACKPORT: tee: indicate privileged dev in gen_caps BACKPORT: tee: optee: interruptible RPC sleep BACKPORT: tee: optee: add const to tee_driver_ops and tee_desc structures BACKPORT: tee: tee_shm: Constify dma_buf_ops structures. BACKPORT: tee: add forward declaration for struct device BACKPORT: tee: optee: fix uninitialized symbol 'parg' BACKPORT: tee.txt: standardize document format BACKPORT: tee: add ARM_SMCCC dependency BACKPORT: selinux: nlmsgtab: add SOCK_DESTROY to the netlink mapping tables Conflicts: security/selinux/nlmsgtab.c Change-Id: I5770a565f39c321f2305f8228e41f822e3cd0625 Signed-off-by: Srinivasarao P <spathi@codeaurora.org>
This commit is contained in:
commit
8c8abdeafc
117 changed files with 2423 additions and 830 deletions
|
@ -271,3 +271,19 @@ Description: Parameters for the CPU cache attributes
|
|||
- WriteBack: data is written only to the cache line and
|
||||
the modified cache line is written to main
|
||||
memory only when it is replaced
|
||||
|
||||
What: /sys/devices/system/cpu/vulnerabilities
|
||||
/sys/devices/system/cpu/vulnerabilities/meltdown
|
||||
/sys/devices/system/cpu/vulnerabilities/spectre_v1
|
||||
/sys/devices/system/cpu/vulnerabilities/spectre_v2
|
||||
Date: January 2018
|
||||
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
|
||||
Description: Information about CPU vulnerabilities
|
||||
|
||||
The files are named after the code names of CPU
|
||||
vulnerabilities. The output of those files reflects the
|
||||
state of the CPUs in the system. Possible output values:
|
||||
|
||||
"Not affected" CPU is not affected by the vulnerability
|
||||
"Vulnerable" CPU is affected and no mitigation in effect
|
||||
"Mitigation: $M" CPU is affected and mitigation $M is in effect
|
||||
|
|
|
@ -2539,8 +2539,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
|
||||
nojitter [IA-64] Disables jitter checking for ITC timers.
|
||||
|
||||
nopti [X86-64] Disable KAISER isolation of kernel from user.
|
||||
|
||||
no-kvmclock [X86,KVM] Disable paravirtualized KVM clock driver
|
||||
|
||||
no-kvmapf [X86,KVM] Disable paravirtualized asynchronous page
|
||||
|
@ -3077,11 +3075,20 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
pt. [PARIDE]
|
||||
See Documentation/blockdev/paride.txt.
|
||||
|
||||
pti= [X86_64]
|
||||
Control KAISER user/kernel address space isolation:
|
||||
on - enable
|
||||
off - disable
|
||||
auto - default setting
|
||||
pti= [X86_64] Control Page Table Isolation of user and
|
||||
kernel address spaces. Disabling this feature
|
||||
removes hardening, but improves performance of
|
||||
system calls and interrupts.
|
||||
|
||||
on - unconditionally enable
|
||||
off - unconditionally disable
|
||||
auto - kernel detects whether your CPU model is
|
||||
vulnerable to issues that PTI mitigates
|
||||
|
||||
Not specifying this option is equivalent to pti=auto.
|
||||
|
||||
nopti [X86_64]
|
||||
Equivalent to pti=off
|
||||
|
||||
pty.legacy_count=
|
||||
[KNL] Number of legacy pty's. Overwrites compiled-in
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
=============
|
||||
TEE subsystem
|
||||
=============
|
||||
|
||||
This document describes the TEE subsystem in Linux.
|
||||
|
||||
A TEE (Trusted Execution Environment) is a trusted OS running in some
|
||||
|
@ -80,7 +83,7 @@ The GlobalPlatform TEE Client API [5] is implemented on top of the generic
|
|||
TEE API.
|
||||
|
||||
Picture of the relationship between the different components in the
|
||||
OP-TEE architecture.
|
||||
OP-TEE architecture::
|
||||
|
||||
User space Kernel Secure world
|
||||
~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~
|
||||
|
@ -109,10 +112,16 @@ kernel are handled by the kernel driver. Other RPC messages will be forwarded to
|
|||
tee-supplicant without further involvement of the driver, except switching
|
||||
shared memory buffer representation.
|
||||
|
||||
References:
|
||||
References
|
||||
==========
|
||||
|
||||
[1] https://github.com/OP-TEE/optee_os
|
||||
|
||||
[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
|
||||
|
||||
[3] drivers/tee/optee/optee_smc.h
|
||||
|
||||
[4] drivers/tee/optee/optee_msg.h
|
||||
|
||||
[5] http://www.globalplatform.org/specificationsdevice.asp look for
|
||||
"TEE Client API Specification v1.0" and click download.
|
||||
|
|
186
Documentation/x86/pti.txt
Normal file
186
Documentation/x86/pti.txt
Normal file
|
@ -0,0 +1,186 @@
|
|||
Overview
|
||||
========
|
||||
|
||||
Page Table Isolation (pti, previously known as KAISER[1]) is a
|
||||
countermeasure against attacks on the shared user/kernel address
|
||||
space such as the "Meltdown" approach[2].
|
||||
|
||||
To mitigate this class of attacks, we create an independent set of
|
||||
page tables for use only when running userspace applications. When
|
||||
the kernel is entered via syscalls, interrupts or exceptions, the
|
||||
page tables are switched to the full "kernel" copy. When the system
|
||||
switches back to user mode, the user copy is used again.
|
||||
|
||||
The userspace page tables contain only a minimal amount of kernel
|
||||
data: only what is needed to enter/exit the kernel such as the
|
||||
entry/exit functions themselves and the interrupt descriptor table
|
||||
(IDT). There are a few strictly unnecessary things that get mapped
|
||||
such as the first C function when entering an interrupt (see
|
||||
comments in pti.c).
|
||||
|
||||
This approach helps to ensure that side-channel attacks leveraging
|
||||
the paging structures do not function when PTI is enabled. It can be
|
||||
enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time.
|
||||
Once enabled at compile-time, it can be disabled at boot with the
|
||||
'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
|
||||
|
||||
Page Table Management
|
||||
=====================
|
||||
|
||||
When PTI is enabled, the kernel manages two sets of page tables.
|
||||
The first set is very similar to the single set which is present in
|
||||
kernels without PTI. This includes a complete mapping of userspace
|
||||
that the kernel can use for things like copy_to_user().
|
||||
|
||||
Although _complete_, the user portion of the kernel page tables is
|
||||
crippled by setting the NX bit in the top level. This ensures
|
||||
that any missed kernel->user CR3 switch will immediately crash
|
||||
userspace upon executing its first instruction.
|
||||
|
||||
The userspace page tables map only the kernel data needed to enter
|
||||
and exit the kernel. This data is entirely contained in the 'struct
|
||||
cpu_entry_area' structure which is placed in the fixmap which gives
|
||||
each CPU's copy of the area a compile-time-fixed virtual address.
|
||||
|
||||
For new userspace mappings, the kernel makes the entries in its
|
||||
page tables like normal. The only difference is when the kernel
|
||||
makes entries in the top (PGD) level. In addition to setting the
|
||||
entry in the main kernel PGD, a copy of the entry is made in the
|
||||
userspace page tables' PGD.
|
||||
|
||||
This sharing at the PGD level also inherently shares all the lower
|
||||
layers of the page tables. This leaves a single, shared set of
|
||||
userspace page tables to manage. One PTE to lock, one set of
|
||||
accessed bits, dirty bits, etc...
|
||||
|
||||
Overhead
|
||||
========
|
||||
|
||||
Protection against side-channel attacks is important. But,
|
||||
this protection comes at a cost:
|
||||
|
||||
1. Increased Memory Use
|
||||
a. Each process now needs an order-1 PGD instead of order-0.
|
||||
(Consumes an additional 4k per process).
|
||||
b. The 'cpu_entry_area' structure must be 2MB in size and 2MB
|
||||
aligned so that it can be mapped by setting a single PMD
|
||||
entry. This consumes nearly 2MB of RAM once the kernel
|
||||
is decompressed, but no space in the kernel image itself.
|
||||
|
||||
2. Runtime Cost
|
||||
a. CR3 manipulation to switch between the page table copies
|
||||
must be done at interrupt, syscall, and exception entry
|
||||
and exit (it can be skipped when the kernel is interrupted,
|
||||
though.) Moves to CR3 are on the order of a hundred
|
||||
cycles, and are required at every entry and exit.
|
||||
b. A "trampoline" must be used for SYSCALL entry. This
|
||||
trampoline depends on a smaller set of resources than the
|
||||
non-PTI SYSCALL entry code, so requires mapping fewer
|
||||
things into the userspace page tables. The downside is
|
||||
that stacks must be switched at entry time.
|
||||
d. Global pages are disabled for all kernel structures not
|
||||
mapped into both kernel and userspace page tables. This
|
||||
feature of the MMU allows different processes to share TLB
|
||||
entries mapping the kernel. Losing the feature means more
|
||||
TLB misses after a context switch. The actual loss of
|
||||
performance is very small, however, never exceeding 1%.
|
||||
d. Process Context IDentifiers (PCID) is a CPU feature that
|
||||
allows us to skip flushing the entire TLB when switching page
|
||||
tables by setting a special bit in CR3 when the page tables
|
||||
are changed. This makes switching the page tables (at context
|
||||
switch, or kernel entry/exit) cheaper. But, on systems with
|
||||
PCID support, the context switch code must flush both the user
|
||||
and kernel entries out of the TLB. The user PCID TLB flush is
|
||||
deferred until the exit to userspace, minimizing the cost.
|
||||
See intel.com/sdm for the gory PCID/INVPCID details.
|
||||
e. The userspace page tables must be populated for each new
|
||||
process. Even without PTI, the shared kernel mappings
|
||||
are created by copying top-level (PGD) entries into each
|
||||
new process. But, with PTI, there are now *two* kernel
|
||||
mappings: one in the kernel page tables that maps everything
|
||||
and one for the entry/exit structures. At fork(), we need to
|
||||
copy both.
|
||||
f. In addition to the fork()-time copying, there must also
|
||||
be an update to the userspace PGD any time a set_pgd() is done
|
||||
on a PGD used to map userspace. This ensures that the kernel
|
||||
and userspace copies always map the same userspace
|
||||
memory.
|
||||
g. On systems without PCID support, each CR3 write flushes
|
||||
the entire TLB. That means that each syscall, interrupt
|
||||
or exception flushes the TLB.
|
||||
h. INVPCID is a TLB-flushing instruction which allows flushing
|
||||
of TLB entries for non-current PCIDs. Some systems support
|
||||
PCIDs, but do not support INVPCID. On these systems, addresses
|
||||
can only be flushed from the TLB for the current PCID. When
|
||||
flushing a kernel address, we need to flush all PCIDs, so a
|
||||
single kernel address flush will require a TLB-flushing CR3
|
||||
write upon the next use of every PCID.
|
||||
|
||||
Possible Future Work
|
||||
====================
|
||||
1. We can be more careful about not actually writing to CR3
|
||||
unless its value is actually changed.
|
||||
2. Allow PTI to be enabled/disabled at runtime in addition to the
|
||||
boot-time switching.
|
||||
|
||||
Testing
|
||||
========
|
||||
|
||||
To test stability of PTI, the following test procedure is recommended,
|
||||
ideally doing all of these in parallel:
|
||||
|
||||
1. Set CONFIG_DEBUG_ENTRY=y
|
||||
2. Run several copies of all of the tools/testing/selftests/x86/ tests
|
||||
(excluding MPX and protection_keys) in a loop on multiple CPUs for
|
||||
several minutes. These tests frequently uncover corner cases in the
|
||||
kernel entry code. In general, old kernels might cause these tests
|
||||
themselves to crash, but they should never crash the kernel.
|
||||
3. Run the 'perf' tool in a mode (top or record) that generates many
|
||||
frequent performance monitoring non-maskable interrupts (see "NMI"
|
||||
in /proc/interrupts). This exercises the NMI entry/exit code which
|
||||
is known to trigger bugs in code paths that did not expect to be
|
||||
interrupted, including nested NMIs. Using "-c" boosts the rate of
|
||||
NMIs, and using two -c with separate counters encourages nested NMIs
|
||||
and less deterministic behavior.
|
||||
|
||||
while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done
|
||||
|
||||
4. Launch a KVM virtual machine.
|
||||
5. Run 32-bit binaries on systems supporting the SYSCALL instruction.
|
||||
This has been a lightly-tested code path and needs extra scrutiny.
|
||||
|
||||
Debugging
|
||||
=========
|
||||
|
||||
Bugs in PTI cause a few different signatures of crashes
|
||||
that are worth noting here.
|
||||
|
||||
* Failures of the selftests/x86 code. Usually a bug in one of the
|
||||
more obscure corners of entry_64.S
|
||||
* Crashes in early boot, especially around CPU bringup. Bugs
|
||||
in the trampoline code or mappings cause these.
|
||||
* Crashes at the first interrupt. Caused by bugs in entry_64.S,
|
||||
like screwing up a page table switch. Also caused by
|
||||
incorrectly mapping the IRQ handler entry code.
|
||||
* Crashes at the first NMI. The NMI code is separate from main
|
||||
interrupt handlers and can have bugs that do not affect
|
||||
normal interrupts. Also caused by incorrectly mapping NMI
|
||||
code. NMIs that interrupt the entry code must be very
|
||||
careful and can be the cause of crashes that show up when
|
||||
running perf.
|
||||
* Kernel crashes at the first exit to userspace. entry_64.S
|
||||
bugs, or failing to map some of the exit code.
|
||||
* Crashes at first interrupt that interrupts userspace. The paths
|
||||
in entry_64.S that return to userspace are sometimes separate
|
||||
from the ones that return to the kernel.
|
||||
* Double faults: overflowing the kernel stack because of page
|
||||
faults upon page faults. Caused by touching non-pti-mapped
|
||||
data in the entry code, or forgetting to switch to kernel
|
||||
CR3 before calling into C functions which are not pti-mapped.
|
||||
* Userspace segfaults early in boot, sometimes manifesting
|
||||
as mount(8) failing to mount the rootfs. These have
|
||||
tended to be TLB invalidation issues. Usually invalidating
|
||||
the wrong PCID, or otherwise missing an invalidation.
|
||||
|
||||
1. https://gruss.cc/files/kaiser.pdf
|
||||
2. https://meltdownattack.com/meltdown.pdf
|
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
|||
VERSION = 4
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 111
|
||||
SUBLEVEL = 112
|
||||
EXTRAVERSION =
|
||||
NAME = Blurry Fish Butt
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
}
|
||||
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
|
||||
data);
|
||||
&data);
|
||||
data = vcpu_data_host_to_guest(vcpu, data, len);
|
||||
vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
|
||||
}
|
||||
|
@ -189,14 +189,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
|
||||
len);
|
||||
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, &data);
|
||||
mmio_write_buf(data_buf, len, data);
|
||||
|
||||
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
|
||||
data_buf);
|
||||
} else {
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
|
||||
fault_ipa, 0);
|
||||
fault_ipa, NULL);
|
||||
|
||||
ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
|
||||
data_buf);
|
||||
|
|
|
@ -664,6 +664,18 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
|
|||
unsigned long switch_count;
|
||||
struct task_struct *t;
|
||||
|
||||
/* If nothing to change, return right away, successfully. */
|
||||
if (value == mips_get_process_fp_mode(task))
|
||||
return 0;
|
||||
|
||||
/* Only accept a mode change if 64-bit FP enabled for o32. */
|
||||
if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* And only for o32 tasks. */
|
||||
if (IS_ENABLED(CONFIG_64BIT) && !test_thread_flag(TIF_32BIT_REGS))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Check the value is valid */
|
||||
if (value & ~known_bits)
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
@ -439,25 +439,38 @@ static int gpr64_set(struct task_struct *target,
|
|||
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
static int fpr_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
/*
|
||||
* Copy the floating-point context to the supplied NT_PRFPREG buffer,
|
||||
* !CONFIG_CPU_HAS_MSA variant. FP context's general register slots
|
||||
* correspond 1:1 to buffer slots. Only general registers are copied.
|
||||
*/
|
||||
static int fpr_get_fpa(struct task_struct *target,
|
||||
unsigned int *pos, unsigned int *count,
|
||||
void **kbuf, void __user **ubuf)
|
||||
{
|
||||
unsigned i;
|
||||
int err;
|
||||
u64 fpr_val;
|
||||
|
||||
/* XXX fcr31 */
|
||||
|
||||
if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
return user_regset_copyout(pos, count, kbuf, ubuf,
|
||||
&target->thread.fpu,
|
||||
0, sizeof(elf_fpregset_t));
|
||||
0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the floating-point context to the supplied NT_PRFPREG buffer,
|
||||
* CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's
|
||||
* general register slots are copied to buffer slots. Only general
|
||||
* registers are copied.
|
||||
*/
|
||||
static int fpr_get_msa(struct task_struct *target,
|
||||
unsigned int *pos, unsigned int *count,
|
||||
void **kbuf, void __user **ubuf)
|
||||
{
|
||||
unsigned int i;
|
||||
u64 fpr_val;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
|
||||
for (i = 0; i < NUM_FPU_REGS; i++) {
|
||||
fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
|
||||
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
err = user_regset_copyout(pos, count, kbuf, ubuf,
|
||||
&fpr_val, i * sizeof(elf_fpreg_t),
|
||||
(i + 1) * sizeof(elf_fpreg_t));
|
||||
if (err)
|
||||
|
@ -467,27 +480,64 @@ static int fpr_get(struct task_struct *target,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fpr_set(struct task_struct *target,
|
||||
/*
|
||||
* Copy the floating-point context to the supplied NT_PRFPREG buffer.
|
||||
* Choose the appropriate helper for general registers, and then copy
|
||||
* the FCSR register separately.
|
||||
*/
|
||||
static int fpr_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
unsigned i;
|
||||
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
|
||||
int err;
|
||||
u64 fpr_val;
|
||||
|
||||
/* XXX fcr31 */
|
||||
if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
|
||||
err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf);
|
||||
else
|
||||
err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
init_fp_ctx(target);
|
||||
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fpu.fcr31,
|
||||
fcr31_pos, fcr31_pos + sizeof(u32));
|
||||
|
||||
if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
|
||||
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the supplied NT_PRFPREG buffer to the floating-point context,
|
||||
* !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP
|
||||
* context's general register slots. Only general registers are copied.
|
||||
*/
|
||||
static int fpr_set_fpa(struct task_struct *target,
|
||||
unsigned int *pos, unsigned int *count,
|
||||
const void **kbuf, const void __user **ubuf)
|
||||
{
|
||||
return user_regset_copyin(pos, count, kbuf, ubuf,
|
||||
&target->thread.fpu,
|
||||
0, sizeof(elf_fpregset_t));
|
||||
0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the supplied NT_PRFPREG buffer to the floating-point context,
|
||||
* CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64
|
||||
* bits only of FP context's general register slots. Only general
|
||||
* registers are copied.
|
||||
*/
|
||||
static int fpr_set_msa(struct task_struct *target,
|
||||
unsigned int *pos, unsigned int *count,
|
||||
const void **kbuf, const void __user **ubuf)
|
||||
{
|
||||
unsigned int i;
|
||||
u64 fpr_val;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
|
||||
for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) {
|
||||
err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) {
|
||||
err = user_regset_copyin(pos, count, kbuf, ubuf,
|
||||
&fpr_val, i * sizeof(elf_fpreg_t),
|
||||
(i + 1) * sizeof(elf_fpreg_t));
|
||||
if (err)
|
||||
|
@ -498,6 +548,53 @@ static int fpr_set(struct task_struct *target,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the supplied NT_PRFPREG buffer to the floating-point context.
|
||||
* Choose the appropriate helper for general registers, and then copy
|
||||
* the FCSR register separately.
|
||||
*
|
||||
* We optimize for the case where `count % sizeof(elf_fpreg_t) == 0',
|
||||
* which is supposed to have been guaranteed by the kernel before
|
||||
* calling us, e.g. in `ptrace_regset'. We enforce that requirement,
|
||||
* so that we can safely avoid preinitializing temporaries for
|
||||
* partial register writes.
|
||||
*/
|
||||
static int fpr_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
|
||||
u32 fcr31;
|
||||
int err;
|
||||
|
||||
BUG_ON(count % sizeof(elf_fpreg_t));
|
||||
|
||||
if (pos + count > sizeof(elf_fpregset_t))
|
||||
return -EIO;
|
||||
|
||||
init_fp_ctx(target);
|
||||
|
||||
if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
|
||||
err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf);
|
||||
else
|
||||
err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (count > 0) {
|
||||
err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&fcr31,
|
||||
fcr31_pos, fcr31_pos + sizeof(u32));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ptrace_setfcr31(target, fcr31);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
enum mips_regset {
|
||||
REGSET_GPR,
|
||||
REGSET_FPR,
|
||||
|
|
|
@ -66,6 +66,7 @@ config X86
|
|||
select GENERIC_CLOCKEVENTS_MIN_ADJUST
|
||||
select GENERIC_CMOS_UPDATE
|
||||
select GENERIC_CPU_AUTOPROBE
|
||||
select GENERIC_CPU_VULNERABILITIES
|
||||
select GENERIC_EARLY_IOREMAP
|
||||
select GENERIC_FIND_FIRST_BIT
|
||||
select GENERIC_IOMAP
|
||||
|
|
|
@ -138,7 +138,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
|
|||
".popsection\n" \
|
||||
".pushsection .altinstr_replacement, \"ax\"\n" \
|
||||
ALTINSTR_REPLACEMENT(newinstr, feature, 1) \
|
||||
".popsection"
|
||||
".popsection\n"
|
||||
|
||||
#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
|
||||
OLDINSTR_2(oldinstr, 1, 2) \
|
||||
|
@ -149,7 +149,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
|
|||
".pushsection .altinstr_replacement, \"ax\"\n" \
|
||||
ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \
|
||||
ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \
|
||||
".popsection"
|
||||
".popsection\n"
|
||||
|
||||
/*
|
||||
* This must be included *after* the definition of ALTERNATIVE due to
|
||||
|
|
|
@ -277,6 +277,9 @@
|
|||
#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */
|
||||
#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */
|
||||
#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */
|
||||
#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */
|
||||
#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */
|
||||
#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
|
||||
|
||||
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
|
||||
|
||||
|
@ -359,6 +362,8 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
|
|||
set_bit(bit, (unsigned long *)cpu_caps_set); \
|
||||
} while (0)
|
||||
|
||||
#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
|
||||
|
||||
#define cpu_has_fpu boot_cpu_has(X86_FEATURE_FPU)
|
||||
#define cpu_has_de boot_cpu_has(X86_FEATURE_DE)
|
||||
#define cpu_has_pse boot_cpu_has(X86_FEATURE_PSE)
|
||||
|
|
|
@ -19,6 +19,16 @@
|
|||
|
||||
#define KAISER_SHADOW_PGD_OFFSET 0x1000
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_ISOLATION
|
||||
/*
|
||||
* A page table address must have this alignment to stay the same when
|
||||
* KAISER_SHADOW_PGD_OFFSET mask is applied
|
||||
*/
|
||||
#define KAISER_KERNEL_PGD_ALIGNMENT (KAISER_SHADOW_PGD_OFFSET << 1)
|
||||
#else
|
||||
#define KAISER_KERNEL_PGD_ALIGNMENT PAGE_SIZE
|
||||
#endif
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef CONFIG_PAGE_TABLE_ISOLATION
|
||||
|
||||
|
|
|
@ -156,8 +156,8 @@ extern struct cpuinfo_x86 boot_cpu_data;
|
|||
extern struct cpuinfo_x86 new_cpu_data;
|
||||
|
||||
extern struct tss_struct doublefault_tss;
|
||||
extern __u32 cpu_caps_cleared[NCAPINTS];
|
||||
extern __u32 cpu_caps_set[NCAPINTS];
|
||||
extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS];
|
||||
extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS];
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <linux/clocksource.h>
|
||||
#include <asm/pvclock-abi.h>
|
||||
|
||||
#ifdef CONFIG_PARAVIRT_CLOCK
|
||||
#ifdef CONFIG_KVM_GUEST
|
||||
extern struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void);
|
||||
#else
|
||||
static inline struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
|
||||
|
|
|
@ -321,13 +321,12 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e
|
|||
#ifdef CONFIG_X86_IO_APIC
|
||||
#define MP_ISA_BUS 0
|
||||
|
||||
static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity,
|
||||
u8 trigger, u32 gsi);
|
||||
|
||||
static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
|
||||
u32 gsi)
|
||||
{
|
||||
int ioapic;
|
||||
int pin;
|
||||
struct mpc_intsrc mp_irq;
|
||||
|
||||
/*
|
||||
* Check bus_irq boundary.
|
||||
*/
|
||||
|
@ -336,14 +335,6 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert 'gsi' to 'ioapic.pin'.
|
||||
*/
|
||||
ioapic = mp_find_ioapic(gsi);
|
||||
if (ioapic < 0)
|
||||
return;
|
||||
pin = mp_find_ioapic_pin(ioapic, gsi);
|
||||
|
||||
/*
|
||||
* TBD: This check is for faulty timer entries, where the override
|
||||
* erroneously sets the trigger to level, resulting in a HUGE
|
||||
|
@ -352,16 +343,8 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
|
|||
if ((bus_irq == 0) && (trigger == 3))
|
||||
trigger = 1;
|
||||
|
||||
mp_irq.type = MP_INTSRC;
|
||||
mp_irq.irqtype = mp_INT;
|
||||
mp_irq.irqflag = (trigger << 2) | polarity;
|
||||
mp_irq.srcbus = MP_ISA_BUS;
|
||||
mp_irq.srcbusirq = bus_irq; /* IRQ */
|
||||
mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
|
||||
mp_irq.dstirq = pin; /* INTIN# */
|
||||
|
||||
mp_save_irq(&mp_irq);
|
||||
|
||||
if (mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi) < 0)
|
||||
return;
|
||||
/*
|
||||
* Reset default identity mapping if gsi is also an legacy IRQ,
|
||||
* otherwise there will be more than one entry with the same GSI
|
||||
|
@ -408,6 +391,34 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity,
|
||||
u8 trigger, u32 gsi)
|
||||
{
|
||||
struct mpc_intsrc mp_irq;
|
||||
int ioapic, pin;
|
||||
|
||||
/* Convert 'gsi' to 'ioapic.pin'(INTIN#) */
|
||||
ioapic = mp_find_ioapic(gsi);
|
||||
if (ioapic < 0) {
|
||||
pr_warn("Failed to find ioapic for gsi : %u\n", gsi);
|
||||
return ioapic;
|
||||
}
|
||||
|
||||
pin = mp_find_ioapic_pin(ioapic, gsi);
|
||||
|
||||
mp_irq.type = MP_INTSRC;
|
||||
mp_irq.irqtype = mp_INT;
|
||||
mp_irq.irqflag = (trigger << 2) | polarity;
|
||||
mp_irq.srcbus = MP_ISA_BUS;
|
||||
mp_irq.srcbusirq = bus_irq;
|
||||
mp_irq.dstapic = mpc_ioapic_id(ioapic);
|
||||
mp_irq.dstirq = pin;
|
||||
|
||||
mp_save_irq(&mp_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
|
||||
{
|
||||
|
@ -452,7 +463,11 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger,
|
|||
if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
|
||||
polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
|
||||
|
||||
if (bus_irq < NR_IRQS_LEGACY)
|
||||
mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
|
||||
else
|
||||
mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi);
|
||||
|
||||
acpi_penalize_sci_irq(bus_irq, trigger, polarity);
|
||||
|
||||
/*
|
||||
|
|
|
@ -339,9 +339,12 @@ done:
|
|||
static void __init_or_module optimize_nops(struct alt_instr *a, u8 *instr)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (instr[0] != 0x90)
|
||||
for (i = 0; i < a->padlen; i++) {
|
||||
if (instr[i] != 0x90)
|
||||
return;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
add_nops(instr + (a->instrlen - a->padlen), a->padlen);
|
||||
|
|
|
@ -20,13 +20,11 @@ obj-y := intel_cacheinfo.o scattered.o topology.o
|
|||
obj-y += common.o
|
||||
obj-y += rdrand.o
|
||||
obj-y += match.o
|
||||
obj-y += bugs.o
|
||||
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
|
||||
|
||||
obj-$(CONFIG_X86_32) += bugs.o
|
||||
obj-$(CONFIG_X86_64) += bugs_64.o
|
||||
|
||||
obj-$(CONFIG_CPU_SUP_INTEL) += intel.o
|
||||
obj-$(CONFIG_CPU_SUP_AMD) += amd.o
|
||||
obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
@ -16,6 +17,8 @@
|
|||
#include <asm/msr.h>
|
||||
#include <asm/paravirt.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
void __init check_bugs(void)
|
||||
{
|
||||
|
@ -28,11 +31,13 @@ void __init check_bugs(void)
|
|||
#endif
|
||||
|
||||
identify_boot_cpu();
|
||||
#ifndef CONFIG_SMP
|
||||
|
||||
if (!IS_ENABLED(CONFIG_SMP)) {
|
||||
pr_info("CPU: ");
|
||||
print_cpu_info(&boot_cpu_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
* Check whether we are able to run this kernel safely on SMP.
|
||||
*
|
||||
|
@ -48,4 +53,46 @@ void __init check_bugs(void)
|
|||
alternative_instructions();
|
||||
|
||||
fpu__init_check_bugs();
|
||||
#else /* CONFIG_X86_64 */
|
||||
alternative_instructions();
|
||||
|
||||
/*
|
||||
* Make sure the first 2MB area is not mapped by huge pages
|
||||
* There are typically fixed size MTRRs in there and overlapping
|
||||
* MTRRs into large pages causes slow downs.
|
||||
*
|
||||
* Right now we don't do that with gbpages because there seems
|
||||
* very little benefit for that case.
|
||||
*/
|
||||
if (!direct_gbpages)
|
||||
set_memory_4k((unsigned long)__va(0), 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
ssize_t cpu_show_meltdown(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN))
|
||||
return sprintf(buf, "Not affected\n");
|
||||
if (boot_cpu_has(X86_FEATURE_KAISER))
|
||||
return sprintf(buf, "Mitigation: PTI\n");
|
||||
return sprintf(buf, "Vulnerable\n");
|
||||
}
|
||||
|
||||
ssize_t cpu_show_spectre_v1(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1))
|
||||
return sprintf(buf, "Not affected\n");
|
||||
return sprintf(buf, "Vulnerable\n");
|
||||
}
|
||||
|
||||
ssize_t cpu_show_spectre_v2(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
|
||||
return sprintf(buf, "Not affected\n");
|
||||
return sprintf(buf, "Vulnerable\n");
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1994 Linus Torvalds
|
||||
* Copyright (C) 2000 SuSE
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
void __init check_bugs(void)
|
||||
{
|
||||
identify_boot_cpu();
|
||||
#if !defined(CONFIG_SMP)
|
||||
printk(KERN_INFO "CPU: ");
|
||||
print_cpu_info(&boot_cpu_data);
|
||||
#endif
|
||||
alternative_instructions();
|
||||
|
||||
/*
|
||||
* Make sure the first 2MB area is not mapped by huge pages
|
||||
* There are typically fixed size MTRRs in there and overlapping
|
||||
* MTRRs into large pages causes slow downs.
|
||||
*
|
||||
* Right now we don't do that with gbpages because there seems
|
||||
* very little benefit for that case.
|
||||
*/
|
||||
if (!direct_gbpages)
|
||||
set_memory_4k((unsigned long)__va(0), 1);
|
||||
}
|
|
@ -432,8 +432,8 @@ static const char *table_lookup_model(struct cpuinfo_x86 *c)
|
|||
return NULL; /* Not found */
|
||||
}
|
||||
|
||||
__u32 cpu_caps_cleared[NCAPINTS];
|
||||
__u32 cpu_caps_set[NCAPINTS];
|
||||
__u32 cpu_caps_cleared[NCAPINTS + NBUGINTS];
|
||||
__u32 cpu_caps_set[NCAPINTS + NBUGINTS];
|
||||
|
||||
void load_percpu_segment(int cpu)
|
||||
{
|
||||
|
@ -664,6 +664,16 @@ void cpu_detect(struct cpuinfo_x86 *c)
|
|||
}
|
||||
}
|
||||
|
||||
static void apply_forced_caps(struct cpuinfo_x86 *c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NCAPINTS + NBUGINTS; i++) {
|
||||
c->x86_capability[i] &= ~cpu_caps_cleared[i];
|
||||
c->x86_capability[i] |= cpu_caps_set[i];
|
||||
}
|
||||
}
|
||||
|
||||
void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 tfms, xlvl;
|
||||
|
@ -820,6 +830,13 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
|
|||
}
|
||||
|
||||
setup_force_cpu_cap(X86_FEATURE_ALWAYS);
|
||||
|
||||
/* Assume for now that ALL x86 CPUs are insecure */
|
||||
setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
|
||||
|
||||
setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
|
||||
setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
|
||||
|
||||
fpu__init_system(c);
|
||||
}
|
||||
|
||||
|
@ -955,11 +972,8 @@ static void identify_cpu(struct cpuinfo_x86 *c)
|
|||
if (this_cpu->c_identify)
|
||||
this_cpu->c_identify(c);
|
||||
|
||||
/* Clear/Set all flags overriden by options, after probe */
|
||||
for (i = 0; i < NCAPINTS; i++) {
|
||||
c->x86_capability[i] &= ~cpu_caps_cleared[i];
|
||||
c->x86_capability[i] |= cpu_caps_set[i];
|
||||
}
|
||||
/* Clear/Set all flags overridden by options, after probe */
|
||||
apply_forced_caps(c);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
|
||||
|
@ -1020,10 +1034,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
|
|||
* Clear/Set all flags overriden by options, need do it
|
||||
* before following smp all cpus cap AND.
|
||||
*/
|
||||
for (i = 0; i < NCAPINTS; i++) {
|
||||
c->x86_capability[i] &= ~cpu_caps_cleared[i];
|
||||
c->x86_capability[i] |= cpu_caps_set[i];
|
||||
}
|
||||
apply_forced_caps(c);
|
||||
|
||||
/*
|
||||
* On SMP, boot_cpu_data holds the common feature set between
|
||||
|
|
|
@ -994,9 +994,17 @@ static bool is_blacklisted(unsigned int cpu)
|
|||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||
|
||||
if (c->x86 == 6 && c->x86_model == 79) {
|
||||
pr_err_once("late loading on model 79 is disabled.\n");
|
||||
return true;
|
||||
/*
|
||||
* Late loading on model 79 with microcode revision less than 0x0b000021
|
||||
* may result in a system hang. This behavior is documented in item
|
||||
* BDF90, #334165 (Intel Xeon Processor E7-8800/4800 v4 Product Family).
|
||||
*/
|
||||
if (c->x86 == 6 &&
|
||||
c->x86_model == 79 &&
|
||||
c->x86_mask == 0x01 &&
|
||||
c->microcode < 0x0b000021) {
|
||||
pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
|
||||
pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -3855,6 +3855,25 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
|||
"mov %%r13, %c[r13](%[svm]) \n\t"
|
||||
"mov %%r14, %c[r14](%[svm]) \n\t"
|
||||
"mov %%r15, %c[r15](%[svm]) \n\t"
|
||||
#endif
|
||||
/*
|
||||
* Clear host registers marked as clobbered to prevent
|
||||
* speculative use.
|
||||
*/
|
||||
"xor %%" _ASM_BX ", %%" _ASM_BX " \n\t"
|
||||
"xor %%" _ASM_CX ", %%" _ASM_CX " \n\t"
|
||||
"xor %%" _ASM_DX ", %%" _ASM_DX " \n\t"
|
||||
"xor %%" _ASM_SI ", %%" _ASM_SI " \n\t"
|
||||
"xor %%" _ASM_DI ", %%" _ASM_DI " \n\t"
|
||||
#ifdef CONFIG_X86_64
|
||||
"xor %%r8, %%r8 \n\t"
|
||||
"xor %%r9, %%r9 \n\t"
|
||||
"xor %%r10, %%r10 \n\t"
|
||||
"xor %%r11, %%r11 \n\t"
|
||||
"xor %%r12, %%r12 \n\t"
|
||||
"xor %%r13, %%r13 \n\t"
|
||||
"xor %%r14, %%r14 \n\t"
|
||||
"xor %%r15, %%r15 \n\t"
|
||||
#endif
|
||||
"pop %%" _ASM_BP
|
||||
:
|
||||
|
|
|
@ -828,8 +828,16 @@ static inline short vmcs_field_to_offset(unsigned long field)
|
|||
{
|
||||
BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
|
||||
|
||||
if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) ||
|
||||
vmcs_field_to_offset_table[field] == 0)
|
||||
if (field >= ARRAY_SIZE(vmcs_field_to_offset_table))
|
||||
return -ENOENT;
|
||||
|
||||
/*
|
||||
* FIXME: Mitigation for CVE-2017-5753. To be replaced with a
|
||||
* generic mechanism.
|
||||
*/
|
||||
asm("lfence");
|
||||
|
||||
if (vmcs_field_to_offset_table[field] == 0)
|
||||
return -ENOENT;
|
||||
|
||||
return vmcs_field_to_offset_table[field];
|
||||
|
@ -8623,6 +8631,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
|
|||
/* Save guest registers, load host registers, keep flags */
|
||||
"mov %0, %c[wordsize](%%" _ASM_SP ") \n\t"
|
||||
"pop %0 \n\t"
|
||||
"setbe %c[fail](%0)\n\t"
|
||||
"mov %%" _ASM_AX ", %c[rax](%0) \n\t"
|
||||
"mov %%" _ASM_BX ", %c[rbx](%0) \n\t"
|
||||
__ASM_SIZE(pop) " %c[rcx](%0) \n\t"
|
||||
|
@ -8639,12 +8648,23 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
|
|||
"mov %%r13, %c[r13](%0) \n\t"
|
||||
"mov %%r14, %c[r14](%0) \n\t"
|
||||
"mov %%r15, %c[r15](%0) \n\t"
|
||||
"xor %%r8d, %%r8d \n\t"
|
||||
"xor %%r9d, %%r9d \n\t"
|
||||
"xor %%r10d, %%r10d \n\t"
|
||||
"xor %%r11d, %%r11d \n\t"
|
||||
"xor %%r12d, %%r12d \n\t"
|
||||
"xor %%r13d, %%r13d \n\t"
|
||||
"xor %%r14d, %%r14d \n\t"
|
||||
"xor %%r15d, %%r15d \n\t"
|
||||
#endif
|
||||
"mov %%cr2, %%" _ASM_AX " \n\t"
|
||||
"mov %%" _ASM_AX ", %c[cr2](%0) \n\t"
|
||||
|
||||
"xor %%eax, %%eax \n\t"
|
||||
"xor %%ebx, %%ebx \n\t"
|
||||
"xor %%esi, %%esi \n\t"
|
||||
"xor %%edi, %%edi \n\t"
|
||||
"pop %%" _ASM_BP "; pop %%" _ASM_DX " \n\t"
|
||||
"setbe %c[fail](%0) \n\t"
|
||||
".pushsection .rodata \n\t"
|
||||
".global vmx_return \n\t"
|
||||
"vmx_return: " _ASM_PTR " 2b \n\t"
|
||||
|
|
|
@ -4114,7 +4114,7 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
|
|||
addr, n, v))
|
||||
&& kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, n, v))
|
||||
break;
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v);
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, v);
|
||||
handled += n;
|
||||
addr += n;
|
||||
len -= n;
|
||||
|
@ -4362,7 +4362,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes)
|
|||
{
|
||||
if (vcpu->mmio_read_completed) {
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
|
||||
vcpu->mmio_fragments[0].gpa, *(u64 *)val);
|
||||
vcpu->mmio_fragments[0].gpa, val);
|
||||
vcpu->mmio_read_completed = 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -4384,14 +4384,14 @@ static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|||
|
||||
static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val)
|
||||
{
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val);
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, val);
|
||||
return vcpu_mmio_write(vcpu, gpa, bytes, val);
|
||||
}
|
||||
|
||||
static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
|
||||
void *val, int bytes)
|
||||
{
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, NULL);
|
||||
return X86EMUL_IO_NEEDED;
|
||||
}
|
||||
|
||||
|
|
|
@ -198,6 +198,8 @@ static int kaiser_add_user_map(const void *__start_addr, unsigned long size,
|
|||
* requires that not to be #defined to 0): so mask it off here.
|
||||
*/
|
||||
flags &= ~_PAGE_GLOBAL;
|
||||
if (!(__supported_pte_mask & _PAGE_NX))
|
||||
flags &= ~_PAGE_NX;
|
||||
|
||||
for (; address < end_addr; address += PAGE_SIZE) {
|
||||
target_address = get_pa_from_mapping(address);
|
||||
|
|
|
@ -750,11 +750,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
|
|||
return 1;
|
||||
|
||||
while (cursor < to) {
|
||||
if (!devmem_is_allowed(pfn)) {
|
||||
pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
|
||||
current->comm, from, to - 1);
|
||||
if (!devmem_is_allowed(pfn))
|
||||
return 0;
|
||||
}
|
||||
cursor += PAGE_SIZE;
|
||||
pfn++;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <asm/cacheflush.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/kaiser.h>
|
||||
|
||||
struct real_mode_header *real_mode_header;
|
||||
u32 *trampoline_cr4_features;
|
||||
|
@ -15,7 +16,8 @@ void __init reserve_real_mode(void)
|
|||
size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
|
||||
|
||||
/* Has to be under 1M so we can execute real-mode AP code. */
|
||||
mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
|
||||
mem = memblock_find_in_range(0, 1 << 20, size,
|
||||
KAISER_KERNEL_PGD_ALIGNMENT);
|
||||
if (!mem)
|
||||
panic("Cannot allocate trampoline\n");
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <asm/msr.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/kaiser.h>
|
||||
#include "realmode.h"
|
||||
|
||||
.text
|
||||
|
@ -139,7 +140,7 @@ tr_gdt:
|
|||
tr_gdt_end:
|
||||
|
||||
.bss
|
||||
.balign PAGE_SIZE
|
||||
.balign KAISER_KERNEL_PGD_ALIGNMENT
|
||||
GLOBAL(trampoline_pgd) .space PAGE_SIZE
|
||||
|
||||
.balign 8
|
||||
|
|
|
@ -168,6 +168,18 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
|
|||
|
||||
spawn->alg = NULL;
|
||||
spawns = &inst->alg.cra_users;
|
||||
|
||||
/*
|
||||
* We may encounter an unregistered instance here, since
|
||||
* an instance's spawns are set up prior to the instance
|
||||
* being registered. An unregistered instance will have
|
||||
* NULL ->cra_users.next, since ->cra_users isn't
|
||||
* properly initialized until registration. But an
|
||||
* unregistered instance cannot have any users, so treat
|
||||
* it the same as ->cra_users being empty.
|
||||
*/
|
||||
if (spawns->next == NULL)
|
||||
break;
|
||||
}
|
||||
} while ((spawns = crypto_more_spawns(alg, &stack, &top,
|
||||
&secondary_spawns)));
|
||||
|
|
13
crypto/api.c
13
crypto/api.c
|
@ -24,6 +24,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/completion.h>
|
||||
#include "internal.h"
|
||||
|
||||
LIST_HEAD(crypto_alg_list);
|
||||
|
@ -611,5 +612,17 @@ int crypto_has_alg(const char *name, u32 type, u32 mask)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_has_alg);
|
||||
|
||||
void crypto_req_done(struct crypto_async_request *req, int err)
|
||||
{
|
||||
struct crypto_wait *wait = req->data;
|
||||
|
||||
if (err == -EINPROGRESS)
|
||||
return;
|
||||
|
||||
wait->err = err;
|
||||
complete(&wait->completion);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_req_done);
|
||||
|
||||
MODULE_DESCRIPTION("Cryptographic core API");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -223,6 +223,9 @@ config GENERIC_CPU_DEVICES
|
|||
config GENERIC_CPU_AUTOPROBE
|
||||
bool
|
||||
|
||||
config GENERIC_CPU_VULNERABILITIES
|
||||
bool
|
||||
|
||||
config SOC_BUS
|
||||
bool
|
||||
|
||||
|
|
|
@ -673,10 +673,58 @@ static void __init cpu_dev_register_generic(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES
|
||||
|
||||
ssize_t __weak cpu_show_meltdown(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "Not affected\n");
|
||||
}
|
||||
|
||||
ssize_t __weak cpu_show_spectre_v1(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "Not affected\n");
|
||||
}
|
||||
|
||||
ssize_t __weak cpu_show_spectre_v2(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "Not affected\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
|
||||
static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
|
||||
static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
|
||||
|
||||
static struct attribute *cpu_root_vulnerabilities_attrs[] = {
|
||||
&dev_attr_meltdown.attr,
|
||||
&dev_attr_spectre_v1.attr,
|
||||
&dev_attr_spectre_v2.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group cpu_root_vulnerabilities_group = {
|
||||
.name = "vulnerabilities",
|
||||
.attrs = cpu_root_vulnerabilities_attrs,
|
||||
};
|
||||
|
||||
static void __init cpu_register_vulnerabilities(void)
|
||||
{
|
||||
if (sysfs_create_group(&cpu_subsys.dev_root->kobj,
|
||||
&cpu_root_vulnerabilities_group))
|
||||
pr_err("Unable to register CPU vulnerabilities\n");
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void cpu_register_vulnerabilities(void) { }
|
||||
#endif
|
||||
|
||||
void __init cpu_dev_init(void)
|
||||
{
|
||||
if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
|
||||
panic("Failed to register CPU subsystem");
|
||||
|
||||
cpu_dev_register_generic();
|
||||
cpu_register_vulnerabilities();
|
||||
}
|
||||
|
|
|
@ -3767,7 +3767,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
|
|||
segment_size = rbd_obj_bytes(&rbd_dev->header);
|
||||
blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);
|
||||
q->limits.max_sectors = queue_max_hw_sectors(q);
|
||||
blk_queue_max_segments(q, segment_size / SECTOR_SIZE);
|
||||
blk_queue_max_segments(q, USHRT_MAX);
|
||||
blk_queue_max_segment_size(q, segment_size);
|
||||
blk_queue_io_min(q, segment_size);
|
||||
blk_queue_io_opt(q, segment_size);
|
||||
|
|
|
@ -238,7 +238,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&reading_mutex);
|
||||
if (mutex_lock_interruptible(&reading_mutex)) {
|
||||
err = -ERESTARTSYS;
|
||||
goto out_put;
|
||||
}
|
||||
if (!data_avail) {
|
||||
bytes_read = rng_get_data(rng, rng_buffer,
|
||||
rng_buffer_size(),
|
||||
|
@ -288,6 +291,7 @@ out:
|
|||
|
||||
out_unlock_reading:
|
||||
mutex_unlock(&reading_mutex);
|
||||
out_put:
|
||||
put_rng(rng);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -70,12 +70,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
|
|||
u64 cursor = from;
|
||||
|
||||
while (cursor < to) {
|
||||
if (!devmem_is_allowed(pfn)) {
|
||||
printk(KERN_INFO
|
||||
"Program %s tried to access /dev/mem between %Lx->%Lx.\n",
|
||||
current->comm, from, to);
|
||||
if (!devmem_is_allowed(pfn))
|
||||
return 0;
|
||||
}
|
||||
cursor += PAGE_SIZE;
|
||||
pfn++;
|
||||
}
|
||||
|
|
|
@ -2678,6 +2678,8 @@ static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv,
|
|||
}
|
||||
|
||||
view_type = vmw_view_cmd_to_type(header->id);
|
||||
if (view_type == vmw_view_max)
|
||||
return -EINVAL;
|
||||
cmd = container_of(header, typeof(*cmd), header);
|
||||
ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
|
||||
user_surface_converter,
|
||||
|
|
|
@ -957,8 +957,7 @@ static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp)
|
|||
return -ENOMEM;
|
||||
|
||||
attr->qp_state = IB_QPS_INIT;
|
||||
attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ |
|
||||
IB_ACCESS_REMOTE_WRITE;
|
||||
attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
|
||||
attr->port_num = ch->sport->port;
|
||||
attr->pkey_index = 0;
|
||||
|
||||
|
|
|
@ -1541,13 +1541,15 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
|
|||
return -ENOMEM;
|
||||
|
||||
arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
|
||||
smmu_domain->pgtbl_ops = pgtbl_ops;
|
||||
|
||||
ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
free_io_pgtable_ops(pgtbl_ops);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
smmu_domain->pgtbl_ops = pgtbl_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct arm_smmu_group *arm_smmu_group_get(struct device *dev)
|
||||
|
|
|
@ -1527,7 +1527,8 @@ static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
|
|||
int l;
|
||||
struct dm_buffer *b, *tmp;
|
||||
unsigned long freed = 0;
|
||||
unsigned long count = nr_to_scan;
|
||||
unsigned long count = c->n_buffers[LIST_CLEAN] +
|
||||
c->n_buffers[LIST_DIRTY];
|
||||
unsigned long retain_target = get_retain_buffers(c);
|
||||
|
||||
for (l = 0; l < LIST_SIZE; l++) {
|
||||
|
@ -1564,6 +1565,7 @@ dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
|||
{
|
||||
struct dm_bufio_client *c;
|
||||
unsigned long count;
|
||||
unsigned long retain_target;
|
||||
|
||||
c = container_of(shrink, struct dm_bufio_client, shrinker);
|
||||
if (sc->gfp_mask & __GFP_FS)
|
||||
|
@ -1572,8 +1574,9 @@ dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
|||
return 0;
|
||||
|
||||
count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
|
||||
retain_target = get_retain_buffers(c);
|
||||
dm_bufio_unlock(c);
|
||||
return count;
|
||||
return (count < retain_target) ? 0 : (count - retain_target);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1461,6 +1461,13 @@ static int usbvision_probe(struct usb_interface *intf,
|
|||
printk(KERN_INFO "%s: %s found\n", __func__,
|
||||
usbvision_device_data[model].model_string);
|
||||
|
||||
/*
|
||||
* this is a security check.
|
||||
* an exploit using an incorrect bInterfaceNumber is known
|
||||
*/
|
||||
if (ifnum >= USB_MAXINTERFACES || !dev->actconfig->interface[ifnum])
|
||||
return -ENODEV;
|
||||
|
||||
if (usbvision_device_data[model].interface >= 0)
|
||||
interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
|
||||
else if (ifnum < dev->actconfig->desc.bNumInterfaces)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* drivers/misc/uid_cputime.c
|
||||
/* drivers/misc/uid_sys_stats.c
|
||||
*
|
||||
* Copyright (C) 2014 - 2015 Google, Inc.
|
||||
*
|
||||
|
|
|
@ -430,7 +430,7 @@ static int gs_usb_set_bittiming(struct net_device *netdev)
|
|||
dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)",
|
||||
rc);
|
||||
|
||||
return rc;
|
||||
return (rc > 0) ? 0 : rc;
|
||||
}
|
||||
|
||||
static void gs_usb_xmit_callback(struct urb *urb)
|
||||
|
|
|
@ -1362,6 +1362,9 @@ out:
|
|||
* Checks to see of the link status of the hardware has changed. If a
|
||||
* change in link status has been detected, then we read the PHY registers
|
||||
* to get the current speed/duplex if link exists.
|
||||
*
|
||||
* Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
|
||||
* up).
|
||||
**/
|
||||
static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
|
@ -1377,7 +1380,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
|
|||
* Change or Rx Sequence Error interrupt.
|
||||
*/
|
||||
if (!mac->get_link_status)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
/* First we want to see if the MII Status Register reports
|
||||
* link. If so, then we want to get the current speed/duplex
|
||||
|
@ -1585,10 +1588,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
|
|||
* different link partner.
|
||||
*/
|
||||
ret_val = e1000e_config_fc_after_link_up(hw);
|
||||
if (ret_val)
|
||||
if (ret_val) {
|
||||
e_dbg("Error configuring flow control\n");
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
|
||||
|
|
|
@ -3176,18 +3176,37 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
|
|||
/* ioremap the TSU registers */
|
||||
if (mdp->cd->tsu) {
|
||||
struct resource *rtsu;
|
||||
|
||||
rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu);
|
||||
if (IS_ERR(mdp->tsu_addr)) {
|
||||
ret = PTR_ERR(mdp->tsu_addr);
|
||||
if (!rtsu) {
|
||||
dev_err(&pdev->dev, "no TSU resource\n");
|
||||
ret = -ENODEV;
|
||||
goto out_release;
|
||||
}
|
||||
/* We can only request the TSU region for the first port
|
||||
* of the two sharing this TSU for the probe to succeed...
|
||||
*/
|
||||
if (devno % 2 == 0 &&
|
||||
!devm_request_mem_region(&pdev->dev, rtsu->start,
|
||||
resource_size(rtsu),
|
||||
dev_name(&pdev->dev))) {
|
||||
dev_err(&pdev->dev, "can't request TSU resource.\n");
|
||||
ret = -EBUSY;
|
||||
goto out_release;
|
||||
}
|
||||
mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start,
|
||||
resource_size(rtsu));
|
||||
if (!mdp->tsu_addr) {
|
||||
dev_err(&pdev->dev, "TSU region ioremap() failed.\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_release;
|
||||
}
|
||||
mdp->port = devno % 2;
|
||||
ndev->features = NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
}
|
||||
|
||||
/* initialize first or needed device */
|
||||
if (!devno || pd->needs_init) {
|
||||
/* Need to init only the first port of the two sharing a TSU */
|
||||
if (devno % 2 == 0) {
|
||||
if (mdp->cd->chip_reset)
|
||||
mdp->cd->chip_reset(ndev);
|
||||
|
||||
|
|
|
@ -272,8 +272,14 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
|
|||
{
|
||||
char *phy_bus_name = priv->plat->phy_bus_name;
|
||||
unsigned long flags;
|
||||
int interface = priv->plat->interface;
|
||||
bool ret = false;
|
||||
|
||||
if ((interface != PHY_INTERFACE_MODE_MII) &&
|
||||
(interface != PHY_INTERFACE_MODE_GMII) &&
|
||||
!phy_interface_mode_is_rgmii(interface))
|
||||
goto out;
|
||||
|
||||
/* Using PCS we cannot dial with the phy registers at this stage
|
||||
* so we do not support extra feature like EEE.
|
||||
*/
|
||||
|
|
|
@ -293,11 +293,8 @@ static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
|||
{
|
||||
int len = skb->len;
|
||||
|
||||
if (skb_headroom(skb) < 2) {
|
||||
struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags);
|
||||
if (skb_cow_head(skb, 2)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = skb2;
|
||||
if (!skb)
|
||||
return NULL;
|
||||
}
|
||||
skb_push(skb, 2);
|
||||
|
|
|
@ -2050,13 +2050,8 @@ static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev,
|
|||
{
|
||||
u32 tx_cmd_a, tx_cmd_b;
|
||||
|
||||
if (skb_headroom(skb) < TX_OVERHEAD) {
|
||||
struct sk_buff *skb2;
|
||||
|
||||
skb2 = skb_copy_expand(skb, TX_OVERHEAD, 0, flags);
|
||||
if (skb_cow_head(skb, TX_OVERHEAD)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = skb2;
|
||||
if (!skb)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
#include <uapi/linux/mdio.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/usb/cdc.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
/* Information for net-next */
|
||||
#define NETNEXT_VERSION "08"
|
||||
|
||||
/* Information for net */
|
||||
#define NET_VERSION "2"
|
||||
#define NET_VERSION "3"
|
||||
|
||||
#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION
|
||||
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
|
||||
|
@ -604,6 +605,9 @@ struct r8152 {
|
|||
struct delayed_work schedule;
|
||||
struct mii_if_info mii;
|
||||
struct mutex control; /* use for hw setting */
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct notifier_block pm_notifier;
|
||||
#endif
|
||||
|
||||
struct rtl_ops {
|
||||
void (*init)(struct r8152 *);
|
||||
|
@ -1943,7 +1947,6 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
|
|||
__le32 tmp[2];
|
||||
u32 ocp_data;
|
||||
|
||||
clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
|
||||
netif_stop_queue(netdev);
|
||||
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
|
||||
ocp_data &= ~RCR_ACPT_ALL;
|
||||
|
@ -2429,8 +2432,6 @@ static void rtl_phy_reset(struct r8152 *tp)
|
|||
u16 data;
|
||||
int i;
|
||||
|
||||
clear_bit(PHY_RESET, &tp->flags);
|
||||
|
||||
data = r8152_mdio_read(tp, MII_BMCR);
|
||||
|
||||
/* don't reset again before the previous one complete */
|
||||
|
@ -2460,23 +2461,23 @@ static void r8153_teredo_off(struct r8152 *tp)
|
|||
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
|
||||
}
|
||||
|
||||
static void r8152b_disable_aldps(struct r8152 *tp)
|
||||
{
|
||||
ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static inline void r8152b_enable_aldps(struct r8152 *tp)
|
||||
static void r8152_aldps_en(struct r8152 *tp, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
|
||||
LINKENA | DIS_SDSAVE);
|
||||
} else {
|
||||
ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA |
|
||||
DIS_SDSAVE);
|
||||
msleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8152_disable(struct r8152 *tp)
|
||||
{
|
||||
r8152b_disable_aldps(tp);
|
||||
r8152_aldps_en(tp, false);
|
||||
rtl_disable(tp);
|
||||
r8152b_enable_aldps(tp);
|
||||
r8152_aldps_en(tp, true);
|
||||
}
|
||||
|
||||
static void r8152b_hw_phy_cfg(struct r8152 *tp)
|
||||
|
@ -2788,30 +2789,26 @@ static void r8153_enter_oob(struct r8152 *tp)
|
|||
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
|
||||
}
|
||||
|
||||
static void r8153_disable_aldps(struct r8152 *tp)
|
||||
static void r8153_aldps_en(struct r8152 *tp, bool enable)
|
||||
{
|
||||
u16 data;
|
||||
|
||||
data = ocp_reg_read(tp, OCP_POWER_CFG);
|
||||
if (enable) {
|
||||
data |= EN_ALDPS;
|
||||
ocp_reg_write(tp, OCP_POWER_CFG, data);
|
||||
} else {
|
||||
data &= ~EN_ALDPS;
|
||||
ocp_reg_write(tp, OCP_POWER_CFG, data);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void r8153_enable_aldps(struct r8152 *tp)
|
||||
{
|
||||
u16 data;
|
||||
|
||||
data = ocp_reg_read(tp, OCP_POWER_CFG);
|
||||
data |= EN_ALDPS;
|
||||
ocp_reg_write(tp, OCP_POWER_CFG, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8153_disable(struct r8152 *tp)
|
||||
{
|
||||
r8153_disable_aldps(tp);
|
||||
r8153_aldps_en(tp, false);
|
||||
rtl_disable(tp);
|
||||
r8153_enable_aldps(tp);
|
||||
r8153_aldps_en(tp, true);
|
||||
usb_enable_lpm(tp->udev);
|
||||
}
|
||||
|
||||
|
@ -2889,10 +2886,9 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
|
|||
r8152_mdio_write(tp, MII_ADVERTISE, anar);
|
||||
r8152_mdio_write(tp, MII_BMCR, bmcr);
|
||||
|
||||
if (test_bit(PHY_RESET, &tp->flags)) {
|
||||
if (test_and_clear_bit(PHY_RESET, &tp->flags)) {
|
||||
int i;
|
||||
|
||||
clear_bit(PHY_RESET, &tp->flags);
|
||||
for (i = 0; i < 50; i++) {
|
||||
msleep(20);
|
||||
if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
|
||||
|
@ -2901,7 +2897,6 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
|
|||
}
|
||||
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2910,9 +2905,9 @@ static void rtl8152_up(struct r8152 *tp)
|
|||
if (test_bit(RTL8152_UNPLUG, &tp->flags))
|
||||
return;
|
||||
|
||||
r8152b_disable_aldps(tp);
|
||||
r8152_aldps_en(tp, false);
|
||||
r8152b_exit_oob(tp);
|
||||
r8152b_enable_aldps(tp);
|
||||
r8152_aldps_en(tp, true);
|
||||
}
|
||||
|
||||
static void rtl8152_down(struct r8152 *tp)
|
||||
|
@ -2923,9 +2918,9 @@ static void rtl8152_down(struct r8152 *tp)
|
|||
}
|
||||
|
||||
r8152_power_cut_en(tp, false);
|
||||
r8152b_disable_aldps(tp);
|
||||
r8152_aldps_en(tp, false);
|
||||
r8152b_enter_oob(tp);
|
||||
r8152b_enable_aldps(tp);
|
||||
r8152_aldps_en(tp, true);
|
||||
}
|
||||
|
||||
static void rtl8153_up(struct r8152 *tp)
|
||||
|
@ -2934,9 +2929,9 @@ static void rtl8153_up(struct r8152 *tp)
|
|||
return;
|
||||
|
||||
r8153_u1u2en(tp, false);
|
||||
r8153_disable_aldps(tp);
|
||||
r8153_aldps_en(tp, false);
|
||||
r8153_first_init(tp);
|
||||
r8153_enable_aldps(tp);
|
||||
r8153_aldps_en(tp, true);
|
||||
r8153_u2p3en(tp, true);
|
||||
r8153_u1u2en(tp, true);
|
||||
usb_enable_lpm(tp->udev);
|
||||
|
@ -2952,9 +2947,9 @@ static void rtl8153_down(struct r8152 *tp)
|
|||
r8153_u1u2en(tp, false);
|
||||
r8153_u2p3en(tp, false);
|
||||
r8153_power_cut_en(tp, false);
|
||||
r8153_disable_aldps(tp);
|
||||
r8153_aldps_en(tp, false);
|
||||
r8153_enter_oob(tp);
|
||||
r8153_enable_aldps(tp);
|
||||
r8153_aldps_en(tp, true);
|
||||
}
|
||||
|
||||
static bool rtl8152_in_nway(struct r8152 *tp)
|
||||
|
@ -2988,7 +2983,6 @@ static void set_carrier(struct r8152 *tp)
|
|||
struct net_device *netdev = tp->netdev;
|
||||
u8 speed;
|
||||
|
||||
clear_bit(RTL8152_LINK_CHG, &tp->flags);
|
||||
speed = rtl8152_get_speed(tp);
|
||||
|
||||
if (speed & LINK_STATUS) {
|
||||
|
@ -3038,20 +3032,18 @@ static void rtl_work_func_t(struct work_struct *work)
|
|||
goto out1;
|
||||
}
|
||||
|
||||
if (test_bit(RTL8152_LINK_CHG, &tp->flags))
|
||||
if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags))
|
||||
set_carrier(tp);
|
||||
|
||||
if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
|
||||
if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags))
|
||||
_rtl8152_set_rx_mode(tp->netdev);
|
||||
|
||||
/* don't schedule napi before linking */
|
||||
if (test_bit(SCHEDULE_NAPI, &tp->flags) &&
|
||||
netif_carrier_ok(tp->netdev)) {
|
||||
clear_bit(SCHEDULE_NAPI, &tp->flags);
|
||||
if (test_and_clear_bit(SCHEDULE_NAPI, &tp->flags) &&
|
||||
netif_carrier_ok(tp->netdev))
|
||||
napi_schedule(&tp->napi);
|
||||
}
|
||||
|
||||
if (test_bit(PHY_RESET, &tp->flags))
|
||||
if (test_and_clear_bit(PHY_RESET, &tp->flags))
|
||||
rtl_phy_reset(tp);
|
||||
|
||||
mutex_unlock(&tp->control);
|
||||
|
@ -3060,6 +3052,33 @@ out1:
|
|||
usb_autopm_put_interface(tp->intf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rtl_notifier(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct r8152 *tp = container_of(nb, struct r8152, pm_notifier);
|
||||
|
||||
switch (action) {
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
case PM_SUSPEND_PREPARE:
|
||||
usb_autopm_get_interface(tp->intf);
|
||||
break;
|
||||
|
||||
case PM_POST_HIBERNATION:
|
||||
case PM_POST_SUSPEND:
|
||||
usb_autopm_put_interface(tp->intf);
|
||||
break;
|
||||
|
||||
case PM_POST_RESTORE:
|
||||
case PM_RESTORE_PREPARE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rtl8152_open(struct net_device *netdev)
|
||||
{
|
||||
struct r8152 *tp = netdev_priv(netdev);
|
||||
|
@ -3102,6 +3121,10 @@ static int rtl8152_open(struct net_device *netdev)
|
|||
mutex_unlock(&tp->control);
|
||||
|
||||
usb_autopm_put_interface(tp->intf);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
tp->pm_notifier.notifier_call = rtl_notifier;
|
||||
register_pm_notifier(&tp->pm_notifier);
|
||||
#endif
|
||||
|
||||
out:
|
||||
return res;
|
||||
|
@ -3112,6 +3135,9 @@ static int rtl8152_close(struct net_device *netdev)
|
|||
struct r8152 *tp = netdev_priv(netdev);
|
||||
int res = 0;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
unregister_pm_notifier(&tp->pm_notifier);
|
||||
#endif
|
||||
napi_disable(&tp->napi);
|
||||
clear_bit(WORK_ENABLE, &tp->flags);
|
||||
usb_kill_urb(tp->intr_urb);
|
||||
|
@ -3250,7 +3276,7 @@ static void r8152b_init(struct r8152 *tp)
|
|||
if (test_bit(RTL8152_UNPLUG, &tp->flags))
|
||||
return;
|
||||
|
||||
r8152b_disable_aldps(tp);
|
||||
r8152_aldps_en(tp, false);
|
||||
|
||||
if (tp->version == RTL_VER_01) {
|
||||
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
|
||||
|
@ -3272,7 +3298,7 @@ static void r8152b_init(struct r8152 *tp)
|
|||
ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
|
||||
|
||||
r8152b_enable_eee(tp);
|
||||
r8152b_enable_aldps(tp);
|
||||
r8152_aldps_en(tp, true);
|
||||
r8152b_enable_fc(tp);
|
||||
rtl_tally_reset(tp);
|
||||
|
||||
|
@ -3290,7 +3316,7 @@ static void r8153_init(struct r8152 *tp)
|
|||
if (test_bit(RTL8152_UNPLUG, &tp->flags))
|
||||
return;
|
||||
|
||||
r8153_disable_aldps(tp);
|
||||
r8153_aldps_en(tp, false);
|
||||
r8153_u1u2en(tp, false);
|
||||
|
||||
for (i = 0; i < 500; i++) {
|
||||
|
@ -3379,7 +3405,7 @@ static void r8153_init(struct r8152 *tp)
|
|||
EEE_SPDWN_EN);
|
||||
|
||||
r8153_enable_eee(tp);
|
||||
r8153_enable_aldps(tp);
|
||||
r8153_aldps_en(tp, true);
|
||||
r8152b_enable_fc(tp);
|
||||
rtl_tally_reset(tp);
|
||||
r8153_u2p3en(tp, true);
|
||||
|
|
|
@ -2193,12 +2193,8 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
|
|||
{
|
||||
u32 tx_cmd_a, tx_cmd_b;
|
||||
|
||||
if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
|
||||
struct sk_buff *skb2 =
|
||||
skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
|
||||
if (skb_cow_head(skb, SMSC75XX_TX_OVERHEAD)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = skb2;
|
||||
if (!skb)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -456,13 +456,8 @@ static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
|||
|
||||
len = skb->len;
|
||||
|
||||
if (skb_headroom(skb) < SR_TX_OVERHEAD) {
|
||||
struct sk_buff *skb2;
|
||||
|
||||
skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
|
||||
if (skb_cow_head(skb, SR_TX_OVERHEAD)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = skb2;
|
||||
if (!skb)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1759,7 +1759,6 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
|||
struct iscsi_tmr_req *tmr_req;
|
||||
struct iscsi_tm *hdr;
|
||||
int out_of_order_cmdsn = 0, ret;
|
||||
bool sess_ref = false;
|
||||
u8 function, tcm_function = TMR_UNKNOWN;
|
||||
|
||||
hdr = (struct iscsi_tm *) buf;
|
||||
|
@ -1801,18 +1800,17 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
|||
buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* TASK_REASSIGN for ERL=2 / connection stays inside of
|
||||
* LIO-Target $FABRIC_MOD
|
||||
*/
|
||||
if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
|
||||
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
|
||||
conn->sess->se_sess, 0, DMA_NONE,
|
||||
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
|
||||
|
||||
target_get_sess_cmd(&cmd->se_cmd, true);
|
||||
sess_ref = true;
|
||||
|
||||
/*
|
||||
* TASK_REASSIGN for ERL=2 / connection stays inside of
|
||||
* LIO-Target $FABRIC_MOD
|
||||
*/
|
||||
if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
|
||||
switch (function) {
|
||||
case ISCSI_TM_FUNC_ABORT_TASK:
|
||||
tcm_function = TMR_ABORT_TASK;
|
||||
|
@ -1951,12 +1949,8 @@ attach:
|
|||
* For connection recovery, this is also the default action for
|
||||
* TMR TASK_REASSIGN.
|
||||
*/
|
||||
if (sess_ref) {
|
||||
pr_debug("Handle TMR, using sess_ref=true check\n");
|
||||
target_put_sess_cmd(&cmd->se_cmd);
|
||||
}
|
||||
|
||||
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
|
||||
target_put_sess_cmd(&cmd->se_cmd);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
|
||||
|
|
|
@ -133,6 +133,15 @@ static bool __target_check_io_state(struct se_cmd *se_cmd,
|
|||
spin_unlock(&se_cmd->t_state_lock);
|
||||
return false;
|
||||
}
|
||||
if (se_cmd->transport_state & CMD_T_PRE_EXECUTE) {
|
||||
if (se_cmd->scsi_status) {
|
||||
pr_debug("Attempted to abort io tag: %llu early failure"
|
||||
" status: 0x%02x\n", se_cmd->tag,
|
||||
se_cmd->scsi_status);
|
||||
spin_unlock(&se_cmd->t_state_lock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (sess->sess_tearing_down || se_cmd->cmd_wait_set) {
|
||||
pr_debug("Attempted to abort io tag: %llu already shutdown,"
|
||||
" skipping\n", se_cmd->tag);
|
||||
|
|
|
@ -1933,6 +1933,7 @@ void target_execute_cmd(struct se_cmd *cmd)
|
|||
}
|
||||
|
||||
cmd->t_state = TRANSPORT_PROCESSING;
|
||||
cmd->transport_state &= ~CMD_T_PRE_EXECUTE;
|
||||
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
|
||||
|
@ -2572,6 +2573,7 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
|
|||
ret = -ESHUTDOWN;
|
||||
goto out;
|
||||
}
|
||||
se_cmd->transport_state |= CMD_T_PRE_EXECUTE;
|
||||
list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
|
||||
out:
|
||||
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Generic Trusted Execution Environment Configuration
|
||||
config TEE
|
||||
tristate "Trusted Execution Environment support"
|
||||
depends on HAVE_ARM_SMCCC || COMPILE_TEST
|
||||
select DMA_SHARED_BUFFER
|
||||
select GENERIC_ALLOCATOR
|
||||
help
|
||||
|
|
|
@ -224,13 +224,14 @@ static void optee_release(struct tee_context *ctx)
|
|||
if (!IS_ERR(shm)) {
|
||||
arg = tee_shm_get_va(shm, 0);
|
||||
/*
|
||||
* If va2pa fails for some reason, we can't call
|
||||
* optee_close_session(), only free the memory. Secure OS
|
||||
* will leak sessions and finally refuse more sessions, but
|
||||
* we will at least let normal world reclaim its memory.
|
||||
* If va2pa fails for some reason, we can't call into
|
||||
* secure world, only free the memory. Secure OS will leak
|
||||
* sessions and finally refuse more sessions, but we will
|
||||
* at least let normal world reclaim its memory.
|
||||
*/
|
||||
if (!IS_ERR(arg))
|
||||
tee_shm_va2pa(shm, arg, &parg);
|
||||
if (tee_shm_va2pa(shm, arg, &parg))
|
||||
arg = NULL; /* prevent usage of parg below */
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
|
||||
|
@ -258,7 +259,7 @@ static void optee_release(struct tee_context *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static struct tee_driver_ops optee_ops = {
|
||||
static const struct tee_driver_ops optee_ops = {
|
||||
.get_version = optee_get_version,
|
||||
.open = optee_open,
|
||||
.release = optee_release,
|
||||
|
@ -268,13 +269,13 @@ static struct tee_driver_ops optee_ops = {
|
|||
.cancel_req = optee_cancel_req,
|
||||
};
|
||||
|
||||
static struct tee_desc optee_desc = {
|
||||
static const struct tee_desc optee_desc = {
|
||||
.name = DRIVER_NAME "-clnt",
|
||||
.ops = &optee_ops,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct tee_driver_ops optee_supp_ops = {
|
||||
static const struct tee_driver_ops optee_supp_ops = {
|
||||
.get_version = optee_get_version,
|
||||
.open = optee_open,
|
||||
.release = optee_release,
|
||||
|
@ -282,7 +283,7 @@ static struct tee_driver_ops optee_supp_ops = {
|
|||
.supp_send = optee_supp_send,
|
||||
};
|
||||
|
||||
static struct tee_desc optee_supp_desc = {
|
||||
static const struct tee_desc optee_supp_desc = {
|
||||
.name = DRIVER_NAME "-supp",
|
||||
.ops = &optee_supp_ops,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -589,7 +590,6 @@ static int __init optee_driver_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
np = of_find_matching_node(fw_np, optee_match);
|
||||
of_node_put(fw_np);
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ struct optee_smc_disable_shm_cache_result {
|
|||
OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE)
|
||||
|
||||
/*
|
||||
* Resume from RPC (for example after processing an IRQ)
|
||||
* Resume from RPC (for example after processing a foreign interrupt)
|
||||
*
|
||||
* Call register usage:
|
||||
* a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC
|
||||
|
@ -383,19 +383,19 @@ struct optee_smc_disable_shm_cache_result {
|
|||
OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FREE)
|
||||
|
||||
/*
|
||||
* Deliver an IRQ in normal world.
|
||||
* Deliver foreign interrupt to normal world.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* a0 OPTEE_SMC_RETURN_RPC_IRQ
|
||||
* a0 OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
|
||||
* a1-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
|
||||
* a1-7 Preserved
|
||||
*/
|
||||
#define OPTEE_SMC_RPC_FUNC_IRQ 4
|
||||
#define OPTEE_SMC_RETURN_RPC_IRQ \
|
||||
OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_IRQ)
|
||||
#define OPTEE_SMC_RPC_FUNC_FOREIGN_INTR 4
|
||||
#define OPTEE_SMC_RETURN_RPC_FOREIGN_INTR \
|
||||
OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FOREIGN_INTR)
|
||||
|
||||
/*
|
||||
* Do an RPC request. The supplied struct optee_msg_arg tells which
|
||||
|
|
|
@ -140,11 +140,8 @@ static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
|
|||
|
||||
msec_to_wait = arg->params[0].u.value.a;
|
||||
|
||||
/* set task's state to interruptible sleep */
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
/* take a nap */
|
||||
msleep(msec_to_wait);
|
||||
/* Go to interruptible sleep */
|
||||
msleep_interruptible(msec_to_wait);
|
||||
|
||||
arg->ret = TEEC_SUCCESS;
|
||||
return;
|
||||
|
@ -374,11 +371,11 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param)
|
|||
shm = reg_pair_to_ptr(param->a1, param->a2);
|
||||
tee_shm_free(shm);
|
||||
break;
|
||||
case OPTEE_SMC_RPC_FUNC_IRQ:
|
||||
case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
|
||||
/*
|
||||
* An IRQ was raised while secure world was executing,
|
||||
* since all IRQs are handled in Linux a dummy RPC is
|
||||
* performed to let Linux take the IRQ through the normal
|
||||
* A foreign interrupt was raised while secure world was
|
||||
* executing, since they are handled in Linux a dummy RPC is
|
||||
* performed to let Linux take the interrupt through the normal
|
||||
* vector.
|
||||
*/
|
||||
break;
|
||||
|
|
|
@ -90,8 +90,13 @@ static int tee_ioctl_version(struct tee_context *ctx,
|
|||
struct tee_ioctl_version_data vers;
|
||||
|
||||
ctx->teedev->desc->ops->get_version(ctx->teedev, &vers);
|
||||
|
||||
if (ctx->teedev->desc->flags & TEE_DESC_PRIVILEGED)
|
||||
vers.gen_caps |= TEE_GEN_CAP_PRIVILEGED;
|
||||
|
||||
if (copy_to_user(uvers, &vers, sizeof(vers)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
|||
size, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static struct dma_buf_ops tee_shm_dma_buf_ops = {
|
||||
static const struct dma_buf_ops tee_shm_dma_buf_ops = {
|
||||
.map_dma_buf = tee_shm_op_map_dma_buf,
|
||||
.unmap_dma_buf = tee_shm_op_unmap_dma_buf,
|
||||
.release = tee_shm_op_release,
|
||||
|
|
|
@ -1071,7 +1071,8 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
|||
|
||||
return 1;
|
||||
fail:
|
||||
|
||||
if (dev->eps[0].ring)
|
||||
xhci_ring_free(xhci, dev->eps[0].ring);
|
||||
if (dev->in_ctx)
|
||||
xhci_free_container_ctx(xhci, dev->in_ctx);
|
||||
if (dev->out_ctx)
|
||||
|
|
|
@ -292,6 +292,8 @@ static int usb3503_probe(struct usb3503 *hub)
|
|||
if (gpio_is_valid(hub->gpio_reset)) {
|
||||
err = devm_gpio_request_one(dev, hub->gpio_reset,
|
||||
GPIOF_OUT_INIT_LOW, "usb3503 reset");
|
||||
/* Datasheet defines a hardware reset to be at least 100us */
|
||||
usleep_range(100, 10000);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"unable to request GPIO %d as reset pin (%d)\n",
|
||||
|
|
|
@ -1001,7 +1001,9 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
|||
break;
|
||||
|
||||
case MON_IOCQ_RING_SIZE:
|
||||
mutex_lock(&rp->fetch_lock);
|
||||
ret = rp->b_size;
|
||||
mutex_unlock(&rp->fetch_lock);
|
||||
break;
|
||||
|
||||
case MON_IOCT_RING_SIZE:
|
||||
|
@ -1228,12 +1230,16 @@ static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
unsigned long offset, chunk_idx;
|
||||
struct page *pageptr;
|
||||
|
||||
mutex_lock(&rp->fetch_lock);
|
||||
offset = vmf->pgoff << PAGE_SHIFT;
|
||||
if (offset >= rp->b_size)
|
||||
if (offset >= rp->b_size) {
|
||||
mutex_unlock(&rp->fetch_lock);
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
chunk_idx = offset / CHUNK_SIZE;
|
||||
pageptr = rp->b_vec[chunk_idx].pg;
|
||||
get_page(pageptr);
|
||||
mutex_unlock(&rp->fetch_lock);
|
||||
vmf->page = pageptr;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -348,7 +348,9 @@ static int ux500_suspend(struct device *dev)
|
|||
struct ux500_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
if (musb)
|
||||
usb_phy_set_suspend(musb->xceiv, 1);
|
||||
|
||||
clk_disable_unprepare(glue->clk);
|
||||
|
||||
return 0;
|
||||
|
@ -366,6 +368,7 @@ static int ux500_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (musb)
|
||||
usb_phy_set_suspend(musb->xceiv, 0);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -120,6 +120,7 @@ static const struct usb_device_id id_table[] = {
|
|||
{ USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */
|
||||
{ USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
|
||||
{ USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */
|
||||
{ USB_DEVICE(0x10C4, 0x85A7) }, /* LifeScan OneTouch Verio IQ */
|
||||
{ USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
|
||||
{ USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
|
||||
{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
|
||||
|
@ -170,6 +171,7 @@ static const struct usb_device_id id_table[] = {
|
|||
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
|
||||
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
|
||||
{ USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
|
||||
{ USB_DEVICE(0x18EF, 0xE030) }, /* ELV ALC 8xxx Battery Charger */
|
||||
{ USB_DEVICE(0x18EF, 0xE032) }, /* ELV TFD500 Data Logger */
|
||||
{ USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
|
||||
{ USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
|
||||
|
|
|
@ -155,6 +155,13 @@ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
|
|||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Icenowy Zheng <icenowy@aosc.io> */
|
||||
UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999,
|
||||
"Norelsys",
|
||||
"NS1068X",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_UAS),
|
||||
|
||||
/* Reported-by: Takeo Nakayama <javhera@gmx.com> */
|
||||
UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999,
|
||||
"JMicron",
|
||||
|
|
|
@ -103,7 +103,7 @@ static void usbip_dump_usb_device(struct usb_device *udev)
|
|||
dev_dbg(dev, " devnum(%d) devpath(%s) usb speed(%s)",
|
||||
udev->devnum, udev->devpath, usb_speed_string(udev->speed));
|
||||
|
||||
pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport);
|
||||
pr_debug("tt hub ttport %d\n", udev->ttport);
|
||||
|
||||
dev_dbg(dev, " ");
|
||||
for (i = 0; i < 16; i++)
|
||||
|
@ -136,12 +136,8 @@ static void usbip_dump_usb_device(struct usb_device *udev)
|
|||
}
|
||||
pr_debug("\n");
|
||||
|
||||
dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus);
|
||||
|
||||
dev_dbg(dev,
|
||||
"descriptor %p, config %p, actconfig %p, rawdescriptors %p\n",
|
||||
&udev->descriptor, udev->config,
|
||||
udev->actconfig, udev->rawdescriptors);
|
||||
dev_dbg(dev, "parent %s, bus %s\n", dev_name(&udev->parent->dev),
|
||||
udev->bus->bus_name);
|
||||
|
||||
dev_dbg(dev, "have_langid %d, string_langid %d\n",
|
||||
udev->have_langid, udev->string_langid);
|
||||
|
@ -249,9 +245,6 @@ void usbip_dump_urb(struct urb *urb)
|
|||
|
||||
dev = &urb->dev->dev;
|
||||
|
||||
dev_dbg(dev, " urb :%p\n", urb);
|
||||
dev_dbg(dev, " dev :%p\n", urb->dev);
|
||||
|
||||
usbip_dump_usb_device(urb->dev);
|
||||
|
||||
dev_dbg(dev, " pipe :%08x ", urb->pipe);
|
||||
|
@ -260,11 +253,9 @@ void usbip_dump_urb(struct urb *urb)
|
|||
|
||||
dev_dbg(dev, " status :%d\n", urb->status);
|
||||
dev_dbg(dev, " transfer_flags :%08X\n", urb->transfer_flags);
|
||||
dev_dbg(dev, " transfer_buffer :%p\n", urb->transfer_buffer);
|
||||
dev_dbg(dev, " transfer_buffer_length:%d\n",
|
||||
urb->transfer_buffer_length);
|
||||
dev_dbg(dev, " actual_length :%d\n", urb->actual_length);
|
||||
dev_dbg(dev, " setup_packet :%p\n", urb->setup_packet);
|
||||
|
||||
if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL)
|
||||
usbip_dump_usb_ctrlrequest(
|
||||
|
@ -274,8 +265,6 @@ void usbip_dump_urb(struct urb *urb)
|
|||
dev_dbg(dev, " number_of_packets :%d\n", urb->number_of_packets);
|
||||
dev_dbg(dev, " interval :%d\n", urb->interval);
|
||||
dev_dbg(dev, " error_count :%d\n", urb->error_count);
|
||||
dev_dbg(dev, " context :%p\n", urb->context);
|
||||
dev_dbg(dev, " complete :%p\n", urb->complete);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbip_dump_urb);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o
|
||||
|
||||
fscrypto-y := crypto.o fname.o policy.o keyinfo.o
|
||||
fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o
|
||||
fscrypto-$(CONFIG_BLOCK) += bio.o
|
||||
|
|
|
@ -126,21 +126,6 @@ struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
|
|||
}
|
||||
EXPORT_SYMBOL(fscrypt_get_ctx);
|
||||
|
||||
/**
|
||||
* page_crypt_complete() - completion callback for page crypto
|
||||
* @req: The asynchronous cipher request context
|
||||
* @res: The result of the cipher operation
|
||||
*/
|
||||
static void page_crypt_complete(struct crypto_async_request *req, int res)
|
||||
{
|
||||
struct fscrypt_completion_result *ecr = req->data;
|
||||
|
||||
if (res == -EINPROGRESS)
|
||||
return;
|
||||
ecr->res = res;
|
||||
complete(&ecr->completion);
|
||||
}
|
||||
|
||||
int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
||||
u64 lblk_num, struct page *src_page,
|
||||
struct page *dest_page, unsigned int len,
|
||||
|
@ -151,7 +136,7 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
|||
u8 padding[FS_IV_SIZE - sizeof(__le64)];
|
||||
} iv;
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_FS_COMPLETION_RESULT(ecr);
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist dst, src;
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_ctfm;
|
||||
|
@ -179,7 +164,7 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
|||
|
||||
skcipher_request_set_callback(
|
||||
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
page_crypt_complete, &ecr);
|
||||
crypto_req_done, &wait);
|
||||
|
||||
sg_init_table(&dst, 1);
|
||||
sg_set_page(&dst, dest_page, len, offs);
|
||||
|
@ -187,14 +172,9 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
|||
sg_set_page(&src, src_page, len, offs);
|
||||
skcipher_request_set_crypt(req, &src, &dst, len, &iv);
|
||||
if (rw == FS_DECRYPT)
|
||||
res = crypto_skcipher_decrypt(req);
|
||||
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
||||
else
|
||||
res = crypto_skcipher_encrypt(req);
|
||||
if (res == -EINPROGRESS || res == -EBUSY) {
|
||||
BUG_ON(req->base.data != &ecr);
|
||||
wait_for_completion(&ecr.completion);
|
||||
res = ecr.res;
|
||||
}
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
|
@ -340,7 +320,7 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
|||
return -ECHILD;
|
||||
|
||||
dir = dget_parent(dentry);
|
||||
if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) {
|
||||
if (!IS_ENCRYPTED(d_inode(dir))) {
|
||||
dput(dir);
|
||||
return 0;
|
||||
}
|
||||
|
@ -410,11 +390,8 @@ int fscrypt_initialize(unsigned int cop_flags)
|
|||
{
|
||||
int i, res = -ENOMEM;
|
||||
|
||||
/*
|
||||
* No need to allocate a bounce page pool if there already is one or
|
||||
* this FS won't use it.
|
||||
*/
|
||||
if (cop_flags & FS_CFLG_OWN_PAGES || fscrypt_bounce_page_pool)
|
||||
/* No need to allocate a bounce page pool if this FS won't use it. */
|
||||
if (cop_flags & FS_CFLG_OWN_PAGES)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&fscrypt_init_mutex);
|
||||
|
|
|
@ -14,21 +14,6 @@
|
|||
#include <linux/ratelimit.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
* fname_crypt_complete() - completion callback for filename crypto
|
||||
* @req: The asynchronous cipher request context
|
||||
* @res: The result of the cipher operation
|
||||
*/
|
||||
static void fname_crypt_complete(struct crypto_async_request *req, int res)
|
||||
{
|
||||
struct fscrypt_completion_result *ecr = req->data;
|
||||
|
||||
if (res == -EINPROGRESS)
|
||||
return;
|
||||
ecr->res = res;
|
||||
complete(&ecr->completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* fname_encrypt() - encrypt a filename
|
||||
*
|
||||
|
@ -40,7 +25,7 @@ static int fname_encrypt(struct inode *inode,
|
|||
const struct qstr *iname, struct fscrypt_str *oname)
|
||||
{
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_FS_COMPLETION_RESULT(ecr);
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_ctfm;
|
||||
int res = 0;
|
||||
|
@ -76,17 +61,12 @@ static int fname_encrypt(struct inode *inode,
|
|||
}
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
fname_crypt_complete, &ecr);
|
||||
crypto_req_done, &wait);
|
||||
sg_init_one(&sg, oname->name, cryptlen);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
|
||||
|
||||
/* Do the encryption */
|
||||
res = crypto_skcipher_encrypt(req);
|
||||
if (res == -EINPROGRESS || res == -EBUSY) {
|
||||
/* Request is being completed asynchronously; wait for it */
|
||||
wait_for_completion(&ecr.completion);
|
||||
res = ecr.res;
|
||||
}
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
|
@ -110,7 +90,7 @@ static int fname_decrypt(struct inode *inode,
|
|||
struct fscrypt_str *oname)
|
||||
{
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_FS_COMPLETION_RESULT(ecr);
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_ctfm;
|
||||
|
@ -131,7 +111,7 @@ static int fname_decrypt(struct inode *inode,
|
|||
}
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
fname_crypt_complete, &ecr);
|
||||
crypto_req_done, &wait);
|
||||
|
||||
/* Initialize IV */
|
||||
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
|
||||
|
@ -140,11 +120,7 @@ static int fname_decrypt(struct inode *inode,
|
|||
sg_init_one(&src_sg, iname->name, iname->len);
|
||||
sg_init_one(&dst_sg, oname->name, oname->len);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
|
||||
res = crypto_skcipher_decrypt(req);
|
||||
if (res == -EINPROGRESS || res == -EBUSY) {
|
||||
wait_for_completion(&ecr.completion);
|
||||
res = ecr.res;
|
||||
}
|
||||
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
|
@ -382,8 +358,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||
memset(fname, 0, sizeof(struct fscrypt_name));
|
||||
fname->usr_fname = iname;
|
||||
|
||||
if (!dir->i_sb->s_cop->is_encrypted(dir) ||
|
||||
fscrypt_is_dot_dotdot(iname)) {
|
||||
if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) {
|
||||
fname->disk_name.name = (unsigned char *)iname->name;
|
||||
fname->disk_name.len = iname->len;
|
||||
return 0;
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
#ifndef _FSCRYPT_PRIVATE_H
|
||||
#define _FSCRYPT_PRIVATE_H
|
||||
|
||||
#include <linux/fscrypt_supp.h>
|
||||
#define __FS_HAS_ENCRYPTION 1
|
||||
#include <linux/fscrypt.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
/* Encryption parameters */
|
||||
|
@ -69,15 +70,6 @@ typedef enum {
|
|||
#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
|
||||
#define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002
|
||||
|
||||
struct fscrypt_completion_result {
|
||||
struct completion completion;
|
||||
int res;
|
||||
};
|
||||
|
||||
#define DECLARE_FS_COMPLETION_RESULT(ecr) \
|
||||
struct fscrypt_completion_result ecr = { \
|
||||
COMPLETION_INITIALIZER_ONSTACK((ecr).completion), 0 }
|
||||
|
||||
/* bio stuffs */
|
||||
#define REQ_OP_READ READ
|
||||
#define REQ_OP_WRITE WRITE
|
||||
|
|
112
fs/crypto/hooks.c
Normal file
112
fs/crypto/hooks.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* fs/crypto/hooks.c
|
||||
*
|
||||
* Encryption hooks for higher-level filesystem operations.
|
||||
*/
|
||||
|
||||
#include <linux/ratelimit.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
* fscrypt_file_open - prepare to open a possibly-encrypted regular file
|
||||
* @inode: the inode being opened
|
||||
* @filp: the struct file being set up
|
||||
*
|
||||
* Currently, an encrypted regular file can only be opened if its encryption key
|
||||
* is available; access to the raw encrypted contents is not supported.
|
||||
* Therefore, we first set up the inode's encryption key (if not already done)
|
||||
* and return an error if it's unavailable.
|
||||
*
|
||||
* We also verify that if the parent directory (from the path via which the file
|
||||
* is being opened) is encrypted, then the inode being opened uses the same
|
||||
* encryption policy. This is needed as part of the enforcement that all files
|
||||
* in an encrypted directory tree use the same encryption policy, as a
|
||||
* protection against certain types of offline attacks. Note that this check is
|
||||
* needed even when opening an *unencrypted* file, since it's forbidden to have
|
||||
* an unencrypted file in an encrypted directory.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
*/
|
||||
int fscrypt_file_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int err;
|
||||
struct dentry *dir;
|
||||
|
||||
err = fscrypt_require_key(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dir = dget_parent(file_dentry(filp));
|
||||
if (IS_ENCRYPTED(d_inode(dir)) &&
|
||||
!fscrypt_has_permitted_context(d_inode(dir), inode)) {
|
||||
pr_warn_ratelimited("fscrypt: inconsistent encryption contexts: %lu/%lu",
|
||||
d_inode(dir)->i_ino, inode->i_ino);
|
||||
err = -EPERM;
|
||||
}
|
||||
dput(dir);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_file_open);
|
||||
|
||||
int __fscrypt_prepare_link(struct inode *inode, struct inode *dir)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_require_key(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!fscrypt_has_permitted_context(dir, inode))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_link);
|
||||
|
||||
int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_require_key(old_dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_require_key(new_dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (old_dir != new_dir) {
|
||||
if (IS_ENCRYPTED(new_dir) &&
|
||||
!fscrypt_has_permitted_context(new_dir,
|
||||
d_inode(old_dentry)))
|
||||
return -EPERM;
|
||||
|
||||
if ((flags & RENAME_EXCHANGE) &&
|
||||
IS_ENCRYPTED(old_dir) &&
|
||||
!fscrypt_has_permitted_context(old_dir,
|
||||
d_inode(new_dentry)))
|
||||
return -EPERM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_rename);
|
||||
|
||||
int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int err = fscrypt_get_encryption_info(dir);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fscrypt_has_encryption_key(dir)) {
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
|
||||
d_set_d_op(dentry, &fscrypt_d_ops);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
|
|
@ -17,17 +17,6 @@
|
|||
|
||||
static struct crypto_shash *essiv_hash_tfm;
|
||||
|
||||
static void derive_crypt_complete(struct crypto_async_request *req, int rc)
|
||||
{
|
||||
struct fscrypt_completion_result *ecr = req->data;
|
||||
|
||||
if (rc == -EINPROGRESS)
|
||||
return;
|
||||
|
||||
ecr->res = rc;
|
||||
complete(&ecr->completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* derive_key_aes() - Derive a key using AES-128-ECB
|
||||
* @deriving_key: Encryption key used for derivation.
|
||||
|
@ -42,7 +31,7 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
|
|||
{
|
||||
int res = 0;
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_FS_COMPLETION_RESULT(ecr);
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
|
||||
|
||||
|
@ -59,7 +48,7 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
|
|||
}
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
derive_crypt_complete, &ecr);
|
||||
crypto_req_done, &wait);
|
||||
res = crypto_skcipher_setkey(tfm, deriving_key,
|
||||
FS_AES_128_ECB_KEY_SIZE);
|
||||
if (res < 0)
|
||||
|
@ -69,11 +58,7 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
|
|||
sg_init_one(&dst_sg, derived_raw_key, source_key->size);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg, source_key->size,
|
||||
NULL);
|
||||
res = crypto_skcipher_encrypt(req);
|
||||
if (res == -EINPROGRESS || res == -EBUSY) {
|
||||
wait_for_completion(&ecr.completion);
|
||||
res = ecr.res;
|
||||
}
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
out:
|
||||
skcipher_request_free(req);
|
||||
crypto_free_skcipher(tfm);
|
||||
|
@ -109,6 +94,11 @@ static int validate_user_key(struct fscrypt_info *crypt_info,
|
|||
goto out;
|
||||
}
|
||||
ukp = user_key_payload(keyring_key);
|
||||
if (!ukp) {
|
||||
/* key was revoked before we acquired its semaphore */
|
||||
res = -EKEYREVOKED;
|
||||
goto out;
|
||||
}
|
||||
if (ukp->datalen != sizeof(struct fscrypt_key)) {
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
|
@ -268,7 +258,7 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
|||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (res < 0) {
|
||||
if (!fscrypt_dummy_context_enabled(inode) ||
|
||||
inode->i_sb->s_cop->is_encrypted(inode))
|
||||
IS_ENCRYPTED(inode))
|
||||
return res;
|
||||
/* Fake up a context for an unencrypted directory */
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
|
|
@ -109,7 +109,7 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
|
|||
struct fscrypt_policy policy;
|
||||
int res;
|
||||
|
||||
if (!inode->i_sb->s_cop->is_encrypted(inode))
|
||||
if (!IS_ENCRYPTED(inode))
|
||||
return -ENODATA;
|
||||
|
||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
|
@ -166,11 +166,11 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
|
|||
return 1;
|
||||
|
||||
/* No restrictions if the parent directory is unencrypted */
|
||||
if (!cops->is_encrypted(parent))
|
||||
if (!IS_ENCRYPTED(parent))
|
||||
return 1;
|
||||
|
||||
/* Encrypted directories must not contain unencrypted files */
|
||||
if (!cops->is_encrypted(child))
|
||||
if (!IS_ENCRYPTED(child))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
|
|
@ -4223,8 +4223,11 @@ void ext4_set_inode_flags(struct inode *inode)
|
|||
new_fl |= S_DIRSYNC;
|
||||
if (test_opt(inode->i_sb, DAX))
|
||||
new_fl |= S_DAX;
|
||||
if (flags & EXT4_ENCRYPT_FL)
|
||||
new_fl |= S_ENCRYPTED;
|
||||
inode_set_flags(inode, new_fl,
|
||||
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX);
|
||||
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX|
|
||||
S_ENCRYPTED);
|
||||
}
|
||||
|
||||
/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
|
||||
|
|
|
@ -23,14 +23,12 @@
|
|||
#include <linux/bio.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/quotaops.h>
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
#include <linux/fscrypt_supp.h>
|
||||
#else
|
||||
#include <linux/fscrypt_notsupp.h>
|
||||
#endif
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/writeback.h>
|
||||
|
||||
#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_F2FS_FS_ENCRYPTION)
|
||||
#include <linux/fscrypt.h>
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
#define f2fs_bug_on(sbi, condition) BUG_ON(condition)
|
||||
#else
|
||||
|
@ -3152,6 +3150,7 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode)
|
|||
{
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
file_set_encrypt(inode);
|
||||
inode->i_flags |= S_ENCRYPTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,11 @@ void f2fs_set_inode_flags(struct inode *inode)
|
|||
new_fl |= S_NOATIME;
|
||||
if (flags & FS_DIRSYNC_FL)
|
||||
new_fl |= S_DIRSYNC;
|
||||
if (f2fs_encrypted_inode(inode))
|
||||
new_fl |= S_ENCRYPTED;
|
||||
inode_set_flags(inode, new_fl,
|
||||
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
|
||||
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|
|
||||
S_ENCRYPTED);
|
||||
}
|
||||
|
||||
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
|
||||
|
|
|
@ -1742,14 +1742,9 @@ static const struct fscrypt_operations f2fs_cryptops = {
|
|||
.key_prefix = "f2fs:",
|
||||
.get_context = f2fs_get_context,
|
||||
.set_context = f2fs_set_context,
|
||||
.is_encrypted = f2fs_encrypted_inode,
|
||||
.empty_dir = f2fs_empty_dir,
|
||||
.max_namelen = f2fs_max_namelen,
|
||||
};
|
||||
#else
|
||||
static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.is_encrypted = f2fs_encrypted_inode,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
|
||||
|
@ -2478,7 +2473,9 @@ try_onemore:
|
|||
#endif
|
||||
|
||||
sb->s_op = &f2fs_sops;
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
sb->s_cop = &f2fs_cryptops;
|
||||
#endif
|
||||
sb->s_xattr = f2fs_xattr_handlers;
|
||||
sb->s_export_op = &f2fs_export_ops;
|
||||
sb->s_magic = F2FS_SUPER_MAGIC;
|
||||
|
|
16
fs/locks.c
16
fs/locks.c
|
@ -2220,10 +2220,12 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
error = do_lock_file_wait(filp, cmd, file_lock);
|
||||
|
||||
/*
|
||||
* Attempt to detect a close/fcntl race and recover by
|
||||
* releasing the lock that was just acquired.
|
||||
* Attempt to detect a close/fcntl race and recover by releasing the
|
||||
* lock that was just acquired. There is no need to do that when we're
|
||||
* unlocking though, or for OFD locks.
|
||||
*/
|
||||
if (!error && file_lock->fl_type != F_UNLCK) {
|
||||
if (!error && file_lock->fl_type != F_UNLCK &&
|
||||
!(file_lock->fl_flags & FL_OFDLCK)) {
|
||||
/*
|
||||
* We need that spin_lock here - it prevents reordering between
|
||||
* update of i_flctx->flc_posix and check for it done in
|
||||
|
@ -2362,10 +2364,12 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
error = do_lock_file_wait(filp, cmd, file_lock);
|
||||
|
||||
/*
|
||||
* Attempt to detect a close/fcntl race and recover by
|
||||
* releasing the lock that was just acquired.
|
||||
* Attempt to detect a close/fcntl race and recover by releasing the
|
||||
* lock that was just acquired. There is no need to do that when we're
|
||||
* unlocking though, or for OFD locks.
|
||||
*/
|
||||
if (!error && file_lock->fl_type != F_UNLCK) {
|
||||
if (!error && file_lock->fl_type != F_UNLCK &&
|
||||
!(file_lock->fl_flags & FL_OFDLCK)) {
|
||||
/*
|
||||
* We need that spin_lock here - it prevents reordering between
|
||||
* update of i_flctx->flc_posix and check for it done in
|
||||
|
|
|
@ -37,6 +37,7 @@ struct bpf_map {
|
|||
u32 value_size;
|
||||
u32 max_entries;
|
||||
u32 pages;
|
||||
bool unpriv_array;
|
||||
struct user_struct *user;
|
||||
const struct bpf_map_ops *ops;
|
||||
struct work_struct work;
|
||||
|
@ -141,6 +142,7 @@ struct bpf_prog_aux {
|
|||
struct bpf_array {
|
||||
struct bpf_map map;
|
||||
u32 elem_size;
|
||||
u32 index_mask;
|
||||
/* 'ownership' of prog_array is claimed by the first program that
|
||||
* is going to use this map or by the first program which FD is stored
|
||||
* in the map to make sure that all callers and callees have the same
|
||||
|
|
|
@ -53,6 +53,13 @@ extern void cpu_remove_dev_attr(struct device_attribute *attr);
|
|||
extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
|
||||
extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
|
||||
|
||||
extern ssize_t cpu_show_meltdown(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
extern ssize_t cpu_show_spectre_v1(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
extern ssize_t cpu_show_spectre_v2(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
|
||||
extern __printf(4, 5)
|
||||
struct device *cpu_device_create(struct device *parent, void *drvdata,
|
||||
const struct attribute_group **groups,
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
/*
|
||||
* Autoloaded crypto modules should only use a prefixed name to avoid allowing
|
||||
|
@ -469,6 +470,45 @@ struct crypto_alg {
|
|||
struct module *cra_module;
|
||||
} CRYPTO_MINALIGN_ATTR;
|
||||
|
||||
/*
|
||||
* A helper struct for waiting for completion of async crypto ops
|
||||
*/
|
||||
struct crypto_wait {
|
||||
struct completion completion;
|
||||
int err;
|
||||
};
|
||||
|
||||
/*
|
||||
* Macro for declaring a crypto op async wait object on stack
|
||||
*/
|
||||
#define DECLARE_CRYPTO_WAIT(_wait) \
|
||||
struct crypto_wait _wait = { \
|
||||
COMPLETION_INITIALIZER_ONSTACK((_wait).completion), 0 }
|
||||
|
||||
/*
|
||||
* Async ops completion helper functioons
|
||||
*/
|
||||
void crypto_req_done(struct crypto_async_request *req, int err);
|
||||
|
||||
static inline int crypto_wait_req(int err, struct crypto_wait *wait)
|
||||
{
|
||||
switch (err) {
|
||||
case -EINPROGRESS:
|
||||
case -EBUSY:
|
||||
wait_for_completion(&wait->completion);
|
||||
reinit_completion(&wait->completion);
|
||||
err = wait->err;
|
||||
break;
|
||||
};
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void crypto_init_wait(struct crypto_wait *wait)
|
||||
{
|
||||
init_completion(&wait->completion);
|
||||
}
|
||||
|
||||
/*
|
||||
* Algorithm registration interface.
|
||||
*/
|
||||
|
|
|
@ -466,6 +466,9 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
|
|||
void bpf_int_jit_compile(struct bpf_prog *fp);
|
||||
bool bpf_helper_changes_skb_data(void *func);
|
||||
|
||||
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
|
||||
const struct bpf_insn *patch, u32 len);
|
||||
|
||||
#ifdef CONFIG_BPF_JIT
|
||||
typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
|
||||
|
||||
|
|
|
@ -1812,6 +1812,7 @@ struct super_operations {
|
|||
#else
|
||||
#define S_DAX 0 /* Make all the DAX code disappear */
|
||||
#endif
|
||||
#define S_ENCRYPTED 16384 /* Encrypted file (using fs/crypto/) */
|
||||
|
||||
/*
|
||||
* Note that nosuid etc flags are inode-specific: setting some file-system
|
||||
|
@ -1850,6 +1851,7 @@ struct super_operations {
|
|||
#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT)
|
||||
#define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC)
|
||||
#define IS_DAX(inode) ((inode)->i_flags & S_DAX)
|
||||
#define IS_ENCRYPTED(inode) ((inode)->i_flags & S_ENCRYPTED)
|
||||
|
||||
#define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \
|
||||
(inode)->i_rdev == WHITEOUT_DEV)
|
||||
|
|
290
include/linux/fscrypt.h
Normal file
290
include/linux/fscrypt.h
Normal file
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* fscrypt.h: declarations for per-file encryption
|
||||
*
|
||||
* Filesystems that implement per-file encryption include this header
|
||||
* file with the __FS_HAS_ENCRYPTION set according to whether that filesystem
|
||||
* is being built with encryption support or not.
|
||||
*
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
*
|
||||
* Written by Michael Halcrow, 2015.
|
||||
* Modified by Jaegeuk Kim, 2015.
|
||||
*/
|
||||
#ifndef _LINUX_FSCRYPT_H
|
||||
#define _LINUX_FSCRYPT_H
|
||||
|
||||
#include <linux/key.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <uapi/linux/fs.h>
|
||||
|
||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||
|
||||
struct fscrypt_info;
|
||||
|
||||
struct fscrypt_ctx {
|
||||
union {
|
||||
struct {
|
||||
struct page *bounce_page; /* Ciphertext page */
|
||||
struct page *control_page; /* Original page */
|
||||
} w;
|
||||
struct {
|
||||
struct bio *bio;
|
||||
struct work_struct work;
|
||||
} r;
|
||||
struct list_head free_list; /* Free list */
|
||||
};
|
||||
u8 flags; /* Flags */
|
||||
};
|
||||
|
||||
/**
|
||||
* For encrypted symlinks, the ciphertext length is stored at the beginning
|
||||
* of the string in little-endian format.
|
||||
*/
|
||||
struct fscrypt_symlink_data {
|
||||
__le16 len;
|
||||
char encrypted_path[1];
|
||||
} __packed;
|
||||
|
||||
struct fscrypt_str {
|
||||
unsigned char *name;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct fscrypt_name {
|
||||
const struct qstr *usr_fname;
|
||||
struct fscrypt_str disk_name;
|
||||
u32 hash;
|
||||
u32 minor_hash;
|
||||
struct fscrypt_str crypto_buf;
|
||||
};
|
||||
|
||||
#define FSTR_INIT(n, l) { .name = n, .len = l }
|
||||
#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
|
||||
#define fname_name(p) ((p)->disk_name.name)
|
||||
#define fname_len(p) ((p)->disk_name.len)
|
||||
|
||||
/*
|
||||
* fscrypt superblock flags
|
||||
*/
|
||||
#define FS_CFLG_OWN_PAGES (1U << 1)
|
||||
|
||||
/*
|
||||
* crypto opertions for filesystems
|
||||
*/
|
||||
struct fscrypt_operations {
|
||||
unsigned int flags;
|
||||
const char *key_prefix;
|
||||
int (*get_context)(struct inode *, void *, size_t);
|
||||
int (*set_context)(struct inode *, const void *, size_t, void *);
|
||||
bool (*dummy_context)(struct inode *);
|
||||
bool (*empty_dir)(struct inode *);
|
||||
unsigned (*max_namelen)(struct inode *);
|
||||
};
|
||||
|
||||
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
|
||||
{
|
||||
if (inode->i_sb->s_cop->dummy_context &&
|
||||
inode->i_sb->s_cop->dummy_context(inode))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
|
||||
u32 filenames_mode)
|
||||
{
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
||||
{
|
||||
if (str->len == 1 && str->name[0] == '.')
|
||||
return true;
|
||||
|
||||
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if __FS_HAS_ENCRYPTION
|
||||
|
||||
static inline struct page *fscrypt_control_page(struct page *page)
|
||||
{
|
||||
return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
||||
{
|
||||
return (inode->i_crypt_info != NULL);
|
||||
}
|
||||
|
||||
#include <linux/fscrypt_supp.h>
|
||||
|
||||
#else /* !__FS_HAS_ENCRYPTION */
|
||||
|
||||
static inline struct page *fscrypt_control_page(struct page *page)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <linux/fscrypt_notsupp.h>
|
||||
#endif /* __FS_HAS_ENCRYPTION */
|
||||
|
||||
/**
|
||||
* fscrypt_require_key - require an inode's encryption key
|
||||
* @inode: the inode we need the key for
|
||||
*
|
||||
* If the inode is encrypted, set up its encryption key if not already done.
|
||||
* Then require that the key be present and return -ENOKEY otherwise.
|
||||
*
|
||||
* No locks are needed, and the key will live as long as the struct inode --- so
|
||||
* it won't go away from under you.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
* if a problem occurred while setting up the encryption key.
|
||||
*/
|
||||
static inline int fscrypt_require_key(struct inode *inode)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
int err = fscrypt_get_encryption_info(inode);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_link - prepare to link an inode into a possibly-encrypted directory
|
||||
* @old_dentry: an existing dentry for the inode being linked
|
||||
* @dir: the target directory
|
||||
* @dentry: negative dentry for the target filename
|
||||
*
|
||||
* A new link can only be added to an encrypted directory if the directory's
|
||||
* encryption key is available --- since otherwise we'd have no way to encrypt
|
||||
* the filename. Therefore, we first set up the directory's encryption key (if
|
||||
* not already done) and return an error if it's unavailable.
|
||||
*
|
||||
* We also verify that the link will not violate the constraint that all files
|
||||
* in an encrypted directory tree use the same encryption policy.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the directory's encryption key is missing,
|
||||
* -EPERM if the link would result in an inconsistent encryption policy, or
|
||||
* another -errno code.
|
||||
*/
|
||||
static inline int fscrypt_prepare_link(struct dentry *old_dentry,
|
||||
struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return __fscrypt_prepare_link(d_inode(old_dentry), dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_rename - prepare for a rename between possibly-encrypted directories
|
||||
* @old_dir: source directory
|
||||
* @old_dentry: dentry for source file
|
||||
* @new_dir: target directory
|
||||
* @new_dentry: dentry for target location (may be negative unless exchanging)
|
||||
* @flags: rename flags (we care at least about %RENAME_EXCHANGE)
|
||||
*
|
||||
* Prepare for ->rename() where the source and/or target directories may be
|
||||
* encrypted. A new link can only be added to an encrypted directory if the
|
||||
* directory's encryption key is available --- since otherwise we'd have no way
|
||||
* to encrypt the filename. A rename to an existing name, on the other hand,
|
||||
* *is* cryptographically possible without the key. However, we take the more
|
||||
* conservative approach and just forbid all no-key renames.
|
||||
*
|
||||
* We also verify that the rename will not violate the constraint that all files
|
||||
* in an encrypted directory tree use the same encryption policy.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if an encryption key is missing, -EPERM if the
|
||||
* rename would cause inconsistent encryption policies, or another -errno code.
|
||||
*/
|
||||
static inline int fscrypt_prepare_rename(struct inode *old_dir,
|
||||
struct dentry *old_dentry,
|
||||
struct inode *new_dir,
|
||||
struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (IS_ENCRYPTED(old_dir) || IS_ENCRYPTED(new_dir))
|
||||
return __fscrypt_prepare_rename(old_dir, old_dentry,
|
||||
new_dir, new_dentry, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_lookup - prepare to lookup a name in a possibly-encrypted directory
|
||||
* @dir: directory being searched
|
||||
* @dentry: filename being looked up
|
||||
* @flags: lookup flags
|
||||
*
|
||||
* Prepare for ->lookup() in a directory which may be encrypted. Lookups can be
|
||||
* done with or without the directory's encryption key; without the key,
|
||||
* filenames are presented in encrypted form. Therefore, we'll try to set up
|
||||
* the directory's encryption key, but even without it the lookup can continue.
|
||||
*
|
||||
* To allow invalidating stale dentries if the directory's encryption key is
|
||||
* added later, we also install a custom ->d_revalidate() method and use the
|
||||
* DCACHE_ENCRYPTED_WITH_KEY flag to indicate whether a given dentry is a
|
||||
* plaintext name (flag set) or a ciphertext name (flag cleared).
|
||||
*
|
||||
* Return: 0 on success, -errno if a problem occurred while setting up the
|
||||
* encryption key
|
||||
*/
|
||||
static inline int fscrypt_prepare_lookup(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return __fscrypt_prepare_lookup(dir, dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_setattr - prepare to change a possibly-encrypted inode's attributes
|
||||
* @dentry: dentry through which the inode is being changed
|
||||
* @attr: attributes to change
|
||||
*
|
||||
* Prepare for ->setattr() on a possibly-encrypted inode. On an encrypted file,
|
||||
* most attribute changes are allowed even without the encryption key. However,
|
||||
* without the encryption key we do have to forbid truncates. This is needed
|
||||
* because the size being truncated to may not be a multiple of the filesystem
|
||||
* block size, and in that case we'd have to decrypt the final block, zero the
|
||||
* portion past i_size, and re-encrypt it. (We *could* allow truncating to a
|
||||
* filesystem block boundary, but it's simpler to just forbid all truncates ---
|
||||
* and we already forbid all other contents modifications without the key.)
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
* if a problem occurred while setting up the encryption key.
|
||||
*/
|
||||
static inline int fscrypt_prepare_setattr(struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
return fscrypt_require_key(d_inode(dentry));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_H */
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* fscrypt_common.h: common declarations for per-file encryption
|
||||
*
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
*
|
||||
* Written by Michael Halcrow, 2015.
|
||||
* Modified by Jaegeuk Kim, 2015.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FSCRYPT_COMMON_H
|
||||
#define _LINUX_FSCRYPT_COMMON_H
|
||||
|
||||
#include <linux/key.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <uapi/linux/fs.h>
|
||||
|
||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||
|
||||
struct fscrypt_info;
|
||||
|
||||
struct fscrypt_ctx {
|
||||
union {
|
||||
struct {
|
||||
struct page *bounce_page; /* Ciphertext page */
|
||||
struct page *control_page; /* Original page */
|
||||
} w;
|
||||
struct {
|
||||
struct bio *bio;
|
||||
struct work_struct work;
|
||||
} r;
|
||||
struct list_head free_list; /* Free list */
|
||||
};
|
||||
u8 flags; /* Flags */
|
||||
};
|
||||
|
||||
/**
|
||||
* For encrypted symlinks, the ciphertext length is stored at the beginning
|
||||
* of the string in little-endian format.
|
||||
*/
|
||||
struct fscrypt_symlink_data {
|
||||
__le16 len;
|
||||
char encrypted_path[1];
|
||||
} __packed;
|
||||
|
||||
struct fscrypt_str {
|
||||
unsigned char *name;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct fscrypt_name {
|
||||
const struct qstr *usr_fname;
|
||||
struct fscrypt_str disk_name;
|
||||
u32 hash;
|
||||
u32 minor_hash;
|
||||
struct fscrypt_str crypto_buf;
|
||||
};
|
||||
|
||||
#define FSTR_INIT(n, l) { .name = n, .len = l }
|
||||
#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
|
||||
#define fname_name(p) ((p)->disk_name.name)
|
||||
#define fname_len(p) ((p)->disk_name.len)
|
||||
|
||||
/*
|
||||
* fscrypt superblock flags
|
||||
*/
|
||||
#define FS_CFLG_OWN_PAGES (1U << 1)
|
||||
|
||||
/*
|
||||
* crypto opertions for filesystems
|
||||
*/
|
||||
struct fscrypt_operations {
|
||||
unsigned int flags;
|
||||
const char *key_prefix;
|
||||
int (*get_context)(struct inode *, void *, size_t);
|
||||
int (*set_context)(struct inode *, const void *, size_t, void *);
|
||||
int (*dummy_context)(struct inode *);
|
||||
bool (*is_encrypted)(struct inode *);
|
||||
bool (*empty_dir)(struct inode *);
|
||||
unsigned (*max_namelen)(struct inode *);
|
||||
};
|
||||
|
||||
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
|
||||
{
|
||||
if (inode->i_sb->s_cop->dummy_context &&
|
||||
inode->i_sb->s_cop->dummy_context(inode))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
|
||||
u32 filenames_mode)
|
||||
{
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
||||
{
|
||||
if (str->len == 1 && str->name[0] == '.')
|
||||
return true;
|
||||
|
||||
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct page *fscrypt_control_page(struct page *page)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
|
||||
#else
|
||||
WARN_ON_ONCE(1);
|
||||
return ERR_PTR(-EINVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int fscrypt_has_encryption_key(const struct inode *inode)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
return (inode->i_crypt_info != NULL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_COMMON_H */
|
|
@ -3,13 +3,16 @@
|
|||
*
|
||||
* This stubs out the fscrypt functions for filesystems configured without
|
||||
* encryption support.
|
||||
*
|
||||
* Do not include this file directly. Use fscrypt.h instead!
|
||||
*/
|
||||
#ifndef _LINUX_FSCRYPT_H
|
||||
#error "Incorrect include of linux/fscrypt_notsupp.h!"
|
||||
#endif
|
||||
|
||||
#ifndef _LINUX_FSCRYPT_NOTSUPP_H
|
||||
#define _LINUX_FSCRYPT_NOTSUPP_H
|
||||
|
||||
#include <linux/fscrypt_common.h>
|
||||
|
||||
/* crypto.c */
|
||||
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
|
||||
gfp_t gfp_flags)
|
||||
|
@ -97,7 +100,7 @@ static inline int fscrypt_setup_filename(struct inode *dir,
|
|||
const struct qstr *iname,
|
||||
int lookup, struct fscrypt_name *fname)
|
||||
{
|
||||
if (dir->i_sb->s_cop->is_encrypted(dir))
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(fname, 0, sizeof(struct fscrypt_name));
|
||||
|
@ -174,4 +177,34 @@ static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* hooks.c */
|
||||
|
||||
static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode))
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_link(struct inode *inode,
|
||||
struct inode *dir)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_rename(struct inode *old_dir,
|
||||
struct dentry *old_dentry,
|
||||
struct inode *new_dir,
|
||||
struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_lookup(struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
/*
|
||||
* fscrypt_supp.h
|
||||
*
|
||||
* This is included by filesystems configured with encryption support.
|
||||
* Do not include this file directly. Use fscrypt.h instead!
|
||||
*/
|
||||
#ifndef _LINUX_FSCRYPT_H
|
||||
#error "Incorrect include of linux/fscrypt_supp.h!"
|
||||
#endif
|
||||
|
||||
#ifndef _LINUX_FSCRYPT_SUPP_H
|
||||
#define _LINUX_FSCRYPT_SUPP_H
|
||||
|
||||
#include <linux/fscrypt_common.h>
|
||||
|
||||
/* crypto.c */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
|
||||
|
@ -142,4 +143,14 @@ extern void fscrypt_pullback_bio_page(struct page **, bool);
|
|||
extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
|
||||
unsigned int);
|
||||
|
||||
/* hooks.c */
|
||||
extern int fscrypt_file_open(struct inode *inode, struct file *filp);
|
||||
extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir);
|
||||
extern int __fscrypt_prepare_rename(struct inode *old_dir,
|
||||
struct dentry *old_dentry,
|
||||
struct inode *new_dir,
|
||||
struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry);
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_SUPP_H */
|
||||
|
|
|
@ -682,6 +682,17 @@ static inline bool phy_is_internal(struct phy_device *phydev)
|
|||
return phydev->is_internal;
|
||||
}
|
||||
|
||||
/**
|
||||
* phy_interface_mode_is_rgmii - Convenience function for testing if a
|
||||
* PHY interface mode is RGMII (all variants)
|
||||
* @mode: the phy_interface_t enum
|
||||
*/
|
||||
static inline bool phy_interface_mode_is_rgmii(phy_interface_t mode)
|
||||
{
|
||||
return mode >= PHY_INTERFACE_MODE_RGMII &&
|
||||
mode <= PHY_INTERFACE_MODE_RGMII_TXID;
|
||||
};
|
||||
|
||||
/**
|
||||
* phy_interface_is_rgmii - Convenience function for testing if a PHY interface
|
||||
* is RGMII (all variants)
|
||||
|
|
|
@ -16,7 +16,6 @@ struct sh_eth_plat_data {
|
|||
unsigned char mac_addr[ETH_ALEN];
|
||||
unsigned no_ether_link:1;
|
||||
unsigned ether_link_active_low:1;
|
||||
unsigned needs_init:1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define TEE_SHM_MAPPED 0x1 /* Memory mapped by the kernel */
|
||||
#define TEE_SHM_DMA_BUF 0x2 /* Memory with dma-buf handle */
|
||||
|
||||
struct device;
|
||||
struct tee_device;
|
||||
struct tee_shm;
|
||||
struct tee_shm_pool;
|
||||
|
|
|
@ -496,6 +496,7 @@ struct se_cmd {
|
|||
#define CMD_T_BUSY (1 << 9)
|
||||
#define CMD_T_TAS (1 << 10)
|
||||
#define CMD_T_FABRIC_STOP (1 << 11)
|
||||
#define CMD_T_PRE_EXECUTE (1 << 12)
|
||||
spinlock_t t_state_lock;
|
||||
struct kref cmd_kref;
|
||||
struct completion t_transport_stop_comp;
|
||||
|
|
|
@ -204,7 +204,7 @@ TRACE_EVENT(kvm_ack_irq,
|
|||
{ KVM_TRACE_MMIO_WRITE, "write" }
|
||||
|
||||
TRACE_EVENT(kvm_mmio,
|
||||
TP_PROTO(int type, int len, u64 gpa, u64 val),
|
||||
TP_PROTO(int type, int len, u64 gpa, void *val),
|
||||
TP_ARGS(type, len, gpa, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
|
@ -218,7 +218,10 @@ TRACE_EVENT(kvm_mmio,
|
|||
__entry->type = type;
|
||||
__entry->len = len;
|
||||
__entry->gpa = gpa;
|
||||
__entry->val = val;
|
||||
__entry->val = 0;
|
||||
if (val)
|
||||
memcpy(&__entry->val, val,
|
||||
min_t(u32, sizeof(__entry->val), len));
|
||||
),
|
||||
|
||||
TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx",
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#define TEE_MAX_ARG_SIZE 1024
|
||||
|
||||
#define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */
|
||||
#define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */
|
||||
|
||||
/*
|
||||
* TEE Implementation ID
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
/* Called from syscall */
|
||||
static struct bpf_map *array_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
u32 elem_size, array_size, index_mask, max_entries;
|
||||
bool unpriv = !capable(CAP_SYS_ADMIN);
|
||||
struct bpf_array *array;
|
||||
u32 elem_size, array_size;
|
||||
u64 mask64;
|
||||
|
||||
/* check sanity of attributes */
|
||||
if (attr->max_entries == 0 || attr->key_size != 4 ||
|
||||
|
@ -36,12 +38,33 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
|
|||
|
||||
elem_size = round_up(attr->value_size, 8);
|
||||
|
||||
max_entries = attr->max_entries;
|
||||
|
||||
/* On 32 bit archs roundup_pow_of_two() with max_entries that has
|
||||
* upper most bit set in u32 space is undefined behavior due to
|
||||
* resulting 1U << 32, so do it manually here in u64 space.
|
||||
*/
|
||||
mask64 = fls_long(max_entries - 1);
|
||||
mask64 = 1ULL << mask64;
|
||||
mask64 -= 1;
|
||||
|
||||
index_mask = mask64;
|
||||
if (unpriv) {
|
||||
/* round up array size to nearest power of 2,
|
||||
* since cpu will speculate within index_mask limits
|
||||
*/
|
||||
max_entries = index_mask + 1;
|
||||
/* Check for overflows. */
|
||||
if (max_entries < attr->max_entries)
|
||||
return ERR_PTR(-E2BIG);
|
||||
}
|
||||
|
||||
/* check round_up into zero and u32 overflow */
|
||||
if (elem_size == 0 ||
|
||||
attr->max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size)
|
||||
max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
array_size = sizeof(*array) + attr->max_entries * elem_size;
|
||||
array_size = sizeof(*array) + max_entries * elem_size;
|
||||
|
||||
/* allocate all map elements and zero-initialize them */
|
||||
array = kzalloc(array_size, GFP_USER | __GFP_NOWARN);
|
||||
|
@ -50,6 +73,8 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
|
|||
if (!array)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
array->index_mask = index_mask;
|
||||
array->map.unpriv_array = unpriv;
|
||||
|
||||
/* copy mandatory map attributes */
|
||||
array->map.key_size = attr->key_size;
|
||||
|
@ -70,7 +95,7 @@ static void *array_map_lookup_elem(struct bpf_map *map, void *key)
|
|||
if (index >= array->map.max_entries)
|
||||
return NULL;
|
||||
|
||||
return array->value + array->elem_size * index;
|
||||
return array->value + array->elem_size * (index & array->index_mask);
|
||||
}
|
||||
|
||||
/* Called from syscall */
|
||||
|
@ -111,7 +136,9 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value,
|
|||
/* all elements already exist */
|
||||
return -EEXIST;
|
||||
|
||||
memcpy(array->value + array->elem_size * index, value, map->value_size);
|
||||
memcpy(array->value +
|
||||
array->elem_size * (index & array->index_mask),
|
||||
value, map->value_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,6 +137,77 @@ void __bpf_prog_free(struct bpf_prog *fp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__bpf_prog_free);
|
||||
|
||||
static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn)
|
||||
{
|
||||
return BPF_CLASS(insn->code) == BPF_JMP &&
|
||||
/* Call and Exit are both special jumps with no
|
||||
* target inside the BPF instruction image.
|
||||
*/
|
||||
BPF_OP(insn->code) != BPF_CALL &&
|
||||
BPF_OP(insn->code) != BPF_EXIT;
|
||||
}
|
||||
|
||||
static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta)
|
||||
{
|
||||
struct bpf_insn *insn = prog->insnsi;
|
||||
u32 i, insn_cnt = prog->len;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++) {
|
||||
if (!bpf_is_jmp_and_has_target(insn))
|
||||
continue;
|
||||
|
||||
/* Adjust offset of jmps if we cross boundaries. */
|
||||
if (i < pos && i + insn->off + 1 > pos)
|
||||
insn->off += delta;
|
||||
else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
|
||||
insn->off -= delta;
|
||||
}
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
|
||||
const struct bpf_insn *patch, u32 len)
|
||||
{
|
||||
u32 insn_adj_cnt, insn_rest, insn_delta = len - 1;
|
||||
struct bpf_prog *prog_adj;
|
||||
|
||||
/* Since our patchlet doesn't expand the image, we're done. */
|
||||
if (insn_delta == 0) {
|
||||
memcpy(prog->insnsi + off, patch, sizeof(*patch));
|
||||
return prog;
|
||||
}
|
||||
|
||||
insn_adj_cnt = prog->len + insn_delta;
|
||||
|
||||
/* Several new instructions need to be inserted. Make room
|
||||
* for them. Likely, there's no need for a new allocation as
|
||||
* last page could have large enough tailroom.
|
||||
*/
|
||||
prog_adj = bpf_prog_realloc(prog, bpf_prog_size(insn_adj_cnt),
|
||||
GFP_USER);
|
||||
if (!prog_adj)
|
||||
return NULL;
|
||||
|
||||
prog_adj->len = insn_adj_cnt;
|
||||
|
||||
/* Patching happens in 3 steps:
|
||||
*
|
||||
* 1) Move over tail of insnsi from next instruction onwards,
|
||||
* so we can patch the single target insn with one or more
|
||||
* new ones (patching is always from 1 to n insns, n > 0).
|
||||
* 2) Inject new instructions at the target location.
|
||||
* 3) Adjust branch offsets if necessary.
|
||||
*/
|
||||
insn_rest = insn_adj_cnt - off - len;
|
||||
|
||||
memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + 1,
|
||||
sizeof(*patch) * insn_rest);
|
||||
memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len);
|
||||
|
||||
bpf_adj_branches(prog_adj, off, insn_delta);
|
||||
|
||||
return prog_adj;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BPF_JIT
|
||||
struct bpf_binary_header *
|
||||
bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
|
||||
|
|
|
@ -447,57 +447,6 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl)
|
|||
list_add(&tl->list_node, &bpf_prog_types);
|
||||
}
|
||||
|
||||
/* fixup insn->imm field of bpf_call instructions:
|
||||
* if (insn->imm == BPF_FUNC_map_lookup_elem)
|
||||
* insn->imm = bpf_map_lookup_elem - __bpf_call_base;
|
||||
* else if (insn->imm == BPF_FUNC_map_update_elem)
|
||||
* insn->imm = bpf_map_update_elem - __bpf_call_base;
|
||||
* else ...
|
||||
*
|
||||
* this function is called after eBPF program passed verification
|
||||
*/
|
||||
static void fixup_bpf_calls(struct bpf_prog *prog)
|
||||
{
|
||||
const struct bpf_func_proto *fn;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < prog->len; i++) {
|
||||
struct bpf_insn *insn = &prog->insnsi[i];
|
||||
|
||||
if (insn->code == (BPF_JMP | BPF_CALL)) {
|
||||
/* we reach here when program has bpf_call instructions
|
||||
* and it passed bpf_check(), means that
|
||||
* ops->get_func_proto must have been supplied, check it
|
||||
*/
|
||||
BUG_ON(!prog->aux->ops->get_func_proto);
|
||||
|
||||
if (insn->imm == BPF_FUNC_get_route_realm)
|
||||
prog->dst_needed = 1;
|
||||
if (insn->imm == BPF_FUNC_get_prandom_u32)
|
||||
bpf_user_rnd_init_once();
|
||||
if (insn->imm == BPF_FUNC_tail_call) {
|
||||
/* mark bpf_tail_call as different opcode
|
||||
* to avoid conditional branch in
|
||||
* interpeter for every normal call
|
||||
* and to prevent accidental JITing by
|
||||
* JIT compiler that doesn't support
|
||||
* bpf_tail_call yet
|
||||
*/
|
||||
insn->imm = 0;
|
||||
insn->code |= BPF_X;
|
||||
continue;
|
||||
}
|
||||
|
||||
fn = prog->aux->ops->get_func_proto(insn->imm);
|
||||
/* all functions that have prototype and verifier allowed
|
||||
* programs to call them, must be real in-kernel functions
|
||||
*/
|
||||
BUG_ON(!fn->func);
|
||||
insn->imm = fn->func - __bpf_call_base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* drop refcnt on maps used by eBPF program and free auxilary data */
|
||||
static void free_used_maps(struct bpf_prog_aux *aux)
|
||||
{
|
||||
|
@ -680,9 +629,6 @@ static int bpf_prog_load(union bpf_attr *attr)
|
|||
if (err < 0)
|
||||
goto free_used_maps;
|
||||
|
||||
/* fixup BPF_CALL->imm field */
|
||||
fixup_bpf_calls(prog);
|
||||
|
||||
/* eBPF program is ready to be JITed */
|
||||
err = bpf_prog_select_runtime(prog);
|
||||
if (err < 0)
|
||||
|
|
|
@ -186,6 +186,13 @@ struct verifier_stack_elem {
|
|||
struct verifier_stack_elem *next;
|
||||
};
|
||||
|
||||
struct bpf_insn_aux_data {
|
||||
union {
|
||||
enum bpf_reg_type ptr_type; /* pointer type for load/store insns */
|
||||
struct bpf_map *map_ptr; /* pointer for call insn into lookup_elem */
|
||||
};
|
||||
};
|
||||
|
||||
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
|
||||
|
||||
/* single container for all structs
|
||||
|
@ -200,6 +207,7 @@ struct verifier_env {
|
|||
struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
|
||||
u32 used_map_cnt; /* number of used maps */
|
||||
bool allow_ptr_leaks;
|
||||
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
|
||||
};
|
||||
|
||||
/* verbose verifier prints what it's seeing
|
||||
|
@ -945,7 +953,7 @@ error:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int check_call(struct verifier_env *env, int func_id)
|
||||
static int check_call(struct verifier_env *env, int func_id, int insn_idx)
|
||||
{
|
||||
struct verifier_state *state = &env->cur_state;
|
||||
const struct bpf_func_proto *fn = NULL;
|
||||
|
@ -981,6 +989,13 @@ static int check_call(struct verifier_env *env, int func_id)
|
|||
err = check_func_arg(env, BPF_REG_2, fn->arg2_type, &map);
|
||||
if (err)
|
||||
return err;
|
||||
if (func_id == BPF_FUNC_tail_call) {
|
||||
if (map == NULL) {
|
||||
verbose("verifier bug\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
env->insn_aux_data[insn_idx].map_ptr = map;
|
||||
}
|
||||
err = check_func_arg(env, BPF_REG_3, fn->arg3_type, &map);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -1784,7 +1799,7 @@ static int do_check(struct verifier_env *env)
|
|||
return err;
|
||||
|
||||
} else if (class == BPF_LDX) {
|
||||
enum bpf_reg_type src_reg_type;
|
||||
enum bpf_reg_type *prev_src_type, src_reg_type;
|
||||
|
||||
/* check for reserved fields is already done */
|
||||
|
||||
|
@ -1813,16 +1828,18 @@ static int do_check(struct verifier_env *env)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (insn->imm == 0) {
|
||||
prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
|
||||
|
||||
if (*prev_src_type == NOT_INIT) {
|
||||
/* saw a valid insn
|
||||
* dst_reg = *(u32 *)(src_reg + off)
|
||||
* use reserved 'imm' field to mark this insn
|
||||
* save type to validate intersecting paths
|
||||
*/
|
||||
insn->imm = src_reg_type;
|
||||
*prev_src_type = src_reg_type;
|
||||
|
||||
} else if (src_reg_type != insn->imm &&
|
||||
} else if (src_reg_type != *prev_src_type &&
|
||||
(src_reg_type == PTR_TO_CTX ||
|
||||
insn->imm == PTR_TO_CTX)) {
|
||||
*prev_src_type == PTR_TO_CTX)) {
|
||||
/* ABuser program is trying to use the same insn
|
||||
* dst_reg = *(u32*) (src_reg + off)
|
||||
* with different pointer types:
|
||||
|
@ -1835,7 +1852,7 @@ static int do_check(struct verifier_env *env)
|
|||
}
|
||||
|
||||
} else if (class == BPF_STX) {
|
||||
enum bpf_reg_type dst_reg_type;
|
||||
enum bpf_reg_type *prev_dst_type, dst_reg_type;
|
||||
|
||||
if (BPF_MODE(insn->code) == BPF_XADD) {
|
||||
err = check_xadd(env, insn);
|
||||
|
@ -1863,11 +1880,13 @@ static int do_check(struct verifier_env *env)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (insn->imm == 0) {
|
||||
insn->imm = dst_reg_type;
|
||||
} else if (dst_reg_type != insn->imm &&
|
||||
prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type;
|
||||
|
||||
if (*prev_dst_type == NOT_INIT) {
|
||||
*prev_dst_type = dst_reg_type;
|
||||
} else if (dst_reg_type != *prev_dst_type &&
|
||||
(dst_reg_type == PTR_TO_CTX ||
|
||||
insn->imm == PTR_TO_CTX)) {
|
||||
*prev_dst_type == PTR_TO_CTX)) {
|
||||
verbose("same insn cannot be used with different pointers\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1902,7 +1921,7 @@ static int do_check(struct verifier_env *env)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = check_call(env, insn->imm);
|
||||
err = check_call(env, insn->imm, insn_idx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -2098,24 +2117,39 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env)
|
|||
insn->src_reg = 0;
|
||||
}
|
||||
|
||||
static void adjust_branches(struct bpf_prog *prog, int pos, int delta)
|
||||
/* single env->prog->insni[off] instruction was replaced with the range
|
||||
* insni[off, off + cnt). Adjust corresponding insn_aux_data by copying
|
||||
* [0, off) and [off, end) to new locations, so the patched range stays zero
|
||||
*/
|
||||
static int adjust_insn_aux_data(struct verifier_env *env, u32 prog_len,
|
||||
u32 off, u32 cnt)
|
||||
{
|
||||
struct bpf_insn *insn = prog->insnsi;
|
||||
int insn_cnt = prog->len;
|
||||
int i;
|
||||
struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++) {
|
||||
if (BPF_CLASS(insn->code) != BPF_JMP ||
|
||||
BPF_OP(insn->code) == BPF_CALL ||
|
||||
BPF_OP(insn->code) == BPF_EXIT)
|
||||
continue;
|
||||
if (cnt == 1)
|
||||
return 0;
|
||||
new_data = vzalloc(sizeof(struct bpf_insn_aux_data) * prog_len);
|
||||
if (!new_data)
|
||||
return -ENOMEM;
|
||||
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));
|
||||
env->insn_aux_data = new_data;
|
||||
vfree(old_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* adjust offset of jmps if necessary */
|
||||
if (i < pos && i + insn->off + 1 > pos)
|
||||
insn->off += delta;
|
||||
else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
|
||||
insn->off -= delta;
|
||||
}
|
||||
static struct bpf_prog *bpf_patch_insn_data(struct verifier_env *env, u32 off,
|
||||
const struct bpf_insn *patch, u32 len)
|
||||
{
|
||||
struct bpf_prog *new_prog;
|
||||
|
||||
new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
|
||||
if (!new_prog)
|
||||
return NULL;
|
||||
if (adjust_insn_aux_data(env, new_prog->len, off, len))
|
||||
return NULL;
|
||||
return new_prog;
|
||||
}
|
||||
|
||||
/* convert load instructions that access fields of 'struct __sk_buff'
|
||||
|
@ -2124,17 +2158,18 @@ static void adjust_branches(struct bpf_prog *prog, int pos, int delta)
|
|||
static int convert_ctx_accesses(struct verifier_env *env)
|
||||
{
|
||||
struct bpf_insn *insn = env->prog->insnsi;
|
||||
int insn_cnt = env->prog->len;
|
||||
const int insn_cnt = env->prog->len;
|
||||
struct bpf_insn insn_buf[16];
|
||||
struct bpf_prog *new_prog;
|
||||
u32 cnt;
|
||||
int i;
|
||||
enum bpf_access_type type;
|
||||
int i, delta = 0;
|
||||
|
||||
if (!env->prog->aux->ops->convert_ctx_access)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++) {
|
||||
u32 cnt;
|
||||
|
||||
if (insn->code == (BPF_LDX | BPF_MEM | BPF_W))
|
||||
type = BPF_READ;
|
||||
else if (insn->code == (BPF_STX | BPF_MEM | BPF_W))
|
||||
|
@ -2142,11 +2177,8 @@ static int convert_ctx_accesses(struct verifier_env *env)
|
|||
else
|
||||
continue;
|
||||
|
||||
if (insn->imm != PTR_TO_CTX) {
|
||||
/* clear internal mark */
|
||||
insn->imm = 0;
|
||||
if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
|
||||
continue;
|
||||
}
|
||||
|
||||
cnt = env->prog->aux->ops->
|
||||
convert_ctx_access(type, insn->dst_reg, insn->src_reg,
|
||||
|
@ -2156,34 +2188,89 @@ static int convert_ctx_accesses(struct verifier_env *env)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cnt == 1) {
|
||||
memcpy(insn, insn_buf, sizeof(*insn));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* several new insns need to be inserted. Make room for them */
|
||||
insn_cnt += cnt - 1;
|
||||
new_prog = bpf_prog_realloc(env->prog,
|
||||
bpf_prog_size(insn_cnt),
|
||||
GFP_USER);
|
||||
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
|
||||
if (!new_prog)
|
||||
return -ENOMEM;
|
||||
|
||||
new_prog->len = insn_cnt;
|
||||
|
||||
memmove(new_prog->insnsi + i + cnt, new_prog->insns + i + 1,
|
||||
sizeof(*insn) * (insn_cnt - i - cnt));
|
||||
|
||||
/* copy substitute insns in place of load instruction */
|
||||
memcpy(new_prog->insnsi + i, insn_buf, sizeof(*insn) * cnt);
|
||||
|
||||
/* adjust branches in the whole program */
|
||||
adjust_branches(new_prog, i, cnt - 1);
|
||||
delta += cnt - 1;
|
||||
|
||||
/* keep walking new program and skip insns we just inserted */
|
||||
env->prog = new_prog;
|
||||
insn = new_prog->insnsi + i + cnt - 1;
|
||||
i += cnt - 1;
|
||||
insn = new_prog->insnsi + i + delta;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fixup insn->imm field of bpf_call instructions
|
||||
*
|
||||
* this function is called after eBPF program passed verification
|
||||
*/
|
||||
static int fixup_bpf_calls(struct verifier_env *env)
|
||||
{
|
||||
struct bpf_prog *prog = env->prog;
|
||||
struct bpf_insn *insn = prog->insnsi;
|
||||
const struct bpf_func_proto *fn;
|
||||
const int insn_cnt = prog->len;
|
||||
struct bpf_insn insn_buf[16];
|
||||
struct bpf_prog *new_prog;
|
||||
struct bpf_map *map_ptr;
|
||||
int i, cnt, delta = 0;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++) {
|
||||
if (insn->code != (BPF_JMP | BPF_CALL))
|
||||
continue;
|
||||
|
||||
if (insn->imm == BPF_FUNC_get_route_realm)
|
||||
prog->dst_needed = 1;
|
||||
if (insn->imm == BPF_FUNC_get_prandom_u32)
|
||||
bpf_user_rnd_init_once();
|
||||
if (insn->imm == BPF_FUNC_tail_call) {
|
||||
/* mark bpf_tail_call as different opcode to avoid
|
||||
* conditional branch in the interpeter for every normal
|
||||
* call and to prevent accidental JITing by JIT compiler
|
||||
* that doesn't support bpf_tail_call yet
|
||||
*/
|
||||
insn->imm = 0;
|
||||
insn->code |= BPF_X;
|
||||
|
||||
/* instead of changing every JIT dealing with tail_call
|
||||
* emit two extra insns:
|
||||
* if (index >= max_entries) goto out;
|
||||
* index &= array->index_mask;
|
||||
* to avoid out-of-bounds cpu speculation
|
||||
*/
|
||||
map_ptr = env->insn_aux_data[i + delta].map_ptr;
|
||||
if (!map_ptr->unpriv_array)
|
||||
continue;
|
||||
insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3,
|
||||
map_ptr->max_entries, 2);
|
||||
insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3,
|
||||
container_of(map_ptr,
|
||||
struct bpf_array,
|
||||
map)->index_mask);
|
||||
insn_buf[2] = *insn;
|
||||
cnt = 3;
|
||||
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
|
||||
if (!new_prog)
|
||||
return -ENOMEM;
|
||||
|
||||
delta += cnt - 1;
|
||||
env->prog = prog = new_prog;
|
||||
insn = new_prog->insnsi + i + delta;
|
||||
continue;
|
||||
}
|
||||
|
||||
fn = prog->aux->ops->get_func_proto(insn->imm);
|
||||
/* all functions that have prototype and verifier allowed
|
||||
* programs to call them, must be real in-kernel functions
|
||||
*/
|
||||
if (!fn->func) {
|
||||
verbose("kernel subsystem misconfigured func %d\n",
|
||||
insn->imm);
|
||||
return -EFAULT;
|
||||
}
|
||||
insn->imm = fn->func - __bpf_call_base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2227,6 +2314,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
|
|||
if (!env)
|
||||
return -ENOMEM;
|
||||
|
||||
env->insn_aux_data = vzalloc(sizeof(struct bpf_insn_aux_data) *
|
||||
(*prog)->len);
|
||||
ret = -ENOMEM;
|
||||
if (!env->insn_aux_data)
|
||||
goto err_free_env;
|
||||
env->prog = *prog;
|
||||
|
||||
/* grab the mutex to protect few globals used by verifier */
|
||||
|
@ -2245,12 +2337,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
|
|||
/* log_* values have to be sane */
|
||||
if (log_size < 128 || log_size > UINT_MAX >> 8 ||
|
||||
log_level == 0 || log_ubuf == NULL)
|
||||
goto free_env;
|
||||
goto err_unlock;
|
||||
|
||||
ret = -ENOMEM;
|
||||
log_buf = vmalloc(log_size);
|
||||
if (!log_buf)
|
||||
goto free_env;
|
||||
goto err_unlock;
|
||||
} else {
|
||||
log_level = 0;
|
||||
}
|
||||
|
@ -2282,6 +2374,9 @@ skip_full_check:
|
|||
/* program is valid, convert *(u32*)(ctx + off) accesses */
|
||||
ret = convert_ctx_accesses(env);
|
||||
|
||||
if (ret == 0)
|
||||
ret = fixup_bpf_calls(env);
|
||||
|
||||
if (log_level && log_len >= log_size - 1) {
|
||||
BUG_ON(log_len >= log_size);
|
||||
/* verifier log exceeded user supplied buffer */
|
||||
|
@ -2319,14 +2414,16 @@ skip_full_check:
|
|||
free_log_buf:
|
||||
if (log_level)
|
||||
vfree(log_buf);
|
||||
free_env:
|
||||
if (!env->prog->aux->used_maps)
|
||||
/* if we didn't copy map pointers into bpf_prog_info, release
|
||||
* them now. Otherwise free_bpf_prog_info() will release them.
|
||||
*/
|
||||
release_maps(env);
|
||||
*prog = env->prog;
|
||||
kfree(env);
|
||||
err_unlock:
|
||||
mutex_unlock(&bpf_verifier_lock);
|
||||
vfree(env->insn_aux_data);
|
||||
err_free_env:
|
||||
kfree(env);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1939,8 +1939,12 @@ static int unqueue_me(struct futex_q *q)
|
|||
|
||||
/* In the common case we don't take the spinlock, which is nice. */
|
||||
retry:
|
||||
lock_ptr = q->lock_ptr;
|
||||
barrier();
|
||||
/*
|
||||
* q->lock_ptr can change between this read and the following spin_lock.
|
||||
* Use READ_ONCE to forbid the compiler from reloading q->lock_ptr and
|
||||
* optimizing lock_ptr out of the logic below.
|
||||
*/
|
||||
lock_ptr = READ_ONCE(q->lock_ptr);
|
||||
if (lock_ptr != NULL) {
|
||||
spin_lock(lock_ptr);
|
||||
/*
|
||||
|
|
|
@ -731,6 +731,7 @@ static inline void
|
|||
__mutex_unlock_common_slowpath(struct mutex *lock, int nested)
|
||||
{
|
||||
unsigned long flags;
|
||||
WAKE_Q(wake_q);
|
||||
|
||||
/*
|
||||
* As a performance measurement, release the lock before doing other
|
||||
|
@ -758,11 +759,11 @@ __mutex_unlock_common_slowpath(struct mutex *lock, int nested)
|
|||
struct mutex_waiter, list);
|
||||
|
||||
debug_mutex_wake_waiter(lock, waiter);
|
||||
|
||||
wake_up_process(waiter->task);
|
||||
wake_q_add(&wake_q, waiter->task);
|
||||
}
|
||||
|
||||
spin_unlock_mutex(&lock->wait_lock, flags);
|
||||
wake_up_q(&wake_q);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -255,7 +255,8 @@ static void reset_cached_positions(struct zone *zone)
|
|||
{
|
||||
zone->compact_cached_migrate_pfn[0] = zone->zone_start_pfn;
|
||||
zone->compact_cached_migrate_pfn[1] = zone->zone_start_pfn;
|
||||
zone->compact_cached_free_pfn = zone_end_pfn(zone);
|
||||
zone->compact_cached_free_pfn =
|
||||
round_down(zone_end_pfn(zone) - 1, pageblock_nr_pages);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -608,13 +609,17 @@ unsigned long
|
|||
isolate_freepages_range(struct compact_control *cc,
|
||||
unsigned long start_pfn, unsigned long end_pfn)
|
||||
{
|
||||
unsigned long isolated, pfn, block_end_pfn;
|
||||
unsigned long isolated, pfn, block_start_pfn, block_end_pfn;
|
||||
LIST_HEAD(freelist);
|
||||
|
||||
pfn = start_pfn;
|
||||
block_start_pfn = pfn & ~(pageblock_nr_pages - 1);
|
||||
if (block_start_pfn < cc->zone->zone_start_pfn)
|
||||
block_start_pfn = cc->zone->zone_start_pfn;
|
||||
block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
|
||||
|
||||
for (; pfn < end_pfn; pfn += isolated,
|
||||
block_start_pfn = block_end_pfn,
|
||||
block_end_pfn += pageblock_nr_pages) {
|
||||
/* Protect pfn from changing by isolate_freepages_block */
|
||||
unsigned long isolate_start_pfn = pfn;
|
||||
|
@ -627,11 +632,13 @@ isolate_freepages_range(struct compact_control *cc,
|
|||
* scanning range to right one.
|
||||
*/
|
||||
if (pfn >= block_end_pfn) {
|
||||
block_start_pfn = pfn & ~(pageblock_nr_pages - 1);
|
||||
block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
|
||||
block_end_pfn = min(block_end_pfn, end_pfn);
|
||||
}
|
||||
|
||||
if (!pageblock_pfn_to_page(pfn, block_end_pfn, cc->zone))
|
||||
if (!pageblock_pfn_to_page(block_start_pfn,
|
||||
block_end_pfn, cc->zone))
|
||||
break;
|
||||
|
||||
isolated = isolate_freepages_block(cc, &isolate_start_pfn,
|
||||
|
@ -948,18 +955,23 @@ unsigned long
|
|||
isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,
|
||||
unsigned long end_pfn)
|
||||
{
|
||||
unsigned long pfn, block_end_pfn;
|
||||
unsigned long pfn, block_start_pfn, block_end_pfn;
|
||||
|
||||
/* Scan block by block. First and last block may be incomplete */
|
||||
pfn = start_pfn;
|
||||
block_start_pfn = pfn & ~(pageblock_nr_pages - 1);
|
||||
if (block_start_pfn < cc->zone->zone_start_pfn)
|
||||
block_start_pfn = cc->zone->zone_start_pfn;
|
||||
block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
|
||||
|
||||
for (; pfn < end_pfn; pfn = block_end_pfn,
|
||||
block_start_pfn = block_end_pfn,
|
||||
block_end_pfn += pageblock_nr_pages) {
|
||||
|
||||
block_end_pfn = min(block_end_pfn, end_pfn);
|
||||
|
||||
if (!pageblock_pfn_to_page(pfn, block_end_pfn, cc->zone))
|
||||
if (!pageblock_pfn_to_page(block_start_pfn,
|
||||
block_end_pfn, cc->zone))
|
||||
continue;
|
||||
|
||||
pfn = isolate_migratepages_block(cc, pfn, block_end_pfn,
|
||||
|
@ -1177,7 +1189,9 @@ int sysctl_compact_unevictable_allowed __read_mostly = 1;
|
|||
static isolate_migrate_t isolate_migratepages(struct zone *zone,
|
||||
struct compact_control *cc)
|
||||
{
|
||||
unsigned long low_pfn, end_pfn;
|
||||
unsigned long block_start_pfn;
|
||||
unsigned long block_end_pfn;
|
||||
unsigned long low_pfn;
|
||||
unsigned long isolate_start_pfn;
|
||||
struct page *page;
|
||||
const isolate_mode_t isolate_mode =
|
||||
|
@ -1189,16 +1203,21 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
|
|||
* initialized by compact_zone()
|
||||
*/
|
||||
low_pfn = cc->migrate_pfn;
|
||||
block_start_pfn = cc->migrate_pfn & ~(pageblock_nr_pages - 1);
|
||||
if (block_start_pfn < zone->zone_start_pfn)
|
||||
block_start_pfn = zone->zone_start_pfn;
|
||||
|
||||
/* Only scan within a pageblock boundary */
|
||||
end_pfn = ALIGN(low_pfn + 1, pageblock_nr_pages);
|
||||
block_end_pfn = ALIGN(low_pfn + 1, pageblock_nr_pages);
|
||||
|
||||
/*
|
||||
* Iterate over whole pageblocks until we find the first suitable.
|
||||
* Do not cross the free scanner.
|
||||
*/
|
||||
for (; end_pfn <= cc->free_pfn;
|
||||
low_pfn = end_pfn, end_pfn += pageblock_nr_pages) {
|
||||
for (; block_end_pfn <= cc->free_pfn;
|
||||
low_pfn = block_end_pfn,
|
||||
block_start_pfn = block_end_pfn,
|
||||
block_end_pfn += pageblock_nr_pages) {
|
||||
|
||||
/*
|
||||
* This can potentially iterate a massively long zone with
|
||||
|
@ -1209,7 +1228,8 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
|
|||
&& compact_should_abort(cc))
|
||||
break;
|
||||
|
||||
page = pageblock_pfn_to_page(low_pfn, end_pfn, zone);
|
||||
page = pageblock_pfn_to_page(block_start_pfn, block_end_pfn,
|
||||
zone);
|
||||
if (!page)
|
||||
continue;
|
||||
|
||||
|
@ -1228,8 +1248,8 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
|
|||
|
||||
/* Perform the isolation */
|
||||
isolate_start_pfn = low_pfn;
|
||||
low_pfn = isolate_migratepages_block(cc, low_pfn, end_pfn,
|
||||
isolate_mode);
|
||||
low_pfn = isolate_migratepages_block(cc, low_pfn,
|
||||
block_end_pfn, isolate_mode);
|
||||
|
||||
if (!low_pfn || cc->contended) {
|
||||
acct_isolated(zone, cc);
|
||||
|
@ -1444,11 +1464,11 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
|
|||
*/
|
||||
cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync];
|
||||
cc->free_pfn = zone->compact_cached_free_pfn;
|
||||
if (cc->free_pfn < start_pfn || cc->free_pfn > end_pfn) {
|
||||
cc->free_pfn = end_pfn & ~(pageblock_nr_pages-1);
|
||||
if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) {
|
||||
cc->free_pfn = round_down(end_pfn - 1, pageblock_nr_pages);
|
||||
zone->compact_cached_free_pfn = cc->free_pfn;
|
||||
}
|
||||
if (cc->migrate_pfn < start_pfn || cc->migrate_pfn > end_pfn) {
|
||||
if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) {
|
||||
cc->migrate_pfn = start_pfn;
|
||||
zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn;
|
||||
zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue