Update to 3.16.3
svn path=/dists/sid/linux/; revision=21865
This commit is contained in:
parent
8ae89f44df
commit
9029a4f67f
|
@ -1,11 +1,88 @@
|
|||
linux (3.16.2-4) UNRELEASED; urgency=medium
|
||||
linux (3.16.3-1) UNRELEASED; urgency=medium
|
||||
|
||||
* New upstream stable update:
|
||||
https://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.16.3
|
||||
- reiserfs: fix corruption introduced by balance_leaf refactor
|
||||
(regression in 3.16) (Closes: #761457)
|
||||
- reiserfs: Fix use after free in journal teardown
|
||||
- media: v4l: vb2: Fix stream start and buffer completion race
|
||||
- [x86] iommu/vt-d: Exclude devices using RMRRs from IOMMU API domains
|
||||
- [powerpc*] powerpc/powernv: Fix IOMMU group lost (regression in 3.15)
|
||||
- [x86] iommu/vt-d: Defer domain removal if device is assigned to a driver
|
||||
- [x86] iommu/amd: Fix cleanup_domain for mass device removal
|
||||
- [s390*] locking: Reenable optimistic spinning
|
||||
- firmware: Do not use WARN_ON(!spin_is_locked())
|
||||
- CAPABILITIES: remove undefined caps from all processes
|
||||
- fanotify: fix double free of pending permission events
|
||||
- ocfs2: do not write error flag to user structure we cannot copy from/to
|
||||
- [powerpc*] mm: fix potential infinite loop in dissolve_free_huge_pages()
|
||||
- drivers/mfd/rtsx_usb.c: export device table (Closes: #761428)
|
||||
- [powerpc*] mm: Use read barrier when creating real_pte
|
||||
- [powerpc*] thp: Add write barrier after updating the valid bit
|
||||
- [powerpc*] thp: Invalidate old 64K based hash page mapping before insert
|
||||
of 4k pte
|
||||
- [powerpc*] thp: Handle combo pages in invalidate
|
||||
- [powerpc*] thp: Invalidate with vpn in loop
|
||||
- [powerpc*] thp: Use ACCESS_ONCE when loading pmdp
|
||||
- SCSI: save command pool address of Scsi_Host (regression in 3.15)
|
||||
- fix regression in SCSI_IOCTL_SEND_COMMAND (regression in 3.16)
|
||||
- [mips*] GIC: Prevent array overrun
|
||||
- [mips*] ptrace: Test correct task's flags in task_user_regset_view()
|
||||
- [mips*] ptrace: Change GP regset to use correct core dump register layout
|
||||
- [mips*] ptrace: Avoid smp_processor_id() when retrieving FPU IR
|
||||
- [mips*] syscall: Fix AUDIT value for O32 processes on MIPS64
|
||||
- [mips*] scall64-o32: Fix indirect syscall detection
|
||||
- [mips,powerpc] bfa: Fix undefined bit shift on big-endian architectures
|
||||
with 32-bit DMA address
|
||||
- ACPI / hotplug: Check scan handlers in acpi_scan_hot_remove()
|
||||
(regression in 3.14)
|
||||
- ACPI: Run fixed event device notifications in process context
|
||||
(regression in 3.15)
|
||||
- ACPI / scan: Allow ACPI drivers to bind to PNP device objects
|
||||
(regression in 3.16)
|
||||
- ACPI / EC: Add support to disallow QR_EC to be issued when SCI_EVT isn't
|
||||
set (regression in 3.14.13, 3.16)
|
||||
- ACPI / EC: Add support to disallow QR_EC to be issued before completing
|
||||
previous QR_EC (regression in 3.14.13, 3.16)
|
||||
- ACPI / scan: not cache _SUN value in struct acpi_device_pnp
|
||||
(regression in 3.14)
|
||||
- ACPI / video: Add a disable_native_backlight quirk
|
||||
- ACPI / video: Disable native_backlight on HP ENVY 15 Notebook PC
|
||||
- ring-buffer: Always reset iterator to reader page
|
||||
- ring-buffer: Up rb_iter_peek() loop count to 3
|
||||
- vfs: get rid of propagate_umount() mistakenly treating slaves as busy.
|
||||
(regression in 3.15)
|
||||
- Bluetooth: Fix tracking local SSP authentication requirement
|
||||
- Bluetooth: Avoid use of session socket after the session gets freed
|
||||
- vfs: __generic_file_write_iter(): fix handling of sync error after DIO
|
||||
(regression in 3.16)
|
||||
- rbd: rework rbd_request_fn() (regression in 3.15)
|
||||
- vfs: fix copy_tree() regression (regression in 3.14)
|
||||
- md/raid1,raid10: always abort recover on write error.
|
||||
- md/raid5: avoid livelock caused by non-aligned writes.
|
||||
(regression in 3.16)
|
||||
- md/raid6: avoid data corruption during recovery of double-degraded RAID6
|
||||
- md/raid10: fix memory leak when reshaping a RAID10.
|
||||
- xfs: ensure verifiers are attached to recovered buffers
|
||||
- xfs: quotacheck leaves dquot buffers without verifiers
|
||||
- xfs: don't dirty buffers beyond EOF
|
||||
- xfs: don't zero partial page cache pages during O_DIRECT writes
|
||||
- xfs: don't zero partial page cache pages during O_DIRECT reads
|
||||
- libceph: set last_piece in ceph_msg_data_pages_cursor_init() correctly
|
||||
- libceph: gracefully handle large reply messages from the mon
|
||||
- libceph: do not hard code max auth ticket len (CVE-2014-6416,
|
||||
CVE-2014-6417, CVE-2014-6418)
|
||||
- CIFS: Fix async reading on reconnects
|
||||
- CIFS: Possible null ptr deref in SMB2_tcon
|
||||
- CIFS: Fix wrong directory attributes after rename
|
||||
- mtd/ftl: fix the double free of the buffers allocated in build_maps()
|
||||
- mtd: nand: omap: Fix 1-bit Hamming code scheme, omap_calculate_ecc()
|
||||
- dm table: propagate QUEUE_FLAG_NO_SG_MERGE (regression in 3.16)
|
||||
- KEYS: Fix use-after-free in assoc_array_gc()
|
||||
- KEYS: Fix termination condition in assoc array garbage collection
|
||||
(CVE-2014-3631)
|
||||
|
||||
[ Ben Hutchings ]
|
||||
* drivers/mfd/rtsx_usb.c: export device table (Closes: #761428)
|
||||
* reiserfs: Apply critical fixes:
|
||||
- fix corruption introduced by balance_leaf refactor (regression in 3.16)
|
||||
(Closes: #761457)
|
||||
- Fix use after free in journal teardown
|
||||
* sfc: Adding PCI ID for Solarflare 7000 series 40G network adapter.
|
||||
* sfc: Add 40G link capability decoding
|
||||
* Bump ABI to 2 (Closes: #761874)
|
||||
|
@ -101,11 +178,6 @@ linux (3.16.2-3) unstable; urgency=medium
|
|||
practice this meant we didn't see them until they appeared in unstable
|
||||
* udeb: Fix typo in dependencies of speakup-modules (fixes FTBFS on
|
||||
mips64el due to interaction with another bug in kernel-wedge)
|
||||
* libceph: Apply critical fixes:
|
||||
- set last_piece in ceph_msg_data_pages_cursor_init() correctly
|
||||
- gracefully handle large reply messages from the mon
|
||||
- add process_one_ticket() helper
|
||||
- do not hard code max auth ticket len
|
||||
|
||||
[ Ian Campbell ]
|
||||
* [armel/orion5x] udeb: Include mvmdio in nic-modules udeb.
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Date: Tue, 12 Aug 2014 13:46:09 -0700
|
||||
Subject: drivers/mfd/rtsx_usb.c: export device table
|
||||
Origin: https://git.kernel.org/linus/1813908986e36119228c158aae1c6a0267c99e77
|
||||
|
||||
The rtsx_usb driver contains the table for the devices it supports but
|
||||
doesn't export it. As a result, no alias is generated and it doesn't
|
||||
get loaded automatically.
|
||||
|
||||
Via https://bugzilla.novell.com/show_bug.cgi?id=890096
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
Reported-by: Marcel Witte <wittemar@googlemail.com>
|
||||
Cc: Roger Tseng <rogerable@realtek.com>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
---
|
||||
drivers/mfd/rtsx_usb.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c
|
||||
index 6352bec..71f387c 100644
|
||||
--- a/drivers/mfd/rtsx_usb.c
|
||||
+++ b/drivers/mfd/rtsx_usb.c
|
||||
@@ -744,6 +744,7 @@ static struct usb_device_id rtsx_usb_usb_ids[] = {
|
||||
{ USB_DEVICE(0x0BDA, 0x0140) },
|
||||
{ }
|
||||
};
|
||||
+MODULE_DEVICE_TABLE(usb, rtsx_usb_usb_ids);
|
||||
|
||||
static struct usb_driver rtsx_usb_driver = {
|
||||
.name = "rtsx_usb",
|
|
@ -1,275 +0,0 @@
|
|||
From: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
Date: Mon, 8 Sep 2014 17:25:34 +0400
|
||||
Subject: libceph: add process_one_ticket() helper
|
||||
Origin: https://git.kernel.org/linus/597cda357716a3cf8d994cb11927af917c8d71fa
|
||||
|
||||
Add a helper for processing individual cephx auth tickets. Needed for
|
||||
the next commit, which deals with allocating ticket buffers. (Most of
|
||||
the diff here is whitespace - view with git diff -b).
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
Reviewed-by: Sage Weil <sage@redhat.com>
|
||||
---
|
||||
net/ceph/auth_x.c | 228 +++++++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 124 insertions(+), 104 deletions(-)
|
||||
|
||||
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
|
||||
index 96238ba..0eb146d 100644
|
||||
--- a/net/ceph/auth_x.c
|
||||
+++ b/net/ceph/auth_x.c
|
||||
@@ -129,17 +129,131 @@ static void remove_ticket_handler(struct ceph_auth_client *ac,
|
||||
kfree(th);
|
||||
}
|
||||
|
||||
+static int process_one_ticket(struct ceph_auth_client *ac,
|
||||
+ struct ceph_crypto_key *secret,
|
||||
+ void **p, void *end,
|
||||
+ void *dbuf, void *ticket_buf)
|
||||
+{
|
||||
+ struct ceph_x_info *xi = ac->private;
|
||||
+ int type;
|
||||
+ u8 tkt_struct_v, blob_struct_v;
|
||||
+ struct ceph_x_ticket_handler *th;
|
||||
+ void *dp, *dend;
|
||||
+ int dlen;
|
||||
+ char is_enc;
|
||||
+ struct timespec validity;
|
||||
+ struct ceph_crypto_key old_key;
|
||||
+ void *tp, *tpend;
|
||||
+ struct ceph_timespec new_validity;
|
||||
+ struct ceph_crypto_key new_session_key;
|
||||
+ struct ceph_buffer *new_ticket_blob;
|
||||
+ unsigned long new_expires, new_renew_after;
|
||||
+ u64 new_secret_id;
|
||||
+ int ret;
|
||||
+
|
||||
+ ceph_decode_need(p, end, sizeof(u32) + 1, bad);
|
||||
+
|
||||
+ type = ceph_decode_32(p);
|
||||
+ dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
|
||||
+
|
||||
+ tkt_struct_v = ceph_decode_8(p);
|
||||
+ if (tkt_struct_v != 1)
|
||||
+ goto bad;
|
||||
+
|
||||
+ th = get_ticket_handler(ac, type);
|
||||
+ if (IS_ERR(th)) {
|
||||
+ ret = PTR_ERR(th);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* blob for me */
|
||||
+ dlen = ceph_x_decrypt(secret, p, end, dbuf,
|
||||
+ TEMP_TICKET_BUF_LEN);
|
||||
+ if (dlen <= 0) {
|
||||
+ ret = dlen;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ dout(" decrypted %d bytes\n", dlen);
|
||||
+ dp = dbuf;
|
||||
+ dend = dp + dlen;
|
||||
+
|
||||
+ tkt_struct_v = ceph_decode_8(&dp);
|
||||
+ if (tkt_struct_v != 1)
|
||||
+ goto bad;
|
||||
+
|
||||
+ memcpy(&old_key, &th->session_key, sizeof(old_key));
|
||||
+ ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+
|
||||
+ ceph_decode_copy(&dp, &new_validity, sizeof(new_validity));
|
||||
+ ceph_decode_timespec(&validity, &new_validity);
|
||||
+ new_expires = get_seconds() + validity.tv_sec;
|
||||
+ new_renew_after = new_expires - (validity.tv_sec / 4);
|
||||
+ dout(" expires=%lu renew_after=%lu\n", new_expires,
|
||||
+ new_renew_after);
|
||||
+
|
||||
+ /* ticket blob for service */
|
||||
+ ceph_decode_8_safe(p, end, is_enc, bad);
|
||||
+ tp = ticket_buf;
|
||||
+ if (is_enc) {
|
||||
+ /* encrypted */
|
||||
+ dout(" encrypted ticket\n");
|
||||
+ dlen = ceph_x_decrypt(&old_key, p, end, ticket_buf,
|
||||
+ TEMP_TICKET_BUF_LEN);
|
||||
+ if (dlen < 0) {
|
||||
+ ret = dlen;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ dlen = ceph_decode_32(&tp);
|
||||
+ } else {
|
||||
+ /* unencrypted */
|
||||
+ ceph_decode_32_safe(p, end, dlen, bad);
|
||||
+ ceph_decode_need(p, end, dlen, bad);
|
||||
+ ceph_decode_copy(p, ticket_buf, dlen);
|
||||
+ }
|
||||
+ tpend = tp + dlen;
|
||||
+ dout(" ticket blob is %d bytes\n", dlen);
|
||||
+ ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
|
||||
+ blob_struct_v = ceph_decode_8(&tp);
|
||||
+ new_secret_id = ceph_decode_64(&tp);
|
||||
+ ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* all is well, update our ticket */
|
||||
+ ceph_crypto_key_destroy(&th->session_key);
|
||||
+ if (th->ticket_blob)
|
||||
+ ceph_buffer_put(th->ticket_blob);
|
||||
+ th->session_key = new_session_key;
|
||||
+ th->ticket_blob = new_ticket_blob;
|
||||
+ th->validity = new_validity;
|
||||
+ th->secret_id = new_secret_id;
|
||||
+ th->expires = new_expires;
|
||||
+ th->renew_after = new_renew_after;
|
||||
+ dout(" got ticket service %d (%s) secret_id %lld len %d\n",
|
||||
+ type, ceph_entity_type_name(type), th->secret_id,
|
||||
+ (int)th->ticket_blob->vec.iov_len);
|
||||
+ xi->have_keys |= th->service;
|
||||
+
|
||||
+out:
|
||||
+ return ret;
|
||||
+
|
||||
+bad:
|
||||
+ ret = -EINVAL;
|
||||
+ goto out;
|
||||
+}
|
||||
+
|
||||
static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||||
struct ceph_crypto_key *secret,
|
||||
void *buf, void *end)
|
||||
{
|
||||
- struct ceph_x_info *xi = ac->private;
|
||||
- int num;
|
||||
void *p = buf;
|
||||
- int ret;
|
||||
char *dbuf;
|
||||
char *ticket_buf;
|
||||
u8 reply_struct_v;
|
||||
+ u32 num;
|
||||
+ int ret;
|
||||
|
||||
dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||||
if (!dbuf)
|
||||
@@ -150,112 +264,18 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||||
if (!ticket_buf)
|
||||
goto out_dbuf;
|
||||
|
||||
- ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
|
||||
- reply_struct_v = ceph_decode_8(&p);
|
||||
+ ceph_decode_8_safe(&p, end, reply_struct_v, bad);
|
||||
if (reply_struct_v != 1)
|
||||
- goto bad;
|
||||
- num = ceph_decode_32(&p);
|
||||
- dout("%d tickets\n", num);
|
||||
- while (num--) {
|
||||
- int type;
|
||||
- u8 tkt_struct_v, blob_struct_v;
|
||||
- struct ceph_x_ticket_handler *th;
|
||||
- void *dp, *dend;
|
||||
- int dlen;
|
||||
- char is_enc;
|
||||
- struct timespec validity;
|
||||
- struct ceph_crypto_key old_key;
|
||||
- void *tp, *tpend;
|
||||
- struct ceph_timespec new_validity;
|
||||
- struct ceph_crypto_key new_session_key;
|
||||
- struct ceph_buffer *new_ticket_blob;
|
||||
- unsigned long new_expires, new_renew_after;
|
||||
- u64 new_secret_id;
|
||||
-
|
||||
- ceph_decode_need(&p, end, sizeof(u32) + 1, bad);
|
||||
-
|
||||
- type = ceph_decode_32(&p);
|
||||
- dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
|
||||
-
|
||||
- tkt_struct_v = ceph_decode_8(&p);
|
||||
- if (tkt_struct_v != 1)
|
||||
- goto bad;
|
||||
-
|
||||
- th = get_ticket_handler(ac, type);
|
||||
- if (IS_ERR(th)) {
|
||||
- ret = PTR_ERR(th);
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- /* blob for me */
|
||||
- dlen = ceph_x_decrypt(secret, &p, end, dbuf,
|
||||
- TEMP_TICKET_BUF_LEN);
|
||||
- if (dlen <= 0) {
|
||||
- ret = dlen;
|
||||
- goto out;
|
||||
- }
|
||||
- dout(" decrypted %d bytes\n", dlen);
|
||||
- dend = dbuf + dlen;
|
||||
- dp = dbuf;
|
||||
-
|
||||
- tkt_struct_v = ceph_decode_8(&dp);
|
||||
- if (tkt_struct_v != 1)
|
||||
- goto bad;
|
||||
+ return -EINVAL;
|
||||
|
||||
- memcpy(&old_key, &th->session_key, sizeof(old_key));
|
||||
- ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
|
||||
- if (ret)
|
||||
- goto out;
|
||||
+ ceph_decode_32_safe(&p, end, num, bad);
|
||||
+ dout("%d tickets\n", num);
|
||||
|
||||
- ceph_decode_copy(&dp, &new_validity, sizeof(new_validity));
|
||||
- ceph_decode_timespec(&validity, &new_validity);
|
||||
- new_expires = get_seconds() + validity.tv_sec;
|
||||
- new_renew_after = new_expires - (validity.tv_sec / 4);
|
||||
- dout(" expires=%lu renew_after=%lu\n", new_expires,
|
||||
- new_renew_after);
|
||||
-
|
||||
- /* ticket blob for service */
|
||||
- ceph_decode_8_safe(&p, end, is_enc, bad);
|
||||
- tp = ticket_buf;
|
||||
- if (is_enc) {
|
||||
- /* encrypted */
|
||||
- dout(" encrypted ticket\n");
|
||||
- dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf,
|
||||
- TEMP_TICKET_BUF_LEN);
|
||||
- if (dlen < 0) {
|
||||
- ret = dlen;
|
||||
- goto out;
|
||||
- }
|
||||
- dlen = ceph_decode_32(&tp);
|
||||
- } else {
|
||||
- /* unencrypted */
|
||||
- ceph_decode_32_safe(&p, end, dlen, bad);
|
||||
- ceph_decode_need(&p, end, dlen, bad);
|
||||
- ceph_decode_copy(&p, ticket_buf, dlen);
|
||||
- }
|
||||
- tpend = tp + dlen;
|
||||
- dout(" ticket blob is %d bytes\n", dlen);
|
||||
- ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
|
||||
- blob_struct_v = ceph_decode_8(&tp);
|
||||
- new_secret_id = ceph_decode_64(&tp);
|
||||
- ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend);
|
||||
+ while (num--) {
|
||||
+ ret = process_one_ticket(ac, secret, &p, end,
|
||||
+ dbuf, ticket_buf);
|
||||
if (ret)
|
||||
goto out;
|
||||
-
|
||||
- /* all is well, update our ticket */
|
||||
- ceph_crypto_key_destroy(&th->session_key);
|
||||
- if (th->ticket_blob)
|
||||
- ceph_buffer_put(th->ticket_blob);
|
||||
- th->session_key = new_session_key;
|
||||
- th->ticket_blob = new_ticket_blob;
|
||||
- th->validity = new_validity;
|
||||
- th->secret_id = new_secret_id;
|
||||
- th->expires = new_expires;
|
||||
- th->renew_after = new_renew_after;
|
||||
- dout(" got ticket service %d (%s) secret_id %lld len %d\n",
|
||||
- type, ceph_entity_type_name(type), th->secret_id,
|
||||
- (int)th->ticket_blob->vec.iov_len);
|
||||
- xi->have_keys |= th->service;
|
||||
}
|
||||
|
||||
ret = 0;
|
|
@ -1,195 +0,0 @@
|
|||
From: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
Date: Tue, 9 Sep 2014 19:39:15 +0400
|
||||
Subject: libceph: do not hard code max auth ticket len
|
||||
Origin: https://git.kernel.org/linus/c27a3e4d667fdcad3db7b104f75659478e0c68d8
|
||||
|
||||
We hard code cephx auth ticket buffer size to 256 bytes. This isn't
|
||||
enough for any moderate setups and, in case tickets themselves are not
|
||||
encrypted, leads to buffer overflows (ceph_x_decrypt() errors out, but
|
||||
ceph_decode_copy() doesn't - it's just a memcpy() wrapper). Since the
|
||||
buffer is allocated dynamically anyway, allocated it a bit later, at
|
||||
the point where we know how much is going to be needed.
|
||||
|
||||
Fixes: http://tracker.ceph.com/issues/8979
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
Reviewed-by: Sage Weil <sage@redhat.com>
|
||||
---
|
||||
net/ceph/auth_x.c | 64 +++++++++++++++++++++++++------------------------------
|
||||
1 file changed, 29 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
|
||||
index 0eb146d..de6662b 100644
|
||||
--- a/net/ceph/auth_x.c
|
||||
+++ b/net/ceph/auth_x.c
|
||||
@@ -13,8 +13,6 @@
|
||||
#include "auth_x.h"
|
||||
#include "auth_x_protocol.h"
|
||||
|
||||
-#define TEMP_TICKET_BUF_LEN 256
|
||||
-
|
||||
static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
|
||||
|
||||
static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
|
||||
@@ -64,7 +62,7 @@ static int ceph_x_encrypt(struct ceph_crypto_key *secret,
|
||||
}
|
||||
|
||||
static int ceph_x_decrypt(struct ceph_crypto_key *secret,
|
||||
- void **p, void *end, void *obuf, size_t olen)
|
||||
+ void **p, void *end, void **obuf, size_t olen)
|
||||
{
|
||||
struct ceph_x_encrypt_header head;
|
||||
size_t head_len = sizeof(head);
|
||||
@@ -75,8 +73,14 @@ static int ceph_x_decrypt(struct ceph_crypto_key *secret,
|
||||
return -EINVAL;
|
||||
|
||||
dout("ceph_x_decrypt len %d\n", len);
|
||||
- ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen,
|
||||
- *p, len);
|
||||
+ if (*obuf == NULL) {
|
||||
+ *obuf = kmalloc(len, GFP_NOFS);
|
||||
+ if (!*obuf)
|
||||
+ return -ENOMEM;
|
||||
+ olen = len;
|
||||
+ }
|
||||
+
|
||||
+ ret = ceph_decrypt2(secret, &head, &head_len, *obuf, &olen, *p, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC)
|
||||
@@ -131,18 +135,19 @@ static void remove_ticket_handler(struct ceph_auth_client *ac,
|
||||
|
||||
static int process_one_ticket(struct ceph_auth_client *ac,
|
||||
struct ceph_crypto_key *secret,
|
||||
- void **p, void *end,
|
||||
- void *dbuf, void *ticket_buf)
|
||||
+ void **p, void *end)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
int type;
|
||||
u8 tkt_struct_v, blob_struct_v;
|
||||
struct ceph_x_ticket_handler *th;
|
||||
+ void *dbuf = NULL;
|
||||
void *dp, *dend;
|
||||
int dlen;
|
||||
char is_enc;
|
||||
struct timespec validity;
|
||||
struct ceph_crypto_key old_key;
|
||||
+ void *ticket_buf = NULL;
|
||||
void *tp, *tpend;
|
||||
struct ceph_timespec new_validity;
|
||||
struct ceph_crypto_key new_session_key;
|
||||
@@ -167,8 +172,7 @@ static int process_one_ticket(struct ceph_auth_client *ac,
|
||||
}
|
||||
|
||||
/* blob for me */
|
||||
- dlen = ceph_x_decrypt(secret, p, end, dbuf,
|
||||
- TEMP_TICKET_BUF_LEN);
|
||||
+ dlen = ceph_x_decrypt(secret, p, end, &dbuf, 0);
|
||||
if (dlen <= 0) {
|
||||
ret = dlen;
|
||||
goto out;
|
||||
@@ -195,20 +199,25 @@ static int process_one_ticket(struct ceph_auth_client *ac,
|
||||
|
||||
/* ticket blob for service */
|
||||
ceph_decode_8_safe(p, end, is_enc, bad);
|
||||
- tp = ticket_buf;
|
||||
if (is_enc) {
|
||||
/* encrypted */
|
||||
dout(" encrypted ticket\n");
|
||||
- dlen = ceph_x_decrypt(&old_key, p, end, ticket_buf,
|
||||
- TEMP_TICKET_BUF_LEN);
|
||||
+ dlen = ceph_x_decrypt(&old_key, p, end, &ticket_buf, 0);
|
||||
if (dlen < 0) {
|
||||
ret = dlen;
|
||||
goto out;
|
||||
}
|
||||
+ tp = ticket_buf;
|
||||
dlen = ceph_decode_32(&tp);
|
||||
} else {
|
||||
/* unencrypted */
|
||||
ceph_decode_32_safe(p, end, dlen, bad);
|
||||
+ ticket_buf = kmalloc(dlen, GFP_NOFS);
|
||||
+ if (!ticket_buf) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ tp = ticket_buf;
|
||||
ceph_decode_need(p, end, dlen, bad);
|
||||
ceph_decode_copy(p, ticket_buf, dlen);
|
||||
}
|
||||
@@ -237,6 +246,8 @@ static int process_one_ticket(struct ceph_auth_client *ac,
|
||||
xi->have_keys |= th->service;
|
||||
|
||||
out:
|
||||
+ kfree(ticket_buf);
|
||||
+ kfree(dbuf);
|
||||
return ret;
|
||||
|
||||
bad:
|
||||
@@ -249,21 +260,10 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||||
void *buf, void *end)
|
||||
{
|
||||
void *p = buf;
|
||||
- char *dbuf;
|
||||
- char *ticket_buf;
|
||||
u8 reply_struct_v;
|
||||
u32 num;
|
||||
int ret;
|
||||
|
||||
- dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||||
- if (!dbuf)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- ret = -ENOMEM;
|
||||
- ticket_buf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||||
- if (!ticket_buf)
|
||||
- goto out_dbuf;
|
||||
-
|
||||
ceph_decode_8_safe(&p, end, reply_struct_v, bad);
|
||||
if (reply_struct_v != 1)
|
||||
return -EINVAL;
|
||||
@@ -272,22 +272,15 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||||
dout("%d tickets\n", num);
|
||||
|
||||
while (num--) {
|
||||
- ret = process_one_ticket(ac, secret, &p, end,
|
||||
- dbuf, ticket_buf);
|
||||
+ ret = process_one_ticket(ac, secret, &p, end);
|
||||
if (ret)
|
||||
- goto out;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
- ret = 0;
|
||||
-out:
|
||||
- kfree(ticket_buf);
|
||||
-out_dbuf:
|
||||
- kfree(dbuf);
|
||||
- return ret;
|
||||
+ return 0;
|
||||
|
||||
bad:
|
||||
- ret = -EINVAL;
|
||||
- goto out;
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
|
||||
@@ -603,13 +596,14 @@ static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
|
||||
struct ceph_x_ticket_handler *th;
|
||||
int ret = 0;
|
||||
struct ceph_x_authorize_reply reply;
|
||||
+ void *preply = &reply;
|
||||
void *p = au->reply_buf;
|
||||
void *end = p + sizeof(au->reply_buf);
|
||||
|
||||
th = get_ticket_handler(ac, au->service);
|
||||
if (IS_ERR(th))
|
||||
return PTR_ERR(th);
|
||||
- ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply));
|
||||
+ ret = ceph_x_decrypt(&th->session_key, &p, end, &preply, sizeof(reply));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != sizeof(reply))
|
|
@ -1,36 +0,0 @@
|
|||
From: Sage Weil <sage@redhat.com>
|
||||
Date: Mon, 4 Aug 2014 07:01:54 -0700
|
||||
Subject: libceph: gracefully handle large reply messages from the mon
|
||||
Origin: https://git.kernel.org/linus/73c3d4812b4c755efeca0140f606f83772a39ce4
|
||||
|
||||
We preallocate a few of the message types we get back from the mon. If we
|
||||
get a larger message than we are expecting, fall back to trying to allocate
|
||||
a new one instead of blindly using the one we have.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Sage Weil <sage@redhat.com>
|
||||
Reviewed-by: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
---
|
||||
net/ceph/mon_client.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
|
||||
index 067d3af..61fcfc3 100644
|
||||
--- a/net/ceph/mon_client.c
|
||||
+++ b/net/ceph/mon_client.c
|
||||
@@ -1181,7 +1181,15 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
|
||||
if (!m) {
|
||||
pr_info("alloc_msg unknown type %d\n", type);
|
||||
*skip = 1;
|
||||
+ } else if (front_len > m->front_alloc_len) {
|
||||
+ pr_warning("mon_alloc_msg front %d > prealloc %d (%u#%llu)\n",
|
||||
+ front_len, m->front_alloc_len,
|
||||
+ (unsigned int)con->peer_name.type,
|
||||
+ le64_to_cpu(con->peer_name.num));
|
||||
+ ceph_msg_put(m);
|
||||
+ m = ceph_msg_new(type, front_len, GFP_NOFS, false);
|
||||
}
|
||||
+
|
||||
return m;
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
Date: Fri, 8 Aug 2014 12:43:39 +0400
|
||||
Subject: libceph: set last_piece in ceph_msg_data_pages_cursor_init()
|
||||
correctly
|
||||
Origin: https://git.kernel.org/linus/5f740d7e1531099b888410e6bab13f68da9b1a4d
|
||||
|
||||
Determining ->last_piece based on the value of ->page_offset + length
|
||||
is incorrect because length here is the length of the entire message.
|
||||
->last_piece set to false even if page array data item length is <=
|
||||
PAGE_SIZE, which results in invalid length passed to
|
||||
ceph_tcp_{send,recv}page() and causes various asserts to fire.
|
||||
|
||||
# cat pages-cursor-init.sh
|
||||
#!/bin/bash
|
||||
rbd create --size 10 --image-format 2 foo
|
||||
FOO_DEV=$(rbd map foo)
|
||||
dd if=/dev/urandom of=$FOO_DEV bs=1M &>/dev/null
|
||||
rbd snap create foo@snap
|
||||
rbd snap protect foo@snap
|
||||
rbd clone foo@snap bar
|
||||
# rbd_resize calls librbd rbd_resize(), size is in bytes
|
||||
./rbd_resize bar $(((4 << 20) + 512))
|
||||
rbd resize --size 10 bar
|
||||
BAR_DEV=$(rbd map bar)
|
||||
# trigger a 512-byte copyup -- 512-byte page array data item
|
||||
dd if=/dev/urandom of=$BAR_DEV bs=1M count=1 seek=5
|
||||
|
||||
The problem exists only in ceph_msg_data_pages_cursor_init(),
|
||||
ceph_msg_data_pages_advance() does the right thing. The size_t cast is
|
||||
unnecessary.
|
||||
|
||||
Cc: stable@vger.kernel.org # 3.10+
|
||||
Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
|
||||
Reviewed-by: Sage Weil <sage@redhat.com>
|
||||
Reviewed-by: Alex Elder <elder@linaro.org>
|
||||
---
|
||||
net/ceph/messenger.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/net/ceph/messenger.c
|
||||
+++ b/net/ceph/messenger.c
|
||||
@@ -900,7 +900,7 @@ static void ceph_msg_data_pages_cursor_i
|
||||
BUG_ON(page_count > (int)USHRT_MAX);
|
||||
cursor->page_count = (unsigned short)page_count;
|
||||
BUG_ON(length > SIZE_MAX - cursor->page_offset);
|
||||
- cursor->last_piece = (size_t)cursor->page_offset + length <= PAGE_SIZE;
|
||||
+ cursor->last_piece = cursor->page_offset + cursor->resid <= PAGE_SIZE;
|
||||
}
|
||||
|
||||
static struct page *
|
|
@ -1,315 +0,0 @@
|
|||
From: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Date: Tue, 29 Jul 2014 15:50:44 -0700
|
||||
Subject: [5/5] mnt: Add tests for unprivileged remount cases that have found
|
||||
to be faulty
|
||||
Origin: https://git.kernel.org/linus/db181ce011e3c033328608299cd6fac06ea50130
|
||||
|
||||
Kenton Varda <kenton@sandstorm.io> discovered that by remounting a
|
||||
read-only bind mount read-only in a user namespace the
|
||||
MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user
|
||||
to the remount a read-only mount read-write.
|
||||
|
||||
Upon review of the code in remount it was discovered that the code allowed
|
||||
nosuid, noexec, and nodev to be cleared. It was also discovered that
|
||||
the code was allowing the per mount atime flags to be changed.
|
||||
|
||||
The first naive patch to fix these issues contained the flaw that using
|
||||
default atime settings when remounting a filesystem could be disallowed.
|
||||
|
||||
To avoid this problems in the future add tests to ensure unprivileged
|
||||
remounts are succeeding and failing at the appropriate times.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
|
||||
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
---
|
||||
tools/testing/selftests/Makefile | 1 +
|
||||
tools/testing/selftests/mount/Makefile | 17 ++
|
||||
.../selftests/mount/unprivileged-remount-test.c | 242 +++++++++++++++++++++
|
||||
3 files changed, 260 insertions(+)
|
||||
create mode 100644 tools/testing/selftests/mount/Makefile
|
||||
create mode 100644 tools/testing/selftests/mount/unprivileged-remount-test.c
|
||||
|
||||
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
|
||||
index e66e710..0a8a9db 100644
|
||||
--- a/tools/testing/selftests/Makefile
|
||||
+++ b/tools/testing/selftests/Makefile
|
||||
@@ -4,6 +4,7 @@ TARGETS += efivarfs
|
||||
TARGETS += kcmp
|
||||
TARGETS += memory-hotplug
|
||||
TARGETS += mqueue
|
||||
+TARGETS += mount
|
||||
TARGETS += net
|
||||
TARGETS += ptrace
|
||||
TARGETS += timers
|
||||
diff --git a/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile
|
||||
new file mode 100644
|
||||
index 0000000..337d853
|
||||
--- /dev/null
|
||||
+++ b/tools/testing/selftests/mount/Makefile
|
||||
@@ -0,0 +1,17 @@
|
||||
+# Makefile for mount selftests.
|
||||
+
|
||||
+all: unprivileged-remount-test
|
||||
+
|
||||
+unprivileged-remount-test: unprivileged-remount-test.c
|
||||
+ gcc -Wall -O2 unprivileged-remount-test.c -o unprivileged-remount-test
|
||||
+
|
||||
+# Allow specific tests to be selected.
|
||||
+test_unprivileged_remount: unprivileged-remount-test
|
||||
+ @if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi
|
||||
+
|
||||
+run_tests: all test_unprivileged_remount
|
||||
+
|
||||
+clean:
|
||||
+ rm -f unprivileged-remount-test
|
||||
+
|
||||
+.PHONY: all test_unprivileged_remount
|
||||
diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c
|
||||
new file mode 100644
|
||||
index 0000000..1b3ff2f
|
||||
--- /dev/null
|
||||
+++ b/tools/testing/selftests/mount/unprivileged-remount-test.c
|
||||
@@ -0,0 +1,242 @@
|
||||
+#define _GNU_SOURCE
|
||||
+#include <sched.h>
|
||||
+#include <stdio.h>
|
||||
+#include <errno.h>
|
||||
+#include <string.h>
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/mount.h>
|
||||
+#include <sys/wait.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <unistd.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <grp.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdarg.h>
|
||||
+
|
||||
+#ifndef CLONE_NEWNS
|
||||
+# define CLONE_NEWNS 0x00020000
|
||||
+#endif
|
||||
+#ifndef CLONE_NEWUTS
|
||||
+# define CLONE_NEWUTS 0x04000000
|
||||
+#endif
|
||||
+#ifndef CLONE_NEWIPC
|
||||
+# define CLONE_NEWIPC 0x08000000
|
||||
+#endif
|
||||
+#ifndef CLONE_NEWNET
|
||||
+# define CLONE_NEWNET 0x40000000
|
||||
+#endif
|
||||
+#ifndef CLONE_NEWUSER
|
||||
+# define CLONE_NEWUSER 0x10000000
|
||||
+#endif
|
||||
+#ifndef CLONE_NEWPID
|
||||
+# define CLONE_NEWPID 0x20000000
|
||||
+#endif
|
||||
+
|
||||
+#ifndef MS_RELATIME
|
||||
+#define MS_RELATIME (1 << 21)
|
||||
+#endif
|
||||
+#ifndef MS_STRICTATIME
|
||||
+#define MS_STRICTATIME (1 << 24)
|
||||
+#endif
|
||||
+
|
||||
+static void die(char *fmt, ...)
|
||||
+{
|
||||
+ va_list ap;
|
||||
+ va_start(ap, fmt);
|
||||
+ vfprintf(stderr, fmt, ap);
|
||||
+ va_end(ap);
|
||||
+ exit(EXIT_FAILURE);
|
||||
+}
|
||||
+
|
||||
+static void write_file(char *filename, char *fmt, ...)
|
||||
+{
|
||||
+ char buf[4096];
|
||||
+ int fd;
|
||||
+ ssize_t written;
|
||||
+ int buf_len;
|
||||
+ va_list ap;
|
||||
+
|
||||
+ va_start(ap, fmt);
|
||||
+ buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
+ va_end(ap);
|
||||
+ if (buf_len < 0) {
|
||||
+ die("vsnprintf failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+ if (buf_len >= sizeof(buf)) {
|
||||
+ die("vsnprintf output truncated\n");
|
||||
+ }
|
||||
+
|
||||
+ fd = open(filename, O_WRONLY);
|
||||
+ if (fd < 0) {
|
||||
+ die("open of %s failed: %s\n",
|
||||
+ filename, strerror(errno));
|
||||
+ }
|
||||
+ written = write(fd, buf, buf_len);
|
||||
+ if (written != buf_len) {
|
||||
+ if (written >= 0) {
|
||||
+ die("short write to %s\n", filename);
|
||||
+ } else {
|
||||
+ die("write to %s failed: %s\n",
|
||||
+ filename, strerror(errno));
|
||||
+ }
|
||||
+ }
|
||||
+ if (close(fd) != 0) {
|
||||
+ die("close of %s failed: %s\n",
|
||||
+ filename, strerror(errno));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void create_and_enter_userns(void)
|
||||
+{
|
||||
+ uid_t uid;
|
||||
+ gid_t gid;
|
||||
+
|
||||
+ uid = getuid();
|
||||
+ gid = getgid();
|
||||
+
|
||||
+ if (unshare(CLONE_NEWUSER) !=0) {
|
||||
+ die("unshare(CLONE_NEWUSER) failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ write_file("/proc/self/uid_map", "0 %d 1", uid);
|
||||
+ write_file("/proc/self/gid_map", "0 %d 1", gid);
|
||||
+
|
||||
+ if (setgroups(0, NULL) != 0) {
|
||||
+ die("setgroups failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+ if (setgid(0) != 0) {
|
||||
+ die ("setgid(0) failed %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+ if (setuid(0) != 0) {
|
||||
+ die("setuid(0) failed %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static
|
||||
+bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags)
|
||||
+{
|
||||
+ pid_t child;
|
||||
+
|
||||
+ child = fork();
|
||||
+ if (child == -1) {
|
||||
+ die("fork failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+ if (child != 0) { /* parent */
|
||||
+ pid_t pid;
|
||||
+ int status;
|
||||
+ pid = waitpid(child, &status, 0);
|
||||
+ if (pid == -1) {
|
||||
+ die("waitpid failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+ if (pid != child) {
|
||||
+ die("waited for %d got %d\n",
|
||||
+ child, pid);
|
||||
+ }
|
||||
+ if (!WIFEXITED(status)) {
|
||||
+ die("child did not terminate cleanly\n");
|
||||
+ }
|
||||
+ return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false;
|
||||
+ }
|
||||
+
|
||||
+ create_and_enter_userns();
|
||||
+ if (unshare(CLONE_NEWNS) != 0) {
|
||||
+ die("unshare(CLONE_NEWNS) failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) {
|
||||
+ die("mount of /tmp failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ create_and_enter_userns();
|
||||
+
|
||||
+ if (unshare(CLONE_NEWNS) != 0) {
|
||||
+ die("unshare(CLONE_NEWNS) failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ if (mount("/tmp", "/tmp", "none",
|
||||
+ MS_REMOUNT | MS_BIND | remount_flags, NULL) != 0) {
|
||||
+ /* system("cat /proc/self/mounts"); */
|
||||
+ die("remount of /tmp failed: %s\n",
|
||||
+ strerror(errno));
|
||||
+ }
|
||||
+
|
||||
+ if (mount("/tmp", "/tmp", "none",
|
||||
+ MS_REMOUNT | MS_BIND | invalid_flags, NULL) == 0) {
|
||||
+ /* system("cat /proc/self/mounts"); */
|
||||
+ die("remount of /tmp with invalid flags "
|
||||
+ "succeeded unexpectedly\n");
|
||||
+ }
|
||||
+ exit(EXIT_SUCCESS);
|
||||
+}
|
||||
+
|
||||
+static bool test_unpriv_remount_simple(int mount_flags)
|
||||
+{
|
||||
+ return test_unpriv_remount(mount_flags, mount_flags, 0);
|
||||
+}
|
||||
+
|
||||
+static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags)
|
||||
+{
|
||||
+ return test_unpriv_remount(mount_flags, mount_flags, invalid_flags);
|
||||
+}
|
||||
+
|
||||
+int main(int argc, char **argv)
|
||||
+{
|
||||
+ if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) {
|
||||
+ die("MS_RDONLY malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_simple(MS_NODEV)) {
|
||||
+ die("MS_NODEV malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) {
|
||||
+ die("MS_NOSUID malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) {
|
||||
+ die("MS_NOEXEC malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV,
|
||||
+ MS_NOATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("MS_RELATIME malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV,
|
||||
+ MS_NOATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("MS_STRICTATIME malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV,
|
||||
+ MS_STRICTATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("MS_RELATIME malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV,
|
||||
+ MS_NOATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("MS_RELATIME malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV,
|
||||
+ MS_NOATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("MS_RELATIME malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV,
|
||||
+ MS_STRICTATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("MS_RELATIME malfunctions\n");
|
||||
+ }
|
||||
+ if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV,
|
||||
+ MS_NOATIME|MS_NODEV))
|
||||
+ {
|
||||
+ die("Default atime malfunctions\n");
|
||||
+ }
|
||||
+ return EXIT_SUCCESS;
|
||||
+}
|
|
@ -1,53 +0,0 @@
|
|||
From: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Date: Mon, 28 Jul 2014 17:36:04 -0700
|
||||
Subject: [4/5] mnt: Change the default remount atime from relatime to the
|
||||
existing value
|
||||
Origin: https://git.kernel.org/linus/ffbc6f0ead47fa5a1dc9642b0331cb75c20a640e
|
||||
|
||||
Since March 2009 the kernel has treated the state that if no
|
||||
MS_..ATIME flags are passed then the kernel defaults to relatime.
|
||||
|
||||
Defaulting to relatime instead of the existing atime state during a
|
||||
remount is silly, and causes problems in practice for people who don't
|
||||
specify any MS_...ATIME flags and to get the default filesystem atime
|
||||
setting. Those users may encounter a permission error because the
|
||||
default atime setting does not work.
|
||||
|
||||
A default that does not work and causes permission problems is
|
||||
ridiculous, so preserve the existing value to have a default
|
||||
atime setting that is always guaranteed to work.
|
||||
|
||||
Using the default atime setting in this way is particularly
|
||||
interesting for applications built to run in restricted userspace
|
||||
environments without /proc mounted, as the existing atime mount
|
||||
options of a filesystem can not be read from /proc/mounts.
|
||||
|
||||
In practice this fixes user space that uses the default atime
|
||||
setting on remount that are broken by the permission checks
|
||||
keeping less privileged users from changing more privileged users
|
||||
atime settings.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
|
||||
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
---
|
||||
fs/namespace.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -2475,6 +2475,14 @@ long do_mount(const char *dev_name, cons
|
||||
if (flags & MS_RDONLY)
|
||||
mnt_flags |= MNT_READONLY;
|
||||
|
||||
+ /* The default atime for remount is preservation */
|
||||
+ if ((flags & MS_REMOUNT) &&
|
||||
+ ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME |
|
||||
+ MS_STRICTATIME)) == 0)) {
|
||||
+ mnt_flags &= ~MNT_ATIME_MASK;
|
||||
+ mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK;
|
||||
+ }
|
||||
+
|
||||
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
|
||||
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
|
||||
MS_STRICTATIME);
|
|
@ -1,125 +0,0 @@
|
|||
From: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Date: Mon, 28 Jul 2014 17:26:07 -0700
|
||||
Subject: [3/5] mnt: Correct permission checks in do_remount
|
||||
Origin: https://git.kernel.org/linus/9566d6742852c527bf5af38af5cbb878dad75705
|
||||
|
||||
While invesgiating the issue where in "mount --bind -oremount,ro ..."
|
||||
would result in later "mount --bind -oremount,rw" succeeding even if
|
||||
the mount started off locked I realized that there are several
|
||||
additional mount flags that should be locked and are not.
|
||||
|
||||
In particular MNT_NOSUID, MNT_NODEV, MNT_NOEXEC, and the atime
|
||||
flags in addition to MNT_READONLY should all be locked. These
|
||||
flags are all per superblock, can all be changed with MS_BIND,
|
||||
and should not be changable if set by a more privileged user.
|
||||
|
||||
The following additions to the current logic are added in this patch.
|
||||
- nosuid may not be clearable by a less privileged user.
|
||||
- nodev may not be clearable by a less privielged user.
|
||||
- noexec may not be clearable by a less privileged user.
|
||||
- atime flags may not be changeable by a less privileged user.
|
||||
|
||||
The logic with atime is that always setting atime on access is a
|
||||
global policy and backup software and auditing software could break if
|
||||
atime bits are not updated (when they are configured to be updated),
|
||||
and serious performance degradation could result (DOS attack) if atime
|
||||
updates happen when they have been explicitly disabled. Therefore an
|
||||
unprivileged user should not be able to mess with the atime bits set
|
||||
by a more privileged user.
|
||||
|
||||
The additional restrictions are implemented with the addition of
|
||||
MNT_LOCK_NOSUID, MNT_LOCK_NODEV, MNT_LOCK_NOEXEC, and MNT_LOCK_ATIME
|
||||
mnt flags.
|
||||
|
||||
Taken together these changes and the fixes for MNT_LOCK_READONLY
|
||||
should make it safe for an unprivileged user to create a user
|
||||
namespace and to call "mount --bind -o remount,... ..." without
|
||||
the danger of mount flags being changed maliciously.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
|
||||
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
---
|
||||
fs/namespace.c | 36 +++++++++++++++++++++++++++++++++---
|
||||
include/linux/mount.h | 5 +++++
|
||||
2 files changed, 38 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -891,8 +891,21 @@ static struct mount *clone_mnt(struct mo
|
||||
|
||||
mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED);
|
||||
/* Don't allow unprivileged users to change mount flags */
|
||||
- if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
|
||||
- mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
|
||||
+ if (flag & CL_UNPRIVILEGED) {
|
||||
+ mnt->mnt.mnt_flags |= MNT_LOCK_ATIME;
|
||||
+
|
||||
+ if (mnt->mnt.mnt_flags & MNT_READONLY)
|
||||
+ mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
|
||||
+
|
||||
+ if (mnt->mnt.mnt_flags & MNT_NODEV)
|
||||
+ mnt->mnt.mnt_flags |= MNT_LOCK_NODEV;
|
||||
+
|
||||
+ if (mnt->mnt.mnt_flags & MNT_NOSUID)
|
||||
+ mnt->mnt.mnt_flags |= MNT_LOCK_NOSUID;
|
||||
+
|
||||
+ if (mnt->mnt.mnt_flags & MNT_NOEXEC)
|
||||
+ mnt->mnt.mnt_flags |= MNT_LOCK_NOEXEC;
|
||||
+ }
|
||||
|
||||
/* Don't allow unprivileged users to reveal what is under a mount */
|
||||
if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire))
|
||||
@@ -1933,6 +1946,23 @@ static int do_remount(struct path *path,
|
||||
!(mnt_flags & MNT_READONLY)) {
|
||||
return -EPERM;
|
||||
}
|
||||
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
|
||||
+ !(mnt_flags & MNT_NODEV)) {
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
|
||||
+ !(mnt_flags & MNT_NOSUID)) {
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
|
||||
+ !(mnt_flags & MNT_NOEXEC)) {
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
|
||||
+ ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+
|
||||
err = security_sb_remount(sb, data);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -2131,7 +2161,7 @@ static int do_new_mount(struct path *pat
|
||||
*/
|
||||
if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) {
|
||||
flags |= MS_NODEV;
|
||||
- mnt_flags |= MNT_NODEV;
|
||||
+ mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
|
||||
}
|
||||
}
|
||||
|
||||
--- a/include/linux/mount.h
|
||||
+++ b/include/linux/mount.h
|
||||
@@ -45,12 +45,17 @@ struct mnt_namespace;
|
||||
#define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \
|
||||
| MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \
|
||||
| MNT_READONLY)
|
||||
+#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME )
|
||||
|
||||
#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
|
||||
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
|
||||
|
||||
#define MNT_INTERNAL 0x4000
|
||||
|
||||
+#define MNT_LOCK_ATIME 0x040000
|
||||
+#define MNT_LOCK_NOEXEC 0x080000
|
||||
+#define MNT_LOCK_NOSUID 0x100000
|
||||
+#define MNT_LOCK_NODEV 0x200000
|
||||
#define MNT_LOCK_READONLY 0x400000
|
||||
#define MNT_LOCKED 0x800000
|
||||
#define MNT_DOOMED 0x1000000
|
|
@ -1,50 +0,0 @@
|
|||
From: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Date: Mon, 28 Jul 2014 17:10:56 -0700
|
||||
Subject: [2/5] mnt: Move the test for MNT_LOCK_READONLY from
|
||||
change_mount_flags into do_remount
|
||||
Origin: https://git.kernel.org/linus/07b645589dcda8b7a5249e096fece2a67556f0f4
|
||||
|
||||
There are no races as locked mount flags are guaranteed to never change.
|
||||
|
||||
Moving the test into do_remount makes it more visible, and ensures all
|
||||
filesystem remounts pass the MNT_LOCK_READONLY permission check. This
|
||||
second case is not an issue today as filesystem remounts are guarded
|
||||
by capable(CAP_DAC_ADMIN) and thus will always fail in less privileged
|
||||
mount namespaces, but it could become an issue in the future.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
|
||||
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
---
|
||||
fs/namespace.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -1898,9 +1898,6 @@ static int change_mount_flags(struct vfs
|
||||
if (readonly_request == __mnt_is_readonly(mnt))
|
||||
return 0;
|
||||
|
||||
- if (mnt->mnt_flags & MNT_LOCK_READONLY)
|
||||
- return -EPERM;
|
||||
-
|
||||
if (readonly_request)
|
||||
error = mnt_make_readonly(real_mount(mnt));
|
||||
else
|
||||
@@ -1926,6 +1923,16 @@ static int do_remount(struct path *path,
|
||||
if (path->dentry != path->mnt->mnt_root)
|
||||
return -EINVAL;
|
||||
|
||||
+ /* Don't allow changing of locked mnt flags.
|
||||
+ *
|
||||
+ * No locks need to be held here while testing the various
|
||||
+ * MNT_LOCK flags because those flags can never be cleared
|
||||
+ * once they are set.
|
||||
+ */
|
||||
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
|
||||
+ !(mnt_flags & MNT_READONLY)) {
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
err = security_sb_remount(sb, data);
|
||||
if (err)
|
||||
return err;
|
|
@ -1,48 +0,0 @@
|
|||
From: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
Date: Mon, 28 Jul 2014 16:26:53 -0700
|
||||
Subject: [1/5] mnt: Only change user settable mount flags in remount
|
||||
Origin: https://git.kernel.org/linus/a6138db815df5ee542d848318e5dae681590fccd
|
||||
|
||||
Kenton Varda <kenton@sandstorm.io> discovered that by remounting a
|
||||
read-only bind mount read-only in a user namespace the
|
||||
MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user
|
||||
to the remount a read-only mount read-write.
|
||||
|
||||
Correct this by replacing the mask of mount flags to preserve
|
||||
with a mask of mount flags that may be changed, and preserve
|
||||
all others. This ensures that any future bugs with this mask and
|
||||
remount will fail in an easy to detect way where new mount flags
|
||||
simply won't change.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
|
||||
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
|
||||
---
|
||||
fs/namespace.c | 2 +-
|
||||
include/linux/mount.h | 4 +++-
|
||||
2 files changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -1939,7 +1939,7 @@ static int do_remount(struct path *path,
|
||||
err = do_remount_sb(sb, flags, data, 0);
|
||||
if (!err) {
|
||||
lock_mount_hash();
|
||||
- mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK;
|
||||
+ mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK;
|
||||
mnt->mnt.mnt_flags = mnt_flags;
|
||||
touch_mnt_namespace(mnt->mnt_ns);
|
||||
unlock_mount_hash();
|
||||
--- a/include/linux/mount.h
|
||||
+++ b/include/linux/mount.h
|
||||
@@ -42,7 +42,9 @@ struct mnt_namespace;
|
||||
* flag, consider how it interacts with shared mounts.
|
||||
*/
|
||||
#define MNT_SHARED_MASK (MNT_UNBINDABLE)
|
||||
-#define MNT_PROPAGATION_MASK (MNT_SHARED | MNT_UNBINDABLE)
|
||||
+#define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \
|
||||
+ | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \
|
||||
+ | MNT_READONLY)
|
||||
|
||||
#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
|
||||
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
|
|
@ -1,86 +0,0 @@
|
|||
From: Jan Kara <jack@suse.cz>
|
||||
Date: Wed, 6 Aug 2014 19:43:56 +0200
|
||||
Subject: [2/2] reiserfs: Fix use after free in journal teardown
|
||||
Origin: https://git.kernel.org/linus/01777836c87081e4f68c4a43c9abe6114805f91e
|
||||
|
||||
If do_journal_release() races with do_journal_end() which requeues
|
||||
delayed works for transaction flushing, we can leave work items for
|
||||
flushing outstanding transactions queued while freeing them. That
|
||||
results in use after free and possible crash in run_timers_softirq().
|
||||
|
||||
Fix the problem by not requeueing works if superblock is being shut down
|
||||
(MS_ACTIVE not set) and using cancel_delayed_work_sync() in
|
||||
do_journal_release().
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Jan Kara <jack@suse.cz>
|
||||
---
|
||||
fs/reiserfs/journal.c | 22 ++++++++++++++++------
|
||||
fs/reiserfs/super.c | 6 +++++-
|
||||
2 files changed, 21 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
|
||||
index e8870de..a88b1b3 100644
|
||||
--- a/fs/reiserfs/journal.c
|
||||
+++ b/fs/reiserfs/journal.c
|
||||
@@ -1947,8 +1947,6 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
|
||||
}
|
||||
}
|
||||
|
||||
- /* wait for all commits to finish */
|
||||
- cancel_delayed_work(&SB_JOURNAL(sb)->j_work);
|
||||
|
||||
/*
|
||||
* We must release the write lock here because
|
||||
@@ -1956,8 +1954,14 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
|
||||
*/
|
||||
reiserfs_write_unlock(sb);
|
||||
|
||||
+ /*
|
||||
+ * Cancel flushing of old commits. Note that neither of these works
|
||||
+ * will be requeued because superblock is being shutdown and doesn't
|
||||
+ * have MS_ACTIVE set.
|
||||
+ */
|
||||
cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work);
|
||||
- flush_workqueue(REISERFS_SB(sb)->commit_wq);
|
||||
+ /* wait for all commits to finish */
|
||||
+ cancel_delayed_work_sync(&SB_JOURNAL(sb)->j_work);
|
||||
|
||||
free_journal_ram(sb);
|
||||
|
||||
@@ -4292,9 +4296,15 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, int flags)
|
||||
if (flush) {
|
||||
flush_commit_list(sb, jl, 1);
|
||||
flush_journal_list(sb, jl, 1);
|
||||
- } else if (!(jl->j_state & LIST_COMMIT_PENDING))
|
||||
- queue_delayed_work(REISERFS_SB(sb)->commit_wq,
|
||||
- &journal->j_work, HZ / 10);
|
||||
+ } else if (!(jl->j_state & LIST_COMMIT_PENDING)) {
|
||||
+ /*
|
||||
+ * Avoid queueing work when sb is being shut down. Transaction
|
||||
+ * will be flushed on journal shutdown.
|
||||
+ */
|
||||
+ if (sb->s_flags & MS_ACTIVE)
|
||||
+ queue_delayed_work(REISERFS_SB(sb)->commit_wq,
|
||||
+ &journal->j_work, HZ / 10);
|
||||
+ }
|
||||
|
||||
/*
|
||||
* if the next transaction has any chance of wrapping, flush
|
||||
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
|
||||
index a392cef..5fd8f57 100644
|
||||
--- a/fs/reiserfs/super.c
|
||||
+++ b/fs/reiserfs/super.c
|
||||
@@ -100,7 +100,11 @@ void reiserfs_schedule_old_flush(struct super_block *s)
|
||||
struct reiserfs_sb_info *sbi = REISERFS_SB(s);
|
||||
unsigned long delay;
|
||||
|
||||
- if (s->s_flags & MS_RDONLY)
|
||||
+ /*
|
||||
+ * Avoid scheduling flush when sb is being shut down. It can race
|
||||
+ * with journal shutdown and free still queued delayed work.
|
||||
+ */
|
||||
+ if (s->s_flags & MS_RDONLY || !(s->s_flags & MS_ACTIVE))
|
||||
return;
|
||||
|
||||
spin_lock(&sbi->old_work_lock);
|
|
@ -1,383 +0,0 @@
|
|||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Date: Mon, 4 Aug 2014 19:51:47 -0400
|
||||
Subject: [1/2] reiserfs: fix corruption introduced by balance_leaf refactor
|
||||
Origin: https://git.kernel.org/linus/27d0e5bc85f3341b9ba66f0c23627cf9d7538c9d
|
||||
|
||||
Commits f1f007c308e (reiserfs: balance_leaf refactor, pull out
|
||||
balance_leaf_insert_left) and cf22df182bf (reiserfs: balance_leaf
|
||||
refactor, pull out balance_leaf_paste_left) missed that the `body'
|
||||
pointer was getting repositioned. Subsequent users of the pointer
|
||||
would expect it to be repositioned, and as a result, parts of the
|
||||
tree would get overwritten. The most common observed corruption
|
||||
is indirect block pointers being overwritten.
|
||||
|
||||
Since the body value isn't actually used anymore in the called routines,
|
||||
we can pass back the offset it should be shifted. We constify the body
|
||||
and ih pointers in the balance_leaf as a mostly-free preventative measure.
|
||||
|
||||
Cc: <stable@vger.kernel.org> # 3.16
|
||||
Reported-and-tested-by: Jeff Chua <jeff.chua.linux@gmail.com>
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
Signed-off-by: Jan Kara <jack@suse.cz>
|
||||
---
|
||||
fs/reiserfs/do_balan.c | 111 ++++++++++++++++++++++++++++---------------------
|
||||
fs/reiserfs/lbalance.c | 5 ++-
|
||||
fs/reiserfs/reiserfs.h | 9 ++--
|
||||
3 files changed, 71 insertions(+), 54 deletions(-)
|
||||
|
||||
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
|
||||
index 54fdf19..4d5e529 100644
|
||||
--- a/fs/reiserfs/do_balan.c
|
||||
+++ b/fs/reiserfs/do_balan.c
|
||||
@@ -286,12 +286,14 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void balance_leaf_insert_left(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+static unsigned int balance_leaf_insert_left(struct tree_balance *tb,
|
||||
+ struct item_head *const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
int ret;
|
||||
struct buffer_info bi;
|
||||
int n = B_NR_ITEMS(tb->L[0]);
|
||||
+ unsigned body_shift_bytes = 0;
|
||||
|
||||
if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
|
||||
/* part of new item falls into L[0] */
|
||||
@@ -329,7 +331,7 @@ static void balance_leaf_insert_left(struct tree_balance *tb,
|
||||
|
||||
put_ih_item_len(ih, new_item_len);
|
||||
if (tb->lbytes > tb->zeroes_num) {
|
||||
- body += (tb->lbytes - tb->zeroes_num);
|
||||
+ body_shift_bytes = tb->lbytes - tb->zeroes_num;
|
||||
tb->zeroes_num = 0;
|
||||
} else
|
||||
tb->zeroes_num -= tb->lbytes;
|
||||
@@ -349,11 +351,12 @@ static void balance_leaf_insert_left(struct tree_balance *tb,
|
||||
tb->insert_size[0] = 0;
|
||||
tb->zeroes_num = 0;
|
||||
}
|
||||
+ return body_shift_bytes;
|
||||
}
|
||||
|
||||
static void balance_leaf_paste_left_shift_dirent(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
int n = B_NR_ITEMS(tb->L[0]);
|
||||
struct buffer_info bi;
|
||||
@@ -413,17 +416,18 @@ static void balance_leaf_paste_left_shift_dirent(struct tree_balance *tb,
|
||||
tb->pos_in_item -= tb->lbytes;
|
||||
}
|
||||
|
||||
-static void balance_leaf_paste_left_shift(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body)
|
||||
+static unsigned int balance_leaf_paste_left_shift(struct tree_balance *tb,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
int n = B_NR_ITEMS(tb->L[0]);
|
||||
struct buffer_info bi;
|
||||
+ int body_shift_bytes = 0;
|
||||
|
||||
if (is_direntry_le_ih(item_head(tbS0, tb->item_pos))) {
|
||||
balance_leaf_paste_left_shift_dirent(tb, ih, body);
|
||||
- return;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
RFALSE(tb->lbytes <= 0,
|
||||
@@ -497,7 +501,7 @@ static void balance_leaf_paste_left_shift(struct tree_balance *tb,
|
||||
* insert_size[0]
|
||||
*/
|
||||
if (l_n > tb->zeroes_num) {
|
||||
- body += (l_n - tb->zeroes_num);
|
||||
+ body_shift_bytes = l_n - tb->zeroes_num;
|
||||
tb->zeroes_num = 0;
|
||||
} else
|
||||
tb->zeroes_num -= l_n;
|
||||
@@ -526,13 +530,14 @@ static void balance_leaf_paste_left_shift(struct tree_balance *tb,
|
||||
*/
|
||||
leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
|
||||
}
|
||||
+ return body_shift_bytes;
|
||||
}
|
||||
|
||||
|
||||
/* appended item will be in L[0] in whole */
|
||||
static void balance_leaf_paste_left_whole(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
int n = B_NR_ITEMS(tb->L[0]);
|
||||
@@ -584,39 +589,44 @@ static void balance_leaf_paste_left_whole(struct tree_balance *tb,
|
||||
tb->zeroes_num = 0;
|
||||
}
|
||||
|
||||
-static void balance_leaf_paste_left(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+static unsigned int balance_leaf_paste_left(struct tree_balance *tb,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
/* we must shift the part of the appended item */
|
||||
if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1)
|
||||
- balance_leaf_paste_left_shift(tb, ih, body);
|
||||
+ return balance_leaf_paste_left_shift(tb, ih, body);
|
||||
else
|
||||
balance_leaf_paste_left_whole(tb, ih, body);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Shift lnum[0] items from S[0] to the left neighbor L[0] */
|
||||
-static void balance_leaf_left(struct tree_balance *tb, struct item_head *ih,
|
||||
- const char *body, int flag)
|
||||
+static unsigned int balance_leaf_left(struct tree_balance *tb,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body, int flag)
|
||||
{
|
||||
if (tb->lnum[0] <= 0)
|
||||
- return;
|
||||
+ return 0;
|
||||
|
||||
/* new item or it part falls to L[0], shift it too */
|
||||
if (tb->item_pos < tb->lnum[0]) {
|
||||
BUG_ON(flag != M_INSERT && flag != M_PASTE);
|
||||
|
||||
if (flag == M_INSERT)
|
||||
- balance_leaf_insert_left(tb, ih, body);
|
||||
+ return balance_leaf_insert_left(tb, ih, body);
|
||||
else /* M_PASTE */
|
||||
- balance_leaf_paste_left(tb, ih, body);
|
||||
+ return balance_leaf_paste_left(tb, ih, body);
|
||||
} else
|
||||
/* new item doesn't fall into L[0] */
|
||||
leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
|
||||
static void balance_leaf_insert_right(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
@@ -704,7 +714,8 @@ static void balance_leaf_insert_right(struct tree_balance *tb,
|
||||
|
||||
|
||||
static void balance_leaf_paste_right_shift_dirent(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
struct buffer_info bi;
|
||||
@@ -754,7 +765,8 @@ static void balance_leaf_paste_right_shift_dirent(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_paste_right_shift(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
int n_shift, n_rem, r_zeroes_number, version;
|
||||
@@ -831,7 +843,8 @@ static void balance_leaf_paste_right_shift(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_paste_right_whole(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
int n = B_NR_ITEMS(tbS0);
|
||||
@@ -874,7 +887,8 @@ static void balance_leaf_paste_right_whole(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_paste_right(struct tree_balance *tb,
|
||||
- struct item_head *ih, const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
int n = B_NR_ITEMS(tbS0);
|
||||
@@ -896,8 +910,9 @@ static void balance_leaf_paste_right(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
/* shift rnum[0] items from S[0] to the right neighbor R[0] */
|
||||
-static void balance_leaf_right(struct tree_balance *tb, struct item_head *ih,
|
||||
- const char *body, int flag)
|
||||
+static void balance_leaf_right(struct tree_balance *tb,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body, int flag)
|
||||
{
|
||||
if (tb->rnum[0] <= 0)
|
||||
return;
|
||||
@@ -911,8 +926,8 @@ static void balance_leaf_right(struct tree_balance *tb, struct item_head *ih,
|
||||
}
|
||||
|
||||
static void balance_leaf_new_nodes_insert(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body,
|
||||
struct item_head *insert_key,
|
||||
struct buffer_head **insert_ptr,
|
||||
int i)
|
||||
@@ -1003,8 +1018,8 @@ static void balance_leaf_new_nodes_insert(struct tree_balance *tb,
|
||||
|
||||
/* we append to directory item */
|
||||
static void balance_leaf_new_nodes_paste_dirent(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body,
|
||||
struct item_head *insert_key,
|
||||
struct buffer_head **insert_ptr,
|
||||
int i)
|
||||
@@ -1058,8 +1073,8 @@ static void balance_leaf_new_nodes_paste_dirent(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_new_nodes_paste_shift(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body,
|
||||
struct item_head *insert_key,
|
||||
struct buffer_head **insert_ptr,
|
||||
int i)
|
||||
@@ -1131,8 +1146,8 @@ static void balance_leaf_new_nodes_paste_shift(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_new_nodes_paste_whole(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body,
|
||||
struct item_head *insert_key,
|
||||
struct buffer_head **insert_ptr,
|
||||
int i)
|
||||
@@ -1184,8 +1199,8 @@ static void balance_leaf_new_nodes_paste_whole(struct tree_balance *tb,
|
||||
|
||||
}
|
||||
static void balance_leaf_new_nodes_paste(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body,
|
||||
struct item_head *insert_key,
|
||||
struct buffer_head **insert_ptr,
|
||||
int i)
|
||||
@@ -1214,8 +1229,8 @@ static void balance_leaf_new_nodes_paste(struct tree_balance *tb,
|
||||
|
||||
/* Fill new nodes that appear in place of S[0] */
|
||||
static void balance_leaf_new_nodes(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body,
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body,
|
||||
struct item_head *insert_key,
|
||||
struct buffer_head **insert_ptr,
|
||||
int flag)
|
||||
@@ -1254,8 +1269,8 @@ static void balance_leaf_new_nodes(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_finish_node_insert(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
struct buffer_info bi;
|
||||
@@ -1271,8 +1286,8 @@ static void balance_leaf_finish_node_insert(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_finish_node_paste_dirent(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
struct item_head *pasted = item_head(tbS0, tb->item_pos);
|
||||
@@ -1305,8 +1320,8 @@ static void balance_leaf_finish_node_paste_dirent(struct tree_balance *tb,
|
||||
}
|
||||
|
||||
static void balance_leaf_finish_node_paste(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body)
|
||||
{
|
||||
struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
|
||||
struct buffer_info bi;
|
||||
@@ -1349,8 +1364,8 @@ static void balance_leaf_finish_node_paste(struct tree_balance *tb,
|
||||
* of the affected item which remains in S
|
||||
*/
|
||||
static void balance_leaf_finish_node(struct tree_balance *tb,
|
||||
- struct item_head *ih,
|
||||
- const char *body, int flag)
|
||||
+ struct item_head * const ih,
|
||||
+ const char * const body, int flag)
|
||||
{
|
||||
/* if we must insert or append into buffer S[0] */
|
||||
if (0 <= tb->item_pos && tb->item_pos < tb->s0num) {
|
||||
@@ -1402,7 +1417,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,
|
||||
&& is_indirect_le_ih(item_head(tbS0, tb->item_pos)))
|
||||
tb->pos_in_item *= UNFM_P_SIZE;
|
||||
|
||||
- balance_leaf_left(tb, ih, body, flag);
|
||||
+ body += balance_leaf_left(tb, ih, body, flag);
|
||||
|
||||
/* tb->lnum[0] > 0 */
|
||||
/* Calculate new item position */
|
||||
diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c
|
||||
index d6744c8..3a74d15 100644
|
||||
--- a/fs/reiserfs/lbalance.c
|
||||
+++ b/fs/reiserfs/lbalance.c
|
||||
@@ -899,8 +899,9 @@ void leaf_delete_items(struct buffer_info *cur_bi, int last_first,
|
||||
|
||||
/* insert item into the leaf node in position before */
|
||||
void leaf_insert_into_buf(struct buffer_info *bi, int before,
|
||||
- struct item_head *inserted_item_ih,
|
||||
- const char *inserted_item_body, int zeros_number)
|
||||
+ struct item_head * const inserted_item_ih,
|
||||
+ const char * const inserted_item_body,
|
||||
+ int zeros_number)
|
||||
{
|
||||
struct buffer_head *bh = bi->bi_bh;
|
||||
int nr, free_space;
|
||||
diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h
|
||||
index bf53888..735c2c2 100644
|
||||
--- a/fs/reiserfs/reiserfs.h
|
||||
+++ b/fs/reiserfs/reiserfs.h
|
||||
@@ -3216,11 +3216,12 @@ int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes);
|
||||
void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
|
||||
int del_num, int del_bytes);
|
||||
void leaf_insert_into_buf(struct buffer_info *bi, int before,
|
||||
- struct item_head *inserted_item_ih,
|
||||
- const char *inserted_item_body, int zeros_number);
|
||||
-void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
|
||||
- int pos_in_item, int paste_size, const char *body,
|
||||
+ struct item_head * const inserted_item_ih,
|
||||
+ const char * const inserted_item_body,
|
||||
int zeros_number);
|
||||
+void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
|
||||
+ int pos_in_item, int paste_size,
|
||||
+ const char * const body, int zeros_number);
|
||||
void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
|
||||
int pos_in_item, int cut_size);
|
||||
void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
|
|
@ -1,61 +0,0 @@
|
|||
From: Alex Smith <alex.smith@imgtec.com>
|
||||
Date: Wed, 23 Jul 2014 14:40:11 +0100
|
||||
Subject: MIPS: O32/32-bit: Fix bug which can cause incorrect system
|
||||
call restarts
|
||||
Origin: https://git.kernel.org/linus/e90e6fddc57055c4c6b57f92787fea1c065d440b
|
||||
|
||||
On 32-bit/O32, pt_regs has a padding area at the beginning into which the
|
||||
syscall arguments passed via the user stack are copied. 4 arguments
|
||||
totalling 16 bytes are copied to offset 16 bytes into this area, however
|
||||
the area is only 24 bytes long. This means the last 2 arguments overwrite
|
||||
pt_regs->regs[{0,1}].
|
||||
|
||||
If a syscall function returns an error, handle_sys stores the original
|
||||
syscall number in pt_regs->regs[0] for syscall restart. signal.c checks
|
||||
whether regs[0] is non-zero, if it is it will check whether the syscall
|
||||
return value is one of the ERESTART* codes to see if it must be
|
||||
restarted.
|
||||
|
||||
Should a syscall be made that results in a non-zero value being copied
|
||||
off the user stack into regs[0], and then returns a positive (non-error)
|
||||
value that matches one of the ERESTART* error codes, this can be mistaken
|
||||
for requiring a syscall restart.
|
||||
|
||||
While the possibility for this to occur has always existed, it is made
|
||||
much more likely to occur by commit 46e12c07b3b9 ("MIPS: O32 / 32-bit:
|
||||
Always copy 4 stack arguments."), since now every syscall will copy 4
|
||||
arguments and overwrite regs[0], rather than just those with 7 or 8
|
||||
arguments.
|
||||
|
||||
Since that commit, booting Debian under a 32-bit MIPS kernel almost
|
||||
always results in a hang early in boot, due to a wait4 syscall returning
|
||||
a PID that matches one of the ERESTART* codes, which then causes an
|
||||
incorrect restart of the syscall.
|
||||
|
||||
The problem is fixed by increasing the size of the padding area so that
|
||||
arguments copied off the stack will not overwrite pt_regs->regs[{0,1}].
|
||||
|
||||
Signed-off-by: Alex Smith <alex.smith@imgtec.com>
|
||||
Cc: <stable@vger.kernel.org> # v3.13+
|
||||
Tested-by: Aurelien Jarno <aurelien@aurel32.net>
|
||||
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
|
||||
---
|
||||
arch/mips/include/asm/ptrace.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
|
||||
index 7e6e682..c301fa9 100644
|
||||
--- a/arch/mips/include/asm/ptrace.h
|
||||
+++ b/arch/mips/include/asm/ptrace.h
|
||||
@@ -23,7 +23,7 @@
|
||||
struct pt_regs {
|
||||
#ifdef CONFIG_32BIT
|
||||
/* Pad bytes for argument save space on the stack. */
|
||||
- unsigned long pad0[6];
|
||||
+ unsigned long pad0[8];
|
||||
#endif
|
||||
|
||||
/* Saved main processor registers. */
|
||||
--
|
||||
1.7.10.4
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
From: Aaro Koskinen <aaro.koskinen@nsn.com>
|
||||
Date: Tue, 22 Jul 2014 14:51:08 +0300
|
||||
Subject: MIPS: OCTEON: make get_system_type() thread-safe
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=726d129dfdc9622197a8c3f5947ce09c1a4c935e
|
||||
|
||||
get_system_type() is not thread-safe on OCTEON. It uses static data,
|
||||
also more dangerous issue is that it's calling cvmx_fuse_read_byte()
|
||||
every time without any synchronization. Currently it's possible to get
|
||||
processes stuck looping forever in kernel simply by launching multiple
|
||||
readers of /proc/cpuinfo:
|
||||
|
||||
(while true; do cat /proc/cpuinfo > /dev/null; done) &
|
||||
(while true; do cat /proc/cpuinfo > /dev/null; done) &
|
||||
...
|
||||
|
||||
Fix by initializing the system type string only once during the early
|
||||
boot.
|
||||
|
||||
Signed-off-by: Aaro Koskinen <aaro.koskinen@nsn.com>
|
||||
Cc: stable@vger.kernel.org
|
||||
Reviewed-by: Markos Chandras <markos.chandras@imgtec.com>
|
||||
Patchwork: http://patchwork.linux-mips.org/patch/7437/
|
||||
Signed-off-by: James Hogan <james.hogan@imgtec.com>
|
||||
---
|
||||
arch/mips/cavium-octeon/setup.c | 18 +++++++++++++-----
|
||||
1 file changed, 13 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
|
||||
index 008e9c8..c9d9c62 100644
|
||||
--- a/arch/mips/cavium-octeon/setup.c
|
||||
+++ b/arch/mips/cavium-octeon/setup.c
|
||||
@@ -458,6 +458,18 @@ static void octeon_halt(void)
|
||||
octeon_kill_core(NULL);
|
||||
}
|
||||
|
||||
+static char __read_mostly octeon_system_type[80];
|
||||
+
|
||||
+static int __init init_octeon_system_type(void)
|
||||
+{
|
||||
+ snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)",
|
||||
+ cvmx_board_type_to_string(octeon_bootinfo->board_type),
|
||||
+ octeon_model_get_string(read_c0_prid()));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+early_initcall(init_octeon_system_type);
|
||||
+
|
||||
/**
|
||||
* Return a string representing the system type
|
||||
*
|
||||
@@ -465,11 +477,7 @@ static void octeon_halt(void)
|
||||
*/
|
||||
const char *octeon_board_type_string(void)
|
||||
{
|
||||
- static char name[80];
|
||||
- sprintf(name, "%s (%s)",
|
||||
- cvmx_board_type_to_string(octeon_bootinfo->board_type),
|
||||
- octeon_model_get_string(read_c0_prid()));
|
||||
- return name;
|
||||
+ return octeon_system_type;
|
||||
}
|
||||
|
||||
const char *get_system_type(void)
|
||||
--
|
||||
1.7.10.4
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
From: Huacai Chen <chenhc@lemote.com>
|
||||
Date: Wed, 16 Jul 2014 09:19:16 +0800
|
||||
Subject: MIPS: Remove BUG_ON(!is_fpu_owner()) in do_ade()
|
||||
Origin: https://git.kernel.org/linus/2e5767a27337812f6850b3fa362419e2f085e5c3
|
||||
|
||||
In do_ade(), is_fpu_owner() isn't preempt-safe. For example, when an
|
||||
unaligned ldc1 is executed, do_cpu() is called and then FPU will be
|
||||
enabled (and TIF_USEDFPU will be set for the current process). Then,
|
||||
do_ade() is called because the access is unaligned. If the current
|
||||
process is preempted at this time, TIF_USEDFPU will be cleard. So when
|
||||
the process is scheduled again, BUG_ON(!is_fpu_owner()) is triggered.
|
||||
|
||||
This small program can trigger this BUG in a preemptible kernel:
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
double u64[2];
|
||||
|
||||
while (1) {
|
||||
asm volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"ldc1 $f3, 4(%0) \n\t"
|
||||
".set pop \n\t"
|
||||
::"r"(u64):
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
V2: Remove the BUG_ON() unconditionally due to Paul's suggestion.
|
||||
|
||||
Signed-off-by: Huacai Chen <chenhc@lemote.com>
|
||||
Signed-off-by: Jie Chen <chenj@lemote.com>
|
||||
Signed-off-by: Rui Wang <wangr@lemote.com>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Cc: John Crispin <john@phrozen.org>
|
||||
Cc: Steven J. Hill <Steven.Hill@imgtec.com>
|
||||
Cc: linux-mips@linux-mips.org
|
||||
Cc: Fuxin Zhang <zhangfx@lemote.com>
|
||||
Cc: Zhangjin Wu <wuzhangjin@gmail.com>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
||||
---
|
||||
arch/mips/kernel/unaligned.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
|
||||
index 2b35172..e11906d 100644
|
||||
--- a/arch/mips/kernel/unaligned.c
|
||||
+++ b/arch/mips/kernel/unaligned.c
|
||||
@@ -690,7 +690,6 @@ static void emulate_load_store_insn(struct pt_regs *regs,
|
||||
case sdc1_op:
|
||||
die_if_kernel("Unaligned FP access in kernel code", regs);
|
||||
BUG_ON(!used_math());
|
||||
- BUG_ON(!is_fpu_owner());
|
||||
|
||||
lose_fpu(1); /* Save FPU state for the emulator. */
|
||||
res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
|
||||
--
|
||||
1.7.10.4
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From: Paul Burton <paul.burton@imgtec.com>
|
||||
Date: Tue, 22 Jul 2014 14:21:21 +0100
|
||||
Subject: MIPS: prevent user from setting FCSR cause bits
|
||||
Origin: https://git.kernel.org/linus/b1442d39fac2fcfbe6a4814979020e993ca59c9e
|
||||
|
||||
If one or more matching FCSR cause & enable bits are set in saved thread
|
||||
context then when that context is restored the kernel will take an FP
|
||||
exception. This is of course undesirable and considered an oops, leading
|
||||
to the kernel writing a backtrace to the console and potentially
|
||||
rebooting depending upon the configuration. Thus the kernel avoids this
|
||||
situation by clearing the cause bits of the FCSR register when handling
|
||||
FP exceptions and after emulating FP instructions.
|
||||
|
||||
However the kernel does not prevent userland from setting arbitrary FCSR
|
||||
cause & enable bits via ptrace, using either the PTRACE_POKEUSR or
|
||||
PTRACE_SETFPREGS requests. This means userland can trivially cause the
|
||||
kernel to oops on any system with an FPU. Prevent this from happening
|
||||
by clearing the cause bits when writing to the saved FCSR context via
|
||||
ptrace.
|
||||
|
||||
This problem appears to exist at least back to the beginning of the git
|
||||
era in the PTRACE_POKEUSR case.
|
||||
|
||||
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
|
||||
Cc: stable@vger.kernel.org
|
||||
Patchwork: http://patchwork.linux-mips.org/patch/7438/
|
||||
Signed-off-by: James Hogan <james.hogan@imgtec.com>
|
||||
---
|
||||
arch/mips/kernel/ptrace.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/mips/kernel/ptrace.c
|
||||
+++ b/arch/mips/kernel/ptrace.c
|
||||
@@ -151,6 +151,7 @@ int ptrace_setfpregs(struct task_struct
|
||||
}
|
||||
|
||||
__get_user(child->thread.fpu.fcr31, data + 64);
|
||||
+ child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
|
||||
|
||||
/* FIR may not be written. */
|
||||
|
||||
@@ -565,7 +566,7 @@ long arch_ptrace(struct task_struct *chi
|
||||
break;
|
||||
#endif
|
||||
case FPC_CSR:
|
||||
- child->thread.fpu.fcr31 = data;
|
||||
+ child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X;
|
||||
break;
|
||||
case DSP_BASE ... DSP_BASE + 5: {
|
||||
dspreg_t *dregs;
|
|
@ -1,35 +0,0 @@
|
|||
From: Huacai Chen <chenhc@lemote.com>
|
||||
Date: Tue, 29 Jul 2014 14:54:40 +0800
|
||||
Subject: MIPS: tlbex: fix a missing statement for HUGETLB
|
||||
Origin: https://git.kernel.org/linus/8393c524a25609a30129e4a8975cf3b91f6c16a5
|
||||
|
||||
In commit 2c8c53e28f1 (MIPS: Optimize TLB handlers for Octeon CPUs)
|
||||
build_r4000_tlb_refill_handler() is modified. But it doesn't compatible
|
||||
with the original code in HUGETLB case. Because there is a copy & paste
|
||||
error and one line of code is missing. It is very easy to produce a bug
|
||||
with LTP's hugemmap05 test.
|
||||
|
||||
Signed-off-by: Huacai Chen <chenhc@lemote.com>
|
||||
Signed-off-by: Binbin Zhou <zhoubb@lemote.com>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Tested-by: Aurelien Jarno <aurelien@aurel32.net>
|
||||
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
|
||||
---
|
||||
arch/mips/mm/tlbex.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
|
||||
index e80e10b..343fe0f 100644
|
||||
--- a/arch/mips/mm/tlbex.c
|
||||
+++ b/arch/mips/mm/tlbex.c
|
||||
@@ -1299,6 +1299,7 @@ static void build_r4000_tlb_refill_handler(void)
|
||||
}
|
||||
#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
|
||||
uasm_l_tlb_huge_update(&l, p);
|
||||
+ UASM_i_LW(&p, K0, 0, K1);
|
||||
build_huge_update_entries(&p, htlb_info.huge_pte, K1);
|
||||
build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random,
|
||||
htlb_info.restore_scratch);
|
||||
--
|
||||
1.7.10.4
|
||||
|
|
@ -52,11 +52,6 @@ bugfix/mips/disable-advansys.patch
|
|||
bugfix/arm/ixp4xx_iobe.patch
|
||||
bugfix/m68k/ethernat-kconfig.patch
|
||||
bugfix/mips/MIPS-ZBOOT-add-missing-linux-string.h-include.patch
|
||||
bugfix/mips/MIPS-OCTEON-make-get_system_type-thread-safe.patch
|
||||
bugfix/mips/MIPS-O32-32-bit-Fix-bug-which-can-cause-incorrect-sy.patch
|
||||
bugfix/mips/MIPS-tlbex-fix-a-missing-statement-for-HUGETLB.patch
|
||||
bugfix/mips/MIPS-prevent-user-from-setting-FCSR-cause-bits.patch
|
||||
bugfix/mips/MIPS-Remove-BUG_ON-is_fpu_owner-in-do_ade.patch
|
||||
bugfix/x86/x86-reject-x32-executables-if-x32-abi-not-supported.patch
|
||||
bugfix/s390/s390-3215-fix-hanging-console-issue.patch
|
||||
bugfix/arm64/arm64-crypto-fix-makefile-rule-for-aes-glue-.o.patch
|
||||
|
@ -110,21 +105,9 @@ bugfix/all/misc-bmp085-Enable-building-as-a-module.patch
|
|||
bugfix/all/kbuild-use-nostdinc-in-compile-tests.patch
|
||||
bugfix/all/disable-some-marvell-phys.patch
|
||||
bugfix/all/aio-fix-reqs_available-handling.patch
|
||||
bugfix/all/mnt-Only-change-user-settable-mount-flags-in-remount.patch
|
||||
bugfix/all/mnt-Move-the-test-for-MNT_LOCK_READONLY-from-change_.patch
|
||||
bugfix/all/mnt-Correct-permission-checks-in-do_remount.patch
|
||||
bugfix/all/mnt-Change-the-default-remount-atime-from-relatime-t.patch
|
||||
bugfix/all/mnt-Add-tests-for-unprivileged-remount-cases-that-ha.patch
|
||||
debian/i2o-disable-i2o_ext_adaptec-on-64bit.patch
|
||||
bugfix/all/aic94xx-remove-broken-fallback-for-missing-ctrl-a.patch
|
||||
bugfix/all/builddeb-put-the-dbg-files-into-the-correct-director.patch
|
||||
bugfix/all/libceph-set-last_piece-in-ceph_msg_data_pages_cursor.patch
|
||||
bugfix/all/libceph-gracefully-handle-large-reply-messages-from-.patch
|
||||
bugfix/all/libceph-add-process_one_ticket-helper.patch
|
||||
bugfix/all/libceph-do-not-hard-code-max-auth-ticket-len.patch
|
||||
bugfix/all/drivers-mfd-rtsx_usb.c-export-device-table.patch
|
||||
bugfix/all/reiserfs-fix-corruption-introduced-by-balance_leaf-r.patch
|
||||
bugfix/all/reiserfs-Fix-use-after-free-in-journal-teardown.patch
|
||||
|
||||
# memfd_create() & kdbus backport
|
||||
features/all/kdbus/mm-allow-drivers-to-prevent-new-writable-mappings.patch
|
||||
|
|
Loading…
Reference in New Issue