/* release all lower object references & free the file info structure */ static int wrapfs_file_release(struct inode *inode, struct file *file) { struct file *lower_file; #ifdef EXTRA_CREDIT int CHKSUM_SIZE =0; char *algo = kmalloc(sizeof(char)*10,GFP_KERNEL); int *algo_len = kmalloc(sizeof(int)*1,GFP_KERNEL); char *getchkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL); #else char *getchkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL); #endif char *has_integrity = kmalloc(sizeof(char)*1,GFP_KERNEL); int rc; lower_file = wrapfs_lower_file(file); if (lower_file) { if(lower_file->f_mode == O_RDONLY) goto out_release; else if(!S_ISDIR(lower_file->f_path.dentry->d_inode->i_mode)&& wrapfs_get_write_dirty(inode) == WRITE_DIRTY_BIT) { #ifdef EXTRA_CREDIT CHKSUM_SIZE = get_default_chksum_size(lower_file->f_path.dentry,algo,algo_len); #endif if(!has_integrity || !getchkbuf) { rc = -ENOMEM; goto out_release; } spin_lock(&inode->i_lock); wrapfs_set_write_dirty(inode,READ_DIRTY_BIT); spin_unlock(&inode->i_lock); if(vfs_getxattr(lower_file->f_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1)>0) { if(!memcmp(has_integrity,"1",1)) { calculate_checksum(lower_file,getchkbuf,CHKSUM_SIZE); rc = vfs_setxattr(lower_file->f_path.dentry,XATTR_INTEGRITY_VAL,getchkbuf,CHKSUM_SIZE,XATTR_CREATE); if(rc == -EEXIST) rc = vfs_setxattr(lower_file->f_path.dentry,XATTR_INTEGRITY_VAL,getchkbuf,CHKSUM_SIZE,XATTR_REPLACE); } } } out_release: wrapfs_set_lower_file(file, NULL); fput(lower_file); } kfree(WRAPFS_F(file)); kfree(getchkbuf); kfree(has_integrity); #ifdef EXTRA_CREDIT kfree(algo); kfree(algo_len); #endif return 0; }
/* * Extended attribute SET operations */ static long setxattr(struct dentry *d, const char __user *name, const void __user *value, size_t size, int flags) { int error; void *kvalue = NULL; char kname[XATTR_NAME_MAX + 1]; if (flags & ~(XATTR_CREATE|XATTR_REPLACE)) return -EINVAL; error = strncpy_from_user(kname, name, sizeof(kname)); if (error == 0 || error == sizeof(kname)) error = -ERANGE; if (error < 0) return error; if (size) { if (size > XATTR_SIZE_MAX) return -E2BIG; kvalue = memdup_user(value, size); if (IS_ERR(kvalue)) return PTR_ERR(kvalue); } error = vfs_setxattr(d, kname, kvalue, size, flags); kfree(kvalue); return error; }
/* * Extended attribute SET operations */ static long setxattr(struct dentry *d, const char __user *name, const void __user *value, size_t size, int flags) { int error; void *kvalue = NULL; char kname[XATTR_NAME_MAX + 1]; if (flags & ~(XATTR_CREATE|XATTR_REPLACE)) return -EINVAL; error = strncpy_from_user(kname, name, sizeof(kname)); if (error == 0 || error == sizeof(kname)) error = -ERANGE; if (error < 0) return error; if (size) { if (size > XATTR_SIZE_MAX) return -E2BIG; kvalue = kmalloc(size, GFP_KERNEL); if (!kvalue) return -ENOMEM; if (copy_from_user(kvalue, value, size)) { kfree(kvalue); return -EFAULT; } } error = vfs_setxattr(d, kname, kvalue, size, flags); kfree(kvalue); return error; }
int ovl_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { int err; struct dentry *upperdentry; err = ovl_want_write(dentry); if (err) goto out; err = -EPERM; if (ovl_is_private_xattr(name)) goto out_drop_write; err = ovl_copy_up(dentry); if (err) goto out_drop_write; upperdentry = ovl_dentry_upper(dentry); err = vfs_setxattr(upperdentry, name, value, size, flags); out_drop_write: ovl_drop_write(dentry); out: return err; }
static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name, const struct posix_acl *acl) { void *buffer; size_t size; int err; if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl) return 0; size = posix_acl_to_xattr(NULL, acl, NULL, 0); buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; size = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); err = size; if (err < 0) goto out_free; err = vfs_setxattr(upperdentry, name, buffer, size, XATTR_CREATE); out_free: kfree(buffer); return err; }
static int set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) { int len; size_t buflen; char *buf = NULL; int error = 0; buflen = posix_acl_xattr_size(pacl->a_count); buf = kmalloc(buflen, GFP_KERNEL); error = -ENOMEM; if (buf == NULL) goto out; len = posix_acl_to_xattr(pacl, buf, buflen); if (len < 0) { error = len; goto out; } error = vfs_setxattr(dentry, key, buf, len, 0); out: kfree(buf); return error; }
int cachefiles_set_object_xattr(struct cachefiles_object *object, struct cachefiles_xattr *auxdata) { struct dentry *dentry = object->dentry; int ret; ASSERT(object->fscache.cookie); ASSERT(dentry); _enter("%p,#%d", object, auxdata->len); /* attempt to install the cache metadata directly */ _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len); ret = vfs_setxattr(dentry, cachefiles_xattr_cache, &auxdata->type, auxdata->len, XATTR_CREATE); if (ret < 0 && ret != -ENOMEM) cachefiles_io_error_obj( object, "Failed to set xattr with error %d", ret); _leave(" = %d", ret); return ret; }
/* * BKL held by caller. * dentry->d_inode->i_mutex locked */ int unionfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct dentry *lower_dentry = NULL; struct dentry *parent; int err = -EOPNOTSUPP; bool valid; unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD); parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT); unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD); valid = __unionfs_d_revalidate(dentry, parent, false); if (unlikely(!valid)) { err = -ESTALE; goto out; } lower_dentry = unionfs_lower_dentry(dentry); err = vfs_setxattr(lower_dentry, (char *) name, (void *) value, size, flags); out: unionfs_check_dentry(dentry); unionfs_unlock_dentry(dentry); unionfs_unlock_parent(dentry, parent); unionfs_read_unlock(dentry->d_sb); return err; }
static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) { int err; struct dentry *newdentry; const struct cred *old_cred; struct cred *override_cred; /* FIXME: recheck lower dentry to see if whiteout is really needed */ err = -ENOMEM; override_cred = prepare_kernel_cred(NULL); if (!override_cred) goto out; override_cred->fsuid = make_kuid(current_user_ns(), 0); if (!uid_valid(override_cred->fsuid)) override_cred->fsuid = GLOBAL_ROOT_UID; override_cred->fsgid = make_kgid(current_user_ns(), 0); if (!gid_valid(override_cred->fsgid)) override_cred->fsgid = GLOBAL_ROOT_GID; old_cred = override_creds(override_cred); newdentry = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len); err = PTR_ERR(newdentry); if (IS_ERR(newdentry)) goto out_put_cred; /* Just been removed within the same locked region */ WARN_ON(newdentry->d_inode); err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink); if (err) goto out_dput; ovl_dentry_version_inc(dentry->d_parent); err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0); if (err) vfs_unlink(upperdir->d_inode, newdentry, NULL); out_dput: dput(newdentry); out_put_cred: revert_creds(old_cred); put_cred(override_cred); out: if (err) { /* * There's no way to recover from failure to whiteout. * What should we do? Log a big fat error and... ? */ pr_err("overlayfs: ERROR - failed to whiteout '%s'\n", dentry->d_name.name); } return err; }
int ovl_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { int err; struct dentry *upperdentry; if (ovl_is_private_xattr(name)) return -EPERM; err = ovl_copy_up(dentry); if (err) return err; upperdentry = ovl_dentry_upper(dentry); return vfs_setxattr(upperdentry, name, value, size, flags); }
int sym_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { int rc = 0; struct dentry *lower_dentry; lower_dentry = wrapfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->setxattr) { rc = -EOPNOTSUPP; goto out; } rc = vfs_setxattr(lower_dentry, name, value, size, flags); out: return rc; }
static int diaryfs_setxattr(struct dentry * dentry, const char * name, const void * value, size_t size, int flags) { int err; struct dentry * lower_dentry; struct path lower_path; diaryfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; if (!lower_dentry->d_inode->i_op->setxattr) { err = -EOPNOTSUPP; goto out; } err = vfs_setxattr(lower_dentry, name, value, size, flags); if (err) goto out; fsstack_copy_attr_all(dentry->d_inode, lower_path.dentry->d_inode); out: diaryfs_put_lower_path(dentry, &lower_path); return err; }
int amfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { int err; struct dentry *lower_dentry; struct path lower_path; amfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; if (!lower_dentry->d_inode->i_op || !lower_dentry->d_inode->i_op->setxattr) { err = -EINVAL; goto out; } err = vfs_setxattr(lower_dentry, name, value, size, flags); out: amfs_put_lower_path(dentry, &lower_path); return err; }
int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name, const void *value, size_t size, int flags) { int err; struct dentry *upperdentry = ovl_i_dentry_upper(inode); struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry); const struct cred *old_cred; err = ovl_want_write(dentry); if (err) goto out; if (!value && !upperdentry) { err = vfs_getxattr(realdentry, name, NULL, 0); if (err < 0) goto out_drop_write; } if (!upperdentry) { err = ovl_copy_up(dentry); if (err) goto out_drop_write; realdentry = ovl_dentry_upper(dentry); } old_cred = ovl_override_creds(dentry->d_sb); if (value) err = vfs_setxattr(realdentry, name, value, size, flags); else { WARN_ON(flags != XATTR_REPLACE); err = vfs_removexattr(realdentry, name); } revert_creds(old_cred); out_drop_write: ovl_drop_write(dentry); out: return err; }
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { int err; struct path realpath; enum ovl_path_type type = ovl_path_real(dentry, &realpath); const struct cred *old_cred; err = ovl_want_write(dentry); if (err) goto out; if (!value && !OVL_TYPE_UPPER(type)) { err = vfs_getxattr(realpath.dentry, name, NULL, 0); if (err < 0) goto out_drop_write; } err = ovl_copy_up(dentry); if (err) goto out_drop_write; if (!OVL_TYPE_UPPER(type)) ovl_path_upper(dentry, &realpath); old_cred = ovl_override_creds(dentry->d_sb); if (value) err = vfs_setxattr(realpath.dentry, name, value, size, flags); else { WARN_ON(flags != XATTR_REPLACE); err = vfs_removexattr(realpath.dentry, name); } revert_creds(old_cred); out_drop_write: ovl_drop_write(dentry); out: return err; }
int ckpt_map_setattr(char *node, struct task_struct *tsk, unsigned long area, char *key, void *value, size_t size) { int ret; struct file *file; char path[MAP_PATH_MAX]; ret = ckpt_map_get_path(node, klnk_get_gpid(tsk), area, path); if (ret) { log_err("failed to get path"); return ret; } file = filp_open(path, MAP_FLAG, MAP_MODE); if (IS_ERR(file)) { log_err("failed to open, path=%s", path); return PTR_ERR(file); } ret = vfs_setxattr(file->f_dentry, key, value, size, 0); filp_close(file, NULL); log_map_setattr(path); return 0; }
int ovl_do_whiteout_v1(struct inode *workdir, struct dentry *dentry) { int err; err = vfs_symlink(workdir, dentry, ovl_whiteout_symlink); if (err) return err; err = vfs_setxattr(dentry, ovl_whiteout_xattr, "y", 1, 0); if (err) vfs_unlink(workdir, dentry, NULL); if (err) { /* * There's no way to recover from failure to whiteout. * What should we do? Log a big fat error and... ? */ pr_err("overlayfs: ERROR - failed to whiteout '%s'\n", dentry->d_name.name); } return err; }
static int wrapfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path, saved_path; int alloc_size = 1024; char *buf = kmalloc(alloc_size, GFP_KERNEL); char *fbuf = kmalloc(alloc_size, GFP_KERNEL); struct vfsmount *mnt = NULL; struct file *filp = NULL; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; pathcpy(&saved_path, &nd->path); pathcpy(&nd->path, &lower_path); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); pathcpy(&nd->path, &saved_path); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /*********************************************************/ if (!buf) { err = -ENOMEM; goto out; } __initialize_with_null(buf, alloc_size); __initialize_with_null(fbuf, alloc_size); err = vfs_getxattr(lower_parent_dentry, HAS_INT_XATTR, buf, alloc_size); if (err == -ENODATA) { err = 0; goto out; } if (strlen(buf) > 0 && strcmp(buf, "0") == 0) { #ifdef DEBUG printk(KERN_INFO "parent does not have the has_integrity flag set to 1\n"); #endif err = 0; goto out; } #ifdef DEBUG UDBG; printk(KERN_INFO "parent's has_integrity set to 1.Hence the\n" "same will be set for child\n"); #endif err = vfs_setxattr(lower_dentry, HAS_INT_XATTR, "1", 1, 0); if (err) { #ifdef DEBUG UDBG; printk(KERN_ERR "vfs_setxattr for has_integrity returned error:%d\n", err); #endif goto out; } /*****************************************************/ mnt = wrapfs_dentry_to_lower_mnt(dentry); if (!mnt) { #ifdef DEBUG UDBG; printk(KERN_INFO "unable to get mount\n"); #endif err = -EIO; goto out; } filp = dentry_open(dget(lower_dentry), mntget(mnt), (O_RDONLY | O_LARGEFILE), current_cred()); if (IS_ERR(filp)) { err = -EIO; goto out; } err = calculate_integrity(filp, fbuf, alloc_size); if (err) goto out; err = vfs_setxattr( lower_dentry, INT_VAL_XATTR, fbuf, strlen(fbuf), 0); if (err) goto out; if (err) goto out; /*********************************************************/ out: if (filp) fput(filp); mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
/* The part that goes here is part of HW2. The methods wrapfs_(set|get|remove|list) xattr are written in line with the smimlar methods from the module ecryptfs */ int wrapfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { int rc = 0; char tval = *((char *)value); struct dentry *lower_dentry; int alloc_size = 1024; char *buf = kmalloc(alloc_size, GFP_KERNEL); char *fbuf = kmalloc(alloc_size, GFP_KERNEL); #ifdef EXTRA_CREDIT char *tbuf = NULL; int s = size; #endif struct file *filp = NULL; struct vfsmount *mnt = NULL; if (!buf || !fbuf) { rc = -ENOMEM; goto out; } __initialize_with_null(buf, alloc_size); __initialize_with_null(fbuf, alloc_size); lower_dentry = wrapfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->setxattr) { rc = -EOPNOTSUPP; goto out; } if (strcmp(name, INT_VAL_XATTR) == 0) { rc = -EACCES; goto out; } #ifdef EXTRA_CREDIT if (strcmp(name, INT_TYPE_XATTR) == 0) { if (current_uid() != 0) { rc = -EACCES; goto out; } tbuf = kmalloc(s+1, GFP_KERNEL); strncpy(tbuf, value, s); *(tbuf+s) = '\0'; rc = is_valid_intigrity_type(tbuf); if (rc) { rc = -EINVAL; goto out; } if (S_ISDIR(dentry->d_inode->i_mode)) { rc = vfs_setxattr( lower_dentry, HAS_INT_XATTR, "1", 1, flags); if (rc) goto out; goto set; } mnt = wrapfs_dentry_to_lower_mnt(dentry); if (!mnt) { rc = -EIO; goto out; } filp = dentry_open(dget(lower_dentry), mntget(mnt), (O_RDONLY | O_LARGEFILE), current_cred()); if (IS_ERR(filp)) { rc = -EIO; goto out; } rc = vfs_setxattr(lower_dentry, name, value, size, flags); if (rc) goto out; rc = calculate_integrity(filp, fbuf, alloc_size); if (rc) goto out; rc = vfs_setxattr( lower_dentry, HAS_INT_XATTR, "1", 1, flags); if (rc) goto out; rc = vfs_setxattr( lower_dentry, INT_VAL_XATTR, fbuf, strlen(fbuf), flags); if (rc) goto out; goto out; } #endif if (strcmp(name, HAS_INT_XATTR) == 0) { if (current_uid() != 0) { rc = -EACCES; goto out; } if (tval == '0') { if (S_ISDIR(dentry->d_inode->i_mode)) { rc = 0; goto set; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->getxattr( lower_dentry, INT_VAL_XATTR, buf, alloc_size); mutex_unlock(&lower_dentry->d_inode->i_mutex); if (rc == -ENODATA) goto set; if (!lower_dentry->d_inode->i_op->removexattr) { rc = -EOPNOTSUPP; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->removexattr( lower_dentry, INT_VAL_XATTR); mutex_unlock(&lower_dentry->d_inode->i_mutex); #ifdef EXTRA_CREDIT mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->removexattr( lower_dentry, INT_TYPE_XATTR); mutex_unlock(&lower_dentry->d_inode->i_mutex); #endif } else if (tval == '1') { if (S_ISDIR(dentry->d_inode->i_mode)) { rc = 0; goto set; } mnt = wrapfs_dentry_to_lower_mnt(dentry); if (!mnt) { rc = -EIO; goto out; } filp = dentry_open(dget(lower_dentry), mntget(mnt), (O_RDONLY | O_LARGEFILE), current_cred()); if (IS_ERR(filp)) { rc = -EIO; goto out; } rc = calculate_integrity(filp, fbuf, alloc_size); if (rc) goto out; rc = vfs_setxattr( lower_dentry, INT_VAL_XATTR, fbuf, strlen(fbuf), flags); if (rc) goto out; } else { rc = -EINVAL; goto out; } } /*end if (strcmp(name, HAS_INT_XATTR) == 0)*/ set: rc = vfs_setxattr(lower_dentry, name, value, size, flags); out: #ifdef EXTRA_CREDIT kfree(tbuf); #endif kfree(buf); kfree(fbuf); if (filp) fput(filp); return rc; }
static int wrapfs_removexattr(struct dentry *dentry, const char *name) { int rc = 0; struct dentry *lower_dentry; #ifdef EXTRA_CREDIT struct vfsmount *mnt = NULL; int alloc_size = 1024; char *fbuf = kmalloc(alloc_size, GFP_KERNEL); struct file *filp = NULL; #endif lower_dentry = wrapfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->removexattr) { rc = -EOPNOTSUPP; goto out; } if (strcmp(name, HAS_INT_XATTR) == 0) { if (current_uid() != 0) { rc = -EACCES; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->removexattr( lower_dentry, INT_VAL_XATTR); #ifdef EXTRA_CREDIT rc = lower_dentry->d_inode->i_op->removexattr( lower_dentry, INT_TYPE_XATTR); #endif mutex_unlock(&lower_dentry->d_inode->i_mutex); } if (strcmp(name, INT_VAL_XATTR) == 0) { rc = -EACCES; goto out; } #ifdef EXTRA_CREDIT if (strcmp(name, INT_TYPE_XATTR) == 0) { if (current_uid() != 0) { rc = -EACCES; goto out; } if (S_ISDIR(dentry->d_inode->i_mode)) { rc = 0; goto rem; } mnt = wrapfs_dentry_to_lower_mnt(dentry); if (!mnt) { rc = -EIO; goto out; } filp = dentry_open(dget(lower_dentry), mntget(mnt), (O_RDONLY | O_LARGEFILE), current_cred()); if (IS_ERR(filp)) { rc = -EIO; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->removexattr( lower_dentry, name); mutex_unlock(&lower_dentry->d_inode->i_mutex); if (rc) goto out; rc = calculate_integrity(filp, fbuf, alloc_size); if (rc) goto out; rc = vfs_setxattr(lower_dentry, INT_VAL_XATTR, fbuf, strlen(fbuf), 0); if (rc) goto out; goto out; } rem: if (filp) fput(filp); #endif mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name); mutex_unlock(&lower_dentry->d_inode->i_mutex); out: #ifdef EXTRA_CREDIT kfree(fbuf); #endif return rc; }
int cachefiles_check_object_type(struct cachefiles_object *object) { struct dentry *dentry = object->dentry; char type[3], xtype[3]; int ret; ASSERT(dentry); ASSERT(dentry->d_inode); if (!object->fscache.cookie) strcpy(type, "C3"); else snprintf(type, 3, "%02x", object->fscache.cookie->def->type); _enter("%p{%s}", object, type); /* attempt to install a type label directly */ ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2, XATTR_CREATE); if (ret == 0) { _debug("SET"); /* we succeeded */ goto error; } if (ret != -EEXIST) { kerror("Can't set xattr on %*.*s [%lu] (err %d)", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, -ret); goto error; } /* read the current type label */ ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3); if (ret < 0) { if (ret == -ERANGE) goto bad_type_length; kerror("Can't read xattr on %*.*s [%lu] (err %d)", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, -ret); goto error; } /* check the type is what we're expecting */ if (ret != 2) goto bad_type_length; if (xtype[0] != type[0] || xtype[1] != type[1]) goto bad_type; ret = 0; error: _leave(" = %d", ret); return ret; bad_type_length: kerror("Cache object %lu type xattr length incorrect", dentry->d_inode->i_ino); ret = -EIO; goto error; bad_type: xtype[2] = 0; kerror("Cache object %*.*s [%lu] type %s not %s", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, xtype, type); ret = -EIO; goto error; }
/* copyup all extended attrs for a given dentry */ static int copyup_xattrs(struct dentry *old_hidden_dentry, struct dentry *new_hidden_dentry) { int err = 0; ssize_t list_size = -1; char *name_list = NULL; char *attr_value = NULL; char *name_list_orig = NULL; list_size = vfs_listxattr(old_hidden_dentry, NULL, 0); if (list_size <= 0) { err = list_size; goto out; } name_list = unionfs_xattr_alloc(list_size + 1, XATTR_LIST_MAX); if (!name_list || IS_ERR(name_list)) { err = PTR_ERR(name_list); goto out; } list_size = vfs_listxattr(old_hidden_dentry, name_list, list_size); attr_value = unionfs_xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX); if (!attr_value || IS_ERR(attr_value)) { err = PTR_ERR(name_list); goto out; } name_list_orig = name_list; while (*name_list) { ssize_t size; /* Lock here since vfs_getxattr doesn't lock for us */ mutex_lock(&old_hidden_dentry->d_inode->i_mutex); size = vfs_getxattr(old_hidden_dentry, name_list, attr_value, XATTR_SIZE_MAX); mutex_unlock(&old_hidden_dentry->d_inode->i_mutex); if (size < 0) { err = size; goto out; } if (size > XATTR_SIZE_MAX) { err = -E2BIG; goto out; } /* Don't lock here since vfs_setxattr does it for us. */ err = vfs_setxattr(new_hidden_dentry, name_list, attr_value, size, 0); if (err < 0) goto out; name_list += strlen(name_list) + 1; } out: name_list = name_list_orig; if (name_list) unionfs_xattr_free(name_list, list_size + 1); if (attr_value) unionfs_xattr_free(attr_value, XATTR_SIZE_MAX); /* It is no big deal if this fails, we just roll with the punches. */ if (err == -ENOTSUPP || err == -EOPNOTSUPP) err = 0; return err; }
static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) { int err; struct dentry *newdentry; const struct cred *old_cred; struct cred *override_cred; /* FIXME: recheck lower dentry to see if whiteout is really needed */ err = -ENOMEM; override_cred = prepare_creds(); if (!override_cred) goto out; /* * CAP_SYS_ADMIN for setxattr * CAP_DAC_OVERRIDE for symlink creation * CAP_FOWNER for unlink in sticky directory */ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); cap_raise(override_cred->cap_effective, CAP_FOWNER); override_cred->fsuid = GLOBAL_ROOT_UID; override_cred->fsgid = GLOBAL_ROOT_GID; old_cred = override_creds(override_cred); newdentry = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len); err = PTR_ERR(newdentry); if (IS_ERR(newdentry)) goto out_put_cred; /* Just been removed within the same locked region */ WARN_ON(newdentry->d_inode); err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink); if (err) goto out_dput; ovl_dentry_version_inc(dentry->d_parent); err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0); if (err) vfs_unlink(upperdir->d_inode, newdentry); out_dput: dput(newdentry); out_put_cred: revert_creds(old_cred); put_cred(override_cred); out: if (err) { /* * There's no way to recover from failure to whiteout. * What should we do? Log a big fat error and... ? */ pr_err("overlayfs: ERROR - failed to whiteout '%s'\n", dentry->d_name.name); } return err; }
static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; int alloc_size = 1024; char *buf = kmalloc(alloc_size, GFP_KERNEL); wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink); /*****************************************************/ if (!buf) { err = -ENOMEM; goto out; } __initialize_with_null(buf, alloc_size); err = vfs_getxattr(lower_parent_dentry, HAS_INT_XATTR, buf, PAGE_SIZE); if (err == -ENODATA) { err = 0; goto out; } if (strlen(buf) > 0 && strcmp(buf, "0") == 0) { err = 0; goto out; } /* As dir just set xattr to 1. NO calculation of integrity is required. */ err = vfs_setxattr(dentry, HAS_INT_XATTR, "1", 1, 0); if (err) goto out; /******************************************************/ out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
/* copyup all extended attrs for a given dentry */ static int copyup_xattrs(struct dentry *old_lower_dentry, struct dentry *new_lower_dentry) { int err = 0; ssize_t list_size = -1; char *name_list = NULL; char *attr_value = NULL; char *name_list_buf = NULL; /* query the actual size of the xattr list */ list_size = vfs_listxattr(old_lower_dentry, NULL, 0); if (list_size <= 0) { err = list_size; goto out; } /* allocate space for the actual list */ name_list = unionfs_xattr_alloc(list_size + 1, XATTR_LIST_MAX); if (unlikely(!name_list || IS_ERR(name_list))) { err = PTR_ERR(name_list); goto out; } name_list_buf = name_list; /* save for kfree at end */ /* now get the actual xattr list of the source file */ list_size = vfs_listxattr(old_lower_dentry, name_list, list_size); if (list_size <= 0) { err = list_size; goto out; } /* allocate space to hold each xattr's value */ attr_value = unionfs_xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX); if (unlikely(!attr_value || IS_ERR(attr_value))) { err = PTR_ERR(name_list); goto out; } /* in a loop, get and set each xattr from src to dst file */ while (*name_list) { ssize_t size; /* Lock here since vfs_getxattr doesn't lock for us */ mutex_lock(&old_lower_dentry->d_inode->i_mutex); size = vfs_getxattr(old_lower_dentry, name_list, attr_value, XATTR_SIZE_MAX); mutex_unlock(&old_lower_dentry->d_inode->i_mutex); if (size < 0) { err = size; goto out; } if (size > XATTR_SIZE_MAX) { err = -E2BIG; goto out; } /* Don't lock here since vfs_setxattr does it for us. */ err = vfs_setxattr(new_lower_dentry, name_list, attr_value, size, 0); /* * Selinux depends on "security.*" xattrs, so to maintain * the security of copied-up files, if Selinux is active, * then we must copy these xattrs as well. So we need to * temporarily get FOWNER privileges. * XXX: move entire copyup code to SIOQ. */ if (err == -EPERM && !capable(CAP_FOWNER)) { cap_raise(current->cap_effective, CAP_FOWNER); err = vfs_setxattr(new_lower_dentry, name_list, attr_value, size, 0); cap_lower(current->cap_effective, CAP_FOWNER); } if (err < 0) goto out; name_list += strlen(name_list) + 1; } out: unionfs_xattr_kfree(name_list_buf); unionfs_xattr_kfree(attr_value); /* Ignore if xattr isn't supported */ if (err == -ENOTSUPP || err == -EOPNOTSUPP) err = 0; return err; }
int cachefiles_check_object_xattr(struct cachefiles_object *object, struct cachefiles_xattr *auxdata) { struct cachefiles_xattr *auxbuf; struct dentry *dentry = object->dentry; int ret; _enter("%p,#%d", object, auxdata->len); ASSERT(dentry); ASSERT(dentry->d_inode); auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); if (!auxbuf) { _leave(" = -ENOMEM"); return -ENOMEM; } /* read the current type label */ ret = vfs_getxattr(dentry, cachefiles_xattr_cache, &auxbuf->type, 512 + 1); if (ret < 0) { if (ret == -ENODATA) goto stale; /* no attribute - power went off * mid-cull? */ if (ret == -ERANGE) goto bad_type_length; cachefiles_io_error_obj(object, "Can't read xattr on %lu (err %d)", dentry->d_inode->i_ino, -ret); goto error; } /* check the on-disk object */ if (ret < 1) goto bad_type_length; if (auxbuf->type != auxdata->type) goto stale; auxbuf->len = ret; /* consult the netfs */ if (object->fscache.cookie->def->check_aux) { enum fscache_checkaux result; unsigned int dlen; dlen = auxbuf->len - 1; _debug("checkaux %s #%u", object->fscache.cookie->def->name, dlen); result = fscache_check_aux(&object->fscache, &auxbuf->data, dlen); switch (result) { /* entry okay as is */ case FSCACHE_CHECKAUX_OKAY: goto okay; /* entry requires update */ case FSCACHE_CHECKAUX_NEEDS_UPDATE: break; /* entry requires deletion */ case FSCACHE_CHECKAUX_OBSOLETE: goto stale; default: BUG(); } /* update the current label */ ret = vfs_setxattr(dentry, cachefiles_xattr_cache, &auxdata->type, auxdata->len, XATTR_REPLACE); if (ret < 0) { cachefiles_io_error_obj(object, "Can't update xattr on %lu" " (error %d)", dentry->d_inode->i_ino, -ret); goto error; } } okay: ret = 0; error: kfree(auxbuf); _leave(" = %d", ret); return ret; bad_type_length: kerror("Cache object %lu xattr length incorrect", dentry->d_inode->i_ino); ret = -EIO; goto error; stale: ret = -ESTALE; goto error; }