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