12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21e51764aSArtem Bityutskiy /*
31e51764aSArtem Bityutskiy * This file is part of UBIFS.
41e51764aSArtem Bityutskiy *
51e51764aSArtem Bityutskiy * Copyright (C) 2006-2008 Nokia Corporation.
61e51764aSArtem Bityutskiy * Copyright (C) 2006, 2007 University of Szeged, Hungary
71e51764aSArtem Bityutskiy *
81e51764aSArtem Bityutskiy * Authors: Zoltan Sogor
91e51764aSArtem Bityutskiy * Artem Bityutskiy (Битюцкий Артём)
101e51764aSArtem Bityutskiy * Adrian Hunter
111e51764aSArtem Bityutskiy */
121e51764aSArtem Bityutskiy
131e51764aSArtem Bityutskiy /* This file implements EXT2-compatible extended attribute ioctl() calls */
141e51764aSArtem Bityutskiy
151e51764aSArtem Bityutskiy #include <linux/compat.h>
161e51764aSArtem Bityutskiy #include <linux/mount.h>
178871d84cSMiklos Szeredi #include <linux/fileattr.h>
181e51764aSArtem Bityutskiy #include "ubifs.h"
191e51764aSArtem Bityutskiy
202fe8b2d5SHou Tao /* Need to be kept consistent with checked flags in ioctl2ubifs() */
21219b0e2cSEric Biggers #define UBIFS_SETTABLE_IOCTL_FLAGS \
222fe8b2d5SHou Tao (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \
232fe8b2d5SHou Tao FS_IMMUTABLE_FL | FS_DIRSYNC_FL)
242fe8b2d5SHou Tao
25219b0e2cSEric Biggers /* Need to be kept consistent with checked flags in ubifs2ioctl() */
26219b0e2cSEric Biggers #define UBIFS_GETTABLE_IOCTL_FLAGS \
27219b0e2cSEric Biggers (UBIFS_SETTABLE_IOCTL_FLAGS | FS_ENCRYPT_FL)
28219b0e2cSEric Biggers
291e51764aSArtem Bityutskiy /**
301e51764aSArtem Bityutskiy * ubifs_set_inode_flags - set VFS inode flags.
311e51764aSArtem Bityutskiy * @inode: VFS inode to set flags for
321e51764aSArtem Bityutskiy *
331e51764aSArtem Bityutskiy * This function propagates flags from UBIFS inode object to VFS inode object.
341e51764aSArtem Bityutskiy */
ubifs_set_inode_flags(struct inode * inode)351e51764aSArtem Bityutskiy void ubifs_set_inode_flags(struct inode *inode)
361e51764aSArtem Bityutskiy {
371e51764aSArtem Bityutskiy unsigned int flags = ubifs_inode(inode)->flags;
381e51764aSArtem Bityutskiy
392ee6a576SEric Biggers inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC |
402ee6a576SEric Biggers S_ENCRYPTED);
411e51764aSArtem Bityutskiy if (flags & UBIFS_SYNC_FL)
421e51764aSArtem Bityutskiy inode->i_flags |= S_SYNC;
431e51764aSArtem Bityutskiy if (flags & UBIFS_APPEND_FL)
441e51764aSArtem Bityutskiy inode->i_flags |= S_APPEND;
451e51764aSArtem Bityutskiy if (flags & UBIFS_IMMUTABLE_FL)
461e51764aSArtem Bityutskiy inode->i_flags |= S_IMMUTABLE;
471e51764aSArtem Bityutskiy if (flags & UBIFS_DIRSYNC_FL)
481e51764aSArtem Bityutskiy inode->i_flags |= S_DIRSYNC;
492ee6a576SEric Biggers if (flags & UBIFS_CRYPT_FL)
502ee6a576SEric Biggers inode->i_flags |= S_ENCRYPTED;
511e51764aSArtem Bityutskiy }
521e51764aSArtem Bityutskiy
531e51764aSArtem Bityutskiy /*
541e51764aSArtem Bityutskiy * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags.
551e51764aSArtem Bityutskiy * @ioctl_flags: flags to convert
561e51764aSArtem Bityutskiy *
57798868c0SRock Lee * This function converts ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags
581e51764aSArtem Bityutskiy * (@UBIFS_COMPR_FL, etc).
591e51764aSArtem Bityutskiy */
ioctl2ubifs(int ioctl_flags)601e51764aSArtem Bityutskiy static int ioctl2ubifs(int ioctl_flags)
611e51764aSArtem Bityutskiy {
621e51764aSArtem Bityutskiy int ubifs_flags = 0;
631e51764aSArtem Bityutskiy
641e51764aSArtem Bityutskiy if (ioctl_flags & FS_COMPR_FL)
651e51764aSArtem Bityutskiy ubifs_flags |= UBIFS_COMPR_FL;
661e51764aSArtem Bityutskiy if (ioctl_flags & FS_SYNC_FL)
671e51764aSArtem Bityutskiy ubifs_flags |= UBIFS_SYNC_FL;
681e51764aSArtem Bityutskiy if (ioctl_flags & FS_APPEND_FL)
691e51764aSArtem Bityutskiy ubifs_flags |= UBIFS_APPEND_FL;
701e51764aSArtem Bityutskiy if (ioctl_flags & FS_IMMUTABLE_FL)
711e51764aSArtem Bityutskiy ubifs_flags |= UBIFS_IMMUTABLE_FL;
721e51764aSArtem Bityutskiy if (ioctl_flags & FS_DIRSYNC_FL)
731e51764aSArtem Bityutskiy ubifs_flags |= UBIFS_DIRSYNC_FL;
741e51764aSArtem Bityutskiy
751e51764aSArtem Bityutskiy return ubifs_flags;
761e51764aSArtem Bityutskiy }
771e51764aSArtem Bityutskiy
781e51764aSArtem Bityutskiy /*
791e51764aSArtem Bityutskiy * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags.
801e51764aSArtem Bityutskiy * @ubifs_flags: flags to convert
811e51764aSArtem Bityutskiy *
82798868c0SRock Lee * This function converts UBIFS inode flags (@UBIFS_COMPR_FL, etc) to ioctl
83798868c0SRock Lee * flags (@FS_COMPR_FL, etc).
841e51764aSArtem Bityutskiy */
ubifs2ioctl(int ubifs_flags)851e51764aSArtem Bityutskiy static int ubifs2ioctl(int ubifs_flags)
861e51764aSArtem Bityutskiy {
871e51764aSArtem Bityutskiy int ioctl_flags = 0;
881e51764aSArtem Bityutskiy
891e51764aSArtem Bityutskiy if (ubifs_flags & UBIFS_COMPR_FL)
901e51764aSArtem Bityutskiy ioctl_flags |= FS_COMPR_FL;
911e51764aSArtem Bityutskiy if (ubifs_flags & UBIFS_SYNC_FL)
921e51764aSArtem Bityutskiy ioctl_flags |= FS_SYNC_FL;
931e51764aSArtem Bityutskiy if (ubifs_flags & UBIFS_APPEND_FL)
941e51764aSArtem Bityutskiy ioctl_flags |= FS_APPEND_FL;
951e51764aSArtem Bityutskiy if (ubifs_flags & UBIFS_IMMUTABLE_FL)
961e51764aSArtem Bityutskiy ioctl_flags |= FS_IMMUTABLE_FL;
971e51764aSArtem Bityutskiy if (ubifs_flags & UBIFS_DIRSYNC_FL)
981e51764aSArtem Bityutskiy ioctl_flags |= FS_DIRSYNC_FL;
99219b0e2cSEric Biggers if (ubifs_flags & UBIFS_CRYPT_FL)
100219b0e2cSEric Biggers ioctl_flags |= FS_ENCRYPT_FL;
1011e51764aSArtem Bityutskiy
1021e51764aSArtem Bityutskiy return ioctl_flags;
1031e51764aSArtem Bityutskiy }
1041e51764aSArtem Bityutskiy
setflags(struct inode * inode,int flags)1051e51764aSArtem Bityutskiy static int setflags(struct inode *inode, int flags)
1061e51764aSArtem Bityutskiy {
1078871d84cSMiklos Szeredi int err, release;
1081e51764aSArtem Bityutskiy struct ubifs_inode *ui = ubifs_inode(inode);
1091e51764aSArtem Bityutskiy struct ubifs_info *c = inode->i_sb->s_fs_info;
1101e51764aSArtem Bityutskiy struct ubifs_budget_req req = { .dirtied_ino = 1,
1111b83ec05SZhihao Cheng .dirtied_ino_d = ALIGN(ui->data_len, 8) };
1121e51764aSArtem Bityutskiy
1131e51764aSArtem Bityutskiy err = ubifs_budget_space(c, &req);
1141e51764aSArtem Bityutskiy if (err)
1151e51764aSArtem Bityutskiy return err;
1161e51764aSArtem Bityutskiy
1171e51764aSArtem Bityutskiy mutex_lock(&ui->ui_mutex);
118219b0e2cSEric Biggers ui->flags &= ~ioctl2ubifs(UBIFS_SETTABLE_IOCTL_FLAGS);
1192b57067aSEric Biggers ui->flags |= ioctl2ubifs(flags);
1201e51764aSArtem Bityutskiy ubifs_set_inode_flags(inode);
121*d07d3a7eSJeff Layton inode_set_ctime_current(inode);
1221e51764aSArtem Bityutskiy release = ui->dirty;
1231e51764aSArtem Bityutskiy mark_inode_dirty_sync(inode);
1241e51764aSArtem Bityutskiy mutex_unlock(&ui->ui_mutex);
1251e51764aSArtem Bityutskiy
1261e51764aSArtem Bityutskiy if (release)
1271e51764aSArtem Bityutskiy ubifs_release_budget(c, &req);
1281e51764aSArtem Bityutskiy if (IS_SYNC(inode))
1291e51764aSArtem Bityutskiy err = write_inode_now(inode, 1);
1301e51764aSArtem Bityutskiy return err;
1311e51764aSArtem Bityutskiy }
1321e51764aSArtem Bityutskiy
ubifs_fileattr_get(struct dentry * dentry,struct fileattr * fa)1338871d84cSMiklos Szeredi int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
1341e51764aSArtem Bityutskiy {
1358871d84cSMiklos Szeredi struct inode *inode = d_inode(dentry);
1368871d84cSMiklos Szeredi int flags = ubifs2ioctl(ubifs_inode(inode)->flags);
1371e51764aSArtem Bityutskiy
1388871d84cSMiklos Szeredi if (d_is_special(dentry))
1398871d84cSMiklos Szeredi return -ENOTTY;
1401e51764aSArtem Bityutskiy
141a9f2fc0eSArtem Bityutskiy dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags);
1428871d84cSMiklos Szeredi fileattr_fill_flags(fa, flags);
1431e51764aSArtem Bityutskiy
1448871d84cSMiklos Szeredi return 0;
1458871d84cSMiklos Szeredi }
1461e51764aSArtem Bityutskiy
ubifs_fileattr_set(struct mnt_idmap * idmap,struct dentry * dentry,struct fileattr * fa)1478782a9aeSChristian Brauner int ubifs_fileattr_set(struct mnt_idmap *idmap,
1488871d84cSMiklos Szeredi struct dentry *dentry, struct fileattr *fa)
1498871d84cSMiklos Szeredi {
1508871d84cSMiklos Szeredi struct inode *inode = d_inode(dentry);
1518871d84cSMiklos Szeredi int flags = fa->flags;
1521e51764aSArtem Bityutskiy
1538871d84cSMiklos Szeredi if (d_is_special(dentry))
1548871d84cSMiklos Szeredi return -ENOTTY;
1558871d84cSMiklos Szeredi
1568871d84cSMiklos Szeredi if (fileattr_has_fsx(fa))
1578871d84cSMiklos Szeredi return -EOPNOTSUPP;
1581e51764aSArtem Bityutskiy
159219b0e2cSEric Biggers if (flags & ~UBIFS_GETTABLE_IOCTL_FLAGS)
1602fe8b2d5SHou Tao return -EOPNOTSUPP;
1618871d84cSMiklos Szeredi
162219b0e2cSEric Biggers flags &= UBIFS_SETTABLE_IOCTL_FLAGS;
1632fe8b2d5SHou Tao
1641e51764aSArtem Bityutskiy if (!S_ISDIR(inode->i_mode))
1651e51764aSArtem Bityutskiy flags &= ~FS_DIRSYNC_FL;
1661e51764aSArtem Bityutskiy
167a9f2fc0eSArtem Bityutskiy dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags);
1688871d84cSMiklos Szeredi return setflags(inode, flags);
1691e51764aSArtem Bityutskiy }
1708871d84cSMiklos Szeredi
ubifs_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1718871d84cSMiklos Szeredi long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1728871d84cSMiklos Szeredi {
1738871d84cSMiklos Szeredi int err;
1748871d84cSMiklos Szeredi struct inode *inode = file_inode(file);
1758871d84cSMiklos Szeredi
1768871d84cSMiklos Szeredi switch (cmd) {
177d475a507SRichard Weinberger case FS_IOC_SET_ENCRYPTION_POLICY: {
178e021986eSRichard Weinberger struct ubifs_info *c = inode->i_sb->s_fs_info;
179d475a507SRichard Weinberger
180e021986eSRichard Weinberger err = ubifs_enable_encryption(c);
181e021986eSRichard Weinberger if (err)
182e021986eSRichard Weinberger return err;
183e021986eSRichard Weinberger
184ec9160daSRichard Weinberger return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
185d475a507SRichard Weinberger }
186cf394967SEric Biggers case FS_IOC_GET_ENCRYPTION_POLICY:
187ec9160daSRichard Weinberger return fscrypt_ioctl_get_policy(file, (void __user *)arg);
1881e51764aSArtem Bityutskiy
18962de2592SEric Biggers case FS_IOC_GET_ENCRYPTION_POLICY_EX:
19062de2592SEric Biggers return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg);
19162de2592SEric Biggers
19262de2592SEric Biggers case FS_IOC_ADD_ENCRYPTION_KEY:
19362de2592SEric Biggers return fscrypt_ioctl_add_key(file, (void __user *)arg);
19462de2592SEric Biggers
19562de2592SEric Biggers case FS_IOC_REMOVE_ENCRYPTION_KEY:
19662de2592SEric Biggers return fscrypt_ioctl_remove_key(file, (void __user *)arg);
19762de2592SEric Biggers
19862de2592SEric Biggers case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
19962de2592SEric Biggers return fscrypt_ioctl_remove_key_all_users(file,
20062de2592SEric Biggers (void __user *)arg);
20162de2592SEric Biggers case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
20262de2592SEric Biggers return fscrypt_ioctl_get_key_status(file, (void __user *)arg);
20362de2592SEric Biggers
204861261f2SEric Biggers case FS_IOC_GET_ENCRYPTION_NONCE:
205861261f2SEric Biggers return fscrypt_ioctl_get_nonce(file, (void __user *)arg);
206861261f2SEric Biggers
2071e51764aSArtem Bityutskiy default:
2081e51764aSArtem Bityutskiy return -ENOTTY;
2091e51764aSArtem Bityutskiy }
2101e51764aSArtem Bityutskiy }
2111e51764aSArtem Bityutskiy
2121e51764aSArtem Bityutskiy #ifdef CONFIG_COMPAT
ubifs_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)2131e51764aSArtem Bityutskiy long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2141e51764aSArtem Bityutskiy {
2151e51764aSArtem Bityutskiy switch (cmd) {
2161e51764aSArtem Bityutskiy case FS_IOC32_GETFLAGS:
2171e51764aSArtem Bityutskiy cmd = FS_IOC_GETFLAGS;
2181e51764aSArtem Bityutskiy break;
2191e51764aSArtem Bityutskiy case FS_IOC32_SETFLAGS:
2201e51764aSArtem Bityutskiy cmd = FS_IOC_SETFLAGS;
2211e51764aSArtem Bityutskiy break;
222a75467d9SEric Biggers case FS_IOC_SET_ENCRYPTION_POLICY:
223a75467d9SEric Biggers case FS_IOC_GET_ENCRYPTION_POLICY:
22462de2592SEric Biggers case FS_IOC_GET_ENCRYPTION_POLICY_EX:
22562de2592SEric Biggers case FS_IOC_ADD_ENCRYPTION_KEY:
22662de2592SEric Biggers case FS_IOC_REMOVE_ENCRYPTION_KEY:
22762de2592SEric Biggers case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
22862de2592SEric Biggers case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
229861261f2SEric Biggers case FS_IOC_GET_ENCRYPTION_NONCE:
230a75467d9SEric Biggers break;
2311e51764aSArtem Bityutskiy default:
2321e51764aSArtem Bityutskiy return -ENOIOCTLCMD;
2331e51764aSArtem Bityutskiy }
2341e51764aSArtem Bityutskiy return ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
2351e51764aSArtem Bityutskiy }
2361e51764aSArtem Bityutskiy #endif
237