int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct sysfs_dirent *sd = dentry->d_fsdata; void *secdata; int error; u32 secdata_len = 0; if (!sd) return -EINVAL; if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; error = security_inode_setsecurity(dentry->d_inode, suffix, value, size, flags); if (error) goto out; error = security_inode_getsecctx(dentry->d_inode, &secdata, &secdata_len); if (error) goto out; mutex_lock(&sysfs_mutex); error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); mutex_unlock(&sysfs_mutex); if (secdata) security_release_secctx(secdata, secdata_len); } else return -EINVAL; out: return error; }
void release_sysfs_dirent(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd; repeat: /* Moving/renaming is always done while holding reference. * sd->s_parent won't change beneath us. */ parent_sd = sd->s_parent; WARN(!(sd->s_flags & SYSFS_FLAG_REMOVED), "sysfs: free using entry: %s/%s\n", parent_sd ? parent_sd->s_name : "", sd->s_name); if (sysfs_type(sd) == SYSFS_KOBJ_LINK) sysfs_put(sd->s_symlink.target_sd); if (sysfs_type(sd) & SYSFS_COPY_NAME) kfree(sd->s_name); if (sd->s_iattr && sd->s_iattr->ia_secdata) security_release_secctx(sd->s_iattr->ia_secdata, sd->s_iattr->ia_secdata_len); kfree(sd->s_iattr); sysfs_free_ino(sd->s_ino); kmem_cache_free(sysfs_dir_cachep, sd); sd = parent_sd; if (sd && atomic_dec_and_test(&sd->s_count)) goto repeat; }
/** * netlbl_audit_start_common - Start an audit message * @type: audit message type * @audit_info: NetLabel audit information * * Description: * Start an audit message using the type specified in @type and fill the audit * message with some fields common to all NetLabel audit messages. Returns * a pointer to the audit buffer on success, NULL on failure. * */ struct audit_buffer *netlbl_audit_start_common(int type, struct netlbl_audit *audit_info) { struct audit_buffer *audit_buf; char *secctx; u32 secctx_len; if (audit_enabled == 0) return NULL; audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type); if (audit_buf == NULL) return NULL; audit_log_format(audit_buf, "netlabel: auid=%u ses=%u", from_kuid(&init_user_ns, audit_info->loginuid), audit_info->sessionid); if (audit_info->secid != 0 && security_secid_to_secctx(audit_info->secid, &secctx, &secctx_len) == 0) { audit_log_format(audit_buf, " subj=%s", secctx); security_release_secctx(secctx, secctx_len); } return audit_buf; }
ssize_t xattr_getsecurity(struct inode *inode, const char *name, void *value, size_t size) { void *buffer = NULL; ssize_t len; if (!value || !size) { len = security_inode_getsecurity(inode, name, &buffer, false); goto out_noalloc; } len = security_inode_getsecurity(inode, name, &buffer, true); if (len < 0) return len; if (size < len) { len = -ERANGE; goto out; } memcpy(value, buffer, len); out: security_release_secctx(buffer, len); out_noalloc: return len; }
static int kernfs_security_xattr_set(const struct xattr_handler *handler, struct dentry *unused, struct inode *inode, const char *suffix, const void *value, size_t size, int flags) { struct kernfs_node *kn = inode->i_private; struct kernfs_iattrs *attrs; void *secdata; u32 secdata_len = 0; int error; attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; error = security_inode_setsecurity(inode, suffix, value, size, flags); if (error) return error; error = security_inode_getsecctx(inode, &secdata, &secdata_len); if (error) return error; mutex_lock(&kernfs_mutex); error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len); mutex_unlock(&kernfs_mutex); if (secdata) security_release_secctx(secdata, secdata_len); return error; }
static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) { char *secdata; u32 seclen, secid; int err; err = security_socket_getpeersec_dgram(NULL, skb, &secid); if (err) return; err = security_secid_to_secctx(secid, &secdata, &seclen); if (err) return; put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata); security_release_secctx(secdata, seclen); }
/** * kernfs_put - put a reference count on a kernfs_node * @kn: the target kernfs_node * * Put a reference count of @kn and destroy it if it reached zero. */ void kernfs_put(struct kernfs_node *kn) { struct kernfs_node *parent; struct kernfs_root *root; if (!kn || !atomic_dec_and_test(&kn->count)) return; root = kernfs_root(kn); repeat: /* * Moving/renaming is always done while holding reference. * kn->parent won't change beneath us. */ parent = kn->parent; WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, "kernfs_put: %s/%s: released with incorrect active_ref %d\n", parent ? parent->name : "", kn->name, atomic_read(&kn->active)); if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); kfree_const(kn->name); if (kn->iattr) { if (kn->iattr->ia_secdata) security_release_secctx(kn->iattr->ia_secdata, kn->iattr->ia_secdata_len); simple_xattrs_free(&kn->iattr->xattrs); } kfree(kn->iattr); ida_simple_remove(&root->ino_ida, kn->ino); kmem_cache_free(kernfs_node_cache, kn); kn = parent; if (kn) { if (atomic_dec_and_test(&kn->count)) goto repeat; } else { /* just released the root kn, free @root too */ ida_destroy(&root->ino_ida); kfree(root); } }
/*! 2017. 3.18 study -ing */ void kernfs_put(struct kernfs_node *kn) { struct kernfs_node *parent; struct kernfs_root *root; if (!kn || !atomic_dec_and_test(&kn->count)) return; root = kernfs_root(kn); repeat: /* Moving/renaming is always done while holding reference. * kn->parent won't change beneath us. */ parent = kn->parent; WARN(!(kn->flags & KERNFS_REMOVED), "kernfs: free using entry: %s/%s\n", parent ? parent->name : "", kn->name); if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); if (!(kn->flags & KERNFS_STATIC_NAME)) kfree(kn->name); if (kn->iattr) { if (kn->iattr->ia_secdata) /*! Do Nothing */ security_release_secctx(kn->iattr->ia_secdata, kn->iattr->ia_secdata_len); simple_xattrs_free(&kn->iattr->xattrs); } kfree(kn->iattr); ida_simple_remove(&root->ino_ida, kn->ino); kmem_cache_free(kernfs_node_cache, kn); kn = parent; if (kn) { if (atomic_dec_and_test(&kn->count)) goto repeat; } else { /* just released the root kn, free @root too */ ida_destroy(&root->ino_ida); kfree(root); } }
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_inode_attrs *iattrs; void *secdata; int error; u32 secdata_len = 0; if (!sd) return -EINVAL; if (!sd->s_iattr) sd->s_iattr = sysfs_init_inode_attrs(sd); if (!sd->s_iattr) return -ENOMEM; iattrs = sd->s_iattr; if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; error = security_inode_setsecurity(dentry->d_inode, suffix, value, size, flags); if (error) goto out; error = security_inode_getsecctx(dentry->d_inode, &secdata, &secdata_len); if (error) goto out; if (iattrs->ia_secdata) security_release_secctx(iattrs->ia_secdata, iattrs->ia_secdata_len); iattrs->ia_secdata = secdata; iattrs->ia_secdata_len = secdata_len; } else return -EINVAL; out: return error; }
int kernfs_iop_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct kernfs_node *kn = dentry->d_fsdata; struct kernfs_iattrs *attrs; void *secdata; int error; u32 secdata_len = 0; attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; error = security_inode_setsecurity(dentry->d_inode, suffix, value, size, flags); if (error) return error; error = security_inode_getsecctx(dentry->d_inode, &secdata, &secdata_len); if (error) return error; mutex_lock(&kernfs_mutex); error = kernfs_node_setsecdata(kn, &secdata, &secdata_len); mutex_unlock(&kernfs_mutex); if (secdata) security_release_secctx(secdata, secdata_len); return error; } else if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) { return simple_xattr_set(&attrs->xattrs, name, value, size, flags); } return -EINVAL; }