Release linux (4.7.8-1).

-----BEGIN PGP SIGNATURE-----
 
 iQKPBAABCgB5BQJYB7RuXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w
 ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQ0NjQ0NDA5ODA4QzE3MUUwNTUzMURERUUw
 NTRDQjhGMzEzNDNDRjQ0EhxjYXJuaWxAZGViaWFuLm9yZwAKCRAFTLjzE0PPRKbv
 EACPw/ltBkYlQohcTxO+Jwg6Pj9J2UAcuQeDBsRLxOONLEcfChUtB6YbWnjpP4n7
 PBjFl1oXFlRL2AIp8yJJDNyLRApNHaIJ5Rw15OU0XBZi61iFkMhvZHtFUJI0VifU
 40otIo4/IAgWfYjcIl445m13bS21XzaYkT5hDmKihp1975gBP51LyVXtMPvYC2HO
 2grpj37HbDEhKfXSxPDG++ID20VrHOyKVNnfyzg9lOe0oNRT36j5i1QJtqQPekh1
 gWx98W/QqVpmeyRV1xvFjit2AzjwrIyp8H22wlN5IOG0HXitOrEA0AiQi1pjcMM0
 3O6wRmWTiOoiMiCQEQ+O+92U+uALTG0ssq/9rubAW70CieiQLKmQBZiSoY3JVDfl
 AojNP89QIx273w2aGQpZUY/RJnFWFy3fdh+c8wuLbTGkV3cCwXTd1VpNvi1EVKKK
 SjFytKI3AGLAihXiThbICSiynqsRKdh7ypWzoCF5OxdURk9/HXSOYpk0Ieuqze+R
 niLpETsVpfZCSHjjlG/7oaPAdGEqTm1BZ8a36HmzuByGftARwZ0XqaSUMsbOJC+n
 nZrljSt1migRNKcONPuAvVucOjtI6Bj52Azdq2KutQiKZt1Kie9jLSA32/VNT6u5
 xCRtMNQnatFCUqdJm5pI0pnUgdpL9nykbggY/g0uPBJfEg==
 =6RXa
 -----END PGP SIGNATURE-----

Merge tag 'debian/4.7.8-1'
This commit is contained in:
Ben Hutchings 2016-10-23 04:43:12 +01:00
commit 68bef0cc04
5 changed files with 872 additions and 0 deletions

165
debian/changelog vendored
View File

