18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of UBIFS. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 68c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2007 University of Szeged, Hungary 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Authors: Zoltan Sogor 98c2ecf20Sopenharmony_ci * Artem Bityutskiy (Битюцкий Артём) 108c2ecf20Sopenharmony_ci * Adrian Hunter 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* This file implements EXT2-compatible extended attribute ioctl() calls */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/compat.h> 168c2ecf20Sopenharmony_ci#include <linux/mount.h> 178c2ecf20Sopenharmony_ci#include "ubifs.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Need to be kept consistent with checked flags in ioctl2ubifs() */ 208c2ecf20Sopenharmony_ci#define UBIFS_SETTABLE_IOCTL_FLAGS \ 218c2ecf20Sopenharmony_ci (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \ 228c2ecf20Sopenharmony_ci FS_IMMUTABLE_FL | FS_DIRSYNC_FL) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* Need to be kept consistent with checked flags in ubifs2ioctl() */ 258c2ecf20Sopenharmony_ci#define UBIFS_GETTABLE_IOCTL_FLAGS \ 268c2ecf20Sopenharmony_ci (UBIFS_SETTABLE_IOCTL_FLAGS | FS_ENCRYPT_FL) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * ubifs_set_inode_flags - set VFS inode flags. 308c2ecf20Sopenharmony_ci * @inode: VFS inode to set flags for 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * This function propagates flags from UBIFS inode object to VFS inode object. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_civoid ubifs_set_inode_flags(struct inode *inode) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci unsigned int flags = ubifs_inode(inode)->flags; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC | 398c2ecf20Sopenharmony_ci S_ENCRYPTED); 408c2ecf20Sopenharmony_ci if (flags & UBIFS_SYNC_FL) 418c2ecf20Sopenharmony_ci inode->i_flags |= S_SYNC; 428c2ecf20Sopenharmony_ci if (flags & UBIFS_APPEND_FL) 438c2ecf20Sopenharmony_ci inode->i_flags |= S_APPEND; 448c2ecf20Sopenharmony_ci if (flags & UBIFS_IMMUTABLE_FL) 458c2ecf20Sopenharmony_ci inode->i_flags |= S_IMMUTABLE; 468c2ecf20Sopenharmony_ci if (flags & UBIFS_DIRSYNC_FL) 478c2ecf20Sopenharmony_ci inode->i_flags |= S_DIRSYNC; 488c2ecf20Sopenharmony_ci if (flags & UBIFS_CRYPT_FL) 498c2ecf20Sopenharmony_ci inode->i_flags |= S_ENCRYPTED; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags. 548c2ecf20Sopenharmony_ci * @ioctl_flags: flags to convert 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * This function converts ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags 578c2ecf20Sopenharmony_ci * (@UBIFS_COMPR_FL, etc). 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_cistatic int ioctl2ubifs(int ioctl_flags) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci int ubifs_flags = 0; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (ioctl_flags & FS_COMPR_FL) 648c2ecf20Sopenharmony_ci ubifs_flags |= UBIFS_COMPR_FL; 658c2ecf20Sopenharmony_ci if (ioctl_flags & FS_SYNC_FL) 668c2ecf20Sopenharmony_ci ubifs_flags |= UBIFS_SYNC_FL; 678c2ecf20Sopenharmony_ci if (ioctl_flags & FS_APPEND_FL) 688c2ecf20Sopenharmony_ci ubifs_flags |= UBIFS_APPEND_FL; 698c2ecf20Sopenharmony_ci if (ioctl_flags & FS_IMMUTABLE_FL) 708c2ecf20Sopenharmony_ci ubifs_flags |= UBIFS_IMMUTABLE_FL; 718c2ecf20Sopenharmony_ci if (ioctl_flags & FS_DIRSYNC_FL) 728c2ecf20Sopenharmony_ci ubifs_flags |= UBIFS_DIRSYNC_FL; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return ubifs_flags; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags. 798c2ecf20Sopenharmony_ci * @ubifs_flags: flags to convert 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * This function converts UBIFS inode flags (@UBIFS_COMPR_FL, etc) to ioctl 828c2ecf20Sopenharmony_ci * flags (@FS_COMPR_FL, etc). 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistatic int ubifs2ioctl(int ubifs_flags) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int ioctl_flags = 0; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (ubifs_flags & UBIFS_COMPR_FL) 898c2ecf20Sopenharmony_ci ioctl_flags |= FS_COMPR_FL; 908c2ecf20Sopenharmony_ci if (ubifs_flags & UBIFS_SYNC_FL) 918c2ecf20Sopenharmony_ci ioctl_flags |= FS_SYNC_FL; 928c2ecf20Sopenharmony_ci if (ubifs_flags & UBIFS_APPEND_FL) 938c2ecf20Sopenharmony_ci ioctl_flags |= FS_APPEND_FL; 948c2ecf20Sopenharmony_ci if (ubifs_flags & UBIFS_IMMUTABLE_FL) 958c2ecf20Sopenharmony_ci ioctl_flags |= FS_IMMUTABLE_FL; 968c2ecf20Sopenharmony_ci if (ubifs_flags & UBIFS_DIRSYNC_FL) 978c2ecf20Sopenharmony_ci ioctl_flags |= FS_DIRSYNC_FL; 988c2ecf20Sopenharmony_ci if (ubifs_flags & UBIFS_CRYPT_FL) 998c2ecf20Sopenharmony_ci ioctl_flags |= FS_ENCRYPT_FL; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return ioctl_flags; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int setflags(struct inode *inode, int flags) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int oldflags, err, release; 1078c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 1088c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 1098c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .dirtied_ino = 1, 1108c2ecf20Sopenharmony_ci .dirtied_ino_d = ALIGN(ui->data_len, 8) }; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 1138c2ecf20Sopenharmony_ci if (err) 1148c2ecf20Sopenharmony_ci return err; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 1178c2ecf20Sopenharmony_ci oldflags = ubifs2ioctl(ui->flags); 1188c2ecf20Sopenharmony_ci err = vfs_ioc_setflags_prepare(inode, oldflags, flags); 1198c2ecf20Sopenharmony_ci if (err) 1208c2ecf20Sopenharmony_ci goto out_unlock; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci ui->flags &= ~ioctl2ubifs(UBIFS_SETTABLE_IOCTL_FLAGS); 1238c2ecf20Sopenharmony_ci ui->flags |= ioctl2ubifs(flags); 1248c2ecf20Sopenharmony_ci ubifs_set_inode_flags(inode); 1258c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 1268c2ecf20Sopenharmony_ci release = ui->dirty; 1278c2ecf20Sopenharmony_ci mark_inode_dirty_sync(inode); 1288c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (release) 1318c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 1328c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 1338c2ecf20Sopenharmony_ci err = write_inode_now(inode, 1); 1348c2ecf20Sopenharmony_ci return err; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciout_unlock: 1378c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 1388c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 1398c2ecf20Sopenharmony_ci return err; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cilong ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci int flags, err; 1458c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci switch (cmd) { 1488c2ecf20Sopenharmony_ci case FS_IOC_GETFLAGS: 1498c2ecf20Sopenharmony_ci flags = ubifs2ioctl(ubifs_inode(inode)->flags); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags); 1528c2ecf20Sopenharmony_ci return put_user(flags, (int __user *) arg); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci case FS_IOC_SETFLAGS: { 1558c2ecf20Sopenharmony_ci if (IS_RDONLY(inode)) 1568c2ecf20Sopenharmony_ci return -EROFS; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!inode_owner_or_capable(inode)) 1598c2ecf20Sopenharmony_ci return -EACCES; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (get_user(flags, (int __user *) arg)) 1628c2ecf20Sopenharmony_ci return -EFAULT; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (flags & ~UBIFS_GETTABLE_IOCTL_FLAGS) 1658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1668c2ecf20Sopenharmony_ci flags &= UBIFS_SETTABLE_IOCTL_FLAGS; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) 1698c2ecf20Sopenharmony_ci flags &= ~FS_DIRSYNC_FL; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * Make sure the file-system is read-write and make sure it 1738c2ecf20Sopenharmony_ci * will not become read-only while we are changing the flags. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci err = mnt_want_write_file(file); 1768c2ecf20Sopenharmony_ci if (err) 1778c2ecf20Sopenharmony_ci return err; 1788c2ecf20Sopenharmony_ci dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags); 1798c2ecf20Sopenharmony_ci err = setflags(inode, flags); 1808c2ecf20Sopenharmony_ci mnt_drop_write_file(file); 1818c2ecf20Sopenharmony_ci return err; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci case FS_IOC_SET_ENCRYPTION_POLICY: { 1848c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci err = ubifs_enable_encryption(c); 1878c2ecf20Sopenharmony_ci if (err) 1888c2ecf20Sopenharmony_ci return err; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return fscrypt_ioctl_set_policy(file, (const void __user *)arg); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY: 1938c2ecf20Sopenharmony_ci return fscrypt_ioctl_get_policy(file, (void __user *)arg); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY_EX: 1968c2ecf20Sopenharmony_ci return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci case FS_IOC_ADD_ENCRYPTION_KEY: 1998c2ecf20Sopenharmony_ci return fscrypt_ioctl_add_key(file, (void __user *)arg); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY: 2028c2ecf20Sopenharmony_ci return fscrypt_ioctl_remove_key(file, (void __user *)arg); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: 2058c2ecf20Sopenharmony_ci return fscrypt_ioctl_remove_key_all_users(file, 2068c2ecf20Sopenharmony_ci (void __user *)arg); 2078c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_KEY_STATUS: 2088c2ecf20Sopenharmony_ci return fscrypt_ioctl_get_key_status(file, (void __user *)arg); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_NONCE: 2118c2ecf20Sopenharmony_ci return fscrypt_ioctl_get_nonce(file, (void __user *)arg); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci default: 2148c2ecf20Sopenharmony_ci return -ENOTTY; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 2198c2ecf20Sopenharmony_cilong ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci switch (cmd) { 2228c2ecf20Sopenharmony_ci case FS_IOC32_GETFLAGS: 2238c2ecf20Sopenharmony_ci cmd = FS_IOC_GETFLAGS; 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case FS_IOC32_SETFLAGS: 2268c2ecf20Sopenharmony_ci cmd = FS_IOC_SETFLAGS; 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case FS_IOC_SET_ENCRYPTION_POLICY: 2298c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY: 2308c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_POLICY_EX: 2318c2ecf20Sopenharmony_ci case FS_IOC_ADD_ENCRYPTION_KEY: 2328c2ecf20Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY: 2338c2ecf20Sopenharmony_ci case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: 2348c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_KEY_STATUS: 2358c2ecf20Sopenharmony_ci case FS_IOC_GET_ENCRYPTION_NONCE: 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci default: 2388c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci return ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci#endif 243