xref: /OK3568_Linux_fs/kernel/fs/ubifs/ioctl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * This file is part of UBIFS.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2006-2008 Nokia Corporation.
6*4882a593Smuzhiyun  * Copyright (C) 2006, 2007 University of Szeged, Hungary
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Authors: Zoltan Sogor
9*4882a593Smuzhiyun  *          Artem Bityutskiy (Битюцкий Артём)
10*4882a593Smuzhiyun  *          Adrian Hunter
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* This file implements EXT2-compatible extended attribute ioctl() calls */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/compat.h>
16*4882a593Smuzhiyun #include <linux/mount.h>
17*4882a593Smuzhiyun #include "ubifs.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /* Need to be kept consistent with checked flags in ioctl2ubifs() */
20*4882a593Smuzhiyun #define UBIFS_SETTABLE_IOCTL_FLAGS \
21*4882a593Smuzhiyun 	(FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \
22*4882a593Smuzhiyun 	 FS_IMMUTABLE_FL | FS_DIRSYNC_FL)
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* Need to be kept consistent with checked flags in ubifs2ioctl() */
25*4882a593Smuzhiyun #define UBIFS_GETTABLE_IOCTL_FLAGS \
26*4882a593Smuzhiyun 	(UBIFS_SETTABLE_IOCTL_FLAGS | FS_ENCRYPT_FL)
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /**
29*4882a593Smuzhiyun  * ubifs_set_inode_flags - set VFS inode flags.
30*4882a593Smuzhiyun  * @inode: VFS inode to set flags for
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * This function propagates flags from UBIFS inode object to VFS inode object.
33*4882a593Smuzhiyun  */
ubifs_set_inode_flags(struct inode * inode)34*4882a593Smuzhiyun void ubifs_set_inode_flags(struct inode *inode)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	unsigned int flags = ubifs_inode(inode)->flags;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC |
39*4882a593Smuzhiyun 			    S_ENCRYPTED);
40*4882a593Smuzhiyun 	if (flags & UBIFS_SYNC_FL)
41*4882a593Smuzhiyun 		inode->i_flags |= S_SYNC;
42*4882a593Smuzhiyun 	if (flags & UBIFS_APPEND_FL)
43*4882a593Smuzhiyun 		inode->i_flags |= S_APPEND;
44*4882a593Smuzhiyun 	if (flags & UBIFS_IMMUTABLE_FL)
45*4882a593Smuzhiyun 		inode->i_flags |= S_IMMUTABLE;
46*4882a593Smuzhiyun 	if (flags & UBIFS_DIRSYNC_FL)
47*4882a593Smuzhiyun 		inode->i_flags |= S_DIRSYNC;
48*4882a593Smuzhiyun 	if (flags & UBIFS_CRYPT_FL)
49*4882a593Smuzhiyun 		inode->i_flags |= S_ENCRYPTED;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun  * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags.
54*4882a593Smuzhiyun  * @ioctl_flags: flags to convert
55*4882a593Smuzhiyun  *
56*4882a593Smuzhiyun  * This function converts ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags
57*4882a593Smuzhiyun  * (@UBIFS_COMPR_FL, etc).
58*4882a593Smuzhiyun  */
ioctl2ubifs(int ioctl_flags)59*4882a593Smuzhiyun static int ioctl2ubifs(int ioctl_flags)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	int ubifs_flags = 0;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (ioctl_flags & FS_COMPR_FL)
64*4882a593Smuzhiyun 		ubifs_flags |= UBIFS_COMPR_FL;
65*4882a593Smuzhiyun 	if (ioctl_flags & FS_SYNC_FL)
66*4882a593Smuzhiyun 		ubifs_flags |= UBIFS_SYNC_FL;
67*4882a593Smuzhiyun 	if (ioctl_flags & FS_APPEND_FL)
68*4882a593Smuzhiyun 		ubifs_flags |= UBIFS_APPEND_FL;
69*4882a593Smuzhiyun 	if (ioctl_flags & FS_IMMUTABLE_FL)
70*4882a593Smuzhiyun 		ubifs_flags |= UBIFS_IMMUTABLE_FL;
71*4882a593Smuzhiyun 	if (ioctl_flags & FS_DIRSYNC_FL)
72*4882a593Smuzhiyun 		ubifs_flags |= UBIFS_DIRSYNC_FL;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	return ubifs_flags;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun  * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags.
79*4882a593Smuzhiyun  * @ubifs_flags: flags to convert
80*4882a593Smuzhiyun  *
81*4882a593Smuzhiyun  * This function converts UBIFS inode flags (@UBIFS_COMPR_FL, etc) to ioctl
82*4882a593Smuzhiyun  * flags (@FS_COMPR_FL, etc).
83*4882a593Smuzhiyun  */
ubifs2ioctl(int ubifs_flags)84*4882a593Smuzhiyun static int ubifs2ioctl(int ubifs_flags)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	int ioctl_flags = 0;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (ubifs_flags & UBIFS_COMPR_FL)
89*4882a593Smuzhiyun 		ioctl_flags |= FS_COMPR_FL;
90*4882a593Smuzhiyun 	if (ubifs_flags & UBIFS_SYNC_FL)
91*4882a593Smuzhiyun 		ioctl_flags |= FS_SYNC_FL;
92*4882a593Smuzhiyun 	if (ubifs_flags & UBIFS_APPEND_FL)
93*4882a593Smuzhiyun 		ioctl_flags |= FS_APPEND_FL;
94*4882a593Smuzhiyun 	if (ubifs_flags & UBIFS_IMMUTABLE_FL)
95*4882a593Smuzhiyun 		ioctl_flags |= FS_IMMUTABLE_FL;
96*4882a593Smuzhiyun 	if (ubifs_flags & UBIFS_DIRSYNC_FL)
97*4882a593Smuzhiyun 		ioctl_flags |= FS_DIRSYNC_FL;
98*4882a593Smuzhiyun 	if (ubifs_flags & UBIFS_CRYPT_FL)
99*4882a593Smuzhiyun 		ioctl_flags |= FS_ENCRYPT_FL;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	return ioctl_flags;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
setflags(struct inode * inode,int flags)104*4882a593Smuzhiyun static int setflags(struct inode *inode, int flags)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	int oldflags, err, release;
107*4882a593Smuzhiyun 	struct ubifs_inode *ui = ubifs_inode(inode);
108*4882a593Smuzhiyun 	struct ubifs_info *c = inode->i_sb->s_fs_info;
109*4882a593Smuzhiyun 	struct ubifs_budget_req req = { .dirtied_ino = 1,
110*4882a593Smuzhiyun 			.dirtied_ino_d = ALIGN(ui->data_len, 8) };
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	err = ubifs_budget_space(c, &req);
113*4882a593Smuzhiyun 	if (err)
114*4882a593Smuzhiyun 		return err;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	mutex_lock(&ui->ui_mutex);
117*4882a593Smuzhiyun 	oldflags = ubifs2ioctl(ui->flags);
118*4882a593Smuzhiyun 	err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
119*4882a593Smuzhiyun 	if (err)
120*4882a593Smuzhiyun 		goto out_unlock;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	ui->flags &= ~ioctl2ubifs(UBIFS_SETTABLE_IOCTL_FLAGS);
123*4882a593Smuzhiyun 	ui->flags |= ioctl2ubifs(flags);
124*4882a593Smuzhiyun 	ubifs_set_inode_flags(inode);
125*4882a593Smuzhiyun 	inode->i_ctime = current_time(inode);
126*4882a593Smuzhiyun 	release = ui->dirty;
127*4882a593Smuzhiyun 	mark_inode_dirty_sync(inode);
128*4882a593Smuzhiyun 	mutex_unlock(&ui->ui_mutex);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (release)
131*4882a593Smuzhiyun 		ubifs_release_budget(c, &req);
132*4882a593Smuzhiyun 	if (IS_SYNC(inode))
133*4882a593Smuzhiyun 		err = write_inode_now(inode, 1);
134*4882a593Smuzhiyun 	return err;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun out_unlock:
137*4882a593Smuzhiyun 	mutex_unlock(&ui->ui_mutex);
138*4882a593Smuzhiyun 	ubifs_release_budget(c, &req);
139*4882a593Smuzhiyun 	return err;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
ubifs_ioctl(struct file * file,unsigned int cmd,unsigned long arg)142*4882a593Smuzhiyun long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	int flags, err;
145*4882a593Smuzhiyun 	struct inode *inode = file_inode(file);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	switch (cmd) {
148*4882a593Smuzhiyun 	case FS_IOC_GETFLAGS:
149*4882a593Smuzhiyun 		flags = ubifs2ioctl(ubifs_inode(inode)->flags);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags);
152*4882a593Smuzhiyun 		return put_user(flags, (int __user *) arg);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	case FS_IOC_SETFLAGS: {
155*4882a593Smuzhiyun 		if (IS_RDONLY(inode))
156*4882a593Smuzhiyun 			return -EROFS;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		if (!inode_owner_or_capable(inode))
159*4882a593Smuzhiyun 			return -EACCES;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 		if (get_user(flags, (int __user *) arg))
162*4882a593Smuzhiyun 			return -EFAULT;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 		if (flags & ~UBIFS_GETTABLE_IOCTL_FLAGS)
165*4882a593Smuzhiyun 			return -EOPNOTSUPP;
166*4882a593Smuzhiyun 		flags &= UBIFS_SETTABLE_IOCTL_FLAGS;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 		if (!S_ISDIR(inode->i_mode))
169*4882a593Smuzhiyun 			flags &= ~FS_DIRSYNC_FL;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		/*
172*4882a593Smuzhiyun 		 * Make sure the file-system is read-write and make sure it
173*4882a593Smuzhiyun 		 * will not become read-only while we are changing the flags.
174*4882a593Smuzhiyun 		 */
175*4882a593Smuzhiyun 		err = mnt_want_write_file(file);
176*4882a593Smuzhiyun 		if (err)
177*4882a593Smuzhiyun 			return err;
178*4882a593Smuzhiyun 		dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags);
179*4882a593Smuzhiyun 		err = setflags(inode, flags);
180*4882a593Smuzhiyun 		mnt_drop_write_file(file);
181*4882a593Smuzhiyun 		return err;
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 	case FS_IOC_SET_ENCRYPTION_POLICY: {
184*4882a593Smuzhiyun 		struct ubifs_info *c = inode->i_sb->s_fs_info;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		err = ubifs_enable_encryption(c);
187*4882a593Smuzhiyun 		if (err)
188*4882a593Smuzhiyun 			return err;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 		return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_POLICY:
193*4882a593Smuzhiyun 		return fscrypt_ioctl_get_policy(file, (void __user *)arg);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
196*4882a593Smuzhiyun 		return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	case FS_IOC_ADD_ENCRYPTION_KEY:
199*4882a593Smuzhiyun 		return fscrypt_ioctl_add_key(file, (void __user *)arg);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
202*4882a593Smuzhiyun 		return fscrypt_ioctl_remove_key(file, (void __user *)arg);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
205*4882a593Smuzhiyun 		return fscrypt_ioctl_remove_key_all_users(file,
206*4882a593Smuzhiyun 							  (void __user *)arg);
207*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
208*4882a593Smuzhiyun 		return fscrypt_ioctl_get_key_status(file, (void __user *)arg);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_NONCE:
211*4882a593Smuzhiyun 		return fscrypt_ioctl_get_nonce(file, (void __user *)arg);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	default:
214*4882a593Smuzhiyun 		return -ENOTTY;
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
ubifs_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)219*4882a593Smuzhiyun long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	switch (cmd) {
222*4882a593Smuzhiyun 	case FS_IOC32_GETFLAGS:
223*4882a593Smuzhiyun 		cmd = FS_IOC_GETFLAGS;
224*4882a593Smuzhiyun 		break;
225*4882a593Smuzhiyun 	case FS_IOC32_SETFLAGS:
226*4882a593Smuzhiyun 		cmd = FS_IOC_SETFLAGS;
227*4882a593Smuzhiyun 		break;
228*4882a593Smuzhiyun 	case FS_IOC_SET_ENCRYPTION_POLICY:
229*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_POLICY:
230*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
231*4882a593Smuzhiyun 	case FS_IOC_ADD_ENCRYPTION_KEY:
232*4882a593Smuzhiyun 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
233*4882a593Smuzhiyun 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
234*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
235*4882a593Smuzhiyun 	case FS_IOC_GET_ENCRYPTION_NONCE:
236*4882a593Smuzhiyun 		break;
237*4882a593Smuzhiyun 	default:
238*4882a593Smuzhiyun 		return -ENOIOCTLCMD;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 	return ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun #endif
243