/* * Return a path relative to our root. */ char * umsdos_d_path(struct dentry *dentry, char * buffer, int len) { struct dentry * old_root; char * path; read_lock(¤t->fs->lock); old_root = dget(current->fs->root); read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */ spin_unlock(&dcache_lock); if (IS_ERR(path)) return path; if (*path == '/') path++; /* skip leading '/' */ if (current->fs->root->d_inode == pseudo_root) { *(path-1) = '/'; path -= (UMSDOS_PSDROOT_LEN+1); memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN); } dput(old_root); return path; }
static int _xx_realpath_from_path(struct path *path, char *newname, int newname_len) { struct dentry *dentry = path->dentry; int error = -ENOMEM; char *sp; if (!dentry || !path->mnt || !newname || newname_len <= 2048) return -EINVAL; if (dentry->d_op && dentry->d_op->d_dname) { /* For "socket:[\$]" and "pipe:[\$]". */ static const int offset = 1536; sp = dentry->d_op->d_dname(dentry, newname + offset, newname_len - offset); } else { /* Taken from d_namespace_path(). */ struct path ns_root = { }; struct path root; struct path tmp; read_lock(¤t->fs->lock); root = current->fs->root; path_get(&root); read_unlock(¤t->fs->lock); spin_lock(&vfsmount_lock); if (root.mnt && root.mnt->mnt_ns) ns_root.mnt = mntget(root.mnt->mnt_ns->root); if (ns_root.mnt) ns_root.dentry = dget(ns_root.mnt->mnt_root); spin_unlock(&vfsmount_lock); spin_lock(&dcache_lock); tmp = ns_root; sp = __d_path(path, &tmp, newname, newname_len); spin_unlock(&dcache_lock); path_put(&root); path_put(&ns_root); } if (IS_ERR(sp)) { error = PTR_ERR(sp); } else { error = _xx_encode(newname, sp - newname, sp); } #if 1 /* Append trailing '/' if dentry is a directory. */ if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) && *newname) { sp = newname + strlen(newname); if (*(sp - 1) != '/') { if (sp < newname + newname_len - 4) { *sp++ = '/'; *sp = '\0'; } else { error = -ENOMEM; } } } #endif return error; }
int _xx_realpath_from_path(struct path *path, char *newname, int newname_len) { int error = -ENOMEM; struct dentry *dentry = path->dentry; char *sp; if (!dentry || !path->mnt || !newname || newname_len <= 2048) return -EINVAL; if (dentry->d_op && dentry->d_op->d_dname) { /* For "socket:[\$]" and "pipe:[\$]". */ static const int offset = 1536; sp = dentry->d_op->d_dname(dentry, newname + offset, newname_len - offset); } else { struct path ns_root = {.mnt = NULL, .dentry = NULL}; spin_lock(&dcache_lock); /* go to whatever namespace root we are under */ sp = __d_path(path, &ns_root, newname, newname_len); spin_unlock(&dcache_lock); /* Prepend "/proc" prefix if using internal proc vfs mount. */ if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) && (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { sp -= 5; if (sp >= newname) memcpy(sp, "/proc", 5); else sp = ERR_PTR(-ENOMEM); } } if (IS_ERR(sp)) error = PTR_ERR(sp); else error = _xx_encode(newname, sp - newname, sp); /* Append trailing '/' if dentry is a directory. */ if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) && *newname) { sp = newname + strlen(newname); if (*(sp - 1) != '/') { if (sp < newname + newname_len - 4) { *sp++ = '/'; *sp = '\0'; } else { error = -ENOMEM; } } } return error; }
/** * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. * * @path: Pointer to "struct path". * @buffer: Pointer to buffer to return value in. * @buflen: Sizeof @buffer. * * Returns the buffer on success, an error code otherwise. * * If dentry is a directory, trailing '/' is appended. */ static char *tomoyo_get_absolute_path(struct path *path, char * const buffer, const int buflen) { char *pos = ERR_PTR(-ENOMEM); if (buflen >= 256) { struct path ns_root = { }; /* go to whatever namespace root we are under */ pos = __d_path(path, &ns_root, buffer, buflen - 1); if (!IS_ERR(pos) && *pos == '/' && pos[1]) { struct inode *inode = path->dentry->d_inode; if (inode && S_ISDIR(inode->i_mode)) { buffer[buflen - 2] = '/'; buffer[buflen - 1] = '\0'; } } } return pos; }
char * tux_print_path (tux_req_t *req, struct dentry *dentry, struct vfsmount *mnt, char *buf, unsigned int max_len) { char *res; struct dentry *cwd, *root; struct vfsmount *cwd_mnt, *rootmnt; cwd = dget(dentry); cwd_mnt = mntget(mnt); root = dget(req->docroot_dentry); rootmnt = mntget(req->docroot_mnt); spin_lock(&dcache_lock); res = __d_path(cwd, cwd_mnt, root, rootmnt, buf, max_len); spin_unlock(&dcache_lock); dput(cwd); mntput(cwd_mnt); dput(root); mntput(rootmnt); return res; }
/** * d_namespace_path - lookup a name associated with a given path * @path: path to lookup (NOT NULL) * @buf: buffer to store path to (NOT NULL) * @buflen: length of @buf * @name: Returns - pointer for start of path name with in @buf (NOT NULL) * @flags: flags controlling path lookup * * Handle path name lookup. * * Returns: %0 else error code if path lookup fails * When no error the path name is returned in @name which points to * to a position in @buf */ static int d_namespace_path(struct path *path, char *buf, int buflen, char **name, int flags) { struct path root, tmp; char *res; int connected, error = 0; /* Get the root we want to resolve too, released below */ if (flags & PATH_CHROOT_REL) { /* resolve paths relative to chroot */ get_fs_root(current->fs, &root); } else { /* resolve paths relative to namespace */ root.mnt = current->nsproxy->mnt_ns->root; root.dentry = root.mnt->mnt_root; path_get(&root); } tmp = root; res = __d_path(path, &tmp, buf, buflen); *name = res; /* handle error conditions - and still allow a partial path to * be returned. */ if (IS_ERR(res)) { error = PTR_ERR(res); *name = buf; goto out; } /* Handle two cases: * 1. A deleted dentry && profile is not allowing mediation of deleted * 2. On some filesystems, newly allocated dentries appear to the * security_path hooks as a deleted dentry except without an inode * allocated. */ if (d_unlinked(path->dentry) && path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) { error = -ENOENT; goto out; } /* Determine if the path is connected to the expected root */ connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt; /* If the path is not connected, * check if it is a sysctl and handle specially else remove any * leading / that __d_path may have returned. * Unless * specifically directed to connect the path, * OR * if in a chroot and doing chroot relative paths and the path * resolves to the namespace root (would be connected outside * of chroot) and specifically directed to connect paths to * namespace root. */ if (!connected) { /* is the disconnect path a sysctl? */ if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC && strncmp(*name, "/sys/", 5) == 0) { /* TODO: convert over to using a per namespace * control instead of hard coded /proc */ error = prepend(name, *name - buf, "/proc", 5); } else if (!(flags & PATH_CONNECT_PATH) && !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) && (tmp.mnt == current->nsproxy->mnt_ns->root && tmp.dentry == tmp.mnt->mnt_root))) { /* disconnected path, don't return pathname starting * with '/' */ error = -ESTALE; if (*res == '/') *name = res + 1; } } out: path_put(&root); return error; }
/** * d_namespace_path - lookup a name associated with a given path * @path: path to lookup (NOT NULL) * @buf: buffer to store path to (NOT NULL) * @buflen: length of @buf * @name: Returns - pointer for start of path name with in @buf (NOT NULL) * @flags: flags controlling path lookup * * Handle path name lookup. * * Returns: %0 else error code if path lookup fails * When no error the path name is returned in @name which points to * to a position in @buf */ static int d_namespace_path(struct path *path, char *buf, int buflen, char **name, int flags) { char *res; int error = 0; int connected = 1; if (path->mnt->mnt_flags & MNT_INTERNAL) { /* it's not mounted anywhere */ res = dentry_path(path->dentry, buf, buflen); *name = res; if (IS_ERR(res)) { *name = buf; return PTR_ERR(res); } if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC && strncmp(*name, "/sys/", 5) == 0) { /* TODO: convert over to using a per namespace * control instead of hard coded /proc */ return prepend(name, *name - buf, "/proc", 5); } return 0; } /* resolve paths relative to chroot?*/ if (flags & PATH_CHROOT_REL) { struct path root; get_fs_root(current->fs, &root); res = __d_path(path, &root, buf, buflen); path_put(&root); } else { res = d_absolute_path(path, buf, buflen); if (!our_mnt(path->mnt)) connected = 0; } /* handle error conditions - and still allow a partial path to * be returned. */ if (!res || IS_ERR(res)) { connected = 0; res = dentry_path_raw(path->dentry, buf, buflen); if (IS_ERR(res)) { error = PTR_ERR(res); *name = buf; goto out; }; } else if (!our_mnt(path->mnt)) connected = 0; *name = res; /* Handle two cases: * 1. A deleted dentry && profile is not allowing mediation of deleted * 2. On some filesystems, newly allocated dentries appear to the * security_path hooks as a deleted dentry except without an inode * allocated. */ if (d_unlinked(path->dentry) && path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) { error = -ENOENT; goto out; } /* If the path is not connected to the expected root, * check if it is a sysctl and handle specially else remove any * leading / that __d_path may have returned. * Unless * specifically directed to connect the path, * OR * if in a chroot and doing chroot relative paths and the path * resolves to the namespace root (would be connected outside * of chroot) and specifically directed to connect paths to * namespace root. */ if (!connected) { if (!(flags & PATH_CONNECT_PATH) && !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) && our_mnt(path->mnt))) { /* disconnected path, don't return pathname starting * with '/' */ error = -ESTALE; if (*res == '/') *name = res + 1; } } out: return error; }
/** * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root. * * @path: Pointer to "struct path". * @newname: Pointer to buffer to return value in. * @newname_len: Size of @newname. * * Returns 0 on success, negative value otherwise. * * If dentry is a directory, trailing '/' is appended. * Characters out of 0x20 < c < 0x7F range are converted to * \ooo style octal string. * Character \ is converted to \\ string. */ int tomoyo_realpath_from_path2(struct path *path, char *newname, int newname_len) { int error = -ENOMEM; struct dentry *dentry = path->dentry; char *sp; if (!dentry || !path->mnt || !newname || newname_len <= 2048) return -EINVAL; if (dentry->d_op && dentry->d_op->d_dname) { /* For "socket:[\$]" and "pipe:[\$]". */ static const int offset = 1536; sp = dentry->d_op->d_dname(dentry, newname + offset, newname_len - offset); } else { /* Taken from d_namespace_path(). */ struct path root; struct path ns_root = { }; struct path tmp; read_lock(¤t->fs->lock); root = current->fs->root; path_get(&root); read_unlock(¤t->fs->lock); spin_lock(&vfsmount_lock); if (root.mnt && root.mnt->mnt_ns) ns_root.mnt = mntget(root.mnt->mnt_ns->root); if (ns_root.mnt) ns_root.dentry = dget(ns_root.mnt->mnt_root); spin_unlock(&vfsmount_lock); spin_lock(&dcache_lock); tmp = ns_root; sp = __d_path(path, &tmp, newname, newname_len); spin_unlock(&dcache_lock); path_put(&root); path_put(&ns_root); /* Prepend "/proc" prefix if using internal proc vfs mount. */ if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) { sp -= 5; if (sp >= newname) memcpy(sp, "/proc", 5); else sp = ERR_PTR(-ENOMEM); } } if (IS_ERR(sp)) error = PTR_ERR(sp); else error = tomoyo_encode(newname, sp - newname, sp); /* Append trailing '/' if dentry is a directory. */ if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) && *newname) { sp = newname + strlen(newname); if (*(sp - 1) != '/') { if (sp < newname + newname_len - 4) { *sp++ = '/'; *sp = '\0'; } else { error = -ENOMEM; } } } if (error) printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); return error; }
/** * d_namespace_path - lookup a name associated with a given path * @path: path to lookup (NOT NULL) * @buf: buffer to store path to (NOT NULL) * @buflen: length of @buf * @name: return pointer for start of path name with in @buf (NOT NULL) * @flags: flags controling path lookup * * Handle path name lookup. * * Returns: %0 else error code if path lookup fails * When no error the path name is returned in @name which points to * to a position in @buf */ static int d_namespace_path(struct path *path, char *buf, int buflen, char **name, int flags) { struct path root, tmp; char *res; int deleted, connected; int error = 0; /* Get the root we want to resolve too */ if (flags & PATH_CHROOT_REL) { /* resolve paths relative to chroot */ read_lock(¤t->fs->lock); root = current->fs->root; /* released below */ path_get(&root); read_unlock(¤t->fs->lock); } else { /* resolve paths relative to namespace */ root.mnt = current->nsproxy->mnt_ns->root; root.dentry = root.mnt->mnt_root; /* released below */ path_get(&root); } spin_lock(&dcache_lock); /* There is a race window between path lookup here and the * need to strip the " (deleted) string that __d_path applies * Detect the race and relookup the path * * The stripping of (deleted) is a hack that could be removed * with an updated __d_path */ do { tmp = root; deleted = d_unlinked(path->dentry); res = __d_path(path, &tmp, buf, buflen); } while (deleted != d_unlinked(path->dentry)); spin_unlock(&dcache_lock); *name = res; /* handle error conditions - and still allow a partial path to * be returned. */ if (IS_ERR(res)) { error = PTR_ERR(res); *name = buf; goto out; } if (deleted) { /* On some filesystems, newly allocated dentries appear to the * security_path hooks as a deleted dentry except without an * inode allocated. * * Remove the appended deleted text and return as string for * normal mediation, or auditing. The (deleted) string is * guarenteed to be added in this case, so just strip it. */ buf[buflen - 11] = 0; /* - (len(" (deleted)") +\0) */ if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) { error = -ENOENT; goto out; } } /* Determine if the path is connected to the expected root */ connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt; /* If the path is not connected, then remove any leading / that * __d_path may have returned. * Unless * specifically directed to connect the path, * OR * if in a chroot and doing chroot relative paths and the path * resolves to the namespace root (would be connected outside * of chroot) and specifically directed to connect paths to * namespace root. */ if (!connected && !(flags & PATH_CONNECT_PATH) && !((flags & PATH_CHROOT_REL) && (flags & PATH_CHROOT_NSCONNECT) && (tmp.mnt == current->nsproxy->mnt_ns->root && tmp.dentry == current->nsproxy->mnt_ns->root->mnt_root))) { /* disconnected path, don't return pathname starting with '/' */ error = -ESTALE; if (*res == '/') *name = res + 1; } out: path_put(&root); return error; }