xref: /openbmc/linux/fs/ubifs/ioctl.c (revision d07d3a7e)
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