]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - contrib/android/perms.c
AOSP: e2fsdroid: use libselinux function to read file context on device
[thirdparty/e2fsprogs.git] / contrib / android / perms.c
CommitLineData
1e43f83f
AS
1#ifndef _GNU_SOURCE
2# define _GNU_SOURCE //asprintf
3#endif
4#include "perms.h"
5#include "support/nls-enable.h"
6#include <time.h>
7#include <sys/stat.h>
8
9#ifndef XATTR_SELINUX_SUFFIX
10# define XATTR_SELINUX_SUFFIX "selinux"
11#endif
12#ifndef XATTR_CAPS_SUFFIX
13# define XATTR_CAPS_SUFFIX "capability"
14#endif
15
16struct inode_params {
17 ext2_filsys fs;
18 char *path;
19 char *filename;
3946ee85 20 char *src_dir;
1e43f83f 21 char *target_out;
3946ee85 22 char *mountpoint;
1e43f83f
AS
23 fs_config_f fs_config_func;
24 struct selabel_handle *sehnd;
25 time_t fixed_time;
26};
27
28static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
29 const void *value, int value_len)
30{
31 errcode_t retval, close_retval;
32 struct ext2_xattr_handle *xhandle;
33
34 retval = ext2fs_xattrs_open(fs, ino, &xhandle);
35 if (retval) {
36 com_err(__func__, retval, _("while opening inode %u"), ino);
37 return retval;
38 }
39 retval = ext2fs_xattrs_read(xhandle);
40 if (retval) {
41 com_err(__func__, retval,
42 _("while reading xattrs of inode %u"), ino);
43 goto xattrs_close;
44 }
45 retval = ext2fs_xattr_set(xhandle, name, value, value_len);
46 if (retval) {
47 com_err(__func__, retval,
48 _("while setting xattrs of inode %u"), ino);
49 goto xattrs_close;
50 }
1e43f83f
AS
51xattrs_close:
52 close_retval = ext2fs_xattrs_close(&xhandle);
53 if (close_retval) {
54 com_err(__func__, close_retval,
55 _("while closing xattrs of inode %u"), ino);
56 return retval ? retval : close_retval;
57 }
58 return retval;
59}
60
61static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
62 struct inode_params *params)
63{
64 errcode_t retval;
65 char *secontext = NULL;
66 struct ext2_inode inode;
67
68 if (params->sehnd == NULL)
69 return 0;
70
71 retval = ext2fs_read_inode(fs, ino, &inode);
72 if (retval) {
73 com_err(__func__, retval,
74 _("while reading inode %u"), ino);
75 return retval;
76 }
77
78 retval = selabel_lookup(params->sehnd, &secontext, params->filename,
79 inode.i_mode);
80 if (retval < 0) {
81 com_err(__func__, retval,
82 _("searching for label \"%s\""), params->filename);
82eb7e90 83 exit(1);
1e43f83f
AS
84 }
85
86 retval = ino_add_xattr(fs, ino, "security." XATTR_SELINUX_SUFFIX,
87 secontext, strlen(secontext) + 1);
88
89 freecon(secontext);
90 return retval;
91}
92
93static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
94 struct inode_params *params)
95{
96 errcode_t retval;
97 uint64_t capabilities = 0;
98 struct ext2_inode inode;
99 struct vfs_cap_data cap_data;
100 unsigned int uid = 0, gid = 0, imode = 0;
101
102 retval = ext2fs_read_inode(fs, ino, &inode);
103 if (retval) {
104 com_err(__func__, retval, _("while reading inode %u"), ino);
105 return retval;
106 }
107
108 /* Permissions */
109 if (params->fs_config_func != NULL) {
110 params->fs_config_func(params->filename, S_ISDIR(inode.i_mode),
111 params->target_out, &uid, &gid, &imode,
112 &capabilities);
113 inode.i_uid = uid & 0xffff;
114 inode.i_gid = gid & 0xffff;
115 inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
116 retval = ext2fs_write_inode(fs, ino, &inode);
117 if (retval) {
118 com_err(__func__, retval,
70964797 119 _("while writing inode %u"), ino);
1e43f83f
AS
120 return retval;
121 }
122 }
123
124 /* Capabilities */
125 if (!capabilities)
126 return 0;
127 memset(&cap_data, 0, sizeof(cap_data));
128 cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
129 cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
130 cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
131 return ino_add_xattr(fs, ino, "security." XATTR_CAPS_SUFFIX,
132 &cap_data, sizeof(cap_data));
133}
134
135static errcode_t set_timestamp(ext2_filsys fs, ext2_ino_t ino,
136 struct inode_params *params)
137{
138 errcode_t retval;
139 struct ext2_inode inode;
3946ee85
JQ
140 struct stat stat;
141 char *src_filename = NULL;
1e43f83f 142
3946ee85
JQ
143 retval = ext2fs_read_inode(fs, ino, &inode);
144 if (retval) {
145 com_err(__func__, retval,
146 _("while reading inode %u"), ino);
147 return retval;
148 }
149
301fed07 150 if (params->fixed_time == -1 && params->src_dir) {
3946ee85
JQ
151 /* replace mountpoint from filename with src_dir */
152 if (asprintf(&src_filename, "%s/%s", params->src_dir,
301fed07 153 params->filename + strlen(params->mountpoint)) < 0) {
3946ee85 154 return -ENOMEM;
301fed07 155 }
3946ee85
JQ
156 retval = lstat(src_filename, &stat);
157 if (retval < 0) {
1e43f83f 158 com_err(__func__, retval,
3946ee85
JQ
159 _("while lstat file %s"), src_filename);
160 goto end;
1e43f83f 161 }
3946ee85
JQ
162 inode.i_atime = inode.i_ctime = inode.i_mtime = stat.st_mtime;
163 } else {
164 inode.i_atime = inode.i_ctime = inode.i_mtime = params->fixed_time;
1e43f83f
AS
165 }
166
3946ee85
JQ
167 retval = ext2fs_write_inode(fs, ino, &inode);
168 if (retval) {
169 com_err(__func__, retval,
70964797 170 _("while writing inode %u"), ino);
3946ee85
JQ
171 goto end;
172 }
173
174end:
175 free(src_filename);
176 return retval;
1e43f83f
AS
177}
178
179static int is_dir(ext2_filsys fs, ext2_ino_t ino)
180{
181 struct ext2_inode inode;
182
183 if (ext2fs_read_inode(fs, ino, &inode))
184 return 0;
185 return S_ISDIR(inode.i_mode);
186}
187
188static errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
189 struct inode_params *params)
190{
191 errcode_t retval;
192
193 retval = set_timestamp(fs, ino, params);
194 if (retval)
195 return retval;
196
197 retval = set_selinux_xattr(fs, ino, params);
198 if (retval)
199 return retval;
200
201 return set_perms_and_caps(fs, ino, params);
202}
203
204static int walk_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
205 int flags EXT2FS_ATTR((unused)),
206 struct ext2_dir_entry *de,
207 int offset EXT2FS_ATTR((unused)),
208 int blocksize EXT2FS_ATTR((unused)),
209 char *buf EXT2FS_ATTR((unused)), void *priv_data)
210{
211 __u16 name_len;
212 errcode_t retval;
213 struct inode_params *params = (struct inode_params *)priv_data;
214
215 name_len = de->name_len & 0xff;
216 if (!strncmp(de->name, ".", name_len)
217 || (!strncmp(de->name, "..", name_len)))
218 return 0;
219
220 if (asprintf(&params->filename, "%s/%.*s", params->path, name_len,
221 de->name) < 0)
222 return -ENOMEM;
223
224 if (!strncmp(de->name, "lost+found", 10)) {
225 retval = set_selinux_xattr(params->fs, de->inode, params);
226 if (retval)
227 goto end;
228 } else {
229 retval = androidify_inode(params->fs, de->inode, params);
230 if (retval)
231 goto end;
232 if (is_dir(params->fs, de->inode)) {
233 char *cur_path = params->path;
234 char *cur_filename = params->filename;
235 params->path = params->filename;
236 ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
237 walk_dir, params);
238 params->path = cur_path;
239 params->filename = cur_filename;
240 }
241 }
242
243end:
244 free(params->filename);
245 return retval;
246}
247
3946ee85
JQ
248errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
249 char *target_out,
1e43f83f
AS
250 char *mountpoint,
251 fs_config_f fs_config_func,
252 struct selabel_handle *sehnd,
253 time_t fixed_time)
254{
255 errcode_t retval;
256 struct inode_params params = {
257 .fs = fs,
3946ee85 258 .src_dir = src_dir,
1e43f83f
AS
259 .target_out = target_out,
260 .fs_config_func = fs_config_func,
261 .sehnd = sehnd,
262 .fixed_time = fixed_time,
263 .path = mountpoint,
d838f79e 264 .filename = mountpoint,
3946ee85 265 .mountpoint = mountpoint,
1e43f83f
AS
266 };
267
d838f79e
JQ
268 /* walk_dir will add the "/". Don't add it twice. */
269 if (strlen(mountpoint) == 1 && mountpoint[0] == '/')
270 params.path = "";
271
1e43f83f
AS
272 retval = set_selinux_xattr(fs, EXT2_ROOT_INO, &params);
273 if (retval)
274 return retval;
275 retval = set_timestamp(fs, EXT2_ROOT_INO, &params);
276 if (retval)
277 return retval;
278
279 return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
280 &params);
281}
282
3946ee85 283errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
1e43f83f 284 char *mountpoint,
8b9e44a0
JQ
285 struct selinux_opt *seopts,
286 unsigned int nopt,
1e43f83f
AS
287 char *fs_config_file, time_t fixed_time)
288{
289 errcode_t retval;
290 fs_config_f fs_config_func = NULL;
291 struct selabel_handle *sehnd = NULL;
292
293 /* Retrieve file contexts */
99c4785d 294#if !defined(__ANDROID__)
8b9e44a0
JQ
295 if (nopt > 0) {
296 sehnd = selabel_open(SELABEL_CTX_FILE, seopts, nopt);
1e43f83f
AS
297 if (!sehnd) {
298 com_err(__func__, -EINVAL,
299 _("while opening file contexts \"%s\""),
300 seopts[0].value);
301 return -EINVAL;
302 }
303 }
99c4785d
JQ
304#else
305 sehnd = selinux_android_file_context_handle();
306 if (!sehnd) {
307 com_err(__func__, -EINVAL,
308 _("while opening android file_contexts"));
309 return -EINVAL;
310 }
311#endif
1e43f83f
AS
312
313 /* Load the FS config */
314 if (fs_config_file) {
315 retval = load_canned_fs_config(fs_config_file);
316 if (retval < 0) {
317 com_err(__func__, retval,
318 _("while loading fs_config \"%s\""),
319 fs_config_file);
320 return retval;
321 }
322 fs_config_func = canned_fs_config;
323 } else if (mountpoint)
324 fs_config_func = fs_config;
325
3946ee85 326 return __android_configure_fs(fs, src_dir, target_out, mountpoint,
1e43f83f
AS
327 fs_config_func, sehnd, fixed_time);
328}