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; }
void v9fs_session_close(struct v9fs_session_info *v9ses) { if (v9ses->clnt) { p9_client_destroy(v9ses->clnt); v9ses->clnt = NULL; } __putname(v9ses->name); __putname(v9ses->remotename); }
void v9fs_session_close(struct v9fs_session_info *v9ses) { if (v9ses->clnt) { p9_client_destroy(v9ses->clnt); v9ses->clnt = NULL; } __putname(v9ses->uname); __putname(v9ses->aname); kfree(v9ses->options); }
void v9fs_session_close(struct v9fs_session_info *v9ses) { if (v9ses->mux) { v9fs_mux_destroy(v9ses->mux); v9ses->mux = NULL; } if (v9ses->transport) { v9ses->transport->close(v9ses->transport); kfree(v9ses->transport); v9ses->transport = NULL; } __putname(v9ses->name); __putname(v9ses->remotename); }
static bool fw_get_filesystem_firmware(struct firmware_buf *buf) { int i; bool success = false; char *path = __getname(); for (i = 0; i < ARRAY_SIZE(fw_path); i++) { struct file *file; /* skip the unset customized path */ if (!fw_path[i][0]) continue; snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id); file = filp_open(path, O_RDONLY, 0); if (IS_ERR(file)) continue; success = fw_read_file_contents(file, buf); fput(file); if (success) break; } __putname(path); return success; }
/* Read in a filename from the context file, obtaining memory from __getname */ const char *__cr_getname(cr_errbuf_t *eb, struct file *filp, int null_ok) { char *name; int err; name = __getname(); if (!name) { CR_ERR_EB(eb, "Couldn't allocate buffer for file name."); err = -ENOMEM; goto out; } /* now read out the name */ err = cr_fgets(eb, name, PATH_MAX, filp); if (err < 0) { CR_ERR_EB(eb, "Bad read of filename."); goto out_free; } else if (err == 0) { if (!null_ok) err = -EIO; goto out_free; } return name; out_free: __putname(name); out: return (err < 0) ? ERR_PTR(err) : NULL; }
/* Create a new link to an existing (but potentially unlinked) dentry. * If the target link already exists we return the dentry, but if the target * exists and is not a link to the desired object, we return -EEXIST. * * NOTE: We once tried to do this via vfs_link(), rather than sys_link(). * That was "better" in the sense that it was able to link to unlinked * targets (which this cannot). However, that was not working over NFS * for reasons I never did figure out. -PHH */ struct dentry * cr_link(cr_errbuf_t *eb, struct path *old_path, const char *name) { struct nameidata nd; char *buf, *old_name; struct dentry *new_dentry = NULL; int retval; mm_segment_t oldfs; /* Lookup the path to the "old" file. * This is the part that prevents us from linking to an unlinked target. */ retval = -ENOMEM; buf = __getname(); if (!buf) goto out; old_name = cr_getpath(old_path, buf, PATH_MAX); if (IS_ERR(old_name)) { retval = PTR_ERR(old_name); goto out_free; } /* Now sys_link() */ oldfs = get_fs(); set_fs(KERNEL_DS); retval = sys_link(old_name, name); set_fs(oldfs); if (retval == -EEXIST) { /* Keep going, it may be the one we want */ } else if (retval < 0) { CR_ERR_EB(eb, "cr_link: sys_link(%s,%s) returned %d", old_name, name, retval); goto out_free; } /* Now get the dentry for the newly-created object. * YES, there is a potential race, but we check below that we have the right object. */ retval = path_lookup(name, LOOKUP_FOLLOW, &nd); if (retval < 0) { CR_ERR_EB(eb, "cr_link: path_lookup(%s) returned %d", name, retval); goto out_free; } new_dentry = dget(nd.nd_dentry); cr_path_release(&nd); /* Check that we have a link to the desired object. * Needed for sys_link() == -EEXIST and for the link-to-lookup race. */ if (new_dentry->d_inode != old_path->dentry->d_inode) { dput(new_dentry); retval = -EEXIST; goto out_free; } out_free: __putname(buf); out: return (retval < 0) ? ERR_PTR(retval) : new_dentry; }
/* * cr_anonymous_rename * * Rewrite a filename to an anonymous value * * len is strlen and size is buffer size */ static char * cr_anonymous_rename(cr_errbuf_t *eb, const char *in_buf, unsigned long id) { size_t len; char *out_buf, *p; len = strlen(in_buf); if (len >= PATH_MAX) { /* XXX: probably not what we want to do */ len = PATH_MAX - 1; } /* strdup() */ out_buf = __getname(); if (out_buf == NULL) { goto out; } memcpy(out_buf, in_buf, len+1); /* dirname() */ p = out_buf + len; while ((p != out_buf) && (*p != '/')) { --p; } ++p; len = p - out_buf; #if BITS_PER_LONG == 32 if (len > PATH_MAX - 20) { CR_ERR_EB(eb, "cr_anonymous_rename - unlinked name too long for renaming"); goto out_free; } sprintf(p, ".blcr_%04x.%08lx", (unsigned int)current->pid, id); #elif BITS_PER_LONG == 64 if (len > PATH_MAX - 24) { CR_ERR_EB(eb, "cr_anonymous_rename - unlinked name too long for renaming"); goto out_free; } sprintf(p, ".blcr_%04x.%016lx", (unsigned int)current->pid, id); #else #error "No value for BITS_PER_LONG" #endif return out_buf; out_free: __putname(out_buf); out: return NULL; }
/* This function is ONLY designed for SVFS_STATE_DA */ int llfs_create(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct svfs_inode *si = SVFS_I(inode); struct svfs_datastore *sd; struct file *llfs_file; char *ref_path; int ret; sd = svfs_datastore_get(LLFS_TYPE_ANY, 0); if (!sd) { ret = PTR_ERR(sd); goto out; } si->llfs_md.llfs_type = sd->type; si->llfs_md.llfs_fsid = svfs_datastore_fsid(sd->pathname); ret = -ENOMEM; ref_path = __getname(); if (!ref_path) goto out; ret = svfs_backing_store_get_path2(SVFS_SB(inode->i_sb), SVFS_SB(inode->i_sb)->bse + inode->i_ino, si->llfs_md.llfs_pathname, NAME_MAX - 1); if (ret) goto out_putname; snprintf(ref_path, PATH_MAX - 1, "%s%s", sd->pathname, si->llfs_md.llfs_pathname); svfs_debug(mdc, "New LLFS path %s, state 0x%x\n", ref_path, si->state); llfs_file = filp_open(ref_path, O_RDWR | O_CREAT, S_IRUGO | S_IWUSR); ret = PTR_ERR(llfs_file); if (IS_ERR(llfs_file)) goto out_putname; si->llfs_md.llfs_filp = llfs_file; si->state |= SVFS_STATE_CONN; si->state &= ~SVFS_STATE_DA; ret = 0; out_putname: __putname(ref_path); out: svfs_exit(mdc, "err %d. [NOTE]: if you get error here," " you should check the LLFS permissions!\n", ret); return ret; }
static char *sysctl_getname(const int *name, int nlen, const struct bin_table **tablep) { char *tmp, *result; result = ERR_PTR(-ENOMEM); tmp = __getname(); if (tmp) { const struct bin_table *table = get_sysctl(name, nlen, tmp); result = tmp; *tablep = table; if (IS_ERR(table)) { __putname(tmp); result = ERR_CAST(table); } } return result; }
/* Saves pathname, returning bytes written (or <0 on error), * NULL dentry yields saved string value of NULL (distinct from empty string). * Uses supplied buf, if any, or will alloc/free otherwise. */ int cr_save_pathname(cr_errbuf_t *eb, struct file *cr_filp, struct path *path, char *orig_buf, int size) { int retval; const char *name = NULL; char *buf = orig_buf; /* Short cut on NULL path or dentry */ if (!path || !path->dentry) { goto write; } /* Allocate buf if none was supplied */ if (!buf) { retval = -ENOMEM; buf = __getname(); if (!buf) { goto out; } size = PATH_MAX; } /* find the file name */ name = cr_getpath(path, buf, size); CR_INFO("file = %s\n"); if (name == NULL) { CR_ERR_EB(eb, "Bad or non/existant name!"); retval = -EBADF; goto out_bad; } /* now write out the name */ write: retval = cr_fputs(eb, name, cr_filp); if (retval < 0) { CR_ERR_EB(eb, "cr_save_pathname - Bad file write! (cr_fputs returned %d)", retval); goto out_bad; } out_bad: if (buf && !orig_buf) { __putname(buf); } out: return retval; }
static int smb_follow_link(struct dentry *dentry, struct nameidata *nd) { char *link = __getname(); DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry)); if (!link) { link = ERR_PTR(-ENOMEM); } else { int len = smb_proc_read_link(server_from_dentry(dentry), dentry, link, PATH_MAX - 1); if (len < 0) { __putname(link); link = ERR_PTR(len); } else { link[len] = 0; } } nd_set_link(nd, link); return 0; }
static ssize_t binary_sysctl(const int *name, int nlen, void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) { const struct bin_table *table = NULL; struct vfsmount *mnt; struct file *file; ssize_t result; char *pathname; int flags; pathname = sysctl_getname(name, nlen, &table); result = PTR_ERR(pathname); if (IS_ERR(pathname)) goto out; if (oldval && oldlen && newval && newlen) { flags = O_RDWR; } else if (newval && newlen) { flags = O_WRONLY; } else if (oldval && oldlen) { flags = O_RDONLY; } else { result = 0; goto out_putname; } mnt = current->nsproxy->pid_ns->proc_mnt; file = file_open_root(mnt->mnt_root, mnt, pathname, flags); result = PTR_ERR(file); if (IS_ERR(file)) goto out_putname; result = table->convert(file, oldval, oldlen, newval, newlen); fput(file); out_putname: __putname(pathname); out: return result; }
/* * ima_d_path - return a pointer to the full pathname * * Attempt to return a pointer to the full pathname for use in the * IMA measurement list, IMA audit records, and auditing logs. * * On failure, return a pointer to a copy of the filename, not dname. * Returning a pointer to dname, could result in using the pointer * after the memory has been freed. */ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) { char *pathname = NULL; *pathbuf = __getname(); if (*pathbuf) { pathname = d_absolute_path(path, *pathbuf, PATH_MAX); if (IS_ERR(pathname)) { __putname(*pathbuf); *pathbuf = NULL; pathname = NULL; } } if (!pathname) { strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX); pathname = namebuf; } return pathname; }
static bool fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf, phys_addr_t dest_addr, size_t dest_size) { int i; bool success = false; char *path = __getname(); for (i = 0; i < ARRAY_SIZE(fw_path); i++) { struct file *file; /* skip the unset customized path */ if (!fw_path[i][0]) continue; snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id); file = filp_open(path, O_RDONLY, 0); if (IS_ERR(file)) continue; success = fw_read_file_contents(file, buf); fput(file); filp_close(file, NULL); if (success) break; } __putname(path); if (success) { dev_dbg(device, "firmware: direct-loading firmware %s\n", buf->fw_id); mutex_lock(&fw_lock); set_bit(FW_STATUS_DONE, &buf->status); complete_all(&buf->completion); mutex_unlock(&fw_lock); } return success; }
static int handle_file_write_req(struct rk_baseband *bb, struct ipc_msg *pmsg) { int ret; const char* fname; loff_t offset; void *buf; size_t sz; char *path = __getname(); struct file *file; /* argv[0] : relative file path */ /* argv[1] : file offset */ /* argv[2] : buffer pointer */ /* argv[3] : length */ if (IPCMSG_GET_ARGC(pmsg) != 4) return -1; fname = (const char*)IPCMSG_GET_ARG(pmsg, 0); offset = (loff_t)IPCMSG_GET_ARG(pmsg, 1); buf = (void*)IPCMSG_GET_ARG(pmsg, 2); sz = (size_t)IPCMSG_GET_ARG(pmsg, 3); snprintf(path, PATH_MAX, "%s/%s", bb->nv_path, fname); file = filp_open(path, O_RDWR, 0); if (IS_ERR(file)) { return -1; } ret = vfs_write(file, buf, sz, &offset); fput(file); __putname(path); return ret; }
struct storage_result *mdsl_read_itb(struct storage_index *si) { struct mmap_window *mw; struct storage_result *sr; char *path; path = __getname(); if (!mpath) { hvfs_err(mdsl, "__getname() failed\n"); return ERR_PTR(-ENOMEM); } mpath = sprintf("%s/%d/md", HVFS_HOME, si->sic.uuid); /* FIXME: how to get the range max quickly? max range based! */ mw = find_get_md_memwin(path, MD_RANGE, si->sic.arg0); max = *(u64 *)(mw->addr + mw->offset); min = *(u64 *)(mw->addr + mw->offset + sizeof(u64)); put_range_memwin(mw); /* FIXME: check whether itbid is in the range (min, max] */ path = sprintf("%s/%d/range.[%016d]", HVFS_HOME, si->sic.uuid, max); /* get the range memory window */ mw = find_get_range_memwin(path, si->sic.arg0); itb_offset = *(u64 *)(mw->addr + mw->offset); put_range_memwin(mw); /* get the ITB */ path = sprintf("%s/%d/itb", HVFS_HOME, si->sic.uuid); sr = get_free_sr(); sr->flag = SR_ITB; sr->data = get_itb(path, itb_offset, &sr->len); if (!sr->data) sr->err = -ENOENT; __putname(path); return sr; }
static struct dentry * InodeOpLookup(struct inode *dir, // IN: parent directory's inode struct dentry *dentry, // IN: dentry to lookup struct nameidata *nd) // IN: lookup intent and information { char *filename; struct inode *inode; int ret; if (!dir || !dentry) { Warning("InodeOpLookup: invalid args from kernel\n"); return ERR_PTR(-EINVAL); } /* The kernel should only pass us our own inodes, but check just to be safe. */ if (!INODE_TO_IINFO(dir)) { Warning("InodeOpLookup: invalid inode provided\n"); return ERR_PTR(-EINVAL); } /* Get a slab from the kernel's names_cache of PATH_MAX-sized buffers. */ filename = __getname(); if (!filename) { Warning("InodeOpLookup: unable to obtain memory for filename.\n"); return ERR_PTR(-ENOMEM); } ret = MakeFullName(dir, dentry, filename, PATH_MAX); if (ret < 0) { Warning("InodeOpLookup: could not construct full name\n"); __putname(filename); return ERR_PTR(ret); } /* Block if there is a pending block on this file */ BlockWaitOnFile(filename, NULL); __putname(filename); inode = Iget(dir->i_sb, dir, dentry, GetNextIno()); if (!inode) { Warning("InodeOpLookup: failed to get inode\n"); return ERR_PTR(-ENOMEM); } dentry->d_op = &LinkDentryOps; dentry->d_time = jiffies; /* * If the actual file's dentry doesn't have an inode, it means the file we * are redirecting to doesn't exist. Give back the inode that was created * for this and add a NULL dentry->inode entry in the dcache. (The NULL * entry is added so ops to create files/directories are invoked by VFS.) */ if (!INODE_TO_ACTUALDENTRY(inode) || !INODE_TO_ACTUALINODE(inode)) { iput(inode); d_add(dentry, NULL); return NULL; } inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_size = INODE_TO_IINFO(inode)->nameLen; inode->i_version = 1; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_uid = inode->i_gid = 0; inode->i_op = &LinkInodeOps; d_add(dentry, inode); return NULL; }
static int process_measurement(struct file *file, int mask, int function, int opened) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; struct ima_template_desc *template_desc; char *pathbuf = NULL; const char *pathname = NULL; int rc = -ENOMEM, action, must_appraise; struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; int xattr_len = 0; bool violation_check; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ action = ima_get_action(inode, mask, function); violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) && (ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) return 0; must_appraise = action & IMA_APPRAISE; /* Is the appraise rule hook specific? */ if (action & IMA_FILE_APPRAISE) function = FILE_CHECK; mutex_lock(&inode->i_mutex); if (action) { iint = integrity_inode_get(inode); if (!iint) goto out; } if (violation_check) { ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, &pathbuf, &pathname); if (!action) { rc = 0; goto out_free; } } /* Determine if already appraised/measured based on bitmask * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * IMA_AUDIT, IMA_AUDITED) */ iint->flags |= action; action &= IMA_DO_MASK; action &= ~((iint->flags & IMA_DONE_MASK) >> 1); /* Nothing to do, just return existing appraised status */ if (!action) { if (must_appraise) rc = ima_get_cache_status(iint, function); goto out_digsig; } template_desc = ima_template_desc_current(); if ((action & IMA_APPRAISE_SUBMASK) || strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) xattr_ptr = &xattr_value; rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); if (rc != 0) { if (file->f_flags & O_DIRECT) rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; goto out_digsig; } if (!pathname) /* ima_rdwr_violation possibly pre-fetched */ pathname = ima_d_path(&file->f_path, &pathbuf); if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, xattr_value, xattr_len); if (action & IMA_APPRAISE_SUBMASK) rc = ima_appraise_measurement(function, iint, file, pathname, xattr_value, xattr_len, opened); if (action & IMA_AUDIT) ima_audit_measurement(iint, pathname); out_digsig: if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) rc = -EACCES; kfree(xattr_value); out_free: if (pathbuf) __putname(pathbuf); out: mutex_unlock(&inode->i_mutex); if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; return 0; }
static int process_measurement(struct file *file, const struct cred *cred, u32 secid, char *buf, loff_t size, int mask, enum ima_hooks func, int opened) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; struct ima_template_desc *template_desc; char *pathbuf = NULL; char filename[NAME_MAX]; const char *pathname = NULL; int rc = 0, action, must_appraise = 0; int pcr = CONFIG_IMA_MEASURE_PCR_IDX; struct evm_ima_xattr_data *xattr_value = NULL; int xattr_len = 0; bool violation_check; enum hash_algo hash_algo; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ action = ima_get_action(inode, cred, secid, mask, func, &pcr); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && (ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) return 0; must_appraise = action & IMA_APPRAISE; /* Is the appraise rule hook specific? */ if (action & IMA_FILE_APPRAISE) func = FILE_CHECK; inode_lock(inode); if (action) { iint = integrity_inode_get(inode); if (!iint) rc = -ENOMEM; } if (!rc && violation_check) ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, &pathbuf, &pathname, filename); inode_unlock(inode); if (rc) goto out; if (!action) goto out; mutex_lock(&iint->mutex); if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) /* reset appraisal flags if ima_inode_post_setattr was called */ iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | IMA_ACTION_FLAGS); /* * Re-evaulate the file if either the xattr has changed or the * kernel has no way of detecting file change on the filesystem. * (Limited to privileged mounted filesystems.) */ if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) || ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) && !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) && !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) { iint->flags &= ~IMA_DONE_MASK; iint->measured_pcrs = 0; } /* Determine if already appraised/measured based on bitmask * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * IMA_AUDIT, IMA_AUDITED) */ iint->flags |= action; action &= IMA_DO_MASK; action &= ~((iint->flags & (IMA_DONE_MASK ^ IMA_MEASURED)) >> 1); /* If target pcr is already measured, unset IMA_MEASURE action */ if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr))) action ^= IMA_MEASURE; /* HASH sets the digital signature and update flags, nothing else */ if ((action & IMA_HASH) && !(test_bit(IMA_DIGSIG, &iint->atomic_flags))) { xattr_len = ima_read_xattr(file_dentry(file), &xattr_value); if ((xattr_value && xattr_len > 2) && (xattr_value->type == EVM_IMA_XATTR_DIGSIG)) set_bit(IMA_DIGSIG, &iint->atomic_flags); iint->flags |= IMA_HASHED; action ^= IMA_HASH; set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); } /* Nothing to do, just return existing appraised status */ if (!action) { if (must_appraise) rc = ima_get_cache_status(iint, func); goto out_locked; } template_desc = ima_template_desc_current(); if ((action & IMA_APPRAISE_SUBMASK) || strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) /* read 'security.ima' */ xattr_len = ima_read_xattr(file_dentry(file), &xattr_value); hash_algo = ima_get_hash_algo(xattr_value, xattr_len); rc = ima_collect_measurement(iint, file, buf, size, hash_algo); if (rc != 0 && rc != -EBADF && rc != -EINVAL) goto out_locked; if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ pathname = ima_d_path(&file->f_path, &pathbuf, filename); if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, xattr_value, xattr_len, pcr); if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { inode_lock(inode); rc = ima_appraise_measurement(func, iint, file, pathname, xattr_value, xattr_len, opened); inode_unlock(inode); } if (action & IMA_AUDIT) ima_audit_measurement(iint, pathname); if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) rc = 0; out_locked: if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) && !(iint->flags & IMA_NEW_FILE)) rc = -EACCES; mutex_unlock(&iint->mutex); kfree(xattr_value); out: if (pathbuf) __putname(pathbuf); if (must_appraise) { if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; if (file->f_mode & FMODE_WRITE) set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); } return 0; }
/* * @inode: svfs inode */ int llfs_lookup(struct inode *inode) { struct svfs_datastore *sd; struct dentry *llfs_dentry; const struct cred *cred = current_cred(); struct nameidata llfs_nd; char *ref_path; int err = 0; if (S_ISDIR(inode->i_mode)) goto out; if (SVFS_I(inode)->state & SVFS_STATE_DA) goto out; if (SVFS_I(inode)->state & SVFS_STATE_CONN) goto out; err = -ENOMEM; ref_path = __getname(); if (!ref_path) goto out; err = -EINVAL; sd = svfs_datastore_get(SVFS_I(inode)->llfs_md.llfs_type, SVFS_I(inode)->llfs_md.llfs_fsid); if (!sd) goto out_release_name; sprintf(ref_path, "%s%s", sd->pathname, SVFS_I(inode)->llfs_md.llfs_pathname); svfs_debug(mdc, "fully ref_path %s\n", ref_path); err = path_lookup(ref_path, LOOKUP_FOLLOW, &llfs_nd); if (err) goto fail_lookup; SVFS_I(inode)->llfs_md.llfs_filp = dentry_open(llfs_nd.path.dentry, llfs_nd.path.mnt, O_RDWR, cred); if (IS_ERR(SVFS_I(inode)->llfs_md.llfs_filp)) goto out_put_path; llfs_dentry = svfs_relay(lookup, SVFS_I(inode)->llfs_md.llfs_type, inode); if (IS_ERR(llfs_dentry)) { SVFS_I(inode)->state |= SVFS_STATE_DISC; svfs_err(mdc, "svfs_relay 'lookup' failed %ld\n", PTR_ERR(llfs_dentry)); goto out_put_filp; } SVFS_I(inode)->state |= SVFS_STATE_CONN; err = 0; out: return err; out_put_filp: fput(SVFS_I(inode)->llfs_md.llfs_filp); goto out; out_put_path: /* path_put(&llfs_nd.path) */ { svfs_debug(mdc, "llfs_nd.path->dentry %d, vfsmount %d\n", atomic_read(&llfs_nd.path.dentry->d_count), atomic_read(&llfs_nd.path.mnt->mnt_count)); } goto out; fail_lookup: out_release_name: __putname(ref_path); goto out; }
/* cr_mknod - based on linux/fs/namei.c:sys_mknod * * Creates regular files or fifos (no devices) making them anonymous (unlinked) * if desired. * Returns a dentry for the resulting filesystem objects, and the corresponding * vfsmnt can be obtained in nd->mnt. Together these two can be passed * to dentry_open() or cr_dentry_open(), even for an unlinked inode. * In the event of an error, no dput() or cr_path_release() is required, * otherwise they are. * * In the event that an object exists with the given name, it will be * check for the proper mode prior to return, yielding -EEXIST on conflict. */ struct dentry * cr_mknod(cr_errbuf_t *eb, struct nameidata *nd, const char *name, int mode, unsigned long unlinked_id) { struct dentry * dentry; int err; if (unlinked_id) { /* Generate a replacement name which we will use instead of the original one. */ name = cr_anonymous_rename(eb, name, unlinked_id); if (!name) { CR_ERR_EB(eb, "cr_mknod - failed to rename unlinked object"); err = -ENOMEM; goto out; } } /* Prior to 2.6.26, lookup_create() would return an exisiting dentry. * Since 2.6.26, it returns -EEXIST if the dentry exists. So, we first * check for an existing dentry. For older kernels this is not required, * but is still correct. */ err = path_lookup(name, LOOKUP_FOLLOW, nd); if (!err) { dentry = dget(nd->nd_dentry); err = -EEXIST; /* Forces mode validation below */ goto have_it; } err = path_lookup(name, LOOKUP_PARENT, nd); if (err) { CR_KTRACE_UNEXPECTED("Couldn't path_lookup for mknod %s. err=%d.", name, err); goto out_free; } dentry = cr_lookup_create(nd, 0); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); CR_KTRACE_UNEXPECTED("Couldn't lookup_create for mknod %s. err=%d.", name, err); goto out_release; } switch (mode & S_IFMT) { case S_IFREG: err = vfs_create(nd->nd_dentry->d_inode, dentry, mode, nd); break; case S_IFIFO: err = cr_vfs_mknod(nd->nd_dentry->d_inode, dentry, nd->nd_mnt, mode, 0 /* ignored */); break; default: CR_ERR_EB(eb, "Unknown/invalid type %d passed to cr_mknod %s.", (mode&S_IFMT), name); err = -EINVAL; } if (unlinked_id && !err) { /* Note that we don't unlink if we failed to create */ dget(dentry); /* ensure unlink doesn't destroy the dentry */ /* Note possibility of silent failure here: */ (void)cr_vfs_unlink(nd->nd_dentry->d_inode, dentry, nd->nd_mnt); dput(dentry); } cr_inode_unlock(nd->nd_dentry->d_inode); have_it: if ((err == -EEXIST) && !((dentry->d_inode->i_mode ^ mode) & S_IFMT)) { /* We fall through and return the dentry */ } else if (err) { CR_KTRACE_UNEXPECTED("Couldn't cr_mknod %s. err=%d.", name, err); goto out_put; } if (unlinked_id) { __putname(name); } return dentry; out_put: dput(dentry); out_release: cr_path_release(nd); out_free: if (unlinked_id) { __putname(name); } out: return (struct dentry *)ERR_PTR(err); }
static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry, *parent; struct file *file; struct inode *dir; struct find_name_by_ino arg; int err; parent = path->dentry; if (nsi_lock) si_read_unlock(parent->d_sb); file = vfsub_dentry_open(path, au_dir_roflags); dentry = (void *)file; if (IS_ERR(file)) goto out; dentry = ERR_PTR(-ENOMEM); arg.name = __getname_gfp(GFP_NOFS); if (unlikely(!arg.name)) goto out_file; arg.ino = ino; arg.found = 0; do { arg.called = 0; /* smp_mb(); */ err = vfsub_readdir(file, find_name_by_ino, &arg); } while (!err && !arg.found && arg.called); dentry = ERR_PTR(err); if (unlikely(err)) goto out_name; dentry = ERR_PTR(-ENOENT); if (!arg.found) goto out_name; /* do not call au_lkup_one() */ dir = parent->d_inode; mutex_lock(&dir->i_mutex); dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); mutex_unlock(&dir->i_mutex); AuTraceErrPtr(dentry); if (IS_ERR(dentry)) goto out_name; AuDebugOn(au_test_anon(dentry)); if (unlikely(!dentry->d_inode)) { dput(dentry); dentry = ERR_PTR(-ENOENT); } out_name: __putname(arg.name); out_file: fput(file); out: if (unlikely(nsi_lock && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) if (!IS_ERR(dentry)) { dput(dentry); dentry = ERR_PTR(-ESTALE); } AuTraceErrPtr(dentry); return dentry; }
struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, const char *dev_name, char *data) { int retval = -EINVAL; struct p9_fid *fid; int rc; v9ses->uname = __getname(); if (!v9ses->uname) return ERR_PTR(-ENOMEM); v9ses->aname = __getname(); if (!v9ses->aname) { __putname(v9ses->uname); return ERR_PTR(-ENOMEM); } v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER; strcpy(v9ses->uname, V9FS_DEFUSER); strcpy(v9ses->aname, V9FS_DEFANAME); v9ses->uid = ~0; v9ses->dfltuid = V9FS_DEFUID; v9ses->dfltgid = V9FS_DEFGID; if (data) { v9ses->options = kstrdup(data, GFP_KERNEL); if (!v9ses->options) { P9_DPRINTK(P9_DEBUG_ERROR, "failed to allocate copy of option string\n"); retval = -ENOMEM; goto error; } } rc = v9fs_parse_options(v9ses); if (rc < 0) { retval = rc; goto error; } v9ses->clnt = p9_client_create(dev_name, v9ses->options); if (IS_ERR(v9ses->clnt)) { retval = PTR_ERR(v9ses->clnt); v9ses->clnt = NULL; P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n"); goto error; } if (!v9ses->clnt->dotu) v9ses->flags &= ~V9FS_EXTENDED; v9ses->maxdata = v9ses->clnt->msize; /* for legacy mode, fall back to V9FS_ACCESS_ANY */ if (!v9fs_extended(v9ses) && ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { v9ses->flags &= ~V9FS_ACCESS_MASK; v9ses->flags |= V9FS_ACCESS_ANY; v9ses->uid = ~0; } fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0, v9ses->aname); if (IS_ERR(fid)) { retval = PTR_ERR(fid); fid = NULL; P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n"); goto error; } if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE) fid->uid = v9ses->uid; else fid->uid = ~0; return fid; error: return ERR_PTR(retval); }
int v9fs_session_init(struct v9fs_session_info *v9ses, const char *dev_name, char *data) { struct v9fs_fcall *fcall = NULL; struct v9fs_transport *trans_proto; int n = 0; int newfid = -1; int retval = -EINVAL; struct v9fs_str *version; v9ses->name = __getname(); if (!v9ses->name) return -ENOMEM; v9ses->remotename = __getname(); if (!v9ses->remotename) { __putname(v9ses->name); return -ENOMEM; } strcpy(v9ses->name, V9FS_DEFUSER); strcpy(v9ses->remotename, V9FS_DEFANAME); v9fs_parse_options(data, v9ses); /* set global debug level */ v9fs_debug_level = v9ses->debug; /* id pools that are session-dependent: fids and tags */ idr_init(&v9ses->fidpool.pool); init_MUTEX(&v9ses->fidpool.lock); switch (v9ses->proto) { case PROTO_TCP: trans_proto = &v9fs_trans_tcp; break; case PROTO_UNIX: trans_proto = &v9fs_trans_unix; *v9ses->remotename = 0; break; case PROTO_FD: trans_proto = &v9fs_trans_fd; *v9ses->remotename = 0; break; default: printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); retval = -ENOPROTOOPT; goto SessCleanUp; }; v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL); if (!v9ses->transport) { retval = -ENOMEM; goto SessCleanUp; } memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport)); if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { eprintk(KERN_ERR, "problem initializing transport\n"); goto SessCleanUp; } v9ses->inprogress = 0; v9ses->shutdown = 0; v9ses->session_hung = 0; v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ, &v9ses->extended); if (IS_ERR(v9ses->mux)) { retval = PTR_ERR(v9ses->mux); v9ses->mux = NULL; dprintk(DEBUG_ERROR, "problem initializing mux\n"); goto SessCleanUp; } if (v9ses->afid == ~0) { if (v9ses->extended) retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u", &fcall); else retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000", &fcall); if (retval < 0) { dprintk(DEBUG_ERROR, "v9fs_t_version failed\n"); goto FreeFcall; } version = &fcall->params.rversion.version; if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) { dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); v9ses->extended = 1; } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) { dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n"); v9ses->extended = 0; } else { retval = -EREMOTEIO; goto FreeFcall; } n = fcall->params.rversion.msize; kfree(fcall); if (n < v9ses->maxdata) v9ses->maxdata = n; } newfid = v9fs_get_idpool(&v9ses->fidpool); if (newfid < 0) { eprintk(KERN_WARNING, "couldn't allocate FID\n"); retval = -ENOMEM; goto SessCleanUp; } /* it is a little bit ugly, but we have to prevent newfid */ /* being the same as afid, so if it is, get a new fid */ if (v9ses->afid != ~0 && newfid == v9ses->afid) { newfid = v9fs_get_idpool(&v9ses->fidpool); if (newfid < 0) { eprintk(KERN_WARNING, "couldn't allocate FID\n"); retval = -ENOMEM; goto SessCleanUp; } } if ((retval = v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid, v9ses->afid, NULL)) < 0) { dprintk(DEBUG_ERROR, "cannot attach\n"); goto SessCleanUp; } if (v9ses->afid != ~0) { dprintk(DEBUG_ERROR, "afid not equal to ~0\n"); if (v9fs_t_clunk(v9ses, v9ses->afid)) dprintk(DEBUG_ERROR, "clunk failed\n"); } return newfid; FreeFcall: kfree(fcall); SessCleanUp: v9fs_session_close(v9ses); return retval; }
static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry, *parent; struct file *file; struct inode *dir; struct find_name_by_ino arg; int err; parent = path->dentry; LKTRTrace("%.*s, i%lu\n", AuDLNPair(parent), (unsigned long)ino); if (nsi_lock) si_read_unlock(parent->d_sb); path_get(path); file = dentry_open(parent, path->mnt, au_dir_roflags); dentry = (void *)file; if (IS_ERR(file)) goto out; dentry = ERR_PTR(-ENOMEM); arg.name = __getname(); if (unlikely(!arg.name)) goto out_file; arg.ino = ino; arg.found = 0; do { arg.called = 0; /* smp_mb(); */ err = vfsub_readdir(file, find_name_by_ino, &arg, /*dlgt*/0); } while (!err && !arg.found && arg.called); dentry = ERR_PTR(err); if (unlikely(err)) goto out_name; dentry = ERR_PTR(-ENOENT); if (!arg.found) goto out_name; /* do not call au_lkup_one(), nor dlgt */ dir = parent->d_inode; vfsub_i_lock(dir); dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); vfsub_i_unlock(dir); AuTraceErrPtr(dentry); if (IS_ERR(dentry)) goto out_name; AuDebugOn(au_test_anon(dentry)); if (unlikely(!dentry->d_inode)) { dput(dentry); dentry = ERR_PTR(-ENOENT); } out_name: __putname(arg.name); out_file: fput(file); out: if (unlikely(nsi_lock && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) if (!IS_ERR(dentry)) { dput(dentry); dentry = ERR_PTR(-ESTALE); } AuTraceErrPtr(dentry); return dentry; }
struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, const char *dev_name, char *data) { int retval = -EINVAL; struct p9_transport *trans; struct p9_fid *fid; v9ses->name = __getname(); if (!v9ses->name) return ERR_PTR(-ENOMEM); v9ses->remotename = __getname(); if (!v9ses->remotename) { __putname(v9ses->name); return ERR_PTR(-ENOMEM); } strcpy(v9ses->name, V9FS_DEFUSER); strcpy(v9ses->remotename, V9FS_DEFANAME); v9fs_parse_options(data, v9ses); switch (v9ses->proto) { case PROTO_TCP: trans = p9_trans_create_tcp(dev_name, v9ses->port); break; case PROTO_UNIX: trans = p9_trans_create_unix(dev_name); *v9ses->remotename = 0; break; case PROTO_FD: trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); *v9ses->remotename = 0; break; #ifdef CONFIG_PCI_9P case PROTO_PCI: trans = p9pci_trans_create(); *v9ses->remotename = 0; break; #endif default: printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); retval = -ENOPROTOOPT; goto error; }; if (IS_ERR(trans)) { retval = PTR_ERR(trans); trans = NULL; goto error; } v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, v9ses->extended); if (IS_ERR(v9ses->clnt)) { retval = PTR_ERR(v9ses->clnt); v9ses->clnt = NULL; P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n"); goto error; } fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, v9ses->remotename); if (IS_ERR(fid)) { retval = PTR_ERR(fid); fid = NULL; P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n"); goto error; } return fid; error: v9fs_session_close(v9ses); return ERR_PTR(retval); }
static void smb_put_link(struct dentry *dentry, struct nameidata *nd) { char *s = nd_get_link(nd); if (!IS_ERR(s)) __putname(s); }
/* cr_mknod * * Creates regular files or fifos (no devices) making them anonymous (unlinked) * if desired, populating the struct path appropriatly. * In the event of an error, no dput() or path_put() is required, * otherwise they are. * * In the event that an object exists with the given name, it will be * check for the proper mode prior to return, yielding -EEXIST on conflict. */ int cr_mknod(cr_errbuf_t *eb, struct path *path, const char *name, int mode, unsigned long unlinked_id) { mm_segment_t oldfs; int err; #if CRI_DEBUG /* first validate mode */ switch (mode & S_IFMT) { case S_IFREG: case S_IFIFO: break; default: CR_ERR_EB(eb, "Unknown/invalid type %d passed to cr_mknod %s.", (mode&S_IFMT), name); err = -EINVAL; goto out; } #endif if (unlinked_id) { /* Generate a replacement name which we will use instead of the original one. */ name = cr_anonymous_rename(eb, name, unlinked_id); if (!name) { CR_ERR_EB(eb, "cr_mknod - failed to rename unlinked object"); err = -ENOMEM; goto out; } } /* sys_mknod() */ oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_mknod(name, mode, 0); set_fs(oldfs); if (err == -EEXIST) { /* Keep going, it may be the one we want */ } else if (err < 0) { goto out_free; } /* Now get the (struct path) for the newly-created object. * YES, there is a potential race, but we check below that we have the right object. */ err = cr_kern_path(name, LOOKUP_FOLLOW, path); if (err < 0) { CR_ERR_EB(eb, "cr_mknod: cr_kern_path(%s) returned %d after sys_mknod()", name, err); goto out_free; } /* Check that we have the desired object type. * Needed for sys_mknod() == -EEXIST and for the mknod-to-lookup race. */ if ((path->dentry->d_inode->i_mode ^ mode) & S_IFMT) { CR_ERR_EB(eb, "cr_mknod: cr_kern_path(%s) found conflicting object", name); err = -EEXIST; path_put(path); goto out_free; } /* unlink if required */ if (unlinked_id) { /* Note possibility of silent failure here: */ oldfs = get_fs(); set_fs(KERNEL_DS); (void) sys_unlink(name); set_fs(oldfs); } out_free: if (unlinked_id) { __putname(name); } out: return err; }