• 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_2 | 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 && params->src_dir) {
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 		}
162 		retval = lstat(src_filename, &stat);
163 		if (retval < 0) {
164 			com_err(__func__, retval,
165 				_("while lstat file %s"), src_filename);
166 			goto end;
167 		}
168 		inode.i_atime = inode.i_ctime = inode.i_mtime = stat.st_mtime;
169 	} else {
170 		inode.i_atime = inode.i_ctime = inode.i_mtime = params->fixed_time;
171 	}
172 
173 	retval = ext2fs_write_inode(fs, ino, &inode);
174 	if (retval) {
175 		com_err(__func__, retval,
176 			_("while writting inode %u"), ino);
177 		goto end;
178 	}
179 
180 end:
181 	free(src_filename);
182 	return retval;
183 }
184 
is_dir(ext2_filsys fs,ext2_ino_t ino)185 static int is_dir(ext2_filsys fs, ext2_ino_t ino)
186 {
187 	struct ext2_inode inode;
188 
189 	if (ext2fs_read_inode(fs, ino, &inode))
190 		return 0;
191 	return S_ISDIR(inode.i_mode);
192 }
193 
androidify_inode(ext2_filsys fs,ext2_ino_t ino,struct inode_params * params)194 static errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
195 				  struct inode_params *params)
196 {
197 	errcode_t retval;
198 
199 	retval = set_timestamp(fs, ino, params);
200 	if (retval)
201 		return retval;
202 
203 	retval = set_selinux_xattr(fs, ino, params);
204 	if (retval)
205 		return retval;
206 
207 	return set_perms_and_caps(fs, ino, params);
208 }
209 
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)210 static int walk_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
211 		    int flags EXT2FS_ATTR((unused)),
212 		    struct ext2_dir_entry *de,
213 		    int offset EXT2FS_ATTR((unused)),
214 		    int blocksize EXT2FS_ATTR((unused)),
215 		    char *buf EXT2FS_ATTR((unused)), void *priv_data)
216 {
217 	__u16 name_len;
218 	errcode_t retval;
219 	struct inode_params *params = (struct inode_params *)priv_data;
220 
221 	name_len = de->name_len & 0xff;
222 	if (!strncmp(de->name, ".", name_len)
223 	    || (!strncmp(de->name, "..", name_len)))
224 		return 0;
225 
226 	if (asprintf(&params->filename, "%s/%.*s", params->path, name_len,
227 		     de->name) < 0)
228 		return -ENOMEM;
229 
230 	if (!strncmp(de->name, "lost+found", 10)) {
231 		retval = set_selinux_xattr(params->fs, de->inode, params);
232 		if (retval)
233 			goto end;
234 	} else {
235 		retval = androidify_inode(params->fs, de->inode, params);
236 		if (retval)
237 			goto end;
238 		if (is_dir(params->fs, de->inode)) {
239 			char *cur_path = params->path;
240 			char *cur_filename = params->filename;
241 			params->path = params->filename;
242 			ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
243 					    walk_dir, params);
244 			params->path = cur_path;
245 			params->filename = cur_filename;
246 		}
247 	}
248 
249 end:
250 	free(params->filename);
251 	return retval;
252 }
253 
__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)254 errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
255 				 char *target_out,
256 				 char *mountpoint,
257 				 fs_config_f fs_config_func,
258 				 struct selabel_handle *sehnd,
259 				 time_t fixed_time)
260 {
261 	errcode_t retval;
262 	struct inode_params params = {
263 		.fs = fs,
264 		.src_dir = src_dir,
265 		.target_out = target_out,
266 		.fs_config_func = fs_config_func,
267 		.sehnd = sehnd,
268 		.fixed_time = fixed_time,
269 		.path = mountpoint,
270 		.filename = mountpoint,
271 		.mountpoint = mountpoint,
272 	};
273 
274 	/* walk_dir will add the "/". Don't add it twice. */
275 	if (strlen(mountpoint) == 1 && mountpoint[0] == '/')
276 		params.path = "";
277 
278 	retval = set_selinux_xattr(fs, EXT2_ROOT_INO, &params);
279 	if (retval)
280 		return retval;
281 	retval = set_timestamp(fs, EXT2_ROOT_INO, &params);
282 	if (retval)
283 		return retval;
284 
285 	return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
286 				   &params);
287 }
288 
android_configure_fs(ext2_filsys fs,char * src_dir,char * target_out,char * mountpoint,struct selinux_opt * seopts EXT2FS_ATTR ((unused)),unsigned int nopt EXT2FS_ATTR ((unused)),char * fs_config_file,time_t fixed_time)289 errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
290 			       char *mountpoint,
291 			       struct selinux_opt *seopts EXT2FS_ATTR((unused)),
292 			       unsigned int nopt EXT2FS_ATTR((unused)),
293 			       char *fs_config_file, time_t fixed_time)
294 {
295 	errcode_t retval;
296 	fs_config_f fs_config_func = NULL;
297 	struct selabel_handle *sehnd = NULL;
298 
299 	/* Retrieve file contexts */
300 #if !defined(__ANDROID__)
301 	if (nopt > 0) {
302 		sehnd = selabel_open(SELABEL_CTX_FILE, seopts, nopt);
303 		if (!sehnd) {
304 			com_err(__func__, -EINVAL,
305 				_("while opening file contexts \"%s\""),
306 				seopts[0].value);
307 			return -EINVAL;
308 		}
309 	}
310 #else
311 	sehnd = selinux_android_file_context_handle();
312 	if (!sehnd) {
313 		com_err(__func__, -EINVAL,
314 			_("while opening android file_contexts"));
315 		return -EINVAL;
316 	}
317 #endif
318 
319 	/* Load the FS config */
320 	if (fs_config_file) {
321 		retval = load_canned_fs_config(fs_config_file);
322 		if (retval < 0) {
323 			com_err(__func__, retval,
324 				_("while loading fs_config \"%s\""),
325 				fs_config_file);
326 			return retval;
327 		}
328 		fs_config_func = canned_fs_config;
329 	} else if (mountpoint)
330 		fs_config_func = fs_config;
331 
332 	return __android_configure_fs(fs, src_dir, target_out, mountpoint,
333 				      fs_config_func, sehnd, fixed_time);
334 }
335