diff --git a/dcache-Handle-escaped-paths-in-prepend_path.patch b/dcache-Handle-escaped-paths-in-prepend_path.patch new file mode 100644 index 000000000..d5040607d --- /dev/null +++ b/dcache-Handle-escaped-paths-in-prepend_path.patch @@ -0,0 +1,65 @@ +From c0ea161a6e7158281f64bc6d41126da43cb08f14 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Sat, 15 Aug 2015 13:36:12 -0500 +Subject: [PATCH 1/2] dcache: Handle escaped paths in prepend_path + +commit cde93be45a8a90d8c264c776fab63487b5038a65 upstream. + +A rename can result in a dentry that by walking up d_parent +will never reach it's mnt_root. For lack of a better term +I call this an escaped path. + +prepend_path is called by four different functions __d_path, +d_absolute_path, d_path, and getcwd. + +__d_path only wants to see paths are connected to the root it passes +in. So __d_path needs prepend_path to return an error. + +d_absolute_path similarly wants to see paths that are connected to +some root. Escaped paths are not connected to any mnt_root so +d_absolute_path needs prepend_path to return an error greater +than 1. So escaped paths will be treated like paths on lazily +unmounted mounts. + +getcwd needs to prepend "(unreachable)" so getcwd also needs +prepend_path to return an error. + +d_path is the interesting hold out. d_path just wants to print +something, and does not care about the weird cases. Which raises +the question what should be printed? + +Given that / should result in -ENOENT I +believe it is desirable for escaped paths to be printed as empty +paths. As there are not really any meaninful path components when +considered from the perspective of a mount tree. + +So tweak prepend_path to return an empty path with an new error +code of 3 when it encounters an escaped path. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Al Viro +--- + fs/dcache.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/fs/dcache.c b/fs/dcache.c +index 9b5fe503f6cb..e3b44ca75a1b 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2926,6 +2926,13 @@ restart: + + if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { + struct mount *parent = ACCESS_ONCE(mnt->mnt_parent); ++ /* Escaped? */ ++ if (dentry != vfsmnt->mnt_root) { ++ bptr = *buffer; ++ blen = *buflen; ++ error = 3; ++ break; ++ } + /* Global root? */ + if (mnt != parent) { + dentry = ACCESS_ONCE(mnt->mnt_mountpoint); +-- +2.4.3 + diff --git a/kernel.spec b/kernel.spec index a314ae631..7e8fceb03 100644 --- a/kernel.spec +++ b/kernel.spec @@ -610,9 +610,6 @@ Patch509: ideapad-laptop-Add-Lenovo-Yoga-3-14-to-no_hw_rfkill-.patch #rhbz 1253789 Patch511: iSCSI-let-session-recovery_tmo-sysfs-writes-persist.patch -#rhbz 1256281 -Patch26265: mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch - #rhbz 1257534 Patch515: nv46-Change-mc-subdev-oclass-from-nv44-to-nv4c.patch @@ -632,6 +629,10 @@ Patch526: 0001-x86-cpu-cacheinfo-Fix-teardown-path.patch #CVE-2015-5257 rhbz 1265607 1265612 Patch527: USB-whiteheat-fix-potential-null-deref-at-probe.patch +#CVE-2015-2925 rhbz 1209367 1209373 +Patch528: dcache-Handle-escaped-paths-in-prepend_path.patch +Patch529: vfs-Test-for-and-handle-paths-that-are-unreachable-f.patch + # END OF PATCH DEFINITIONS %endif @@ -1359,12 +1360,6 @@ ApplyPatch ideapad-laptop-Add-Lenovo-Yoga-3-14-to-no_hw_rfkill-.patch #rhbz 1253789 ApplyPatch iSCSI-let-session-recovery_tmo-sysfs-writes-persist.patch -#rhbz 1250717 -ApplyPatch ext4-dont-manipulate-recovery-flag-when-freezing.patch - -#rhbz 1256281 -ApplyPatch mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch - #rhbz 1257534 ApplyPatch nv46-Change-mc-subdev-oclass-from-nv44-to-nv4c.patch @@ -1372,9 +1367,6 @@ ApplyPatch nv46-Change-mc-subdev-oclass-from-nv44-to-nv4c.patch ApplyPatch vmwgfx-Rework-device-initialization.patch ApplyPatch drm-vmwgfx-Allow-dropped-masters-render-node-like-ac.patch -#rhbz 1259231 -ApplyPatch make-flush-workqueue-available-to-non-GPL-modules.patch - #rhbz 1237136 ApplyPatch block-blkg_destroy_all-should-clear-q-root_blkg-and-.patch @@ -1389,6 +1381,10 @@ ApplyPatch USB-whiteheat-fix-potential-null-deref-at-probe.patch ApplyPatch regulator-axp20x-module-alias.patch +#CVE-2015-2925 rhbz 1209367 1209373 +ApplyPatch dcache-Handle-escaped-paths-in-prepend_path.patch +ApplyPatch vfs-Test-for-and-handle-paths-that-are-unreachable-f.patch + # END OF PATCH APPLICATIONS %endif @@ -2239,6 +2235,9 @@ fi # # %changelog +* Thu Oct 01 2015 Josh Boyer +- CVE-2015-2925 Don't allow bind mount escape (rhbz 1209367 1209373) + * Tue Sep 29 2015 Justin M. Forbes - - Linux v4.2.2 diff --git a/mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch b/mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch deleted file mode 100644 index c755534a0..000000000 --- a/mmc-sdhci-fix-dma-memory-leak-in-sdhci_pre_req.patch +++ /dev/null @@ -1,203 +0,0 @@ -From: Haibo Chen -Date: Tue, 25 Aug 2015 10:02:11 +0800 -Subject: [PATCH] mmc: sdhci: fix dma memory leak in sdhci_pre_req() - -Currently one mrq->data maybe execute dma_map_sg() twice -when mmc subsystem prepare over one new request, and the -following log show up: - sdhci[sdhci_pre_dma_transfer] invalid cookie: 24, next-cookie 25 - -In this condition, mrq->date map a dma-memory(1) in sdhci_pre_req -for the first time, and map another dma-memory(2) in sdhci_prepare_data -for the second time. But driver only unmap the dma-memory(2), and -dma-memory(1) never unmapped, which cause the dma memory leak issue. - -This patch use another method to map the dma memory for the mrq->data -which can fix this dma memory leak issue. - -Fixes: commit 348487cb28e66b0 ("mmc: sdhci: use pipeline mmc requests to improve performance") -Cc: stable@vger.kernel.org # 4.0+ -Reported-and-tested-by: Jiri Slaby -Signed-off-by: Haibo Chen ---- - drivers/mmc/host/sdhci.c | 67 ++++++++++++++++++------------------------------ - drivers/mmc/host/sdhci.h | 8 +++--- - 2 files changed, 29 insertions(+), 46 deletions(-) - -diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 1dbe932..ea10ebc 100644 ---- a/drivers/mmc/host/sdhci.c -+++ b/drivers/mmc/host/sdhci.c -@@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *); - static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); - static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); - static int sdhci_pre_dma_transfer(struct sdhci_host *host, -- struct mmc_data *data, -- struct sdhci_host_next *next); -+ struct mmc_data *data); - static int sdhci_do_get_cd(struct sdhci_host *host); - - #ifdef CONFIG_PM -@@ -496,7 +495,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, - goto fail; - BUG_ON(host->align_addr & host->align_mask); - -- host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); -+ host->sg_count = sdhci_pre_dma_transfer(host, data); - if (host->sg_count < 0) - goto unmap_align; - -@@ -635,9 +634,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, - } - } - -- if (!data->host_cookie) -+ if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); -+ data->host_cookie = COOKIE_UNMAPPED; -+ } - } - - static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) -@@ -833,7 +834,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) - } else { - int sg_cnt; - -- sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); -+ sg_cnt = sdhci_pre_dma_transfer(host, data); - if (sg_cnt <= 0) { - /* - * This only happens when someone fed -@@ -949,11 +950,13 @@ static void sdhci_finish_data(struct sdhci_host *host) - if (host->flags & SDHCI_USE_ADMA) - sdhci_adma_table_post(host, data); - else { -- if (!data->host_cookie) -+ if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); -+ data->host_cookie = COOKIE_UNMAPPED; -+ } - } - } - -@@ -2097,49 +2100,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, - struct mmc_data *data = mrq->data; - - if (host->flags & SDHCI_REQ_USE_DMA) { -- if (data->host_cookie) -+ if (data->host_cookie == COOKIE_GIVEN || -+ data->host_cookie == COOKIE_MAPPED) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); -- mrq->data->host_cookie = 0; -+ data->host_cookie = COOKIE_UNMAPPED; - } - } - - static int sdhci_pre_dma_transfer(struct sdhci_host *host, -- struct mmc_data *data, -- struct sdhci_host_next *next) -+ struct mmc_data *data) - { - int sg_count; - -- if (!next && data->host_cookie && -- data->host_cookie != host->next_data.cookie) { -- pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", -- __func__, data->host_cookie, host->next_data.cookie); -- data->host_cookie = 0; -+ if (data->host_cookie == COOKIE_MAPPED) { -+ data->host_cookie = COOKIE_GIVEN; -+ return data->sg_count; - } - -- /* Check if next job is already prepared */ -- if (next || -- (!next && data->host_cookie != host->next_data.cookie)) { -- sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, -- data->sg_len, -- data->flags & MMC_DATA_WRITE ? -- DMA_TO_DEVICE : DMA_FROM_DEVICE); -- -- } else { -- sg_count = host->next_data.sg_count; -- host->next_data.sg_count = 0; -- } -+ WARN_ON(data->host_cookie == COOKIE_GIVEN); - -+ sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, -+ data->flags & MMC_DATA_WRITE ? -+ DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (sg_count == 0) -- return -EINVAL; -+ return -ENOSPC; - -- if (next) { -- next->sg_count = sg_count; -- data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; -- } else -- host->sg_count = sg_count; -+ data->sg_count = sg_count; -+ data->host_cookie = COOKIE_MAPPED; - - return sg_count; - } -@@ -2149,16 +2139,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - { - struct sdhci_host *host = mmc_priv(mmc); - -- if (mrq->data->host_cookie) { -- mrq->data->host_cookie = 0; -- return; -- } -+ mrq->data->host_cookie = COOKIE_UNMAPPED; - - if (host->flags & SDHCI_REQ_USE_DMA) -- if (sdhci_pre_dma_transfer(host, -- mrq->data, -- &host->next_data) < 0) -- mrq->data->host_cookie = 0; -+ sdhci_pre_dma_transfer(host, mrq->data); - } - - static void sdhci_card_event(struct mmc_host *mmc) -@@ -3030,7 +3014,6 @@ int sdhci_add_host(struct sdhci_host *host) - host->max_clk = host->ops->get_max_clock(host); - } - -- host->next_data.cookie = 1; - /* - * In case of Host Controller v3.00, find out whether clock - * multiplier is supported. -diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h -index 5521d29..a9512a4 100644 ---- a/drivers/mmc/host/sdhci.h -+++ b/drivers/mmc/host/sdhci.h -@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc { - */ - #define SDHCI_MAX_SEGS 128 - --struct sdhci_host_next { -- unsigned int sg_count; -- s32 cookie; -+enum sdhci_cookie { -+ COOKIE_UNMAPPED, -+ COOKIE_MAPPED, -+ COOKIE_GIVEN, - }; - - struct sdhci_host { -@@ -503,7 +504,6 @@ struct sdhci_host { - unsigned int tuning_mode; /* Re-tuning mode supported by host */ - #define SDHCI_TUNING_MODE_1 0 - -- struct sdhci_host_next next_data; - unsigned long private[0] ____cacheline_aligned; - }; - diff --git a/vfs-Test-for-and-handle-paths-that-are-unreachable-f.patch b/vfs-Test-for-and-handle-paths-that-are-unreachable-f.patch new file mode 100644 index 000000000..f9e7e6e61 --- /dev/null +++ b/vfs-Test-for-and-handle-paths-that-are-unreachable-f.patch @@ -0,0 +1,110 @@ +From 14588dfe2e411056df5ba85ef88ad51730a2fa0a Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Sat, 15 Aug 2015 20:27:13 -0500 +Subject: [PATCH 2/2] vfs: Test for and handle paths that are unreachable from + their mnt_root + +commit 397d425dc26da728396e66d392d5dcb8dac30c37 upstream. + +In rare cases a directory can be renamed out from under a bind mount. +In those cases without special handling it becomes possible to walk up +the directory tree to the root dentry of the filesystem and down +from the root dentry to every other file or directory on the filesystem. + +Like division by zero .. from an unconnected path can not be given +a useful semantic as there is no predicting at which path component +the code will realize it is unconnected. We certainly can not match +the current behavior as the current behavior is a security hole. + +Therefore when encounting .. when following an unconnected path +return -ENOENT. + +- Add a function path_connected to verify path->dentry is reachable + from path->mnt.mnt_root. AKA to validate that rename did not do + something nasty to the bind mount. + + To avoid races path_connected must be called after following a path + component to it's next path component. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Al Viro +--- + fs/namei.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/fs/namei.c b/fs/namei.c +index 1c2105ed20c5..29b927938b8c 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -560,6 +560,24 @@ static int __nd_alloc_stack(struct nameidata *nd) + return 0; + } + ++/** ++ * path_connected - Verify that a path->dentry is below path->mnt.mnt_root ++ * @path: nameidate to verify ++ * ++ * Rename can sometimes move a file or directory outside of a bind ++ * mount, path_connected allows those cases to be detected. ++ */ ++static bool path_connected(const struct path *path) ++{ ++ struct vfsmount *mnt = path->mnt; ++ ++ /* Only bind mounts can have disconnected paths */ ++ if (mnt->mnt_root == mnt->mnt_sb->s_root) ++ return true; ++ ++ return is_subdir(path->dentry, mnt->mnt_root); ++} ++ + static inline int nd_alloc_stack(struct nameidata *nd) + { + if (likely(nd->depth != EMBEDDED_LEVELS)) +@@ -1296,6 +1314,8 @@ static int follow_dotdot_rcu(struct nameidata *nd) + return -ECHILD; + nd->path.dentry = parent; + nd->seq = seq; ++ if (unlikely(!path_connected(&nd->path))) ++ return -ENOENT; + break; + } else { + struct mount *mnt = real_mount(nd->path.mnt); +@@ -1396,7 +1416,7 @@ static void follow_mount(struct path *path) + } + } + +-static void follow_dotdot(struct nameidata *nd) ++static int follow_dotdot(struct nameidata *nd) + { + if (!nd->root.mnt) + set_root(nd); +@@ -1412,6 +1432,8 @@ static void follow_dotdot(struct nameidata *nd) + /* rare case of legitimate dget_parent()... */ + nd->path.dentry = dget_parent(nd->path.dentry); + dput(old); ++ if (unlikely(!path_connected(&nd->path))) ++ return -ENOENT; + break; + } + if (!follow_up(&nd->path)) +@@ -1419,6 +1441,7 @@ static void follow_dotdot(struct nameidata *nd) + } + follow_mount(&nd->path); + nd->inode = nd->path.dentry->d_inode; ++ return 0; + } + + /* +@@ -1634,7 +1657,7 @@ static inline int handle_dots(struct nameidata *nd, int type) + if (nd->flags & LOOKUP_RCU) { + return follow_dotdot_rcu(nd); + } else +- follow_dotdot(nd); ++ return follow_dotdot(nd); + } + return 0; + } +-- +2.4.3 +