@ -104,6 +104,171 @@ linux (4.8~rc5-1~exp1) experimental; urgency=medium
-- Ben Hutchings <ben@decadent.org.uk> Wed, 07 Sep 2016 21:52:47 +0100
linux (4.7.8-1) unstable; urgency=high
* New upstream stable update:
https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.7.7
- cpuset: handle race between CPU hotplug and cpuset_hotplug_work
- cgroup: fix invalid controller enable rejections with cgroup namespace
- scripts/recordmcount.c: account for .softirqentry.text
- mm,ksm: fix endless looping in allocating memory when ksm enable
- can: dev: fix deadlock reported after bus-off
- [x86] init: Fix cr4_init_shadow() on CR4-less machines
- drm/udl: fix line iterator in damage handling
- drm/nouveau/fifo/nv04: avoid ramht race against cookie insertion
- drm/radeon/si/dpm: add workaround for for Jet parts
- [armel,armhf] 8616/1: dt: Respect property size when parsing CPUs
- [armel,armhf] 8617/1: dma: fix dma_max_pfn()
- mwifiex: illegal assignment
- i40e: avoid null pointer dereference
- pinctrl: Flag strict is a field in struct pinmux_ops
- i2c: mux: demux-pinctrl: run properly with multiple instances
- rcuperf: Don't treat gp_exp mis-setting as a WARN
- [armhf,arm64] drivers/perf: arm_pmu: Fix leak in error path
- perf/core: Use this_cpu_ptr() when stopping AUX events
- [armhf,arm64] mmc: tegra: Only advertise UHS modes if IO regulator is
present
- nvmem: Declare nvmem_cell_read() consistently
- hwmon: (adt7411) set bit 3 in CFG1 register
- sched/cputime: Fix prev steal time accouting during CPU hotplug
- iwlwifi: mvm: checksum IPv6 fragmented packet
- iwlwifi: mvm: fix txq aggregation bug
- iwlwifi: mvm: write the correct internal TXF index
- iwlwifi: mvm: unmap the paging memory before freeing it
- iwlwifi: pcie: fix access to scratch buffer
- iwlwifi: mvm: free RX reorder buffer on restart
- iwlwifi: mvm: avoid harmless -Wmaybe-uninialized warning
- iwlwifi: mvm: don't use ret when not initialised
- [armhf] usb: gadget: fsl_qe_udc: signedness bug in qe_get_frame()
- mac80211: check skb_linearize() return value
- i40iw: Protect req_resource_num update
- i40iw: Add missing check for interface already open
- i40iw: Change mem_resources pointer to a u8
- i40iw: Fix double free of allocated_buffer
- i40iw: Do not set self-referencing pointer to NULL after kfree
- i40iw: Avoid writing to freed memory
- i40iw: Add missing NULL check for MPA private data
- i40iw: Send last streaming mode message for loopback connections
- i40iw: Update hw_iwarp_state
- i40iw: Receive notification events correctly
- batman-adv: Add missing refcnt for last_candidate
- batman-adv: fix elp packet data reservation
- [armhf,arm64] irqchip/gicv3: Silence noisy DEBUG_PER_CPU_MAPS warning
- [armhf] 8618/1: decompressor: reset ttbcr fields to use TTBR0 on ARMv7
- [arm64] debug: avoid resetting stepping state machine when TIF_SINGLESTEP
- [mips*] uprobes: remove incorrect set_orig_insn
- [mips*] fix uretprobe implementation
- [mips*/*-malta] Fix IOCU disable switch read for MIPS64
- [mips*] uprobes: fix use of uninitialised variable
- printk: fix parsing of "brl=" option
- Bluetooth: split sk_filter in l2cap_sock_recv_cb
- tpm: fix byte-order for the value read by tpm2_get_tpm_pt
- regulator: pwm: Fix regulator ramp delay for continuous mode
- [arm64] regulator: qcom_spmi: Add support for S4 supply on pm8941
- [arm64] regulator: qcom_spmi: Add support for get_mode/set_mode on
switches
- [arm64] regulator: qcom_spmi: Update mvs1/mvs2 switches on pm8941
- [arm64] regulator: qcom_smd: Fix voltage ranges for pm8x41
- [arm64] regulator: qcom_smd: Fix voltage ranges for pma8084 ftsmps and
pldo
- [armhf] dts: imx6sx-sabreauto: Fix misspelled property
- [armhf] sun5i: Fix typo in trip point temperature
- pcmcia: ds: fix suspend/resume
- [armhf] hwrng: omap - Fix assumption that runtime_get_sync will always
succeed
- blk-mq: actually hook up defer list when running requests
- pstore: drop file opened reference count
- fm10k: fix incorrect index calculation in fm10k_write_reta
- iwlmvm: mvm: set correct state in smart-fifo configuration
- [armhf,arm64] em28xx-i2c: rt_mutex_trylock() returns zero on failure
- gspca: avoid unused variable warnings
- ath9k: Fix programming of minCCA power threshold
- qla2xxx: Fix BBCR offset
- fnic: pci_dma_mapping_error() doesn't return an error code
- tracing: Have HIST_TRIGGERS select TRACING
- NFS/pnfs: Do not clobber existing pgio_done_cb in nfs4_proc_read_setup
- svc: Avoid garbage replies when pc_func() returns rpc_drop_reply
- NFS: Don't drop CB requests with invalid principals
- pNFS/files: Fix layoutcommit after a commit to DS
- pNFS/flexfiles: Fix layoutcommit after a commit to DS
- watchdog: core: Clear WDOG_HW_RUNNING before calling the stop function
- xprtrdma: Remove FMRs from the unmap list after unmapping
- [x86] ASoC: Intel: Skylake: Fix error return code in skl_probe()
- brcmfmac: Fix glob_skb leak in brcmf_sdiod_recv_chain
- brcmsmac: Free packet if dma_mapping_error() fails in dma_rxfill
- brcmsmac: Initialize power in brcms_c_stf_ss_algo_channel_get()
- [powerpc*] prom: Fix sub-processor option passed to ibm,
client-architecture-support
- sysctl: handle error writing UINT_MAX to u32 fields
- IB/core: Fix possible memory leak in cma_resolve_iboe_route()
- kernel/fork: fix CLONE_CHILD_CLEARTID regression in nscd
- SUNRPC: Silence WARN_ON when NFSv4.1 over RDMA is in use
- pNFS/flexfiles: Fix layoutstat periodic reporting
- lib/test_hash.c: fix warning in preprocessor symbol evaluation
- [x86] KVM: nVMX: postpone VMCS changes on MSR_IA32_APICBASE write
- ceph: do not modify fi->frag in need_reset_readdir()
- IB/ipoib: Fix memory corruption in ipoib cm mode connect flow
- ath10k: fix get rx_status from htt context
- IB/core: Fix use after free in send_leave function
- regmap: rbtree: Avoid overlapping nodes
- scsi: ses: use scsi_is_sas_rphy instead of is_sas_attached
- IB/ipoib: Don't allow MC joins during light MC flush
- IB/mlx4: Fix incorrect MC join state bit-masking on SR-IOV
- IB/mlx4: Fix code indentation in QP1 MAD flow
- IB/mlx4: Use correct subnet-prefix in QP1 mads under SR-IOV
- IB/mlx5: Enable MAD_IFC commands for IB ports only
- IB/mlx5: Set source mac address in FTE
- batman-adv: remove unused callback from batadv_algo_ops struct
- aio: mark AIO pseudo-fs noexec
- dm log writes: fix bug with too large bios
- usb: misc: legousbtower: Fix NULL pointer deference
- [x86] usb: usbip: vudc: fix left shift overflow
- Revert "usbtmc: convert to devm_kzalloc"
- [x86] ALSA: hda - Adding one more ALC255 pin definition for headset
problem
- [x86] ALSA: hda - Fix headset mic detection problem for several Dell
laptops
- [x86] ALSA: hda - Add the top speaker pin config for HP Spectre x360
https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.7.8
- [powerpc*] pseries: use pci_host_bridge.release_fn() to kfree(phb)
- [powerpc*] cxl: use pcibios_free_controller_deferred() when removing
vPHBs
- timekeeping: Fix __ktime_get_fast_ns() regression
- ALSA: ali5451: Fix out-of-bound position reporting
- ALSA: usb-audio: Extend DragonFly dB scale quirk to cover other variants
- mfd: rtsx_usb: Avoid setting ucr->current_sg.status
- [x86] xen: Update topology map for PV VCPUs
- [powerpc*] KVM: PPC: Book3s PR: Allow access to unprivileged MMCR2
register
- [arm64] KVM: arm64: Require in-kernel irqchip for PMU support
- [arm64] KVM: arm/arm64: vgic: Don't flush/sync without a working vgic
- [powerpc*] KVM: PPC: BookE: Fix a sanity check
- [arm64] fix dump_backtrace/unwind_frame with NULL tsk
- [x86] boot: Fix kdump, cleanup aborted E820_PRAM max_pfn manipulation
- [x86] irq: Prevent force migration of irqs which are not in the vector
domain
- [x86] apic: Get rid of apic_version[] array
- [x86] arch/x86: Handle non enumerated CPU after physical hotplug
- [x86] dumpstack: Fix x86_32 kernel_stack_pointer() previous stack access
- [armhf] dts: mvebu: armada-390: add missing compatibility string and
bracket
- [arm64] dts: MSM8064 remove flags from SPMI/MPP IRQs
- [arm64] cpuidle: Fix error return code
- [x86] tpm: fix a race condition in tpm2_unseal_trusted()
- [x86] tpm_crb: fix crb_req_canceled behavior
[ Ben Hutchings ]
* net: add recursion limit to GRO (CVE-2016-7039)
* posix_acl: Clear SGID bit when setting file permissions (CVE-2016-7097)
* scsi: arcmsr: Buffer overflow in arcmsr_iop_message_xfer() (CVE-2016-7425)
[ Salvatore Bonaccorso ]
* KEYS: Fix short sprintf buffer in /proc/keys show function (CVE-2016-7042)
* mm: remove gup_flags FOLL_WRITE games from __get_user_pages()
(CVE-2016-5195)
-- Salvatore Bonaccorso <carnil@debian.org> Wed, 19 Oct 2016 17:56:57 +0200
linux (4.7.6-1) unstable; urgency=medium
* New upstream stable update:

View File

@ -0,0 +1,70 @@
From: David Howells <dhowells@redhat.com>
Date: Thu, 13 Oct 2016 22:38:46 +0200
Subject: KEYS: Fix short sprintf buffer in /proc/keys show function
Origin: https://bugzilla.redhat.com/attachment.cgi?id=1200212
Fix a short sprintf buffer in proc_keys_show(). If the gcc stack protector
is turned on, this can cause a panic due to stack corruption.
The problem is that xbuf[] is not big enough to hold a 64-bit timeout
rendered as weeks:
(gdb) p 0xffffffffffffffffULL/(60*60*24*7)
$2 = 30500568904943
That's 14 chars plus NUL, not 11 chars plus NUL.
Expand the buffer to 16 chars.
I think the unpatched code apparently works if the stack-protector is not
enabled because on a 32-bit machine the buffer won't be overflowed and on a
64-bit machine there's a 64-bit aligned pointer at one side and an int that
isn't checked again on the other side.
The panic incurred looks something like:
Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffff81352ebe
CPU: 0 PID: 1692 Comm: reproducer Not tainted 4.7.2-201.fc24.x86_64 #1
Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
0000000000000086 00000000fbbd2679 ffff8800a044bc00 ffffffff813d941f
ffffffff81a28d58 ffff8800a044bc98 ffff8800a044bc88 ffffffff811b2cb6
ffff880000000010 ffff8800a044bc98 ffff8800a044bc30 00000000fbbd2679
Call Trace:
[<ffffffff813d941f>] dump_stack+0x63/0x84
[<ffffffff811b2cb6>] panic+0xde/0x22a
[<ffffffff81352ebe>] ? proc_keys_show+0x3ce/0x3d0
[<ffffffff8109f7f9>] __stack_chk_fail+0x19/0x30
[<ffffffff81352ebe>] proc_keys_show+0x3ce/0x3d0
[<ffffffff81350410>] ? key_validate+0x50/0x50
[<ffffffff8134db30>] ? key_default_cmp+0x20/0x20
[<ffffffff8126b31c>] seq_read+0x2cc/0x390
[<ffffffff812b6b12>] proc_reg_read+0x42/0x70
[<ffffffff81244fc7>] __vfs_read+0x37/0x150
[<ffffffff81357020>] ? security_file_permission+0xa0/0xc0
[<ffffffff81246156>] vfs_read+0x96/0x130
[<ffffffff81247635>] SyS_read+0x55/0xc0
[<ffffffff817eb872>] entry_SYSCALL_64_fastpath+0x1a/0xa4
Reported-by: Ondrej Kozina <okozina@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Ondrej Kozina <okozina@redhat.com>
---
security/keys/proc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/keys/proc.c b/security/keys/proc.c
index f0611a6..b9f531c 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -181,7 +181,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
struct timespec now;
unsigned long timo;
key_ref_t key_ref, skey_ref;
- char xbuf[12];
+ char xbuf[16];
int rc;
struct keyring_search_context ctx = {
--
2.9.3

View File

@ -0,0 +1,201 @@
From: Sabrina Dubroca <sd@queasysnail.net>
Date: Mon, 10 Oct 2016 15:43:46 +0200
Subject: net: add recursion limit to GRO
Origin: https://patchwork.ozlabs.org/patch/680412/
Currently, GRO can do unlimited recursion through the gro_receive
handlers. This was fixed for tunneling protocols by limiting tunnel GRO
to one level with encap_mark, but both VLAN and TEB still have this
problem. Thus, the kernel is vulnerable to a stack overflow, if we
receive a packet composed entirely of VLAN headers.
This patch adds a recursion counter to the GRO layer to prevent stack
overflow. When a gro_receive function hits the recursion limit, GRO is
aborted for this skb and it is processed normally.
Thanks to Vladimír Beneš <vbenes@redhat.com> for the initial bug report.
Fixes: CVE-2016-7039
Fixes: 9b174d88c257 ("net: Add Transparent Ethernet Bridging GRO support.")
Fixes: 66e5133f19e9 ("vlan: Add GRO support for non hardware accelerated vlan")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Reviewed-by: Jiri Benc <jbenc@redhat.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
drivers/net/geneve.c | 2 +-
drivers/net/vxlan.c | 2 +-
include/linux/netdevice.h | 24 +++++++++++++++++++++++-
net/8021q/vlan.c | 2 +-
net/core/dev.c | 1 +
net/ethernet/eth.c | 2 +-
net/ipv4/af_inet.c | 2 +-
net/ipv4/fou.c | 4 ++--
net/ipv4/gre_offload.c | 2 +-
net/ipv4/udp_offload.c | 8 +++++++-
net/ipv6/ip6_offload.c | 2 +-
11 files changed, 40 insertions(+), 11 deletions(-)
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -471,7 +471,7 @@ static struct sk_buff **geneve_gro_recei
skb_gro_pull(skb, gh_len);
skb_gro_postpull_rcsum(skb, gh, gh_len);
- pp = ptype->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
flush = 0;
out_unlock:
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -601,7 +601,7 @@ static struct sk_buff **vxlan_gro_receiv
}
}
- pp = eth_gro_receive(head, skb);
+ pp = call_gro_receive(eth_gro_receive, head, skb);
flush = 0;
out:
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2114,7 +2114,10 @@ struct napi_gro_cb {
/* Used to determine if flush_id can be ignored */
u8 is_atomic:1;
- /* 5 bit hole */
+ /* Number of gro_receive callbacks this packet already went through */
+ u8 recursion_counter:4;
+
+ /* 1 bit hole */
/* used to support CHECKSUM_COMPLETE for tunneling protocols */
__wsum csum;
@@ -2125,6 +2128,25 @@ struct napi_gro_cb {
#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
+#define GRO_RECURSION_LIMIT 15
+static inline int gro_recursion_inc_test(struct sk_buff *skb)
+{
+ return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
+}
+
+typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *);
+static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
+ struct sk_buff **head,
+ struct sk_buff *skb)
+{
+ if (gro_recursion_inc_test(skb)) {
+ NAPI_GRO_CB(skb)->flush |= 1;
+ return NULL;
+ }
+
+ return cb(head, skb);
+}
+
struct packet_type {
__be16 type; /* This is really htons(ether_type). */
struct net_device *dev; /* NULL is wildcarded here */
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive
skb_gro_pull(skb, sizeof(*vhdr));
skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
- pp = ptype->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
out_unlock:
rcu_read_unlock();
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4500,6 +4500,7 @@ static enum gro_result dev_gro_receive(s
NAPI_GRO_CB(skb)->flush = 0;
NAPI_GRO_CB(skb)->free = 0;
NAPI_GRO_CB(skb)->encap_mark = 0;
+ NAPI_GRO_CB(skb)->recursion_counter = 0;
NAPI_GRO_CB(skb)->is_fou = 0;
NAPI_GRO_CB(skb)->is_atomic = 1;
NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -439,7 +439,7 @@ struct sk_buff **eth_gro_receive(struct
skb_gro_pull(skb, sizeof(*eh));
skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
- pp = ptype->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
out_unlock:
rcu_read_unlock();
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1388,7 +1388,7 @@ struct sk_buff **inet_gro_receive(struct
skb_gro_pull(skb, sizeof(*iph));
skb_set_transport_header(skb, skb_gro_offset(skb));
- pp = ops->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
out_unlock:
rcu_read_unlock();
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -219,7 +219,7 @@ static struct sk_buff **fou_gro_receive(
if (!ops || !ops->callbacks.gro_receive)
goto out_unlock;
- pp = ops->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
out_unlock:
rcu_read_unlock();
@@ -387,7 +387,7 @@ static struct sk_buff **gue_gro_receive(
if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
goto out_unlock;
- pp = ops->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
flush = 0;
out_unlock:
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -227,7 +227,7 @@ static struct sk_buff **gre_gro_receive(
/* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
skb_gro_postpull_rcsum(skb, greh, grehlen);
- pp = ptype->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
flush = 0;
out_unlock:
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -293,7 +293,13 @@ unflush:
skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
- pp = udp_sk(sk)->gro_receive(sk, head, skb);
+
+ if (gro_recursion_inc_test(skb)) {
+ flush = 1;
+ pp = NULL;
+ } else {
+ pp = udp_sk(sk)->gro_receive(sk, head, skb);
+ }
out_unlock:
rcu_read_unlock();
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -243,7 +243,7 @@ static struct sk_buff **ipv6_gro_receive
skb_gro_postpull_rcsum(skb, iph, nlen);
- pp = ops->callbacks.gro_receive(head, skb);
+ pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
out_unlock:
rcu_read_unlock();

View File

@ -0,0 +1,433 @@
From: Jan Kara <jack@suse.cz>
Date: Mon, 19 Sep 2016 17:39:09 +0200
Subject: posix_acl: Clear SGID bit when setting file permissions
Origin: https://git.kernel.org/linus/073931017b49d9458aa351605b43a7e34598caef
When file permissions are modified via chmod(2) and the user is not in
the owning group or capable of CAP_FSETID, the setgid bit is cleared in
inode_change_ok(). Setting a POSIX ACL via setxattr(2) sets the file
permissions as well as the new ACL, but doesn't clear the setgid bit in
a similar way; this allows to bypass the check in chmod(2). Fix that.
References: CVE-2016-7097
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/9p/acl.c | 40 +++++++++++++++++-----------------------
fs/btrfs/acl.c | 6 ++----
fs/ceph/acl.c | 6 ++----
fs/ext2/acl.c | 12 ++++--------
fs/ext4/acl.c | 12 ++++--------
fs/f2fs/acl.c | 6 ++----
fs/gfs2/acl.c | 12 +++---------
fs/hfsplus/posix_acl.c | 4 ++--
fs/jffs2/acl.c | 9 ++++-----
fs/jfs/acl.c | 6 ++----
fs/ocfs2/acl.c | 10 ++++------
fs/orangefs/acl.c | 15 +++++----------
fs/posix_acl.c | 31 +++++++++++++++++++++++++++++++
fs/reiserfs/xattr_acl.c | 8 ++------
fs/xfs/xfs_acl.c | 13 ++++---------
include/linux/posix_acl.h | 1 +
16 files changed, 89 insertions(+), 102 deletions(-)
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 5b6a1743ea17..b3c2cc79c20d 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -276,32 +276,26 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
switch (handler->flags) {
case ACL_TYPE_ACCESS:
if (acl) {
- umode_t mode = inode->i_mode;
- retval = posix_acl_equiv_mode(acl, &mode);
- if (retval < 0)
+ struct iattr iattr;
+
+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+ if (retval)
goto err_out;
- else {
- struct iattr iattr;
- if (retval == 0) {
- /*
- * ACL can be represented
- * by the mode bits. So don't
- * update ACL.
- */
- acl = NULL;
- value = NULL;
- size = 0;
- }
- /* Updte the mode bits */
- iattr.ia_mode = ((mode & S_IALLUGO) |
- (inode->i_mode & ~S_IALLUGO));
- iattr.ia_valid = ATTR_MODE;
- /* FIXME should we update ctime ?
- * What is the following setxattr update the
- * mode ?
+ if (!acl) {
+ /*
+ * ACL can be represented
+ * by the mode bits. So don't
+ * update ACL.
*/
- v9fs_vfs_setattr_dotl(dentry, &iattr);
+ value = NULL;
+ size = 0;
}
+ iattr.ia_valid = ATTR_MODE;
+ /* FIXME should we update ctime ?
+ * What is the following setxattr update the
+ * mode ?
+ */
+ v9fs_vfs_setattr_dotl(dentry, &iattr);
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 53bb7af4e5f0..247b8dfaf6e5 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -79,11 +79,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (ret < 0)
+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (ret)
return ret;
- if (ret == 0)
- acl = NULL;
}
ret = 0;
break;
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
index 4f67227f69a5..d0b6b342dff9 100644
--- a/fs/ceph/acl.c
+++ b/fs/ceph/acl.c
@@ -95,11 +95,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- ret = posix_acl_equiv_mode(acl, &new_mode);
- if (ret < 0)
+ ret = posix_acl_update_mode(inode, &new_mode, &acl);
+ if (ret)
goto out;
- if (ret == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 42f1d1814083..e725aa0890e0 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -190,15 +190,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- if (error == 0)
- acl = NULL;
- }
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
}
break;
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index c6601a476c02..dfa519979038 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -193,15 +193,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- if (error == 0)
- acl = NULL;
- }
+ inode->i_ctime = ext4_current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
}
break;
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 4dcc9e28dc5c..31344247ce89 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -210,12 +210,10 @@ static int __f2fs_set_acl(struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
set_acl_inode(inode, inode->i_mode);
- if (error == 0)
- acl = NULL;
}
break;
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 363ba9e9d8d0..2524807ee070 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -92,17 +92,11 @@ int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode(acl, &mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
-
- if (error == 0)
- acl = NULL;
-
- if (mode != inode->i_mode) {
- inode->i_mode = mode;
+ if (mode != inode->i_mode)
mark_inode_dirty(inode);
- }
}
if (acl) {
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
index ab7ea2506b4d..9b92058a1240 100644
--- a/fs/hfsplus/posix_acl.c
+++ b/fs/hfsplus/posix_acl.c
@@ -65,8 +65,8 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
case ACL_TYPE_ACCESS:
xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- err = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (err < 0)
+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (err)
return err;
}
err = 0;
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index bc2693d56298..2a0f2a1044c1 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -233,9 +233,10 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
xprefix = JFFS2_XPREFIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- rc = posix_acl_equiv_mode(acl, &mode);
- if (rc < 0)
+ umode_t mode;
+
+ rc = posix_acl_update_mode(inode, &mode, &acl);
+ if (rc)
return rc;
if (inode->i_mode != mode) {
struct iattr attr;
@@ -247,8 +248,6 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
if (rc < 0)
return rc;
}
- if (rc == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 21fa92ba2c19..3a1e1554a4e3 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -78,13 +78,11 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
case ACL_TYPE_ACCESS:
ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (rc < 0)
+ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (rc)
return rc;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- if (rc == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index 2162434728c0..164307b99405 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,
case ACL_TYPE_ACCESS:
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- ret = posix_acl_equiv_mode(acl, &mode);
- if (ret < 0)
- return ret;
+ umode_t mode;
- if (ret == 0)
- acl = NULL;
+ ret = posix_acl_update_mode(inode, &mode, &acl);
+ if (ret)
+ return ret;
ret = ocfs2_acl_set_mode(inode, di_bh,
handle, mode);
diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c
index 28f2195cd798..7a3754488312 100644
--- a/fs/orangefs/acl.c
+++ b/fs/orangefs/acl.c
@@ -73,14 +73,11 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- /*
- * can we represent this with the traditional file
- * mode permission bits?
- */
- error = posix_acl_equiv_mode(acl, &mode);
- if (error < 0) {
- gossip_err("%s: posix_acl_equiv_mode err: %d\n",
+ umode_t mode;
+
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error) {
+ gossip_err("%s: posix_acl_update_mode err: %d\n",
__func__,
error);
return error;
@@ -90,8 +87,6 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
SetModeFlag(orangefs_inode);
inode->i_mode = mode;
mark_inode_dirty_sync(inode);
- if (error == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 59d47ab0791a..bfc3ec388322 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -626,6 +626,37 @@ posix_acl_create(struct inode *dir, umode_t *mode,
}
EXPORT_SYMBOL_GPL(posix_acl_create);
+/**
+ * posix_acl_update_mode - update mode in set_acl
+ *
+ * Update the file mode when setting an ACL: compute the new file permission
+ * bits based on the ACL. In addition, if the ACL is equivalent to the new
+ * file mode, set *acl to NULL to indicate that no ACL should be set.
+ *
+ * As with chmod, clear the setgit bit if the caller is not in the owning group
+ * or capable of CAP_FSETID (see inode_change_ok).
+ *
+ * Called from set_acl inode operations.
+ */
+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
+ struct posix_acl **acl)
+{
+ umode_t mode = inode->i_mode;
+ int error;
+
+ error = posix_acl_equiv_mode(*acl, &mode);
+ if (error < 0)
+ return error;
+ if (error == 0)
+ *acl = NULL;
+ if (!in_group_p(inode->i_gid) &&
+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
+ mode &= ~S_ISGID;
+ *mode_p = mode;
+ return 0;
+}
+EXPORT_SYMBOL(posix_acl_update_mode);
+
/*
* Fix up the uids and gids in posix acl extended attributes in place.
*/
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index dbed42f755e0..27376681c640 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -242,13 +242,9 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- if (error == 0)
- acl = NULL;
- }
}
break;
case ACL_TYPE_DEFAULT:
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index b6e527b8eccb..8a0dec89ca56 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -257,16 +257,11 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return error;
if (type == ACL_TYPE_ACCESS) {
- umode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode(acl, &mode);
-
- if (error <= 0) {
- acl = NULL;
-
- if (error < 0)
- return error;
- }
+ umode_t mode;
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error)
+ return error;
error = xfs_set_mode(inode, mode);
if (error)
return error;
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index d5d3d741f028..bf1046d0397b 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -93,6 +93,7 @@ extern int set_posix_acl(struct inode *, int, struct posix_acl *);
extern int posix_acl_chmod(struct inode *, umode_t);
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
struct posix_acl **);
+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
extern int simple_set_acl(struct inode *, struct posix_acl *, int);
extern int simple_acl_create(struct inode *, struct inode *);

View File

@ -93,6 +93,9 @@ features/all/securelevel/arm64-add-kernel-config-option-to-set-securelevel-wh.pa
# Security fixes
bugfix/all/ptrace-being-capable-wrt-a-process-requires-mapped-uids-gids.patch
debian/i386-686-pae-pci-set-pci-nobios-by-default.patch
bugfix/all/net-add-recursion-limit-to-gro.patch
bugfix/all/posix_acl-clear-sgid-bit-when-setting-file-permissio.patch
bugfix/all/KEYS-Fix-short-sprintf-buffer-in-proc-keys-show-func.patch
# ABI maintenance