/* * 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; }
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; }
/* * The inode of symbolic link is different to data stream. * The data stream become link name. Unless the LONG_SYMLINK * flag is set. */ static int befs_symlink_readpage(struct file *unused, struct page *page) { struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; struct befs_inode_info *befs_ino = BEFS_I(inode); befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; char *link = page_address(page); if (len == 0 || len > PAGE_SIZE) { befs_error(sb, "Long symlink with illegal length"); goto fail; } befs_debug(sb, "Follow long symlink"); if (befs_read_lsymlink(sb, data, link, len) != len) { befs_error(sb, "Failed to read entire long symlink"); goto fail; } link[len - 1] = '\0'; SetPageUptodate(page); unlock_page(page); return 0; fail: SetPageError(page); unlock_page(page); return -EIO; }
static int befs_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct super_block *sb = dentry->d_sb; befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); char *link; int res; if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t linklen = data->size; befs_debug(sb, "Read long symlink"); link = kmalloc(linklen, GFP_NOFS); if (link == NULL) return -ENOMEM; if (befs_read_lsymlink(sb, data, link, linklen) != linklen) { kfree(link); befs_error(sb, "Failed to read entire long symlink"); return -EIO; } res = vfs_readlink(dentry, buffer, buflen, link); kfree(link); } else { link = befs_ino->i_data.symlink; res = vfs_readlink(dentry, buffer, buflen, link); } return res; }