/** * @brief Changes ownership of the dev * * @param name pointer to character * @param user uid_t type data * @param group gid_t type data * @return 0--success otherwise failure */ int mbtchar_chown(char *name, uid_t user, gid_t group) { struct path path; struct inode *inode = NULL; struct iattr newattrs; int ret = 0; int retrycount = 0; ENTER(); do { os_sched_timeout(30); ret = kern_path(name, LOOKUP_FOLLOW, &path); if (++retrycount >= 10) { PRINTM(ERROR, "mbtchar_chown(): fail to get kern_path\n"); LEAVE(); return -EFAULT; } } while (ret); inode = path.dentry->d_inode; mutex_lock(&inode->i_mutex); ret = mnt_want_write(path.mnt); if (ret) goto out_unlock; newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) (-1)) { newattrs.ia_valid |= ATTR_UID; newattrs.ia_uid = user; } if (group != (gid_t) (-1)) { newattrs.ia_valid |= ATTR_GID; newattrs.ia_gid = group; } if (!S_ISDIR(inode->i_mode)) newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; if (inode->i_op->setattr) ret = inode->i_op->setattr(path.dentry, &newattrs); else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ret = simple_setattr(path.dentry, &newattrs); #else ret = inode_setattr(inode, &newattrs); #endif mutex_unlock(&inode->i_mutex); mnt_drop_write(path.mnt); path_put(&path); LEAVE(); return ret; out_unlock: mutex_unlock(&inode->i_mutex); mnt_drop_write(path.mnt); path_put(&path); return ret; }
int configfs_setattr(struct dentry * dentry, struct iattr * iattr) { struct inode * inode = dentry->d_inode; struct configfs_dirent * sd = dentry->d_fsdata; struct iattr * sd_iattr; unsigned int ia_valid = iattr->ia_valid; int error; if (!sd) return -EINVAL; sd_iattr = sd->s_iattr; if (!sd_iattr) { /* setting attributes for the first time, allocate now */ sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); if (!sd_iattr) return -ENOMEM; /* assign default attributes */ sd_iattr->ia_mode = sd->s_mode; sd_iattr->ia_uid = 0; sd_iattr->ia_gid = 0; sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; sd->s_iattr = sd_iattr; } /* attributes were changed atleast once in past */ error = simple_setattr(dentry, iattr); if (error) return error; if (ia_valid & ATTR_UID) sd_iattr->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) sd_iattr->ia_gid = iattr->ia_gid; if (ia_valid & ATTR_ATIME) sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, inode->i_sb->s_time_gran); if (ia_valid & ATTR_MTIME) sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, inode->i_sb->s_time_gran); if (ia_valid & ATTR_CTIME) sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, inode->i_sb->s_time_gran); if (ia_valid & ATTR_MODE) { umode_t mode = iattr->ia_mode; if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) mode &= ~S_ISGID; sd_iattr->ia_mode = sd->s_mode = mode; } return error; }
/** * @brief Changes permissions of the dev * * @param name pointer to character * @param mode mode_t type data * @return 0--success otherwise failure */ int mbtchar_chmod(char *name, mode_t mode) { struct path path; struct inode *inode; struct iattr newattrs; int ret; int retrycount = 0; ENTER(); do { os_sched_timeout(30); ret = kern_path(name, LOOKUP_FOLLOW, &path); if (++retrycount >= 10) { PRINTM(ERROR, "mbtchar_chmod(): fail to get kern_path\n"); LEAVE(); return -EFAULT; } } while (ret); inode = path.dentry->d_inode; mutex_lock(&inode->i_mutex); ret = mnt_want_write(path.mnt); if (ret) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; if (inode->i_op->setattr) ret = inode->i_op->setattr(path.dentry, &newattrs); else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ret = simple_setattr(path.dentry, &newattrs); #else ret = inode_setattr(inode, &newattrs); #endif mutex_unlock(&inode->i_mutex); mnt_drop_write(path.mnt); path_put(&path); LEAVE(); return ret; out_unlock: mutex_unlock(&inode->i_mutex); mnt_drop_write(path.mnt); path_put(&path); return ret; }
int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; umode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex)); if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; } if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) { if (attr->ia_size != inode->i_size) inode_inc_iversion(inode); } if ((ia_valid & ATTR_MODE)) { umode_t amode = attr->ia_mode; /* Flag setting protected by i_mutex */ if (is_sxid(amode)) inode->i_flags &= ~S_NOSEC; } now = current_fs_time(inode->i_sb); attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; if (ia_valid & ATTR_KILL_PRIV) { attr->ia_valid &= ~ATTR_KILL_PRIV; ia_valid &= ~ATTR_KILL_PRIV; error = security_inode_need_killpriv(dentry); if (error > 0) error = security_inode_killpriv(dentry); if (error) return error; } /* * We now pass ATTR_KILL_S*ID to the lower level setattr function so * that the function has the ability to reinterpret a mode change * that's due to these bits. This adds an implicit restriction that * no function will ever call notify_change with both ATTR_MODE and * ATTR_KILL_S*ID set. */ if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && (ia_valid & ATTR_MODE)) BUG(); if (ia_valid & ATTR_KILL_SUID) { if (mode & S_ISUID) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = (inode->i_mode & ~S_ISUID); } } if (ia_valid & ATTR_KILL_SGID) { if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = inode->i_mode; } attr->ia_mode &= ~S_ISGID; } } if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) return 0; error = security_inode_setattr(dentry, attr); if (error) return error; if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); if (!error) { fsnotify_change(dentry, ia_valid); ima_inode_post_setattr(dentry); evm_inode_post_setattr(dentry, ia_valid); } return error; }
/** * notify_change - modify attributes of a filesytem object * @dentry: object affected * @iattr: new attributes * @delegated_inode: returns inode, if the inode is delegated * * The caller must hold the i_mutex on the affected object. * * If notify_change discovers a delegation in need of breaking, * it will return -EWOULDBLOCK and return a reference to the inode in * delegated_inode. The caller should then break the delegation and * retry. Because breaking a delegation may take a long time, the * caller should drop the i_mutex before doing so. * * Alternatively, a caller may pass NULL for delegated_inode. This may * be appropriate for callers that expect the underlying filesystem not * to be NFS exported. Also, passing NULL is fine for callers holding * the file open for write, as there can be no conflicting delegation in * that case. */ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode) { struct inode *inode = dentry->d_inode; umode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; WARN_ON_ONCE(!inode_is_locked(inode)); if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; } /* * If utimes(2) and friends are called with times == NULL (or both * times are UTIME_NOW), then we need to check for write permission */ if (ia_valid & ATTR_TOUCH) { if (IS_IMMUTABLE(inode)) return -EPERM; if (!inode_owner_or_capable(inode)) { error = inode_permission(inode, MAY_WRITE); if (error) return error; } } if ((ia_valid & ATTR_MODE)) { umode_t amode = attr->ia_mode; /* Flag setting protected by i_mutex */ if (is_sxid(amode)) inode->i_flags &= ~S_NOSEC; } now = current_fs_time(inode->i_sb); attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; if (ia_valid & ATTR_KILL_PRIV) { attr->ia_valid &= ~ATTR_KILL_PRIV; ia_valid &= ~ATTR_KILL_PRIV; error = security_inode_need_killpriv(dentry); if (error > 0) error = security_inode_killpriv(dentry); if (error) return error; } /* * We now pass ATTR_KILL_S*ID to the lower level setattr function so * that the function has the ability to reinterpret a mode change * that's due to these bits. This adds an implicit restriction that * no function will ever call notify_change with both ATTR_MODE and * ATTR_KILL_S*ID set. */ if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && (ia_valid & ATTR_MODE)) BUG(); if (ia_valid & ATTR_KILL_SUID) { if (mode & S_ISUID) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = (inode->i_mode & ~S_ISUID); } } if (ia_valid & ATTR_KILL_SGID) { if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = inode->i_mode; } attr->ia_mode &= ~S_ISGID; } } if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) return 0; /* * Verify that uid/gid changes are valid in the target * namespace of the superblock. */ if (ia_valid & ATTR_UID && !kuid_has_mapping(inode->i_sb->s_user_ns, attr->ia_uid)) return -EOVERFLOW; if (ia_valid & ATTR_GID && !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid)) return -EOVERFLOW; /* Don't allow modifications of files with invalid uids or * gids unless those uids & gids are being made valid. */ if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid)) return -EOVERFLOW; if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid)) return -EOVERFLOW; error = security_inode_setattr(dentry, attr); if (error) return error; error = try_break_deleg(inode, delegated_inode); if (error) return error; if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); if (!error) { fsnotify_change(dentry, ia_valid); ima_inode_post_setattr(dentry); evm_inode_post_setattr(dentry, ia_valid); } return error; }
int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; umode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; } if ((ia_valid & ATTR_MODE)) { umode_t amode = attr->ia_mode; /* */ if (is_sxid(amode)) inode->i_flags &= ~S_NOSEC; } now = current_fs_time(inode->i_sb); attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; if (ia_valid & ATTR_KILL_PRIV) { attr->ia_valid &= ~ATTR_KILL_PRIV; ia_valid &= ~ATTR_KILL_PRIV; error = security_inode_need_killpriv(dentry); if (error > 0) error = security_inode_killpriv(dentry); if (error) return error; } /* */ if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && (ia_valid & ATTR_MODE)) BUG(); if (ia_valid & ATTR_KILL_SUID) { if (mode & S_ISUID) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = (inode->i_mode & ~S_ISUID); } } if (ia_valid & ATTR_KILL_SGID) { if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = inode->i_mode; } attr->ia_mode &= ~S_ISGID; } } if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) return 0; error = security_inode_setattr(dentry, attr); if (error) return error; if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); if (!error) { fsnotify_change(dentry, ia_valid); evm_inode_post_setattr(dentry, ia_valid); } return error; }
int sjfs_file_iops_setattr(struct dentry *dentry, struct iattr *iattr) { printk("sjfs_file_iops_setattr -> simple_setattr (for testing only)\n"); // TODO: rewrite this to save the attributes back to user space return simple_setattr(dentry, iattr); }
int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; mode_t mode = inode->i_mode; int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; } now = current_fs_time(inode->i_sb); attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; if (ia_valid & ATTR_KILL_PRIV) { attr->ia_valid &= ~ATTR_KILL_PRIV; ia_valid &= ~ATTR_KILL_PRIV; error = security_inode_need_killpriv(dentry); if (error > 0) error = security_inode_killpriv(dentry); if (error) return error; } /* * We now pass ATTR_KILL_S*ID to the lower level setattr function so * that the function has the ability to reinterpret a mode change * that's due to these bits. This adds an implicit restriction that * no function will ever call notify_change with both ATTR_MODE and * ATTR_KILL_S*ID set. */ if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && (ia_valid & ATTR_MODE)) BUG(); if (ia_valid & ATTR_KILL_SUID) { if (mode & S_ISUID) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = (inode->i_mode & ~S_ISUID); } } if (ia_valid & ATTR_KILL_SGID) { if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = inode->i_mode; } attr->ia_mode &= ~S_ISGID; } } if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) return 0; error = security_inode_setattr(dentry, attr); if (error) return error; if (ia_valid & ATTR_SIZE) down_write(&dentry->d_inode->i_alloc_sem); if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); if (ia_valid & ATTR_SIZE) up_write(&dentry->d_inode->i_alloc_sem); if (!error) fsnotify_change(dentry, ia_valid); return error; }
/* This is really VOP_SETATTR() in sheep's clothing */ int vnode_iop_notify_change( DENT_T *dent_p, struct iattr * iattr_p ) { VNODE_T *vp; VATTR_T *vap; VNODE_T *cvp; int err = 0; DENT_T *rdent; CALL_DATA_T cd; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) mdki_boolean_t tooksem = FALSE; #endif if (iattr_p->ia_valid & ATTR_SIZE) { ASSERT_I_SEM_MINE(dent_p->d_inode); } if (MDKI_INOISMVFS(dent_p->d_inode)) { vap = VATTR_ALLOC(); if (vap != NULL) { vnode_iop_iattr2vattr(iattr_p, vap); /* reject attempts to use setattr to change object type */ vap->va_mask &= ~AT_TYPE; mdki_linux_init_call_data(&cd); vp = ITOV(dent_p->d_inode); err = VOP_SETATTR(vp, vap, 0, &cd); err = mdki_errno_unix_to_linux(err); /* Any underlying cleartxt got its inode truncated via changeattr * if there's a need to change its size. */ if (!err) mdki_linux_vattr_pullup(vp, vap, vap->va_mask); VATTR_FREE(vap); mdki_linux_destroy_call_data(&cd); } else { err = -ENOMEM; } } else { rdent = REALDENTRY_LOCKED(dent_p, &cvp); VNODE_DGET(rdent); if (rdent && rdent->d_inode) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) err = inode_setattr(dent_p->d_inode, iattr_p); if (err == 0) { if (iattr_p->ia_valid & ATTR_SIZE) { LOCK_INODE(rdent->d_inode); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) #if !defined RHEL_UPDATE || RHEL_UPDATE < 5 down_write(&rdent->d_inode->i_alloc_sem); #endif #endif /* * be paranoid and record the 'taken'ness in case * the called function squashes ia_valid (as is * done in nfs_setattr). */ tooksem = TRUE; } err = MDKI_NOTIFY_CHANGE(rdent, CVN_TO_VFSMNT(cvp), iattr_p); if (tooksem) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) #if !defined(RHEL_UPDATE) || RHEL_UPDATE < 5 up_write(&rdent->d_inode->i_alloc_sem); #endif #endif UNLOCK_INODE(rdent->d_inode); } } #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) */ err = simple_setattr(dent_p, iattr_p); if (err == 0) err = MDKI_NOTIFY_CHANGE(rdent, CVN_TO_VFSMNT(cvp), iattr_p); #endif /* else LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) */ } else { /* It looks as though someone removed the realdentry on us. * I am not sure why this should happen. */ err = -ENOENT; } if (rdent) { VNODE_DPUT(rdent); REALDENTRY_UNLOCK(dent_p, cvp); } } return err; }
int yramfs_file_inode_set_attr(struct dentry *dentry, struct iattr *iattr) { DBG_PRINT(""); simple_setattr(dentry, iattr); return 0; }