From 1aba5d43f06a9c374d67dd0925d7387a4cd87d36 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 14 Feb 2016 14:18:20 -0800 Subject: [PATCH] 4.3-stable patches added patches: crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch crypto-algif_skcipher-do-not-assume-that-req-is-unchanged.patch crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch crypto-algif_skcipher-do-not-set-may_backlog-on-the-async-path.patch crypto-marvell-cesa-fix-test-in-mv_cesa_dev_dma_init.patch crypto-user-lock-crypto_alg_list-on-alg-dump.patch drm-nouveau-pmu-do-not-assume-a-pmu-is-present.patch evm-use-crypto_memneq-for-digest-comparisons.patch fs-cache-add-missing-initialization-of-ret-in-cachefiles_write_page.patch fs-cache-don-t-override-netfs-s-primary_index-if-registering-failed.patch fs-cache-handle-a-write-to-the-page-immediately-beyond-the-eof-marker.patch fs-cache-increase-reference-of-parent-after-registering-netfs-success.patch hid-multitouch-fetch-feature-reports-on-demand-for-win8-devices.patch rtlwifi-rtl8821ae-fix-lockups-on-boot.patch zram-don-t-call-idr_remove-from-zram_remove.patch zram-try-vmalloc-after-kmalloc.patch zram-zcomp-use-gfp_noio-to-allocate-streams.patch zsmalloc-fix-migrate_zspage-zs_free-race-condition.patch --- ...it-for-crypto_ahash_init-to-complete.patch | 40 +++++ ...-do-not-assume-that-req-is-unchanged.patch | 150 +++++++++++++++++ ...-dereference-ctx-without-socket-lock.patch | 70 ++++++++ ...ot-set-may_backlog-on-the-async-path.patch | 41 +++++ ...esa-fix-test-in-mv_cesa_dev_dma_init.patch | 31 ++++ ...ser-lock-crypto_alg_list-on-alg-dump.patch | 99 +++++++++++ ...u-pmu-do-not-assume-a-pmu-is-present.patch | 32 ++++ ...crypto_memneq-for-digest-comparisons.patch | 44 +++++ ...tion-of-ret-in-cachefiles_write_page.patch | 40 +++++ ...-primary_index-if-registering-failed.patch | 95 +++++++++++ ...ge-immediately-beyond-the-eof-marker.patch | 141 ++++++++++++++++ ...rent-after-registering-netfs-success.patch | 59 +++++++ ...e-reports-on-demand-for-win8-devices.patch | 133 +++++++++++++++ ...tlwifi-rtl8821ae-fix-lockups-on-boot.patch | 51 ++++++ queue-4.3/series | 18 ++ ...n-t-call-idr_remove-from-zram_remove.patch | 54 ++++++ .../zram-try-vmalloc-after-kmalloc.patch | 155 ++++++++++++++++++ ...omp-use-gfp_noio-to-allocate-streams.patch | 150 +++++++++++++++++ ...igrate_zspage-zs_free-race-condition.patch | 96 +++++++++++ 19 files changed, 1499 insertions(+) create mode 100644 queue-4.3/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch create mode 100644 queue-4.3/crypto-algif_skcipher-do-not-assume-that-req-is-unchanged.patch create mode 100644 queue-4.3/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch create mode 100644 queue-4.3/crypto-algif_skcipher-do-not-set-may_backlog-on-the-async-path.patch create mode 100644 queue-4.3/crypto-marvell-cesa-fix-test-in-mv_cesa_dev_dma_init.patch create mode 100644 queue-4.3/crypto-user-lock-crypto_alg_list-on-alg-dump.patch create mode 100644 queue-4.3/drm-nouveau-pmu-do-not-assume-a-pmu-is-present.patch create mode 100644 queue-4.3/evm-use-crypto_memneq-for-digest-comparisons.patch create mode 100644 queue-4.3/fs-cache-add-missing-initialization-of-ret-in-cachefiles_write_page.patch create mode 100644 queue-4.3/fs-cache-don-t-override-netfs-s-primary_index-if-registering-failed.patch create mode 100644 queue-4.3/fs-cache-handle-a-write-to-the-page-immediately-beyond-the-eof-marker.patch create mode 100644 queue-4.3/fs-cache-increase-reference-of-parent-after-registering-netfs-success.patch create mode 100644 queue-4.3/hid-multitouch-fetch-feature-reports-on-demand-for-win8-devices.patch create mode 100644 queue-4.3/rtlwifi-rtl8821ae-fix-lockups-on-boot.patch create mode 100644 queue-4.3/zram-don-t-call-idr_remove-from-zram_remove.patch create mode 100644 queue-4.3/zram-try-vmalloc-after-kmalloc.patch create mode 100644 queue-4.3/zram-zcomp-use-gfp_noio-to-allocate-streams.patch create mode 100644 queue-4.3/zsmalloc-fix-migrate_zspage-zs_free-race-condition.patch diff --git a/queue-4.3/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch b/queue-4.3/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch new file mode 100644 index 00000000000..932ed71ccd4 --- /dev/null +++ b/queue-4.3/crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch @@ -0,0 +1,40 @@ +From fe09786178f9df713a4b2dd6b93c0a722346bf5e Mon Sep 17 00:00:00 2001 +From: "Wang, Rui Y" +Date: Wed, 27 Jan 2016 17:08:37 +0800 +Subject: crypto: algif_hash - wait for crypto_ahash_init() to complete + +From: Wang, Rui Y + +commit fe09786178f9df713a4b2dd6b93c0a722346bf5e upstream. + +hash_sendmsg/sendpage() need to wait for the completion +of crypto_ahash_init() otherwise it can cause panic. + +Signed-off-by: Rui Wang +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_hash.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -54,7 +54,8 @@ static int hash_sendmsg(struct socket *s + + lock_sock(sk); + if (!ctx->more) { +- err = crypto_ahash_init(&ctx->req); ++ err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), ++ &ctx->completion); + if (err) + goto unlock; + } +@@ -125,6 +126,7 @@ static ssize_t hash_sendpage(struct sock + } else { + if (!ctx->more) { + err = crypto_ahash_init(&ctx->req); ++ err = af_alg_wait_for_completion(err, &ctx->completion); + if (err) + goto unlock; + } diff --git a/queue-4.3/crypto-algif_skcipher-do-not-assume-that-req-is-unchanged.patch b/queue-4.3/crypto-algif_skcipher-do-not-assume-that-req-is-unchanged.patch new file mode 100644 index 00000000000..12f9aefeeb4 --- /dev/null +++ b/queue-4.3/crypto-algif_skcipher-do-not-assume-that-req-is-unchanged.patch @@ -0,0 +1,150 @@ +From ec69bbfb9902c32a5c1492f2b1b8ad032a66d724 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 3 Feb 2016 21:39:24 +0800 +Subject: crypto: algif_skcipher - Do not assume that req is unchanged + +From: Herbert Xu + +commit ec69bbfb9902c32a5c1492f2b1b8ad032a66d724 upstream. + +The async path in algif_skcipher assumes that the crypto completion +function will be called with the original request. This is not +necessarily the case. In fact there is no need for this anyway +since we already embed information into the request with struct +skcipher_async_req. + +This patch adds a pointer to that struct and then passes it as +the data to the callback function. + +Signed-off-by: Herbert Xu +Tested-by: Tadeusz Struk +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_skcipher.c | 60 ++++++++++++++++++++++-------------------------- + 1 file changed, 28 insertions(+), 32 deletions(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -65,18 +65,10 @@ struct skcipher_async_req { + struct skcipher_async_rsgl first_sgl; + struct list_head list; + struct scatterlist *tsg; +- char iv[]; ++ atomic_t *inflight; ++ struct skcipher_request req; + }; + +-#define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \ +- crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))) +- +-#define GET_REQ_SIZE(ctx) \ +- crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)) +- +-#define GET_IV_SIZE(ctx) \ +- crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req)) +- + #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \ + sizeof(struct scatterlist) - 1) + +@@ -102,15 +94,12 @@ static void skcipher_free_async_sgls(str + + static void skcipher_async_cb(struct crypto_async_request *req, int err) + { +- struct sock *sk = req->data; +- struct alg_sock *ask = alg_sk(sk); +- struct skcipher_ctx *ctx = ask->private; +- struct skcipher_async_req *sreq = GET_SREQ(req, ctx); ++ struct skcipher_async_req *sreq = req->data; + struct kiocb *iocb = sreq->iocb; + +- atomic_dec(&ctx->inflight); ++ atomic_dec(sreq->inflight); + skcipher_free_async_sgls(sreq); +- kfree(req); ++ kzfree(sreq); + iocb->ki_complete(iocb, err, err); + } + +@@ -509,37 +498,42 @@ static int skcipher_recvmsg_async(struct + { + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); ++ struct sock *psk = ask->parent; ++ struct alg_sock *pask = alg_sk(psk); + struct skcipher_ctx *ctx = ask->private; ++ struct skcipher_tfm *skc = pask->private; ++ struct crypto_skcipher *tfm = skc->skcipher; + struct skcipher_sg_list *sgl; + struct scatterlist *sg; + struct skcipher_async_req *sreq; + struct skcipher_request *req; + struct skcipher_async_rsgl *last_rsgl = NULL; + unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx); +- unsigned int reqlen = sizeof(struct skcipher_async_req) + +- GET_REQ_SIZE(ctx) + GET_IV_SIZE(ctx); ++ unsigned int reqsize = crypto_skcipher_reqsize(tfm); ++ unsigned int ivsize = crypto_skcipher_ivsize(tfm); + int err = -ENOMEM; + bool mark = false; ++ char *iv; + +- lock_sock(sk); +- req = kmalloc(reqlen, GFP_KERNEL); +- if (unlikely(!req)) +- goto unlock; ++ sreq = kzalloc(sizeof(*sreq) + reqsize + ivsize, GFP_KERNEL); ++ if (unlikely(!sreq)) ++ goto out; + +- sreq = GET_SREQ(req, ctx); ++ req = &sreq->req; ++ iv = (char *)(req + 1) + reqsize; + sreq->iocb = msg->msg_iocb; +- memset(&sreq->first_sgl, '\0', sizeof(struct skcipher_async_rsgl)); + INIT_LIST_HEAD(&sreq->list); ++ sreq->inflight = &ctx->inflight; ++ ++ lock_sock(sk); + sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL); +- if (unlikely(!sreq->tsg)) { +- kfree(req); ++ if (unlikely(!sreq->tsg)) + goto unlock; +- } + sg_init_table(sreq->tsg, tx_nents); +- memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx)); +- skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req)); ++ memcpy(iv, ctx->iv, ivsize); ++ skcipher_request_set_tfm(req, tfm); + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, +- skcipher_async_cb, sk); ++ skcipher_async_cb, sreq); + + while (iov_iter_count(&msg->msg_iter)) { + struct skcipher_async_rsgl *rsgl; +@@ -615,20 +609,22 @@ static int skcipher_recvmsg_async(struct + sg_mark_end(sreq->tsg + txbufs - 1); + + skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg, +- len, sreq->iv); ++ len, iv); + err = ctx->enc ? crypto_skcipher_encrypt(req) : + crypto_skcipher_decrypt(req); + if (err == -EINPROGRESS) { + atomic_inc(&ctx->inflight); + err = -EIOCBQUEUED; ++ sreq = NULL; + goto unlock; + } + free: + skcipher_free_async_sgls(sreq); +- kfree(req); + unlock: + skcipher_wmem_wakeup(sk); + release_sock(sk); ++ kzfree(sreq); ++out: + return err; + } + diff --git a/queue-4.3/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch b/queue-4.3/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch new file mode 100644 index 00000000000..c069e326c96 --- /dev/null +++ b/queue-4.3/crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch @@ -0,0 +1,70 @@ +From 6454c2b83f719057069777132b13949e4c6b6350 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 3 Feb 2016 21:39:26 +0800 +Subject: crypto: algif_skcipher - Do not dereference ctx without socket lock + +From: Herbert Xu + +commit 6454c2b83f719057069777132b13949e4c6b6350 upstream. + +Any access to non-constant bits of the private context must be +done under the socket lock, in particular, this includes ctx->req. + +This patch moves such accesses under the lock, and fetches the +tfm from the parent socket which is guaranteed to be constant, +rather than from ctx->req. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_skcipher.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -295,8 +295,11 @@ static int skcipher_sendmsg(struct socke + { + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); ++ struct sock *psk = ask->parent; ++ struct alg_sock *pask = alg_sk(psk); + struct skcipher_ctx *ctx = ask->private; +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req); ++ struct skcipher_tfm *skc = pask->private; ++ struct crypto_skcipher *tfm = skc->skcipher; + unsigned ivsize = crypto_skcipher_ivsize(tfm); + struct skcipher_sg_list *sgl; + struct af_alg_control con = {}; +@@ -508,7 +511,7 @@ static int skcipher_recvmsg_async(struct + struct skcipher_async_req *sreq; + struct skcipher_request *req; + struct skcipher_async_rsgl *last_rsgl = NULL; +- unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx); ++ unsigned int txbufs = 0, len = 0, tx_nents; + unsigned int reqsize = crypto_skcipher_reqsize(tfm); + unsigned int ivsize = crypto_skcipher_ivsize(tfm); + int err = -ENOMEM; +@@ -526,6 +529,7 @@ static int skcipher_recvmsg_async(struct + sreq->inflight = &ctx->inflight; + + lock_sock(sk); ++ tx_nents = skcipher_all_sg_nents(ctx); + sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL); + if (unlikely(!sreq->tsg)) + goto unlock; +@@ -633,9 +637,12 @@ static int skcipher_recvmsg_sync(struct + { + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); ++ struct sock *psk = ask->parent; ++ struct alg_sock *pask = alg_sk(psk); + struct skcipher_ctx *ctx = ask->private; +- unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm( +- &ctx->req)); ++ struct skcipher_tfm *skc = pask->private; ++ struct crypto_skcipher *tfm = skc->skcipher; ++ unsigned bs = crypto_skcipher_blocksize(tfm); + struct skcipher_sg_list *sgl; + struct scatterlist *sg; + int err = -EAGAIN; diff --git a/queue-4.3/crypto-algif_skcipher-do-not-set-may_backlog-on-the-async-path.patch b/queue-4.3/crypto-algif_skcipher-do-not-set-may_backlog-on-the-async-path.patch new file mode 100644 index 00000000000..604ad0a7f98 --- /dev/null +++ b/queue-4.3/crypto-algif_skcipher-do-not-set-may_backlog-on-the-async-path.patch @@ -0,0 +1,41 @@ +From dad41997063723eaf5f77bc2015606a5a9bce320 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 3 Feb 2016 21:39:27 +0800 +Subject: crypto: algif_skcipher - Do not set MAY_BACKLOG on the async path + +From: Herbert Xu + +commit dad41997063723eaf5f77bc2015606a5a9bce320 upstream. + +The async path cannot use MAY_BACKLOG because it is not meant to +block, which is what MAY_BACKLOG does. On the other hand, both +the sync and async paths can make use of MAY_SLEEP. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_skcipher.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -536,7 +536,7 @@ static int skcipher_recvmsg_async(struct + sg_init_table(sreq->tsg, tx_nents); + memcpy(iv, ctx->iv, ivsize); + skcipher_request_set_tfm(req, tfm); +- skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, ++ skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, + skcipher_async_cb, sreq); + + while (iov_iter_count(&msg->msg_iter)) { +@@ -950,7 +950,8 @@ static int skcipher_accept_parent_nokey( + ask->private = ctx; + + skcipher_request_set_tfm(&ctx->req, skcipher); +- skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, ++ skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, + af_alg_complete, &ctx->completion); + + sk->sk_destruct = skcipher_sock_destruct; diff --git a/queue-4.3/crypto-marvell-cesa-fix-test-in-mv_cesa_dev_dma_init.patch b/queue-4.3/crypto-marvell-cesa-fix-test-in-mv_cesa_dev_dma_init.patch new file mode 100644 index 00000000000..89cf609406a --- /dev/null +++ b/queue-4.3/crypto-marvell-cesa-fix-test-in-mv_cesa_dev_dma_init.patch @@ -0,0 +1,31 @@ +From 8a3978ad55fb4c0564d285fb2f6cdee2313fce01 Mon Sep 17 00:00:00 2001 +From: Boris BREZILLON +Date: Fri, 5 Feb 2016 17:45:48 +0100 +Subject: crypto: marvell/cesa - fix test in mv_cesa_dev_dma_init() + +From: Boris BREZILLON + +commit 8a3978ad55fb4c0564d285fb2f6cdee2313fce01 upstream. + +We are checking twice if dma->cache_pool is not NULL but are never testing +dma->padding_pool value. + +Signed-off-by: Boris Brezillon +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/crypto/marvell/cesa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/crypto/marvell/cesa.c ++++ b/drivers/crypto/marvell/cesa.c +@@ -306,7 +306,7 @@ static int mv_cesa_dev_dma_init(struct m + return -ENOMEM; + + dma->padding_pool = dmam_pool_create("cesa_padding", dev, 72, 1, 0); +- if (!dma->cache_pool) ++ if (!dma->padding_pool) + return -ENOMEM; + + cesa->dma = dma; diff --git a/queue-4.3/crypto-user-lock-crypto_alg_list-on-alg-dump.patch b/queue-4.3/crypto-user-lock-crypto_alg_list-on-alg-dump.patch new file mode 100644 index 00000000000..bc0059d87a0 --- /dev/null +++ b/queue-4.3/crypto-user-lock-crypto_alg_list-on-alg-dump.patch @@ -0,0 +1,99 @@ +From 63e41ebc6630f39422d87f8a4bade1e793f37a01 Mon Sep 17 00:00:00 2001 +From: Mathias Krause +Date: Mon, 1 Feb 2016 14:27:30 +0100 +Subject: crypto: user - lock crypto_alg_list on alg dump + +From: Mathias Krause + +commit 63e41ebc6630f39422d87f8a4bade1e793f37a01 upstream. + +We miss to take the crypto_alg_sem semaphore when traversing the +crypto_alg_list for CRYPTO_MSG_GETALG dumps. This allows a race with +crypto_unregister_alg() removing algorithms from the list while we're +still traversing it, thereby leading to a use-after-free as show below: + +[ 3482.071639] general protection fault: 0000 [#1] SMP +[ 3482.075639] Modules linked in: aes_x86_64 glue_helper lrw ablk_helper cryptd gf128mul ipv6 pcspkr serio_raw virtio_net microcode virtio_pci virtio_ring virtio sr_mod cdrom [last unloaded: aesni_intel] +[ 3482.075639] CPU: 1 PID: 11065 Comm: crconf Not tainted 4.3.4-grsec+ #126 +[ 3482.075639] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 +[ 3482.075639] task: ffff88001cd41a40 ti: ffff88001cd422c8 task.ti: ffff88001cd422c8 +[ 3482.075639] RIP: 0010:[] [] strncpy+0x13/0x30 +[ 3482.075639] RSP: 0018:ffff88001f713b60 EFLAGS: 00010202 +[ 3482.075639] RAX: ffff88001f6c4430 RBX: ffff88001f6c43a0 RCX: ffff88001f6c4430 +[ 3482.075639] RDX: 0000000000000040 RSI: fefefefefefeff16 RDI: ffff88001f6c4430 +[ 3482.075639] RBP: ffff88001f713b60 R08: ffff88001f6c4470 R09: ffff88001f6c4480 +[ 3482.075639] R10: 0000000000000002 R11: 0000000000000246 R12: ffff88001ce2aa28 +[ 3482.075639] R13: ffff880000093700 R14: ffff88001f5e4bf8 R15: 0000000000003b20 +[ 3482.075639] FS: 0000033826fa2700(0000) GS:ffff88001e900000(0000) knlGS:0000000000000000 +[ 3482.075639] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 3482.075639] CR2: ffffffffff600400 CR3: 00000000139ec000 CR4: 00000000001606f0 +[ 3482.075639] Stack: +[ 3482.075639] ffff88001f713bd8 ffffffff936ccd00 ffff88001e5c4200 ffff880000093700 +[ 3482.075639] ffff88001f713bd0 ffffffff938ef4bf 0000000000000000 0000000000003b20 +[ 3482.075639] ffff88001f5e4bf8 ffff88001f5e4848 0000000000000000 0000000000003b20 +[ 3482.075639] Call Trace: +[ 3482.075639] [] crypto_report_alg+0xc0/0x3e0 +[ 3482.075639] [] ? __alloc_skb+0x16f/0x300 +[ 3482.075639] [] crypto_dump_report+0x6a/0x90 +[ 3482.075639] [] netlink_dump+0x147/0x2e0 +[ 3482.075639] [] __netlink_dump_start+0x159/0x190 +[ 3482.075639] [] crypto_user_rcv_msg+0xc3/0x130 +[ 3482.075639] [] ? crypto_report_alg+0x3e0/0x3e0 +[ 3482.075639] [] ? alg_test_crc32c+0x120/0x120 +[ 3482.075639] [] ? __netlink_lookup+0xd5/0x120 +[ 3482.075639] [] ? crypto_add_alg+0x1d0/0x1d0 +[ 3482.075639] [] netlink_rcv_skb+0xe1/0x130 +[ 3482.075639] [] crypto_netlink_rcv+0x28/0x40 +[ 3482.075639] [] netlink_unicast+0x108/0x180 +[ 3482.075639] [] netlink_sendmsg+0x541/0x770 +[ 3482.075639] [] sock_sendmsg+0x21/0x40 +[ 3482.075639] [] SyS_sendto+0xf3/0x130 +[ 3482.075639] [] ? bad_area_nosemaphore+0x13/0x20 +[ 3482.075639] [] ? __do_page_fault+0x80/0x3a0 +[ 3482.075639] [] entry_SYSCALL_64_fastpath+0x12/0x6e +[ 3482.075639] Code: 88 4a ff 75 ed 5d 48 0f ba 2c 24 3f c3 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 85 d2 48 89 f8 48 89 f9 4c 8d 04 17 48 89 e5 74 15 <0f> b6 16 80 fa 01 88 11 48 83 de ff 48 83 c1 01 4c 39 c1 75 eb +[ 3482.075639] RIP [] strncpy+0x13/0x30 + +To trigger the race run the following loops simultaneously for a while: + $ while : ; do modprobe aesni-intel; rmmod aesni-intel; done + $ while : ; do crconf show all > /dev/null; done + +Fix the race by taking the crypto_alg_sem read lock, thereby preventing +crypto_unregister_alg() from modifying the algorithm list during the +dump. + +This bug has been detected by the PaX memory sanitize feature. + +Signed-off-by: Mathias Krause +Cc: Steffen Klassert +Cc: PaX Team +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/crypto_user.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/crypto/crypto_user.c ++++ b/crypto/crypto_user.c +@@ -499,6 +499,7 @@ static int crypto_user_rcv_msg(struct sk + if (link->dump == NULL) + return -EINVAL; + ++ down_read(&crypto_alg_sem); + list_for_each_entry(alg, &crypto_alg_list, cra_list) + dump_alloc += CRYPTO_REPORT_MAXSIZE; + +@@ -508,8 +509,11 @@ static int crypto_user_rcv_msg(struct sk + .done = link->done, + .min_dump_alloc = dump_alloc, + }; +- return netlink_dump_start(crypto_nlsk, skb, nlh, &c); ++ err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); + } ++ up_read(&crypto_alg_sem); ++ ++ return err; + } + + err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, diff --git a/queue-4.3/drm-nouveau-pmu-do-not-assume-a-pmu-is-present.patch b/queue-4.3/drm-nouveau-pmu-do-not-assume-a-pmu-is-present.patch new file mode 100644 index 00000000000..244fa09015d --- /dev/null +++ b/queue-4.3/drm-nouveau-pmu-do-not-assume-a-pmu-is-present.patch @@ -0,0 +1,32 @@ +From 579b7c58215329803ce184704463de09f0f310ac Mon Sep 17 00:00:00 2001 +From: Alexandre Courbot +Date: Thu, 3 Sep 2015 17:39:52 +0900 +Subject: drm/nouveau/pmu: do not assume a PMU is present + +From: Alexandre Courbot + +commit 579b7c58215329803ce184704463de09f0f310ac upstream. + +Some devices may not have a PMU. Avoid a NULL pointer dereference in +such cases by checking whether the pointer given to nvkm_pmu_pgob() is +valid. + +Signed-off-by: Alexandre Courbot +Signed-off-by: Ben Skeggs +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +@@ -28,7 +28,7 @@ + void + nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable) + { +- if (pmu->func->pgob) ++ if (pmu && pmu->func->pgob) + pmu->func->pgob(pmu, enable); + } + diff --git a/queue-4.3/evm-use-crypto_memneq-for-digest-comparisons.patch b/queue-4.3/evm-use-crypto_memneq-for-digest-comparisons.patch new file mode 100644 index 00000000000..0c36da32485 --- /dev/null +++ b/queue-4.3/evm-use-crypto_memneq-for-digest-comparisons.patch @@ -0,0 +1,44 @@ +From 613317bd212c585c20796c10afe5daaa95d4b0a1 Mon Sep 17 00:00:00 2001 +From: Ryan Ware +Date: Thu, 11 Feb 2016 15:58:44 -0800 +Subject: EVM: Use crypto_memneq() for digest comparisons + +From: Ryan Ware + +commit 613317bd212c585c20796c10afe5daaa95d4b0a1 upstream. + +This patch fixes vulnerability CVE-2016-2085. The problem exists +because the vm_verify_hmac() function includes a use of memcmp(). +Unfortunately, this allows timing side channel attacks; specifically +a MAC forgery complexity drop from 2^128 to 2^12. This patch changes +the memcmp() to the cryptographically safe crypto_memneq(). + +Reported-by: Xiaofei Rex Guo +Signed-off-by: Ryan Ware +Signed-off-by: Mimi Zohar +Signed-off-by: James Morris +Signed-off-by: Greg Kroah-Hartman + +--- + security/integrity/evm/evm_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/security/integrity/evm/evm_main.c ++++ b/security/integrity/evm/evm_main.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include "evm.h" + + int evm_initialized; +@@ -148,7 +149,7 @@ static enum integrity_status evm_verify_ + xattr_value_len, calc.digest); + if (rc) + break; +- rc = memcmp(xattr_data->digest, calc.digest, ++ rc = crypto_memneq(xattr_data->digest, calc.digest, + sizeof(calc.digest)); + if (rc) + rc = -EINVAL; diff --git a/queue-4.3/fs-cache-add-missing-initialization-of-ret-in-cachefiles_write_page.patch b/queue-4.3/fs-cache-add-missing-initialization-of-ret-in-cachefiles_write_page.patch new file mode 100644 index 00000000000..54e0e50a18b --- /dev/null +++ b/queue-4.3/fs-cache-add-missing-initialization-of-ret-in-cachefiles_write_page.patch @@ -0,0 +1,40 @@ +From cf89752645e47d86ba8a4157f4b121fcb33434c5 Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Thu, 12 Nov 2015 11:46:23 +0000 +Subject: FS-Cache: Add missing initialization of ret in cachefiles_write_page() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Geert Uytterhoeven + +commit cf89752645e47d86ba8a4157f4b121fcb33434c5 upstream. + +fs/cachefiles/rdwr.c: In function ‘cachefiles_write_page’: +fs/cachefiles/rdwr.c:882: warning: ‘ret’ may be used uninitialized in +this function + +If the jump to label "error" is taken, "ret" will indeed be +uninitialized, and random stack data may be printed by the debug code. + +Fixes: 102f4d900c9c8f5e ("FS-Cache: Handle a write to the page immediately beyond the EOF marker") +Signed-off-by: Geert Uytterhoeven +Signed-off-by: David Howells +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cachefiles/rdwr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/cachefiles/rdwr.c ++++ b/fs/cachefiles/rdwr.c +@@ -885,7 +885,7 @@ int cachefiles_write_page(struct fscache + loff_t pos, eof; + size_t len; + void *data; +- int ret; ++ int ret = -ENOBUFS; + + ASSERT(op != NULL); + ASSERT(page != NULL); diff --git a/queue-4.3/fs-cache-don-t-override-netfs-s-primary_index-if-registering-failed.patch b/queue-4.3/fs-cache-don-t-override-netfs-s-primary_index-if-registering-failed.patch new file mode 100644 index 00000000000..de820e406db --- /dev/null +++ b/queue-4.3/fs-cache-don-t-override-netfs-s-primary_index-if-registering-failed.patch @@ -0,0 +1,95 @@ +From b130ed5998e62879a66bad08931a2b5e832da95c Mon Sep 17 00:00:00 2001 +From: Kinglong Mee +Date: Wed, 4 Nov 2015 15:20:24 +0000 +Subject: FS-Cache: Don't override netfs's primary_index if registering failed + +From: Kinglong Mee + +commit b130ed5998e62879a66bad08931a2b5e832da95c upstream. + +Only override netfs->primary_index when registering success. + +Signed-off-by: Kinglong Mee +Signed-off-by: David Howells +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fscache/netfs.c | 37 ++++++++++++++++++------------------- + 1 file changed, 18 insertions(+), 19 deletions(-) + +--- a/fs/fscache/netfs.c ++++ b/fs/fscache/netfs.c +@@ -22,6 +22,7 @@ static LIST_HEAD(fscache_netfs_list); + int __fscache_register_netfs(struct fscache_netfs *netfs) + { + struct fscache_netfs *ptr; ++ struct fscache_cookie *cookie; + int ret; + + _enter("{%s}", netfs->name); +@@ -29,26 +30,25 @@ int __fscache_register_netfs(struct fsca + INIT_LIST_HEAD(&netfs->link); + + /* allocate a cookie for the primary index */ +- netfs->primary_index = +- kmem_cache_zalloc(fscache_cookie_jar, GFP_KERNEL); ++ cookie = kmem_cache_zalloc(fscache_cookie_jar, GFP_KERNEL); + +- if (!netfs->primary_index) { ++ if (!cookie) { + _leave(" = -ENOMEM"); + return -ENOMEM; + } + + /* initialise the primary index cookie */ +- atomic_set(&netfs->primary_index->usage, 1); +- atomic_set(&netfs->primary_index->n_children, 0); +- atomic_set(&netfs->primary_index->n_active, 1); +- +- netfs->primary_index->def = &fscache_fsdef_netfs_def; +- netfs->primary_index->parent = &fscache_fsdef_index; +- netfs->primary_index->netfs_data = netfs; +- netfs->primary_index->flags = 1 << FSCACHE_COOKIE_ENABLED; ++ atomic_set(&cookie->usage, 1); ++ atomic_set(&cookie->n_children, 0); ++ atomic_set(&cookie->n_active, 1); ++ ++ cookie->def = &fscache_fsdef_netfs_def; ++ cookie->parent = &fscache_fsdef_index; ++ cookie->netfs_data = netfs; ++ cookie->flags = 1 << FSCACHE_COOKIE_ENABLED; + +- spin_lock_init(&netfs->primary_index->lock); +- INIT_HLIST_HEAD(&netfs->primary_index->backing_objects); ++ spin_lock_init(&cookie->lock); ++ INIT_HLIST_HEAD(&cookie->backing_objects); + + /* check the netfs type is not already present */ + down_write(&fscache_addremove_sem); +@@ -59,9 +59,10 @@ int __fscache_register_netfs(struct fsca + goto already_registered; + } + +- atomic_inc(&netfs->primary_index->parent->usage); +- atomic_inc(&netfs->primary_index->parent->n_children); ++ atomic_inc(&cookie->parent->usage); ++ atomic_inc(&cookie->parent->n_children); + ++ netfs->primary_index = cookie; + list_add(&netfs->link, &fscache_netfs_list); + ret = 0; + +@@ -70,10 +71,8 @@ int __fscache_register_netfs(struct fsca + already_registered: + up_write(&fscache_addremove_sem); + +- if (ret < 0) { +- kmem_cache_free(fscache_cookie_jar, netfs->primary_index); +- netfs->primary_index = NULL; +- } ++ if (ret < 0) ++ kmem_cache_free(fscache_cookie_jar, cookie); + + _leave(" = %d", ret); + return ret; diff --git a/queue-4.3/fs-cache-handle-a-write-to-the-page-immediately-beyond-the-eof-marker.patch b/queue-4.3/fs-cache-handle-a-write-to-the-page-immediately-beyond-the-eof-marker.patch new file mode 100644 index 00000000000..9a84fc1eeef --- /dev/null +++ b/queue-4.3/fs-cache-handle-a-write-to-the-page-immediately-beyond-the-eof-marker.patch @@ -0,0 +1,141 @@ +From 102f4d900c9c8f5ed89ae4746d493fe3ebd7ba64 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 4 Nov 2015 15:20:42 +0000 +Subject: FS-Cache: Handle a write to the page immediately beyond the EOF marker + +From: David Howells + +commit 102f4d900c9c8f5ed89ae4746d493fe3ebd7ba64 upstream. + +Handle a write being requested to the page immediately beyond the EOF +marker on a cache object. Currently this gets an assertion failure in +CacheFiles because the EOF marker is used there to encode information about +a partial page at the EOF - which could lead to an unknown blank spot in +the file if we extend the file over it. + +The problem is actually in fscache where we check the index of the page +being written against store_limit. store_limit is set to the number of +pages that we're allowed to store by fscache_set_store_limit() - which +means it's one more than the index of the last page we're allowed to store. +The problem is that we permit writing to a page with an index _equal_ to +the store limit - when we should reject that case. + +Whilst we're at it, change the triggered assertion in CacheFiles to just +return -ENOBUFS instead. + +The assertion failure looks something like this: + +CacheFiles: Assertion failed +1000 < 7b1 is false +------------[ cut here ]------------ +kernel BUG at fs/cachefiles/rdwr.c:962! +... +RIP: 0010:[] [] cachefiles_write_page+0x273/0x2d0 [cachefiles] + +Signed-off-by: David Howells +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cachefiles/rdwr.c | 67 ++++++++++++++++++++++++++++----------------------- + fs/fscache/page.c | 2 - + 2 files changed, 38 insertions(+), 31 deletions(-) + +--- a/fs/cachefiles/rdwr.c ++++ b/fs/cachefiles/rdwr.c +@@ -905,6 +905,15 @@ int cachefiles_write_page(struct fscache + cache = container_of(object->fscache.cache, + struct cachefiles_cache, cache); + ++ pos = (loff_t)page->index << PAGE_SHIFT; ++ ++ /* We mustn't write more data than we have, so we have to beware of a ++ * partial page at EOF. ++ */ ++ eof = object->fscache.store_limit_l; ++ if (pos >= eof) ++ goto error; ++ + /* write the page to the backing filesystem and let it store it in its + * own time */ + path.mnt = cache->mnt; +@@ -912,40 +921,38 @@ int cachefiles_write_page(struct fscache + file = dentry_open(&path, O_RDWR | O_LARGEFILE, cache->cache_cred); + if (IS_ERR(file)) { + ret = PTR_ERR(file); +- } else { +- pos = (loff_t) page->index << PAGE_SHIFT; +- +- /* we mustn't write more data than we have, so we have +- * to beware of a partial page at EOF */ +- eof = object->fscache.store_limit_l; +- len = PAGE_SIZE; +- if (eof & ~PAGE_MASK) { +- ASSERTCMP(pos, <, eof); +- if (eof - pos < PAGE_SIZE) { +- _debug("cut short %llx to %llx", +- pos, eof); +- len = eof - pos; +- ASSERTCMP(pos + len, ==, eof); +- } +- } +- +- data = kmap(page); +- ret = __kernel_write(file, data, len, &pos); +- kunmap(page); +- if (ret != len) +- ret = -EIO; +- fput(file); ++ goto error_2; + } + +- if (ret < 0) { +- if (ret == -EIO) +- cachefiles_io_error_obj( +- object, "Write page to backing file failed"); +- ret = -ENOBUFS; ++ len = PAGE_SIZE; ++ if (eof & ~PAGE_MASK) { ++ if (eof - pos < PAGE_SIZE) { ++ _debug("cut short %llx to %llx", ++ pos, eof); ++ len = eof - pos; ++ ASSERTCMP(pos + len, ==, eof); ++ } + } + +- _leave(" = %d", ret); +- return ret; ++ data = kmap(page); ++ ret = __kernel_write(file, data, len, &pos); ++ kunmap(page); ++ fput(file); ++ if (ret != len) ++ goto error_eio; ++ ++ _leave(" = 0"); ++ return 0; ++ ++error_eio: ++ ret = -EIO; ++error_2: ++ if (ret == -EIO) ++ cachefiles_io_error_obj(object, ++ "Write page to backing file failed"); ++error: ++ _leave(" = -ENOBUFS [%d]", ret); ++ return -ENOBUFS; + } + + /* +--- a/fs/fscache/page.c ++++ b/fs/fscache/page.c +@@ -816,7 +816,7 @@ static void fscache_write_op(struct fsca + goto superseded; + page = results[0]; + _debug("gang %d [%lx]", n, page->index); +- if (page->index > op->store_limit) { ++ if (page->index >= op->store_limit) { + fscache_stat(&fscache_n_store_pages_over_limit); + goto superseded; + } diff --git a/queue-4.3/fs-cache-increase-reference-of-parent-after-registering-netfs-success.patch b/queue-4.3/fs-cache-increase-reference-of-parent-after-registering-netfs-success.patch new file mode 100644 index 00000000000..865c4faab36 --- /dev/null +++ b/queue-4.3/fs-cache-increase-reference-of-parent-after-registering-netfs-success.patch @@ -0,0 +1,59 @@ +From 86108c2e34a26e4bec3c6ddb23390bf8cedcf391 Mon Sep 17 00:00:00 2001 +From: Kinglong Mee +Date: Wed, 4 Nov 2015 15:20:15 +0000 +Subject: FS-Cache: Increase reference of parent after registering, netfs success + +From: Kinglong Mee + +commit 86108c2e34a26e4bec3c6ddb23390bf8cedcf391 upstream. + +If netfs exist, fscache should not increase the reference of parent's +usage and n_children, otherwise, never be decreased. + +v2: thanks David's suggest, + move increasing reference of parent if success + use kmem_cache_free() freeing primary_index directly + +v3: don't move "netfs->primary_index->parent = &fscache_fsdef_index;" + +Signed-off-by: Kinglong Mee +Signed-off-by: David Howells +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fscache/netfs.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/fs/fscache/netfs.c ++++ b/fs/fscache/netfs.c +@@ -47,9 +47,6 @@ int __fscache_register_netfs(struct fsca + netfs->primary_index->netfs_data = netfs; + netfs->primary_index->flags = 1 << FSCACHE_COOKIE_ENABLED; + +- atomic_inc(&netfs->primary_index->parent->usage); +- atomic_inc(&netfs->primary_index->parent->n_children); +- + spin_lock_init(&netfs->primary_index->lock); + INIT_HLIST_HEAD(&netfs->primary_index->backing_objects); + +@@ -62,6 +59,9 @@ int __fscache_register_netfs(struct fsca + goto already_registered; + } + ++ atomic_inc(&netfs->primary_index->parent->usage); ++ atomic_inc(&netfs->primary_index->parent->n_children); ++ + list_add(&netfs->link, &fscache_netfs_list); + ret = 0; + +@@ -71,8 +71,7 @@ already_registered: + up_write(&fscache_addremove_sem); + + if (ret < 0) { +- netfs->primary_index->parent = NULL; +- __fscache_cookie_put(netfs->primary_index); ++ kmem_cache_free(fscache_cookie_jar, netfs->primary_index); + netfs->primary_index = NULL; + } + diff --git a/queue-4.3/hid-multitouch-fetch-feature-reports-on-demand-for-win8-devices.patch b/queue-4.3/hid-multitouch-fetch-feature-reports-on-demand-for-win8-devices.patch new file mode 100644 index 00000000000..cade1b4400a --- /dev/null +++ b/queue-4.3/hid-multitouch-fetch-feature-reports-on-demand-for-win8-devices.patch @@ -0,0 +1,133 @@ +From 6d4f5440a3a2bb2e9d0d582bbf98234e9e9bb095 Mon Sep 17 00:00:00 2001 +From: Mika Westerberg +Date: Wed, 7 Oct 2015 15:33:43 +0300 +Subject: HID: multitouch: Fetch feature reports on demand for Win8 devices + +From: Mika Westerberg + +commit 6d4f5440a3a2bb2e9d0d582bbf98234e9e9bb095 upstream. + +Some newer Intel Skylake based Dell laptops with Win8 precision touchpad +fail when initial feature reports are fetched from it. Below is an example +output with some additional debug included: + + i2c_hid i2c-DLL0704:01: Fetching the HID descriptor + i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=20 00 + i2c_hid i2c-DLL0704:01: HID Descriptor: 1e 00 00 01 99 02 21 00 24 ... + ... + i2c_hid i2c-DLL0704:01: i2c_hid_get_report + i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 38 02 23 00 + i2c_hid i2c-DLL0704:01: report (len=4): 04 00 08 05 + i2c_hid i2c-DLL0704:01: report id 13 + i2c_hid i2c-DLL0704:01: i2c_hid_get_report + i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 3d 02 23 00 + i2c_hid i2c-DLL0704:01: failed to retrieve report from device. + i2c_hid i2c-DLL0704:01: report id 7 + i2c_hid i2c-DLL0704:01: i2c_hid_get_report + i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 37 02 23 00 + i2c_hid i2c-DLL0704:01: report (len=259): 03 01 07 fc 28 fe 84 40 ... + i2c_hid i2c-DLL0704:01: report id 4 + i2c_hid i2c-DLL0704:01: i2c_hid_get_report + i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 34 02 23 00 + +We manage to fetch few reports but then the touchpad dies: + + i2c_designware i2c_designware.1: i2c_dw_handle_tx_abort: lost arbitration + i2c_hid i2c-DLL0704:01: failed to retrieve report from device. + +it eventually pulls the whole I2C bus low: + + i2c_designware i2c_designware.1: controller timed out + i2c_hid i2c-DLL0704:01: failed to set a report to device. + +Fix this by preventing initial feature report retrieval for Win8 devices. +Instead we fetch reports as needed in mt_feature_mapping(). This prevents +fetching reports which might cause problems with the device in question. + +Suggested-by: Benjamin Tissoires +Signed-off-by: Mika Westerberg +Reviewed-by: Benjamin Tissoires +Tested-by: Seth Forshee +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-multitouch.c | 45 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 44 insertions(+), 1 deletion(-) + +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -309,6 +309,41 @@ static struct attribute_group mt_attribu + .attrs = sysfs_attrs + }; + ++static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) ++{ ++ struct mt_device *td = hid_get_drvdata(hdev); ++ int ret, size = hid_report_len(report); ++ u8 *buf; ++ ++ /* ++ * Only fetch the feature report if initial reports are not already ++ * been retrieved. Currently this is only done for Windows 8 touch ++ * devices. ++ */ ++ if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS)) ++ return; ++ if (td->mtclass.name != MT_CLS_WIN_8) ++ return; ++ ++ buf = hid_alloc_report_buf(report, GFP_KERNEL); ++ if (!buf) ++ return; ++ ++ ret = hid_hw_raw_request(hdev, report->id, buf, size, ++ HID_FEATURE_REPORT, HID_REQ_GET_REPORT); ++ if (ret < 0) { ++ dev_warn(&hdev->dev, "failed to fetch feature %d\n", ++ report->id); ++ } else { ++ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, ++ size, 0); ++ if (ret) ++ dev_warn(&hdev->dev, "failed to report feature\n"); ++ } ++ ++ kfree(buf); ++} ++ + static void mt_feature_mapping(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage) + { +@@ -327,6 +362,8 @@ static void mt_feature_mapping(struct hi + + break; + case HID_DG_CONTACTMAX: ++ mt_get_feature(hdev, field->report); ++ + td->maxcontact_report_id = field->report->id; + td->maxcontacts = field->value[0]; + if (!td->maxcontacts && +@@ -343,6 +380,7 @@ static void mt_feature_mapping(struct hi + break; + } + ++ mt_get_feature(hdev, field->report); + if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) + td->is_buttonpad = true; + +@@ -1026,8 +1064,13 @@ static int mt_probe(struct hid_device *h + * reports. Fortunately, the Win8 spec says that all touches + * should be sent during each report, making the initialization + * of input reports unnecessary. ++ * ++ * In addition some touchpads do not behave well if we read ++ * all feature reports from them. Instead we prevent ++ * initial report fetching and then selectively fetch each ++ * report we are interested in. + */ +- hdev->quirks |= HID_QUIRK_NO_INIT_INPUT_REPORTS; ++ hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; + + td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); + if (!td) { diff --git a/queue-4.3/rtlwifi-rtl8821ae-fix-lockups-on-boot.patch b/queue-4.3/rtlwifi-rtl8821ae-fix-lockups-on-boot.patch new file mode 100644 index 00000000000..ad301562422 --- /dev/null +++ b/queue-4.3/rtlwifi-rtl8821ae-fix-lockups-on-boot.patch @@ -0,0 +1,51 @@ +From eeec5d0ef7ee54a75e09e861c3cc44177b8752c7 Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Tue, 10 Nov 2015 10:46:11 -0600 +Subject: rtlwifi: rtl8821ae: Fix lockups on boot + +From: Larry Finger + +commit eeec5d0ef7ee54a75e09e861c3cc44177b8752c7 upstream. + +In commit 54328e64047a5 ("rtlwifi: rtl8821ae: Fix system lockups on boot"), +an attempt was made to fix a regression introduced in commit 1277fa2ab2f9 +("rtlwifi: Remove the clear interrupt routine from all drivers"). +Unfortunately, there were logic errors in that patch that prevented +affected boxes from booting even after that patch was applied. + +The actual cause of the original problem is unknown as none of the +developers have systems that are affected. + +Fixes: 54328e64047a ("rtlwifi: rtl8821ae: Fix system lockups on boot") +Signed-off-by: Larry Finger +Signed-off-by: Kalle Valo +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | 2 +- + drivers/net/wireless/rtlwifi/rtl8821ae/sw.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +@@ -2272,7 +2272,7 @@ void rtl8821ae_enable_interrupt(struct i + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +- if (!rtlpci->int_clear) ++ if (rtlpci->int_clear) + rtl8821ae_clear_interrupt(hw);/*clear it here first*/ + + rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); +--- a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c +@@ -448,7 +448,7 @@ MODULE_PARM_DESC(fwlps, "Set to 1 to use + MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n"); + MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); +-MODULE_PARM_DESC(int_clear, "Set to 1 to disable interrupt clear before set (default 0)\n"); ++MODULE_PARM_DESC(int_clear, "Set to 0 to disable interrupt clear before set (default 1)\n"); + + static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); + diff --git a/queue-4.3/series b/queue-4.3/series index a35c096df53..229d2196a46 100644 --- a/queue-4.3/series +++ b/queue-4.3/series @@ -178,3 +178,21 @@ crypto-algif_skcipher-sendmsg-sg-marking-is-off-by-one.patch crypto-caam-make-write-transactions-bufferable-on-ppc-platforms.patch crypto-chacha20-ssse3-align-stack-pointer-to-64-bytes.patch crypto-shash-fix-has_key-setting.patch +crypto-algif_hash-wait-for-crypto_ahash_init-to-complete.patch +evm-use-crypto_memneq-for-digest-comparisons.patch +crypto-user-lock-crypto_alg_list-on-alg-dump.patch +crypto-algif_skcipher-do-not-assume-that-req-is-unchanged.patch +crypto-algif_skcipher-do-not-dereference-ctx-without-socket-lock.patch +crypto-algif_skcipher-do-not-set-may_backlog-on-the-async-path.patch +crypto-marvell-cesa-fix-test-in-mv_cesa_dev_dma_init.patch +fs-cache-increase-reference-of-parent-after-registering-netfs-success.patch +fs-cache-don-t-override-netfs-s-primary_index-if-registering-failed.patch +fs-cache-handle-a-write-to-the-page-immediately-beyond-the-eof-marker.patch +fs-cache-add-missing-initialization-of-ret-in-cachefiles_write_page.patch +rtlwifi-rtl8821ae-fix-lockups-on-boot.patch +hid-multitouch-fetch-feature-reports-on-demand-for-win8-devices.patch +drm-nouveau-pmu-do-not-assume-a-pmu-is-present.patch +zram-zcomp-use-gfp_noio-to-allocate-streams.patch +zram-try-vmalloc-after-kmalloc.patch +zram-don-t-call-idr_remove-from-zram_remove.patch +zsmalloc-fix-migrate_zspage-zs_free-race-condition.patch diff --git a/queue-4.3/zram-don-t-call-idr_remove-from-zram_remove.patch b/queue-4.3/zram-don-t-call-idr_remove-from-zram_remove.patch new file mode 100644 index 00000000000..a0c97fc4b5d --- /dev/null +++ b/queue-4.3/zram-don-t-call-idr_remove-from-zram_remove.patch @@ -0,0 +1,54 @@ +From 17ec4cd985780a7e30aa45bb8f272237c12502a4 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Fri, 15 Jan 2016 16:54:48 -0800 +Subject: zram: don't call idr_remove() from zram_remove() + +From: Jerome Marchand + +commit 17ec4cd985780a7e30aa45bb8f272237c12502a4 upstream. + +The use of idr_remove() is forbidden in the callback functions of +idr_for_each(). It is therefore unsafe to call idr_remove in +zram_remove(). + +This patch moves the call to idr_remove() from zram_remove() to +hot_remove_store(). In the detroy_devices() path, idrs are removed by +idr_destroy(). This solves an use-after-free detected by KASan. + +[akpm@linux-foundation.org: fix coding stype, per Sergey] +Signed-off-by: Jerome Marchand +Acked-by: Sergey Senozhatsky +Cc: Minchan Kim +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/zram/zram_drv.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -1324,7 +1324,6 @@ static int zram_remove(struct zram *zram + + pr_info("Removed device: %s\n", zram->disk->disk_name); + +- idr_remove(&zram_index_idr, zram->disk->first_minor); + blk_cleanup_queue(zram->disk->queue); + del_gendisk(zram->disk); + put_disk(zram->disk); +@@ -1366,10 +1365,12 @@ static ssize_t hot_remove_store(struct c + mutex_lock(&zram_index_mutex); + + zram = idr_find(&zram_index_idr, dev_id); +- if (zram) ++ if (zram) { + ret = zram_remove(zram); +- else ++ idr_remove(&zram_index_idr, dev_id); ++ } else { + ret = -ENODEV; ++ } + + mutex_unlock(&zram_index_mutex); + return ret ? ret : count; diff --git a/queue-4.3/zram-try-vmalloc-after-kmalloc.patch b/queue-4.3/zram-try-vmalloc-after-kmalloc.patch new file mode 100644 index 00000000000..bcfb8c67835 --- /dev/null +++ b/queue-4.3/zram-try-vmalloc-after-kmalloc.patch @@ -0,0 +1,155 @@ +From d913897abace843bba20249f3190167f7895e9c3 Mon Sep 17 00:00:00 2001 +From: Kyeongdon Kim +Date: Thu, 14 Jan 2016 15:22:29 -0800 +Subject: zram: try vmalloc() after kmalloc() + +From: Kyeongdon Kim + +commit d913897abace843bba20249f3190167f7895e9c3 upstream. + +When we're using LZ4 multi compression streams for zram swap, we found +out page allocation failure message in system running test. That was +not only once, but a few(2 - 5 times per test). Also, some failure +cases were continually occurring to try allocation order 3. + +In order to make parallel compression private data, we should call +kzalloc() with order 2/3 in runtime(lzo/lz4). But if there is no order +2/3 size memory to allocate in that time, page allocation fails. This +patch makes to use vmalloc() as fallback of kmalloc(), this prevents +page alloc failure warning. + +After using this, we never found warning message in running test, also +It could reduce process startup latency about 60-120ms in each case. + +For reference a call trace : + + Binder_1: page allocation failure: order:3, mode:0x10c0d0 + CPU: 0 PID: 424 Comm: Binder_1 Tainted: GW 3.10.49-perf-g991d02b-dirty #20 + Call trace: + dump_backtrace+0x0/0x270 + show_stack+0x10/0x1c + dump_stack+0x1c/0x28 + warn_alloc_failed+0xfc/0x11c + __alloc_pages_nodemask+0x724/0x7f0 + __get_free_pages+0x14/0x5c + kmalloc_order_trace+0x38/0xd8 + zcomp_lz4_create+0x2c/0x38 + zcomp_strm_alloc+0x34/0x78 + zcomp_strm_multi_find+0x124/0x1ec + zcomp_strm_find+0xc/0x18 + zram_bvec_rw+0x2fc/0x780 + zram_make_request+0x25c/0x2d4 + generic_make_request+0x80/0xbc + submit_bio+0xa4/0x15c + __swap_writepage+0x218/0x230 + swap_writepage+0x3c/0x4c + shrink_page_list+0x51c/0x8d0 + shrink_inactive_list+0x3f8/0x60c + shrink_lruvec+0x33c/0x4cc + shrink_zone+0x3c/0x100 + try_to_free_pages+0x2b8/0x54c + __alloc_pages_nodemask+0x514/0x7f0 + __get_free_pages+0x14/0x5c + proc_info_read+0x50/0xe4 + vfs_read+0xa0/0x12c + SyS_read+0x44/0x74 + DMA: 3397*4kB (MC) 26*8kB (RC) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB + 0*512kB 0*1024kB 0*2048kB 0*4096kB = 13796kB + +[minchan@kernel.org: change vmalloc gfp and adding comment about gfp] +[sergey.senozhatsky@gmail.com: tweak comments and styles] +Signed-off-by: Kyeongdon Kim +Signed-off-by: Minchan Kim +Acked-by: Sergey Senozhatsky +Sergey Senozhatsky +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/zram/zcomp_lz4.c | 23 +++++++++++++++++++++-- + drivers/block/zram/zcomp_lzo.c | 23 +++++++++++++++++++++-- + 2 files changed, 42 insertions(+), 4 deletions(-) + +--- a/drivers/block/zram/zcomp_lz4.c ++++ b/drivers/block/zram/zcomp_lz4.c +@@ -10,17 +10,36 @@ + #include + #include + #include ++#include ++#include + + #include "zcomp_lz4.h" + + static void *zcomp_lz4_create(void) + { +- return kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO); ++ void *ret; ++ ++ /* ++ * This function can be called in swapout/fs write path ++ * so we can't use GFP_FS|IO. And it assumes we already ++ * have at least one stream in zram initialization so we ++ * don't do best effort to allocate more stream in here. ++ * A default stream will work well without further multiple ++ * streams. That's why we use NORETRY | NOWARN. ++ */ ++ ret = kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY | ++ __GFP_NOWARN); ++ if (!ret) ++ ret = __vmalloc(LZ4_MEM_COMPRESS, ++ GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_ZERO | __GFP_HIGHMEM, ++ PAGE_KERNEL); ++ return ret; + } + + static void zcomp_lz4_destroy(void *private) + { +- kfree(private); ++ kvfree(private); + } + + static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst, +--- a/drivers/block/zram/zcomp_lzo.c ++++ b/drivers/block/zram/zcomp_lzo.c +@@ -10,17 +10,36 @@ + #include + #include + #include ++#include ++#include + + #include "zcomp_lzo.h" + + static void *lzo_create(void) + { +- return kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO); ++ void *ret; ++ ++ /* ++ * This function can be called in swapout/fs write path ++ * so we can't use GFP_FS|IO. And it assumes we already ++ * have at least one stream in zram initialization so we ++ * don't do best effort to allocate more stream in here. ++ * A default stream will work well without further multiple ++ * streams. That's why we use NORETRY | NOWARN. ++ */ ++ ret = kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY | ++ __GFP_NOWARN); ++ if (!ret) ++ ret = __vmalloc(LZO1X_MEM_COMPRESS, ++ GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_ZERO | __GFP_HIGHMEM, ++ PAGE_KERNEL); ++ return ret; + } + + static void lzo_destroy(void *private) + { +- kfree(private); ++ kvfree(private); + } + + static int lzo_compress(const unsigned char *src, unsigned char *dst, diff --git a/queue-4.3/zram-zcomp-use-gfp_noio-to-allocate-streams.patch b/queue-4.3/zram-zcomp-use-gfp_noio-to-allocate-streams.patch new file mode 100644 index 00000000000..c9d5bddbaea --- /dev/null +++ b/queue-4.3/zram-zcomp-use-gfp_noio-to-allocate-streams.patch @@ -0,0 +1,150 @@ +From 3d5fe03a3ea013060ebba2a811aeb0f23f56aefa Mon Sep 17 00:00:00 2001 +From: Sergey Senozhatsky +Date: Thu, 14 Jan 2016 15:22:26 -0800 +Subject: zram/zcomp: use GFP_NOIO to allocate streams + +From: Sergey Senozhatsky + +commit 3d5fe03a3ea013060ebba2a811aeb0f23f56aefa upstream. + +We can end up allocating a new compression stream with GFP_KERNEL from +within the IO path, which may result is nested (recursive) IO +operations. That can introduce problems if the IO path in question is a +reclaimer, holding some locks that will deadlock nested IOs. + +Allocate streams and working memory using GFP_NOIO flag, forbidding +recursive IO and FS operations. + +An example: + + inconsistent {IN-RECLAIM_FS-W} -> {RECLAIM_FS-ON-W} usage. + git/20158 [HC0[0]:SC0[0]:HE1:SE1] takes: + (jbd2_handle){+.+.?.}, at: start_this_handle+0x4ca/0x555 + {IN-RECLAIM_FS-W} state was registered at: + __lock_acquire+0x8da/0x117b + lock_acquire+0x10c/0x1a7 + start_this_handle+0x52d/0x555 + jbd2__journal_start+0xb4/0x237 + __ext4_journal_start_sb+0x108/0x17e + ext4_dirty_inode+0x32/0x61 + __mark_inode_dirty+0x16b/0x60c + iput+0x11e/0x274 + __dentry_kill+0x148/0x1b8 + shrink_dentry_list+0x274/0x44a + prune_dcache_sb+0x4a/0x55 + super_cache_scan+0xfc/0x176 + shrink_slab.part.14.constprop.25+0x2a2/0x4d3 + shrink_zone+0x74/0x140 + kswapd+0x6b7/0x930 + kthread+0x107/0x10f + ret_from_fork+0x3f/0x70 + irq event stamp: 138297 + hardirqs last enabled at (138297): debug_check_no_locks_freed+0x113/0x12f + hardirqs last disabled at (138296): debug_check_no_locks_freed+0x33/0x12f + softirqs last enabled at (137818): __do_softirq+0x2d3/0x3e9 + softirqs last disabled at (137813): irq_exit+0x41/0x95 + + other info that might help us debug this: + Possible unsafe locking scenario: + CPU0 + ---- + lock(jbd2_handle); + + lock(jbd2_handle); + + *** DEADLOCK *** + 5 locks held by git/20158: + #0: (sb_writers#7){.+.+.+}, at: [] mnt_want_write+0x24/0x4b + #1: (&type->i_mutex_dir_key#2/1){+.+.+.}, at: [] lock_rename+0xd9/0xe3 + #2: (&sb->s_type->i_mutex_key#11){+.+.+.}, at: [] lock_two_nondirectories+0x3f/0x6b + #3: (&sb->s_type->i_mutex_key#11/4){+.+.+.}, at: [] lock_two_nondirectories+0x66/0x6b + #4: (jbd2_handle){+.+.?.}, at: [] start_this_handle+0x4ca/0x555 + + stack backtrace: + CPU: 2 PID: 20158 Comm: git Not tainted 4.1.0-rc7-next-20150615-dbg-00016-g8bdf555-dirty #211 + Call Trace: + dump_stack+0x4c/0x6e + mark_lock+0x384/0x56d + mark_held_locks+0x5f/0x76 + lockdep_trace_alloc+0xb2/0xb5 + kmem_cache_alloc_trace+0x32/0x1e2 + zcomp_strm_alloc+0x25/0x73 [zram] + zcomp_strm_multi_find+0xe7/0x173 [zram] + zcomp_strm_find+0xc/0xe [zram] + zram_bvec_rw+0x2ca/0x7e0 [zram] + zram_make_request+0x1fa/0x301 [zram] + generic_make_request+0x9c/0xdb + submit_bio+0xf7/0x120 + ext4_io_submit+0x2e/0x43 + ext4_bio_write_page+0x1b7/0x300 + mpage_submit_page+0x60/0x77 + mpage_map_and_submit_buffers+0x10f/0x21d + ext4_writepages+0xc8c/0xe1b + do_writepages+0x23/0x2c + __filemap_fdatawrite_range+0x84/0x8b + filemap_flush+0x1c/0x1e + ext4_alloc_da_blocks+0xb8/0x117 + ext4_rename+0x132/0x6dc + ? mark_held_locks+0x5f/0x76 + ext4_rename2+0x29/0x2b + vfs_rename+0x540/0x636 + SyS_renameat2+0x359/0x44d + SyS_rename+0x1e/0x20 + entry_SYSCALL_64_fastpath+0x12/0x6f + +[minchan@kernel.org: add stable mark] +Signed-off-by: Sergey Senozhatsky +Acked-by: Minchan Kim +Cc: Kyeongdon Kim +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/zram/zcomp.c | 4 ++-- + drivers/block/zram/zcomp_lz4.c | 2 +- + drivers/block/zram/zcomp_lzo.c | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/block/zram/zcomp.c ++++ b/drivers/block/zram/zcomp.c +@@ -76,7 +76,7 @@ static void zcomp_strm_free(struct zcomp + */ + static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) + { +- struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL); ++ struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_NOIO); + if (!zstrm) + return NULL; + +@@ -85,7 +85,7 @@ static struct zcomp_strm *zcomp_strm_all + * allocate 2 pages. 1 for compressed data, plus 1 extra for the + * case when compressed size is larger than the original one + */ +- zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); ++ zstrm->buffer = (void *)__get_free_pages(GFP_NOIO | __GFP_ZERO, 1); + if (!zstrm->private || !zstrm->buffer) { + zcomp_strm_free(comp, zstrm); + zstrm = NULL; +--- a/drivers/block/zram/zcomp_lz4.c ++++ b/drivers/block/zram/zcomp_lz4.c +@@ -15,7 +15,7 @@ + + static void *zcomp_lz4_create(void) + { +- return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL); ++ return kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO); + } + + static void zcomp_lz4_destroy(void *private) +--- a/drivers/block/zram/zcomp_lzo.c ++++ b/drivers/block/zram/zcomp_lzo.c +@@ -15,7 +15,7 @@ + + static void *lzo_create(void) + { +- return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); ++ return kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO); + } + + static void lzo_destroy(void *private) diff --git a/queue-4.3/zsmalloc-fix-migrate_zspage-zs_free-race-condition.patch b/queue-4.3/zsmalloc-fix-migrate_zspage-zs_free-race-condition.patch new file mode 100644 index 00000000000..2bb3977b491 --- /dev/null +++ b/queue-4.3/zsmalloc-fix-migrate_zspage-zs_free-race-condition.patch @@ -0,0 +1,96 @@ +From c102f07ca0b04f2cb49cfc161c83f6239d17f491 Mon Sep 17 00:00:00 2001 +From: Junil Lee +Date: Wed, 20 Jan 2016 14:58:18 -0800 +Subject: zsmalloc: fix migrate_zspage-zs_free race condition + +From: Junil Lee + +commit c102f07ca0b04f2cb49cfc161c83f6239d17f491 upstream. + +record_obj() in migrate_zspage() does not preserve handle's +HANDLE_PIN_BIT, set by find_aloced_obj()->trypin_tag(), and implicitly +(accidentally) un-pins the handle, while migrate_zspage() still performs +an explicit unpin_tag() on the that handle. This additional explicit +unpin_tag() introduces a race condition with zs_free(), which can pin +that handle by this time, so the handle becomes un-pinned. + +Schematically, it goes like this: + + CPU0 CPU1 + migrate_zspage + find_alloced_obj + trypin_tag + set HANDLE_PIN_BIT zs_free() + pin_tag() + obj_malloc() -- new object, no tag + record_obj() -- remove HANDLE_PIN_BIT set HANDLE_PIN_BIT + unpin_tag() -- remove zs_free's HANDLE_PIN_BIT + +The race condition may result in a NULL pointer dereference: + + Unable to handle kernel NULL pointer dereference at virtual address 00000000 + CPU: 0 PID: 19001 Comm: CookieMonsterCl Tainted: + PC is at get_zspage_mapping+0x0/0x24 + LR is at obj_free.isra.22+0x64/0x128 + Call trace: + get_zspage_mapping+0x0/0x24 + zs_free+0x88/0x114 + zram_free_page+0x64/0xcc + zram_slot_free_notify+0x90/0x108 + swap_entry_free+0x278/0x294 + free_swap_and_cache+0x38/0x11c + unmap_single_vma+0x480/0x5c8 + unmap_vmas+0x44/0x60 + exit_mmap+0x50/0x110 + mmput+0x58/0xe0 + do_exit+0x320/0x8dc + do_group_exit+0x44/0xa8 + get_signal+0x538/0x580 + do_signal+0x98/0x4b8 + do_notify_resume+0x14/0x5c + +This patch keeps the lock bit in migration path and update value +atomically. + +Signed-off-by: Junil Lee +Signed-off-by: Minchan Kim +Acked-by: Vlastimil Babka +Cc: Sergey Senozhatsky +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/zsmalloc.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/mm/zsmalloc.c ++++ b/mm/zsmalloc.c +@@ -304,7 +304,12 @@ static void free_handle(struct zs_pool * + + static void record_obj(unsigned long handle, unsigned long obj) + { +- *(unsigned long *)handle = obj; ++ /* ++ * lsb of @obj represents handle lock while other bits ++ * represent object value the handle is pointing so ++ * updating shouldn't do store tearing. ++ */ ++ WRITE_ONCE(*(unsigned long *)handle, obj); + } + + /* zpool driver */ +@@ -1629,6 +1634,13 @@ static int migrate_zspage(struct zs_pool + free_obj = obj_malloc(d_page, class, handle); + zs_object_copy(free_obj, used_obj, class); + index++; ++ /* ++ * record_obj updates handle's value to free_obj and it will ++ * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which ++ * breaks synchronization using pin_tag(e,g, zs_free) so ++ * let's keep the lock bit. ++ */ ++ free_obj |= BIT(HANDLE_PIN_BIT); + record_obj(handle, free_obj); + unpin_tag(handle); + obj_free(pool, class, used_obj); -- 2.47.3