static int diaryfs_permission(struct inode *inode, int mask) { struct inode * lower_inode; int err; lower_inode = diaryfs_lower_inode(inode); err = inode_permission(lower_inode, mask); return err; }
/* copy of may_create in fs/namei.c() */ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) { if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; return inode_permission(dir, MAY_WRITE | MAY_EXEC); }
static int ccfs_permission(struct inode *inode, int mask) { int rc = inode_permission(ccfs_get_nested_inode(inode), mask); mdbg(INFO3,"Permission check for inode %p [%ld] returned [%d]", inode, inode->i_ino, rc); return rc; }
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) { const struct cred *old_cred; struct cred *override_cred; struct path path; struct inode *inode; int res; if (mode & ~S_IRWXO) return -EINVAL; override_cred = prepare_creds(); if (!override_cred) return -ENOMEM; override_cred->fsuid = override_cred->uid; override_cred->fsgid = override_cred->gid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (override_cred->uid) cap_clear(override_cred->cap_effective); else override_cred->cap_effective = override_cred->cap_permitted; } old_cred = override_creds(override_cred); res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); if (res) goto out; inode = path.dentry->d_inode; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { res = -EACCES; if (path.mnt->mnt_flags & MNT_NOEXEC) goto out_path_release; } res = inode_permission(inode, mode | MAY_ACCESS); if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; if (__mnt_is_readonly(path.mnt)) res = -EROFS; out_path_release: path_put(&path); out: revert_creds(old_cred); put_cred(override_cred); return res; }
long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = filp->f_dentry->d_inode; long old_block, new_block; int result = -EINVAL; if (inode_permission(inode, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); result = -EPERM; goto out; } if (!arg) { udf_debug("invalid argument to udf_ioctl\n"); result = -EINVAL; goto out; } switch (cmd) { case UDF_GETVOLIDENT: if (copy_to_user((char __user *)arg, UDF_SB(inode->i_sb)->s_volume_ident, 32)) result = -EFAULT; else result = 0; goto out; case UDF_RELOCATE_BLOCKS: if (!capable(CAP_SYS_ADMIN)) { result = -EACCES; goto out; } if (get_user(old_block, (long __user *)arg)) { result = -EFAULT; goto out; } result = udf_relocate_blocks(inode->i_sb, old_block, &new_block); if (result == 0) result = put_user(new_block, (long __user *)arg); goto out; case UDF_GETEASIZE: result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg); goto out; case UDF_GETEABLOCK: result = copy_to_user((char __user *)arg, UDF_I(inode)->i_ext.i_data, UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0; goto out; } out: return result; }
STATIC int base0fs_permission(inode_t *inode, int mask) { inode_t *lower_inode; int err; print_entry_location(); lower_inode = INODE_TO_LOWER(inode); err = inode_permission(lower_inode, mask); print_exit_status(err); return err; }
/* Check whether we are allowed to dedupe the destination file */ static bool allow_file_dedupe(struct file *file) { if (capable(CAP_SYS_ADMIN)) return true; if (file->f_mode & FMODE_WRITE) return true; if (uid_eq(current_fsuid(), file_inode(file)->i_uid)) return true; if (!inode_permission(file_inode(file), MAY_WRITE)) return true; return false; }
long vfs_truncate(struct path *path, loff_t length) { struct inode *inode; long error; inode = path->dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ if (S_ISDIR(inode->i_mode)) return -EISDIR; if (!S_ISREG(inode->i_mode)) return -EINVAL; error = mnt_want_write(path->mnt); if (error) goto out; error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; error = -EPERM; if (IS_APPEND(inode)) goto mnt_drop_write_and_out; error = get_write_access(inode); if (error) goto mnt_drop_write_and_out; /* * Make sure that there are no leases. get_write_access() protects * against the truncate racing with a lease-granting setlease(). */ error = break_lease(inode, O_WRONLY); if (error) goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) error = security_path_truncate(path, length, 0); if (!error) { vfs_dq_init(inode); error = do_truncate(path->dentry, length, 0, NULL); } put_write_and_out: put_write_access(inode); mnt_drop_write_and_out: mnt_drop_write(path->mnt); out: return error; }
static int u2fs_permission(struct inode *inode, int mask) { struct inode *lower_inode; int err=0; if(U2FS_I(inode)->lower_inode[LEFT] != NULL) lower_inode = u2fs_lower_inode(inode, LEFT); else lower_inode = u2fs_lower_inode(inode, RIGHT); err = inode_permission(lower_inode, mask); return err; }
static int unionfs_permission(struct inode *inode, int mask, struct nameidata *nd) { struct inode *hidden_inode = NULL; int err = 0; int bindex, bstart, bend; const int is_file = !S_ISDIR(inode->i_mode); const int write_mask = (mask & MAY_WRITE) && !(mask & MAY_READ); print_entry_location(); bstart = ibstart(inode); bend = ibend(inode); fist_print_inode("IN unionfs_permission", inode); for (bindex = bstart; bindex <= bend; bindex++) { hidden_inode = itohi_index(inode, bindex); if (!hidden_inode) continue; /* check the condition for D-F-D underlying files/directories, * we dont have to check for files, if we are checking for * directories. */ if (!is_file && !S_ISDIR(hidden_inode->i_mode)) continue; /* We use our own special version of permission, such that * only the first branch returns -EROFS. */ err = inode_permission(hidden_inode, mask, nd, bindex); /* The permissions are an intersection of the overall directory * permissions, so we fail if one fails. */ if (err) goto out; /* only the leftmost file matters. */ if (is_file || write_mask) { if (is_file && write_mask) { err = get_write_access(hidden_inode); if (!err) put_write_access(hidden_inode); } break; } } out: print_exit_status(err); return err; }
static int wrapfs_permission(struct inode *inode, int mask) { struct inode *lower_inode; int err; if(wrapfs_get_debug(inode->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); lower_inode = wrapfs_lower_inode(inode); err = inode_permission(lower_inode, mask); if(wrapfs_get_debug(inode->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
long vfs_truncate(struct path *path, loff_t length) { struct inode *inode; long error; inode = path->dentry->d_inode; if (S_ISDIR(inode->i_mode)) return -EISDIR; if (!S_ISREG(inode->i_mode)) return -EINVAL; error = mnt_want_write(path->mnt); if (error) goto out; error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; error = -EPERM; if (IS_APPEND(inode)) goto mnt_drop_write_and_out; error = get_write_access(inode); if (error) goto mnt_drop_write_and_out; error = break_lease(inode, O_WRONLY); if (error) goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) error = security_path_truncate(path); if (!error) error = do_truncate(path->dentry, length, 0, NULL); put_write_and_out: put_write_access(inode); mnt_drop_write_and_out: mnt_drop_write(path->mnt); out: return error; }
extern int vnode_shadow_iop_permission( INODE_T *inode, int mask #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) , struct nameidata *nd #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) , unsigned int flags #endif ) { INODE_T *real_inode; DENT_T *dp; int err; /* we don't have multiple dentries per shadow inode, so this is OK */ dp = vnlayer_inode2dentry_internal(inode, NULL, NULL, NULL); ASSERT(dp != NULL); real_inode = REALDENTRY(dp)->d_inode; if (real_inode == NULL) { /* just in case; not expected! */ VNODE_DPUT(dp); return -EACCES; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) err = permission(real_inode, mask, nd); #else err = inode_permission(real_inode, mask); #endif if (err == 0) { /* don't call permission() on inode, it will call back to us! */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) err = vfs_permission(inode, mask); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) err = generic_permission(inode, mask, NULL); #else err = generic_permission(inode, mask, flags, NULL); #endif } VNODE_DPUT(dp); return(err); }
int gr_handle_hardlink(const struct dentry *dentry, const struct vfsmount *mnt, struct inode *inode, const int mode, const char *to) { #ifdef CONFIG_GRKERNSEC_LINK const struct cred *cred = current_cred(); if (grsec_enable_link && cred->fsuid != inode->i_uid && (!S_ISREG(mode) || (mode & S_ISUID) || ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) || (inode_permission(inode, MAY_READ | MAY_WRITE))) && !capable(CAP_FOWNER) && cred->uid) { gr_log_fs_int2_str(GR_DONT_AUDIT, GR_HARDLINK_MSG, dentry, mnt, inode->i_uid, inode->i_gid, to); return -EPERM; } #endif return 0; }
int gr_handle_hardlink(const struct dentry *dentry, const struct vfsmount *mnt, const struct filename *to) { #ifdef CONFIG_GRKERNSEC_LINK struct inode *inode = d_backing_inode(dentry); const struct cred *cred = current_cred(); if (grsec_enable_link && !uid_eq(cred->fsuid, inode->i_uid) && (!d_is_reg(dentry) || is_privileged_binary(dentry) || (inode_permission(inode, MAY_READ | MAY_WRITE))) && !capable(CAP_FOWNER) && gr_is_global_nonroot(cred->uid)) { gr_log_fs_int2_str(GR_DONT_AUDIT, GR_HARDLINK_MSG, dentry, mnt, inode->i_uid, inode->i_gid, to->name); return -EPERM; } #endif return 0; }
SYSCALL_DEFINE1(chdir, const char __user *, filename) { struct path path; int error; error = user_path_dir(filename, &path); if (error) goto out; error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; set_fs_pwd(current->fs, &path); dput_and_out: path_put(&path); out: return error; }
asmlinkage long sys_chdir(const char __user * filename) { struct path path; int error; error = user_path_dir(filename, &path); if (error) goto out; error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); if (error) goto dput_and_out; set_fs_pwd(current->fs, &path); dput_and_out: path_put(&path); out: return error; }
SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct fd f = fdget_raw(fd); int error; error = -EBADF; if (!f.file) goto out; error = -ENOTDIR; if (!d_can_lookup(f.file->f_path.dentry)) goto out_putf; error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: fdput(f); out: return error; }
/* * Check permissions for extended attribute access. This is a bit complicated * because different namespaces have very different rules. */ static int xattr_permission(struct inode *inode, const char *name, int mask) { /* * We can never set or remove an extended attribute on a read-only * filesystem or on an immutable / append-only inode. */ if (mask & MAY_WRITE) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; } /* * No restriction for security.* and system.* from the VFS. Decision * on these is left to the underlying filesystem / security module. */ if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return 0; /* * The trusted.* namespace can only be accessed by a privileged user. */ if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM); /* In user.* namespace, only regular files and directories can have * extended attributes. For sticky directories, only the owner and * privileged user can write attributes. */ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) return -EPERM; if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && (mask & MAY_WRITE) && !is_owner_or_cap(inode)) return -EPERM; } return inode_permission(inode, mask); }
/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, struct file *h_file) { int err; struct inode *h_inode; h_inode = h_path->dentry->d_inode; if (!h_file) { err = mnt_want_write(h_path->mnt); if (err) goto out; err = inode_permission(h_inode, MAY_WRITE); if (err) goto out_mnt; err = get_write_access(h_inode); if (err) goto out_mnt; err = break_lease(h_inode, O_WRONLY); if (err) goto out_inode; } err = locks_verify_truncate(h_inode, h_file, length); if (!err) err = security_path_truncate(h_path); if (!err) { lockdep_off(); err = do_truncate(h_path->dentry, length, attr, h_file); lockdep_on(); } out_inode: if (!h_file) put_write_access(h_inode); out_mnt: if (!h_file) mnt_drop_write(h_path->mnt); out: return err; }
static int sdcardfs_permission(struct inode *inode, int mask, unsigned int flags) { int err; if (flags & IPERM_FLAG_RCU) return -ECHILD; /* * Permission check on sdcardfs inode. * Calling process should have AID_SDCARD_RW permission */ err = generic_permission(inode, mask, 0, inode->i_op->check_acl); /* XXX * Original sdcardfs code calls inode_permission(lower_inode,.. ) * for checking inode permission. But doing such things here seems * duplicated work, because the functions called after this func, * such as vfs_create, vfs_unlink, vfs_rename, and etc, * does exactly same thing, i.e., they calls inode_permission(). * So we just let they do the things. * If there are any security hole, just uncomment following if block. */ #if 0 if (!err) { /* * Permission check on lower_inode(=EXT4). * we check it with AID_MEDIA_RW permission */ struct inode *lower_inode; OVERRIDE_CRED(SDCARDFS_SB(inode->sb)); lower_inode = sdcardfs_lower_inode(inode); err = inode_permission(lower_inode, mask); REVERT_CRED(); } #endif return err; }
SYSCALL_DEFINE1(chroot, const char __user *, filename) { struct path path; int error; error = user_path_dir(filename, &path); if (error) goto out; error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); if (error) goto dput_and_out; error = -EPERM; if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; set_fs_root(current->fs, &path); error = 0; dput_and_out: path_put(&path); out: return error; }
SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct fd f = fdget_raw(fd); struct inode *inode; int error = -EBADF; error = -EBADF; if (!f.file) goto out; inode = file_inode(f.file); error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) goto out_putf; error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: fdput(f); out: return error; }
/* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) { const struct cred *old_cred; struct cred *override_cred; struct path path; struct inode *inode; int res; if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; override_cred = prepare_creds(); if (!override_cred) return -ENOMEM; override_cred->fsuid = override_cred->uid; override_cred->fsgid = override_cred->gid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { /* Clear the capabilities if we switch to a non-root user */ if (override_cred->uid) cap_clear(override_cred->cap_effective); else override_cred->cap_effective = override_cred->cap_permitted; } old_cred = override_creds(override_cred); res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); if (res) goto out; inode = path.dentry->d_inode; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { /* * MAY_EXEC on regular files is denied if the fs is mounted * with the "noexec" flag. */ res = -EACCES; if (path.mnt->mnt_flags & MNT_NOEXEC) goto out_path_release; } res = inode_permission(inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; /* * This is a rare case where using __mnt_is_readonly() * is OK without a mnt_want/drop_write() pair. Since * no actual write to the fs is performed here, we do * not need to telegraph to that to anyone. * * By doing this, we accept that this access is * inherently racy and know that the fs may change * state before we even see this result. */ if (__mnt_is_readonly(path.mnt)) res = -EROFS; out_path_release: path_put(&path); out: revert_creds(old_cred); put_cred(override_cred); return res; }
int au_test_h_perm(struct inode *h_inode, int mask) { if (!current_fsuid()) return 0; return inode_permission(h_inode, mask); }
static int utimes_common(struct path *path, struct timespec *times) { int error; struct iattr newattrs; struct inode *inode = path->dentry->d_inode; struct inode *delegated_inode = NULL; error = mnt_want_write(path->mnt); if (error) goto out; if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) times = NULL; newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { if (times[0].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_ATIME; else if (times[0].tv_nsec != UTIME_NOW) { newattrs.ia_atime.tv_sec = times[0].tv_sec; newattrs.ia_atime.tv_nsec = times[0].tv_nsec; newattrs.ia_valid |= ATTR_ATIME_SET; } if (times[1].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_MTIME; else if (times[1].tv_nsec != UTIME_NOW) { newattrs.ia_mtime.tv_sec = times[1].tv_sec; newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; newattrs.ia_valid |= ATTR_MTIME_SET; } /* * Tell inode_change_ok(), that this is an explicit time * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET * were used. */ newattrs.ia_valid |= ATTR_TIMES_SET; } else { /* * If times is NULL (or both times are UTIME_NOW), * then we need to check permissions, because * inode_change_ok() won't do it. */ error = -EACCES; if (IS_IMMUTABLE(inode)) goto mnt_drop_write_and_out; if (!inode_owner_or_capable(inode)) { error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; } } retry_deleg: inode_lock(inode); error = notify_change(path->dentry, &newattrs, &delegated_inode); inode_unlock(inode); if (delegated_inode) { error = break_deleg_wait(&delegated_inode); if (!error) goto retry_deleg; } mnt_drop_write_and_out: mnt_drop_write(path->mnt); out: return error; }
long vfs_truncate(const struct path *path, loff_t length) { struct inode *inode; struct dentry *upperdentry; long error; inode = path->dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ if (S_ISDIR(inode->i_mode)) return -EISDIR; if (!S_ISREG(inode->i_mode)) return -EINVAL; error = mnt_want_write(path->mnt); if (error) goto out; error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; error = -EPERM; if (IS_APPEND(inode)) goto mnt_drop_write_and_out; /* * If this is an overlayfs then do as if opening the file so we get * write access on the upper inode, not on the overlay inode. For * non-overlay filesystems d_real() is an identity function. */ upperdentry = d_real(path->dentry, NULL, O_WRONLY, 0); error = PTR_ERR(upperdentry); if (IS_ERR(upperdentry)) goto mnt_drop_write_and_out; error = get_write_access(upperdentry->d_inode); if (error) goto mnt_drop_write_and_out; /* * Make sure that there are no leases. get_write_access() protects * against the truncate racing with a lease-granting setlease(). */ error = break_lease(inode, O_WRONLY); if (error) goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) error = security_path_truncate(path); if (!error) error = do_truncate(path->dentry, length, 0, NULL); put_write_and_out: put_write_access(upperdentry->d_inode); mnt_drop_write_and_out: mnt_drop_write(path->mnt); out: 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; }
static long do_sys_truncate(const char __user *pathname, loff_t length) { struct path path; struct inode *inode; int error; error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; error = user_path(pathname, &path); if (error) goto out; inode = path.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; if (S_ISDIR(inode->i_mode)) goto dput_and_out; error = -EINVAL; if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = mnt_want_write(path.mnt); if (error) goto dput_and_out; error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; error = -EPERM; if (IS_APPEND(inode)) goto mnt_drop_write_and_out; error = get_write_access(inode); if (error) goto mnt_drop_write_and_out; /* * Make sure that there are no leases. get_write_access() protects * against the truncate racing with a lease-granting setlease(). */ error = break_lease(inode, O_WRONLY); if (error) goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) error = security_path_truncate(&path); if (!error) error = do_truncate(path.dentry, length, 0, NULL); put_write_and_out: put_write_access(inode); mnt_drop_write_and_out: mnt_drop_write(path.mnt); dput_and_out: path_put(&path); out: return error; }
int au_test_h_perm(struct inode *h_inode, int mask) { if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) return 0; return inode_permission(h_inode, mask); }