static void * zpl_follow_link(struct dentry *dentry, struct nameidata *nd) { cred_t *cr = CRED(); struct inode *ip = dentry->d_inode; struct iovec iov; uio_t uio; char *link; int error; crhold(cr); iov.iov_len = MAXPATHLEN; iov.iov_base = link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = (MAXPATHLEN - 1); uio.uio_segflg = UIO_SYSSPACE; error = -zfs_readlink(ip, &uio, cr); if (error) { kmem_free(link, MAXPATHLEN); nd_set_link(nd, ERR_PTR(error)); } else { nd_set_link(nd, link); } crfree(cr); return (NULL); }
static void * ospfs_follow_link(struct dentry *dentry, struct nameidata *nd) { ospfs_symlink_inode_t *oi = (ospfs_symlink_inode_t *) ospfs_inode(dentry->d_inode->i_ino); // check for conditional symlink if (strncmp(oi->oi_symlink, "root?", 5) == 0) { // find the pivot between first and second paths int pivot = strchr(oi->oi_symlink, ':') - oi->oi_symlink; // root user if (current->uid == 0) { // use null-terminator to indicate ending oi->oi_symlink[pivot] = '\0'; nd_set_link(nd, oi->oi_symlink + 5 + 1); // use first path } // normal user else nd_set_link(nd, oi->oi_symlink + pivot + 1); // use second path } else nd_set_link(nd, oi->oi_symlink); return (void *) 0; }
/* * careful here - this function can get called recursively, so * we need to be very careful about how much stack we use. * uio is kmalloced for this reason... */ STATIC void * xfs_vn_follow_link( struct dentry *dentry, struct nameidata *nd) { char *link; int error = -ENOMEM; link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); if (!link) goto out_err; error = -xfs_readlink(XFS_I(dentry->d_inode), link); if (unlikely(error)) goto out_kfree; nd_set_link(nd, link); return NULL; out_kfree: kfree(link); out_err: nd_set_link(nd, ERR_PTR(error)); return NULL; }
static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; struct page *page; void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode)); if (err) goto read_failed; page = read_cache_page(&inode->i_data, 0, (filler_t *)nfs_symlink_filler, inode); if (IS_ERR(page)) { err = page; goto read_failed; } if (!PageUptodate(page)) { err = ERR_PTR(-EIO); goto getlink_read_error; } nd_set_link(nd, kmap(page)); return page; getlink_read_error: page_cache_release(page); read_failed: nd_set_link(nd, err); return NULL; }
/* * careful here - this function can get called recursively, so * we need to be very careful about how much stack we use. * uio is kmalloced for this reason... */ STATIC void * linvfs_follow_link( struct dentry *dentry, struct nameidata *nd) { vnode_t *vp; uio_t *uio; iovec_t iov; int error; char *link; ASSERT(dentry); ASSERT(nd); link = (char *)kmalloc(MAXPATHLEN+1, GFP_KERNEL); if (!link) { nd_set_link(nd, ERR_PTR(-ENOMEM)); return NULL; } uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); if (!uio) { kfree(link); nd_set_link(nd, ERR_PTR(-ENOMEM)); return NULL; } vp = LINVFS_GET_VP(dentry->d_inode); iov.iov_base = link; iov.iov_len = MAXPATHLEN; uio->uio_iov = &iov; uio->uio_offset = 0; uio->uio_segflg = UIO_SYSSPACE; uio->uio_resid = MAXPATHLEN; uio->uio_iovcnt = 1; VOP_READLINK(vp, uio, 0, NULL, error); if (error) { kfree(link); link = ERR_PTR(-error); } else { link[MAXPATHLEN - uio->uio_resid] = '\0'; } kfree(uio); nd_set_link(nd, link); return NULL; }
static void * zpl_follow_link(struct dentry *dentry, struct nameidata *nd) { char *link = NULL; int error; error = zpl_get_link_common(dentry, dentry->d_inode, &link); if (error) nd_set_link(nd, ERR_PTR(error)); else nd_set_link(nd, link); return (NULL); }
static void * v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd) { int retval; struct p9_fid *fid; char *link = __getname(); char *target; P9_DPRINTK(P9_DEBUG_VFS, "%s\n", dentry->d_name.name); if (!link) { link = ERR_PTR(-ENOMEM); goto ndset; } fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) { __putname(link); link = ERR_CAST(fid); goto ndset; } retval = p9_client_readlink(fid, &target); if (!retval) { strcpy(link, target); kfree(target); goto ndset; } __putname(link); link = ERR_PTR(retval); ndset: nd_set_link(nd, link); return NULL; }
static void HgfsPutlink(struct dentry *dentry, // dentry struct nameidata *nd) // lookup name information #endif { char *fileName = NULL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) fileName = cookie; LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n", __func__, fileName)); #else LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n", __func__, dentry->d_name.name)); fileName = nd_get_link(nd); #endif if (!IS_ERR(fileName)) { LOG(6, (KERN_DEBUG "VMware hgfs: %s: putting %s\n", __func__, fileName)); kfree(fileName); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) nd_set_link(nd, NULL); #endif } }
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { unsigned char *buf; buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); nd_set_link(nd, buf); return 0; }
static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd) { int error = -ENOMEM; unsigned long page = get_zeroed_page(GFP_KERNEL); if (page) { error = configfs_getlink(dentry, (char *)page); if (!error) { nd_set_link(nd, (char *)page); return (void *)page; } } nd_set_link(nd, ERR_PTR(error)); return NULL; }
/** * vxfs_immed_follow_link - follow immed symlink * @dp: dentry for the link * @np: pathname lookup data for the current path walk * * Description: * vxfs_immed_follow_link restarts the pathname lookup with * the data obtained from @dp. * * Returns: * Zero on success, else a negative error code. */ static int vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) { struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); nd_set_link(np, vip->vii_immed.vi_immed); return 0; }
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *buf; int len = PAGE_SIZE, rc; mm_segment_t old_fs; /* Released in ecryptfs_put_link(); only release here on error */ buf = kmalloc(len, GFP_KERNEL); if (!buf) { buf = ERR_PTR(-ENOMEM); goto out; } old_fs = get_fs(); set_fs(get_ds()); rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); set_fs(old_fs); if (rc < 0) { kfree(buf); buf = ERR_PTR(rc); } else buf[rc] = '\0'; out: nd_set_link(nd, buf); return NULL; }
/** * vxfs_immed_follow_link - follow immed symlink * @dp: dentry for the link * @np: pathname lookup data for the current path walk * * Description: * vxfs_immed_follow_link restarts the pathname lookup with * the data obtained from @dp. * * Returns: * Zero on success, else a negative error code. */ static void * vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) { struct vxfs_inode_info *vip = VXFS_INO(d_inode(dp)); nd_set_link(np, vip->vii_immed.vi_immed); return NULL; }
static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd) # endif { struct inode *inode = dentry->d_inode; struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); struct sf_inode_info *sf_i = GET_INODE_INFO(inode); int error = -ENOMEM; char *path = (char*)get_zeroed_page(GFP_KERNEL); int rc; if (path) { error = 0; rc = vboxReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path); if (RT_FAILURE(rc)) { LogFunc(("vboxReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc)); free_page((unsigned long)path); error = -EPROTO; } } # if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) return error ? ERR_PTR(error) : (*cookie = path); # else nd_set_link(nd, error ? ERR_PTR(error) : path); return NULL; # endif }
static void * CVE_2011_2928_linux2_6_23_befs_follow_link(struct dentry *dentry, struct nameidata *nd) { befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); char *link; if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { struct super_block *sb = dentry->d_sb; befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; befs_debug(sb, "Follow long symlink"); link = kmalloc(len, GFP_NOFS); if (!link) { link = ERR_PTR(-ENOMEM); } else if (befs_read_lsymlink(sb, data, link, len) != len) { kfree(link); befs_error(sb, "Failed to read entire long symlink"); link = ERR_PTR(-EIO); } } else { link = befs_ino->i_data.symlink; } nd_set_link(nd, link); return NULL; }
static void * befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd) { befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); nd_set_link(nd, befs_ino->i_data.symlink); return NULL; }
static void *wrapfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *buf; int len = PAGE_SIZE, err; mm_segment_t old_fs; /* This is freed by the put_link method assuming a successful call. */ buf = kmalloc(len, GFP_KERNEL); if (!buf) { buf = ERR_PTR(-ENOMEM); goto out; } /* read the symlink, and then we will follow it */ old_fs = get_fs(); set_fs(KERNEL_DS); err = wrapfs_readlink(dentry, buf, len); set_fs(old_fs); if (err < 0) { kfree(buf); buf = ERR_PTR(err); } else { buf[err] = '\0'; } out: nd_set_link(nd, buf); return NULL; }
static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct exofs_i_info *oi = exofs_i(dentry->d_inode); nd_set_link(nd, (char *)oi->i_data); return NULL; }
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *buf; int len = PAGE_SIZE, rc; mm_segment_t old_fs; /* Released in ecryptfs_put_link(); only release here on error */ buf = kmalloc(len, GFP_KERNEL); if (!buf) { rc = -ENOMEM; goto out; } old_fs = get_fs(); set_fs(get_ds()); ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ " "dentry->d_name.name = [%s]\n", dentry->d_name.name); rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); set_fs(old_fs); if (rc < 0) goto out_free; else buf[rc] = '\0'; rc = 0; nd_set_link(nd, buf); goto out; out_free: kfree(buf); out: return ERR_PTR(rc); }
static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); char *p = (char *)f->target; /* * We don't acquire the f->sem mutex here since the only data we * use is f->target. * * 1. If we are here the inode has already built and f->target has * to point to the target path. * 2. Nobody uses f->target (if the inode is symlink's inode). The * exception is inode freeing function which frees f->target. But * it can't be called while we are here and before VFS has * stopped using our f->target string which we provide by means of * nd_set_link() call. */ if (!p) { printk(KERN_ERR "jffs2_follow_link(): can't find symlink target\n"); p = ERR_PTR(-EIO); } D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target)); nd_set_link(nd, p); /* * We will unlock the f->sem mutex but VFS will use the f->target string. This is safe * since the only way that may cause f->target to be changed is iput() operation. * But VFS will not use f->target after iput() has been called. */ return NULL; }
/* * The inode of symbolic link is different to data stream. * The data stream become link name. Unless the LONG_SYMLINK * flag is set. */ static void * befs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dentry->d_sb; befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; char *link; if (len == 0) { befs_error(sb, "Long symlink with illegal length"); link = ERR_PTR(-EIO); } else { befs_debug(sb, "Follow long symlink"); link = kmalloc(len, GFP_NOFS); if (!link) { link = ERR_PTR(-ENOMEM); } else if (befs_read_lsymlink(sb, data, link, len) != len) { kfree(link); befs_error(sb, "Failed to read entire long symlink"); link = ERR_PTR(-EIO); } else { link[len - 1] = '\0'; } } nd_set_link(nd, link); return NULL; }
const char * zpl_follow_link(struct dentry *dentry, void **symlink_cookie) #endif { cred_t *cr = CRED(); struct inode *ip = dentry->d_inode; struct iovec iov; uio_t uio; char *link; int error; fstrans_cookie_t cookie; crhold(cr); iov.iov_len = MAXPATHLEN; iov.iov_base = link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_skip = 0; uio.uio_resid = (MAXPATHLEN - 1); uio.uio_segflg = UIO_SYSSPACE; cookie = spl_fstrans_mark(); error = -zfs_readlink(ip, &uio, cr); spl_fstrans_unmark(cookie); if (error) kmem_free(link, MAXPATHLEN); crfree(cr); #ifdef HAVE_FOLLOW_LINK_NAMEIDATA if (error) nd_set_link(nd, ERR_PTR(error)); else nd_set_link(nd, link); return (NULL); #else if (error) return (ERR_PTR(error)); else return (*symlink_cookie = link); #endif }
static int HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link struct nameidata *nd) // OUT: Contains target dentry #endif { HgfsAttrInfo attr; char *fileName = NULL; int error; ASSERT(dentry); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ASSERT(nd); #endif if (!dentry) { LOG(4, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: null input\n")); error = -EINVAL; goto out; } LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling HgfsPrivateGetattr %s\n", __func__, dentry->d_name.name)); error = HgfsPrivateGetattr(dentry, &attr, &fileName); LOG(6, (KERN_DEBUG "VMware hgfs: %s: HgfsPrivateGetattr %s ret %d\n", __func__, dentry->d_name.name, error)); if (!error) { /* Let's make sure we got called on a symlink. */ if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called " "on something that wasn't a symlink\n")); error = -EINVAL; kfree(fileName); } else { LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling nd_set_link %s\n", __func__, fileName)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) *cookie = fileName; #else nd_set_link(nd, fileName); #endif } } out: #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) if (!error) { return *cookie; } else { return ERR_PTR(error); } #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) return ERR_PTR(error); #else return error; #endif }
static int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) { int error = -ENOMEM; unsigned long page = get_zeroed_page(GFP_KERNEL); if (page) error = sysfs_getlink(dentry, (char *) page); nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); return 0; }
void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; int rc = -EACCES; int xid; char *full_path = NULL; char * target_path = ERR_PTR(-ENOMEM); struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; xid = GetXid(); full_path = build_path_from_dentry(direntry); if (!full_path) goto out_no_free; cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); if (!target_path) { target_path = ERR_PTR(-ENOMEM); goto out; } /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ if (pTcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, target_path, PATH_MAX-1, cifs_sb->local_nls); else { /* rc = CIFSSMBQueryReparseLinkInfo */ /* BB Add code to Query ReparsePoint info */ /* BB Add MAC style xsymlink check here if enabled */ } if (rc == 0) { /* BB Add special case check for Samba DFS symlinks */ target_path[PATH_MAX-1] = 0; } else { kfree(target_path); target_path = ERR_PTR(rc); } out: kfree(full_path); out_no_free: FreeXid(xid); nd_set_link(nd, target_path); return NULL; /* No cookie */ }
void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = d_inode(direntry); int rc = -ENOMEM; unsigned int xid; char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = NULL; struct cifs_tcon *tcon; struct TCP_Server_Info *server; xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); tlink = NULL; goto out; } tcon = tlink_tcon(tlink); server = tcon->ses->server; full_path = build_path_from_dentry(direntry); if (!full_path) goto out; cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); rc = -EACCES; /* * First try Minshall+French Symlinks, if configured * and fallback to UNIX Extensions Symlinks. */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) rc = query_mf_symlink(xid, tcon, cifs_sb, full_path, &target_path); if (rc != 0 && server->ops->query_symlink) rc = server->ops->query_symlink(xid, tcon, full_path, &target_path, cifs_sb); kfree(full_path); out: if (rc != 0) { kfree(target_path); target_path = ERR_PTR(rc); } free_xid(xid); if (tlink) cifs_put_tlink(tlink); nd_set_link(nd, target_path); return NULL; }
static void * ospfs_follow_link(struct dentry *dentry, struct nameidata *nd) { ospfs_symlink_inode_t *oi = (ospfs_symlink_inode_t *) ospfs_inode(dentry->d_inode->i_ino); // Exercise: Your code here. nd_set_link(nd, oi->oi_symlink); return (void *) 0; }
int #endif vnode_iop_follow_link( DENT_T *dentry, /* link */ struct nameidata *nd /* link resolution */ ) { INODE_T *ip; struct uio uio; iovec_t iov; int err = 0; char *buf = KMEM_ALLOC(PATH_MAX, KM_SLEEP); CALL_DATA_T cd; if (buf == NULL) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) return ERR_PTR(-ENOMEM); #else return -ENOMEM; #endif uio.uio_iov = &iov; mfs_uioset(&uio, buf, PATH_MAX-1, 0, UIO_SYSSPACE); mdki_linux_init_call_data(&cd); ip = dentry->d_inode; ASSERT_KERNEL_UNLOCKED(); ASSERT_I_SEM_NOT_MINE(ip); err = VOP_READLINK(ITOV(ip), &uio, &cd); err = mdki_errno_unix_to_linux(err); mdki_linux_destroy_call_data(&cd); if (err == 0) { if (uio.uio_resid == 0) err = -ENAMETOOLONG; else { /* readlink doesn't copy a NUL at the end, we must do it */ buf[uio.uio_offset] = '\0'; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) /* follow the link */ err = vfs_follow_link(nd, buf); #else nd_set_link(nd, buf); return(buf); /* vnop_iop_put_link() will free this buf. */ #endif } } KMEM_FREE(buf, PATH_MAX); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) return ERR_PTR(err); #else return(err); #endif }
static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) { int error = -ENOMEM; unsigned long page = get_zeroed_page(GFP_KERNEL); if (page) { error = sysfs_getlink(dentry, (char *) page); if (error < 0) free_page((unsigned long)page); } nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); return NULL; }
/** * \<\<private\>\> Provides symlink resolution. * Supplies the pathname of the target entry that the symlink refers to. * This code is adapted from sysfs/symlink.c. * - allocates a whole page for the pathname (faster than kmalloc) * - extracts the symlink from the dentry * - asks the symlink for path resolution * * @param *dentry - points to the dentry of the symlink that is to be * resolved * @param *nd - where the pathname is to be stored * @return NULL upon success */ static void* tcmi_ctlfs_symlink_follow_link(struct dentry *dentry, struct nameidata *nd) { int error = -ENOMEM; unsigned long page = get_zeroed_page(GFP_ATOMIC); struct tcmi_ctlfs_symlink *symlink; if (page) { symlink = TCMI_CTLFS_SYMLINK(TCMI_CTLFS_DENTRY_TO_ENTRY(dentry)); error = tcmi_ctlfs_symlink_get_link(symlink, (char *) page, PAGE_SIZE); } nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); return NULL; }