vfs: Test for and handle paths that are unreachable from their mnt_root
A message that is not in the archive (sent off-list or not yet received): abcd326bbd6833b04b56738cd1734419@local
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "Eric W. Biederman" <[email protected]>
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.
--- fs/namei.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-)
fs/namei.c +29 -3
@@ -434,6 +434,24 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name,return dentry; } +/** +* 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); +} +/* * Short-cut version of permission(), for calling by * path_walk(), when dcache lock is held. Combines parts
@@ -754,7 +772,7 @@ int follow_down(struct path *path)return 0 ; } -static __always_inline void follow_dotdot(struct nameidata *nd) +static __always_inline int follow_dotdot(struct nameidata *nd) {set_root (nd);
@@ -771,6 +789,8 @@ static __always_inline void follow_dotdot(struct nameidata *nd) nd->path.dentry =dget (nd->path.dentry->d_parent);spin_unlock (&dcache_lock);dput (old); +if (unlikely (!path_connected (&nd->path))) +return -ENOENT ;break ; }spin_unlock (&dcache_lock);
@@ -788,6 +808,7 @@ static __always_inline void follow_dotdot(struct nameidata *nd) nd->path.mnt = parent; }follow_mount (&nd->path); +return 0 ; }/*
@@ -905,7 +926,9 @@ static int __link_path_walk(const char *name, struct nameidata *nd)case 2 :if (this.name[1 ] !='.' )break ; -follow_dotdot (nd); + err =follow_dotdot (nd); +if (err <0 ) + goto out_nd_path_put; inode = nd->path.dentry->d_inode;/* fallthrough */ case 1 :
@@ -960,7 +983,9 @@ last_component:case 2 :if (this.name[1 ] !='.' )break ; -follow_dotdot (nd); + err =follow_dotdot (nd); +if (err <0 ) + goto out_nd_path_put; inode = nd->path.dentry->d_inode;/* fallthrough */ case 1 :
@@ -1022,6 +1047,7 @@ out_dput:path_put_conditional (&next, nd);break ; } +out_nd_path_put:path_put (&nd->path); return_err:return err;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 19/38 pagemap: hide physical addresses from non-privileged users
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Khlebnikov <[email protected]>
commit 1c90308e7a77af6742a97d1021cca923b23b7f0d upstream.
This patch makes pagemap readable for normal users and hides physical addresses from them. For some use-cases PFN isn't required at all.
See http://lkml.kernel.org/r/[email protected]
[bwh: Backported to 3.2:
- Add the same check in the places where we look up a PFN
- Add struct pagemapread * parameters where necessary
- Open-code file_ns_capable()
- Delete pagemap_open() entirely, as it would always return 0]
[wt: adjusted context, no pagemap_hugetlb_range() in 2.6.32, needs
cred argument to security_capable(), tested OK ]
--- fs/proc/task_mmu.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-)
fs/proc/task_mmu.c +8 -13
@@ -8,6 +8,7 @@#include <linux/mempolicy.h> #include <linux/swap.h> #include <linux/swapops.h> +#include <linux/security.h> #include <asm/elf.h> #include <asm/uaccess.h>
@@ -539,6 +540,7 @@ const struct file_operations proc_clear_refs_operations = {struct pagemapread {u64 __user *out, *end; +bool show_pfn; };#define PM_ENTRY_BYTES sizeof(u64)
@@ -589,14 +591,14 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte)return swp_type (e) | (swp_offset (e) <<MAX_SWAPFILES_SHIFT ); } -static u64 pte_to_pagemap_entry (pte_t pte) +static u64 pte_to_pagemap_entry (struct pagemapread *pm,pte_t pte) {u64 pme =0 ;if (is_swap_pte (pte)) pme =PM_PFRAME (swap_pte_to_pagemap_entry (pte)) |PM_PSHIFT (PAGE_SHIFT ) |PM_SWAP ;else if (pte_present (pte)) - pme =PM_PFRAME (pte_pfn (pte)) + pme = (pm->show_pfn ?PM_PFRAME (pte_pfn (pte)) :0 ) |PM_PSHIFT (PAGE_SHIFT ) |PM_PRESENT ;return pme; }
@@ -624,7 +626,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,if (vma && (vma->vm_start <= addr) && !is_vm_hugetlb_page (vma)) { pte =pte_offset_map (pmd, addr); - pfn =pte_to_pagemap_entry (*pte); + pfn =pte_to_pagemap_entry (pm, *pte);/* unmap before userspace copy */ pte_unmap (pte); }
@@ -695,6 +697,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,if (!count) goto out_task; +/* do not disclose physical addresses: attack vector */ + pm.show_pfn = !security_capable (file->f_cred,CAP_SYS_ADMIN ); + mm =get_task_mm (task);if (!mm) goto out_task;
@@ -773,19 +778,9 @@ out: return ret; } -static int pagemap_open (struct inode *inode,struct file *file) -{ -/* do not disclose physical addresses to unprivileged -userspace (closes a rowhammer attack vector) */ -if (!capable (CAP_SYS_ADMIN )) -return -EPERM ; -return 0 ; -} -const struct file_operations proc_pagemap_operations = { .llseek = mem_lseek,/* borrow this */ .read = pagemap_read, - .open = pagemap_open, };#endif /* CONFIG_PROC_PAGE_MONITOR */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
[PATCH 2.6.32 40/38] security: add cred argument to security_capable()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Chris Wright <[email protected]>
commit 6037b715d6fab139742c3df8851db4c823081561 upstream.
Expand security_capable() to include cred, so that it can be usable in a wider range of call sites.
--- include/linux/security.h | 6 +++--- kernel/capability.c | 2 +- security/security.c | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-)
include/linux/security.h +3 -3
@@ -1733,7 +1733,7 @@ int security_capset(struct cred *new, const struct cred *old,const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); -int security_capable (int cap); +int security_capable (const struct cred *cred,int cap);int security_real_capable (struct task_struct *tsk,int cap);int security_real_capable_noaudit (struct task_struct *tsk,int cap);int security_acct (struct file *file);
@@ -1938,9 +1938,9 @@ static inline int security_capset(struct cred *new,return cap_capset (new, old, effective, inheritable, permitted); } -static inline int security_capable (int cap) +static inline int security_capable (const struct cred *cred,int cap) { -return cap_capable (current,current_cred (), cap,SECURITY_CAP_AUDIT ); +return cap_capable (current, cred, cap,SECURITY_CAP_AUDIT ); }static inline int security_real_capable (struct task_struct *tsk,int cap)
kernel/capability.c +1 -1
@@ -305,7 +305,7 @@ int capable(int cap)BUG (); } -if (security_capable (cap) ==0 ) { +if (security_capable (current_cred (), cap) ==0 ) { current->flags |=PF_SUPERPRIV ;return 1 ; }
security/security.c +2 -3
@@ -151,10 +151,9 @@ int security_capset(struct cred *new, const struct cred *old, effective, inheritable, permitted); } -int security_capable (int cap) +int security_capable (const struct cred *cred,int cap) { -return security_ops->capable (current,current_cred (), cap, -SECURITY_CAP_AUDIT ); +return security_ops->capable (current, cred, cap,SECURITY_CAP_AUDIT ); }int security_real_capable (struct task_struct *tsk,int cap)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [PATCH 2.6.32 00/38] 2.6.32.69-longterm review
In reply to a message not in the archiveQuoted 21 lines · Willy Tarreau
Here comes 2.6.32.69-rc2.
It adds or replaces the following patches on top of -rc1 that were needed or incorrectly backported as spotted by Ben :
Chris Wright (1):
security: add cred argument tosecurity_capable()Eric W. Biederman (1):
vfs: Test for and handle paths that are unreachable from theirmnt_rootKonstantin Khlebnikov (1):
pagemap: hide physical addresses from non-privileged usersThese patches will be posted as a response to this one (with 39 and 40 being the extra ones). If anyone has any issue with these being applied, please let me know. If anyone is a maintainer of the proper subsystem, and wants to add a Signed-off-by: line to the patch, please respond with it. If anyone thinks some important patches are missing and should be added prior to the release, please report them quickly with their respective mainline commit IDs.
Quoted 4 lines
Last response delay remains unchanged : Sat Dec 5 22:47:02 CET 2015.
The updated patch series can be found in one patch at :
https://kernel.org/pub/linux/kernel/v2.6/longterm-review/patch-2.6.32.69-rc2.gz
I've applied this to the Debian 6.0 kernel source, and all looks good.
Ben.
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [PATCH 2.6.32 00/38] 2.6.32.69-longterm review
Quoted 22 lines · Ben Hutchings
Quoted 21 lines · Willy Tarreau
Here comes 2.6.32.69-rc2.
It adds or replaces the following patches on top of -rc1 that were needed or incorrectly backported as spotted by Ben :
� Chris Wright (1):
������security: add cred argument tosecurity_capable()� Eric W. Biederman (1):
������vfs: Test for and handle paths that are unreachable from theirmnt_root� Konstantin Khlebnikov (1):
������pagemap: hide physical addresses from non-privileged usersThese patches will be posted as a response to this one (with 39 and 40 being the extra ones). If anyone has any issue with these being applied, please let me know. If anyone is a maintainer of the proper subsystem, and wants to add a Signed-off-by: line to the patch, please respond with it. If anyone thinks some important patches are missing and should be added prior to the release, please report them quickly with their respective mainline commit IDs.
Quoted 6 lines
Quoted 4 lines
Last response delay remains unchanged : Sat Dec��5 22:47:02 CET 2015.
The updated patch series can be found in one patch at :
�����https://kernel.org/pub/linux/kernel/v2.6/longterm-review/patch-2.6.32.69-rc2.gzI've applied this to the Debian 6.0 kernel source, and all looks good.
Thanks for the feedback Ben!
Willy