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