mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
144 lines
4.6 KiB
Diff
144 lines
4.6 KiB
Diff
From: John Johansen <jjohansen@suse.de>
|
|
Subject: Fix __d_path to allow for old and new behavior bnc#380763
|
|
|
|
Fix __d_path so that it can be told whether or not to connect
|
|
disconnect path to the root. This is easier and more efficient
|
|
than trying to reconnect these paths for d_path and get_cwd
|
|
after the fact.
|
|
|
|
Signed-off-by: John Johansen <jjohansen@suse.de>
|
|
|
|
---
|
|
fs/dcache.c | 57 ++++++++++++++++++-------------------------------
|
|
fs/namespace.c | 2 -
|
|
include/linux/dcache.h | 2 -
|
|
3 files changed, 24 insertions(+), 37 deletions(-)
|
|
|
|
--- a/fs/dcache.c
|
|
+++ b/fs/dcache.c
|
|
@@ -1772,6 +1772,7 @@ shouldnt_be_hashed:
|
|
* @buffer: buffer to return value in
|
|
* @buflen: buffer length
|
|
* @fail_deleted: what to return for deleted files
|
|
+ * @disconnect: don't return a path starting with / when disconnected
|
|
*
|
|
* Convert a dentry into an ASCII path name. If the entry has been deleted,
|
|
* then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
|
|
@@ -1784,9 +1785,10 @@ shouldnt_be_hashed:
|
|
*/
|
|
char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
|
struct dentry *root, struct vfsmount *rootmnt,
|
|
- char *buffer, int buflen, int fail_deleted)
|
|
+ char *buffer, int buflen, int fail_deleted, int disconnect)
|
|
{
|
|
- int namelen, is_slash, vfsmount_locked = 0;
|
|
+ int namelen, vfsmount_locked = 0;
|
|
+ const unsigned char *name;
|
|
|
|
if (buflen < 2)
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
@@ -1847,27 +1849,26 @@ global_root:
|
|
* unconnected dentry, or the file is on a pseudo filesystem.
|
|
*/
|
|
namelen = dentry->d_name.len;
|
|
- is_slash = (namelen == 1 && *dentry->d_name.name == '/');
|
|
- if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
|
|
- /*
|
|
- * Make sure we won't return a pathname starting with '/'.
|
|
- *
|
|
- * Historically, we also glue together the root dentry and
|
|
- * remaining name for pseudo filesystems like pipefs, which
|
|
- * have the MS_NOUSER flag set. This results in pathnames
|
|
- * like "pipe:[439336]".
|
|
- */
|
|
- if (*buffer == '/') {
|
|
- buffer++;
|
|
- buflen++;
|
|
- }
|
|
- if (is_slash)
|
|
- goto out;
|
|
+ name = dentry->d_name.name;
|
|
+
|
|
+ /*
|
|
+ * If this is a root dentry, then overwrite the slash. This
|
|
+ * will also DTRT with pseudo filesystems which have root
|
|
+ * dentries named "foo:".
|
|
+ */
|
|
+ if (IS_ROOT(dentry)) {
|
|
+ buffer++;
|
|
+ buflen++;
|
|
+ }
|
|
+ if (disconnect && *name == '/') {
|
|
+ /* Make sure we won't return a pathname starting with '/' */
|
|
+ name++;
|
|
+ namelen--;
|
|
}
|
|
if (buflen < namelen)
|
|
goto Elong;
|
|
buffer -= namelen;
|
|
- memcpy(buffer, dentry->d_name.name, namelen);
|
|
+ memcpy(buffer, name, namelen);
|
|
goto out;
|
|
|
|
Elong:
|
|
@@ -1875,18 +1876,6 @@ Elong:
|
|
goto out;
|
|
}
|
|
|
|
-static char *__connect_d_path(char *path, char *buffer)
|
|
-{
|
|
- if (!IS_ERR(path) && *path != '/') {
|
|
- /* Pretend that disconnected paths are hanging off the root. */
|
|
- if (path == buffer)
|
|
- path = ERR_PTR(-ENAMETOOLONG);
|
|
- else
|
|
- *--path = '/';
|
|
- }
|
|
- return path;
|
|
-}
|
|
-
|
|
/* write full pathname into buffer and return start of pathname */
|
|
char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
|
|
int buflen)
|
|
@@ -1909,8 +1898,7 @@ char *d_path(struct dentry *dentry, stru
|
|
rootmnt = mntget(current->fs->rootmnt);
|
|
root = dget(current->fs->root);
|
|
read_unlock(¤t->fs->lock);
|
|
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
|
|
- res = __connect_d_path(res, buf);
|
|
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0, 0);
|
|
dput(root);
|
|
mntput(rootmnt);
|
|
return res;
|
|
@@ -1972,8 +1960,7 @@ asmlinkage long sys_getcwd(char __user *
|
|
root = dget(current->fs->root);
|
|
read_unlock(¤t->fs->lock);
|
|
|
|
- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
|
|
- cwd = __connect_d_path(cwd, page);
|
|
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1, 0);
|
|
error = PTR_ERR(cwd);
|
|
if (IS_ERR(cwd))
|
|
goto out;
|
|
--- a/fs/namespace.c
|
|
+++ b/fs/namespace.c
|
|
@@ -1901,7 +1901,7 @@ char *d_namespace_path(struct dentry *de
|
|
mntput(rootmnt);
|
|
if (nsrootmnt)
|
|
root = dget(nsrootmnt->mnt_root);
|
|
- res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1);
|
|
+ res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1, 1);
|
|
dput(root);
|
|
mntput(nsrootmnt);
|
|
/* Prevent empty path for lazily unmounted filesystems. */
|
|
--- a/include/linux/dcache.h
|
|
+++ b/include/linux/dcache.h
|
|
@@ -301,7 +301,7 @@ extern int d_validate(struct dentry *, s
|
|
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
|
|
|
|
extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *,
|
|
- struct vfsmount *, char *, int, int);
|
|
+ struct vfsmount *, char *, int, int, int);
|
|
extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
|
|
|
|
/* Allocation counts.. */
|