/* * 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 const char * xfs_vn_get_link( struct dentry *dentry, struct inode *inode, struct delayed_call *done) { char *link; int error = -ENOMEM; if (!dentry) return ERR_PTR(-ECHILD); link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); if (!link) goto out_err; error = xfs_readlink(XFS_I(d_inode(dentry)), link); if (unlikely(error)) goto out_kfree; set_delayed_call(done, kfree_link, link); return link; out_kfree: kfree(link); out_err: return ERR_PTR(error); }
static const char *fuse_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); char *link; ssize_t ret; if (!dentry) return ERR_PTR(-ECHILD); link = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!link) return ERR_PTR(-ENOMEM); args.in.h.opcode = FUSE_READLINK; args.in.h.nodeid = get_node_id(inode); args.out.argvar = 1; args.out.numargs = 1; args.out.args[0].size = PAGE_SIZE - 1; args.out.args[0].value = link; ret = fuse_simple_request(fc, &args); if (ret < 0) { kfree(link); link = ERR_PTR(ret); } else { link[ret] = '\0'; set_delayed_call(done, kfree_link, link); } fuse_invalidate_atime(inode); return link; }
static const char *nfs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct page *page; void *err; if (!dentry) { err = ERR_PTR(nfs_revalidate_mapping_rcu(inode)); if (err) return err; page = find_get_page(inode->i_mapping, 0); if (!page) return ERR_PTR(-ECHILD); if (!PageUptodate(page)) { put_page(page); return ERR_PTR(-ECHILD); } } else { err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping)); if (err) return err; page = read_cache_page(&inode->i_data, 0, nfs_symlink_filler, inode); if (IS_ERR(page)) return ERR_CAST(page); } set_delayed_call(done, page_put_link, page); return page_address(page); }
static const char *ext4_encrypted_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct page *cpage = NULL; char *caddr, *paddr = NULL; struct fscrypt_str cstr, pstr; struct fscrypt_symlink_data *sd; int res; u32 max_size = inode->i_sb->s_blocksize; if (!dentry) return ERR_PTR(-ECHILD); res = fscrypt_get_encryption_info(inode); if (res) return ERR_PTR(res); if (ext4_inode_is_fast_symlink(inode)) { caddr = (char *) EXT4_I(inode)->i_data; max_size = sizeof(EXT4_I(inode)->i_data); } else { cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); caddr = page_address(cpage); } /* Symlink is encrypted */ sd = (struct fscrypt_symlink_data *)caddr; cstr.name = sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ res = -EFSCORRUPTED; goto errout; } res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); if (res) goto errout; paddr = pstr.name; res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); if (res) goto errout; /* Null-terminate the name */ paddr[pstr.len] = '\0'; if (cpage) put_page(cpage); set_delayed_call(done, kfree_link, paddr); return paddr; errout: if (cpage) put_page(cpage); kfree(paddr); return ERR_PTR(res); }
const char * cifs_get_link(struct dentry *direntry, struct inode *inode, struct delayed_call *done) { 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; if (!direntry) return ERR_PTR(-ECHILD); xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { free_xid(xid); return ERR_CAST(tlink); } tcon = tlink_tcon(tlink); server = tcon->ses->server; full_path = build_path_from_dentry(direntry); if (!full_path) { free_xid(xid); cifs_put_tlink(tlink); return ERR_PTR(-ENOMEM); } 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); free_xid(xid); cifs_put_tlink(tlink); if (rc != 0) { kfree(target_path); return ERR_PTR(rc); } set_delayed_call(done, kfree_link, target_path); return target_path; }
/** * fscrypt_get_symlink - get the target of an encrypted symlink * @inode: the symlink inode * @caddr: the on-disk contents of the symlink * @max_size: size of @caddr buffer * @done: if successful, will be set up to free the returned target * * If the symlink's encryption key is available, we decrypt its target. * Otherwise, we encode its target for presentation. * * This may sleep, so the filesystem must have dropped out of RCU mode already. * * Return: the presentable symlink target or an ERR_PTR() */ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, unsigned int max_size, struct delayed_call *done) { const struct fscrypt_symlink_data *sd; struct fscrypt_str cstr, pstr; int err; /* This is for encrypted symlinks only */ if (WARN_ON(!IS_ENCRYPTED(inode))) return ERR_PTR(-EINVAL); /* * Try to set up the symlink's encryption key, but we can continue * regardless of whether the key is available or not. */ err = fscrypt_get_encryption_info(inode); if (err) return ERR_PTR(err); /* * For historical reasons, encrypted symlink targets are prefixed with * the ciphertext length, even though this is redundant with i_size. */ if (max_size < sizeof(*sd)) return ERR_PTR(-EUCLEAN); sd = caddr; cstr.name = (unsigned char *)sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); if (cstr.len == 0) return ERR_PTR(-EUCLEAN); if (cstr.len + sizeof(*sd) - 1 > max_size) return ERR_PTR(-EUCLEAN); err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); if (err) return ERR_PTR(err); err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); if (err) goto err_kfree; err = -EUCLEAN; if (pstr.name[0] == '\0') goto err_kfree; pstr.name[pstr.len] = '\0'; set_delayed_call(done, kfree_link, pstr.name); return pstr.name; err_kfree: kfree(pstr.name); return ERR_PTR(err); }
const char * zpl_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { char *link = NULL; int error; if (!dentry) return (ERR_PTR(-ECHILD)); error = zpl_get_link_common(dentry, inode, &link); if (error) return (ERR_PTR(error)); set_delayed_call(done, zpl_put_link, link); return (link); }
static const char *proc_self_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct pid_namespace *ns = inode->i_sb->s_fs_info; pid_t tgid = task_tgid_nr_ns(current, ns); char *name; if (!tgid) return ERR_PTR(-ENOENT); /* 11 for max length of signed int in decimal + NULL term */ name = kmalloc(12, dentry ? GFP_KERNEL : GFP_ATOMIC); if (unlikely(!name)) return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); sprintf(name, "%d", tgid); set_delayed_call(done, kfree_link, name); return name; }
static const char *ecryptfs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { size_t len; char *buf; if (!dentry) return ERR_PTR(-ECHILD); buf = ecryptfs_readlink_lower(dentry, &len); if (IS_ERR(buf)) return buf; fsstack_copy_attr_atime(d_inode(dentry), d_inode(ecryptfs_dentry_to_lower(dentry))); buf[len] = '\0'; set_delayed_call(done, kfree_link, buf); return buf; }
static const char *proc_thread_self_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct pid_namespace *ns = inode->i_sb->s_fs_info; pid_t tgid = task_tgid_nr_ns(current, ns); pid_t pid = task_pid_nr_ns(current, ns); char *name; if (!pid) return ERR_PTR(-ENOENT); name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, dentry ? GFP_KERNEL : GFP_ATOMIC); if (unlikely(!name)) return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); sprintf(name, "%d/task/%d", tgid, pid); set_delayed_call(done, kfree_link, name); return name; }
static const char *kernfs_iop_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { char *body; int error; if (!dentry) return ERR_PTR(-ECHILD); body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) return ERR_PTR(-ENOMEM); error = kernfs_getlink(dentry, body); if (unlikely(error < 0)) { kfree(body); return ERR_PTR(error); } set_delayed_call(done, kfree_link, body); return body; }
/* * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "vfsmod.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) # if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) # if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) static const char *sf_follow_link(struct dentry *dentry, void **cookie) # else 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 = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfReadLink 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 } # if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) static void sf_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { char *page = nd_get_link(nd); if (!IS_ERR(page)) free_page((unsigned long)page); } # endif # else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) */ static const char *sf_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); struct sf_inode_info *sf_i = GET_INODE_INFO(inode); char *path; int rc; if (!dentry) return ERR_PTR(-ECHILD); path = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!path) return ERR_PTR(-ENOMEM); rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc)); kfree(path); return ERR_PTR(-EPROTO); } set_delayed_call(done, kfree_link, path); return path; }
static const char *fuse_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *callback) { struct fuse_conn *fc = get_fuse_conn(inode); struct page *page; int err; err = -EIO; if (is_bad_inode(inode)) goto out_err; if (fc->cache_symlinks) return page_get_link(dentry, inode, callback); err = -ECHILD; if (!dentry) goto out_err; page = alloc_page(GFP_KERNEL); err = -ENOMEM; if (!page) goto out_err; err = fuse_readlink_page(inode, page); if (err) { __free_page(page); goto out_err; } set_delayed_call(callback, page_put_link, page); return page_address(page); out_err: return ERR_PTR(err); }
static const char *ext4_encrypted_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct page *cpage = NULL; char *caddr, *paddr = NULL; struct ext4_str cstr, pstr; struct ext4_encrypted_symlink_data *sd; loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); int res; u32 plen, max_size = inode->i_sb->s_blocksize; if (!dentry) return ERR_PTR(-ECHILD); res = ext4_get_encryption_info(inode); if (res) return ERR_PTR(res); if (ext4_inode_is_fast_symlink(inode)) { caddr = (char *) EXT4_I(inode)->i_data; max_size = sizeof(EXT4_I(inode)->i_data); } else { cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); caddr = page_address(cpage); caddr[size] = 0; } /* Symlink is encrypted */ sd = (struct ext4_encrypted_symlink_data *)caddr; cstr.name = sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); if ((cstr.len + sizeof(struct ext4_encrypted_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ res = -EFSCORRUPTED; goto errout; } plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ? EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len; paddr = kmalloc(plen + 1, GFP_NOFS); if (!paddr) { res = -ENOMEM; goto errout; } pstr.name = paddr; pstr.len = plen; res = _ext4_fname_disk_to_usr(inode, NULL, &cstr, &pstr); if (res < 0) goto errout; /* Null-terminate the name */ if (res <= plen) paddr[res] = '\0'; if (cpage) put_page(cpage); set_delayed_call(done, kfree_link, paddr); return paddr; errout: if (cpage) put_page(cpage); kfree(paddr); return ERR_PTR(res); }
static const char *f2fs_encrypted_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct page *cpage = NULL; char *caddr, *paddr = NULL; struct fscrypt_str cstr = FSTR_INIT(NULL, 0); struct fscrypt_str pstr = FSTR_INIT(NULL, 0); struct fscrypt_symlink_data *sd; u32 max_size = inode->i_sb->s_blocksize; int res; if (!dentry) return ERR_PTR(-ECHILD); res = fscrypt_get_encryption_info(inode); if (res) return ERR_PTR(res); cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); caddr = page_address(cpage); /* Symlink is encrypted */ sd = (struct fscrypt_symlink_data *)caddr; cstr.name = sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); /* this is broken symlink case */ if (unlikely(cstr.len == 0)) { res = -ENOENT; goto errout; } if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ res = -EIO; goto errout; } res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); if (res) goto errout; res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); if (res) goto errout; /* this is broken symlink case */ if (unlikely(pstr.name[0] == 0)) { res = -ENOENT; goto errout; } paddr = pstr.name; /* Null-terminate the name */ paddr[pstr.len] = '\0'; put_page(cpage); set_delayed_call(done, kfree_link, paddr); return paddr; errout: fscrypt_fname_free_buffer(&pstr); put_page(cpage); return ERR_PTR(res); }