2 # define _GNU_SOURCE //asprintf
5 #include "support/nls-enable.h"
9 #ifndef XATTR_SELINUX_SUFFIX
10 # define XATTR_SELINUX_SUFFIX "selinux"
12 #ifndef XATTR_CAPS_SUFFIX
13 # define XATTR_CAPS_SUFFIX "capability"
23 fs_config_f fs_config_func;
24 struct selabel_handle *sehnd;
26 const struct ugid_map* uid_map;
27 const struct ugid_map* gid_map;
30 static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
31 const void *value, int value_len)
33 errcode_t retval, close_retval;
34 struct ext2_xattr_handle *xhandle;
36 retval = ext2fs_xattrs_open(fs, ino, &xhandle);
38 com_err(__func__, retval, _("while opening inode %u"), ino);
41 retval = ext2fs_xattrs_read(xhandle);
43 com_err(__func__, retval,
44 _("while reading xattrs of inode %u"), ino);
47 retval = ext2fs_xattr_set(xhandle, name, value, value_len);
49 com_err(__func__, retval,
50 _("while setting xattrs of inode %u"), ino);
54 close_retval = ext2fs_xattrs_close(&xhandle);
56 com_err(__func__, close_retval,
57 _("while closing xattrs of inode %u"), ino);
58 return retval ? retval : close_retval;
63 static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
64 struct inode_params *params)
67 char *secontext = NULL;
68 struct ext2_inode inode;
70 if (params->sehnd == NULL)
73 retval = ext2fs_read_inode(fs, ino, &inode);
75 com_err(__func__, retval,
76 _("while reading inode %u"), ino);
80 retval = selabel_lookup(params->sehnd, &secontext, params->filename,
83 com_err(__func__, retval,
84 _("searching for label \"%s\""), params->filename);
88 retval = ino_add_xattr(fs, ino, "security." XATTR_SELINUX_SUFFIX,
89 secontext, strlen(secontext) + 1);
96 * Returns mapped UID/GID if there is a corresponding entry in |mapping|.
97 * Otherwise |id| as is.
99 static unsigned int resolve_ugid(const struct ugid_map* mapping,
103 for (i = 0; i < mapping->size; ++i) {
104 const struct ugid_map_entry* entry = &mapping->entries[i];
105 if (entry->parent_id <= id &&
106 id < entry->parent_id + entry->length) {
107 return id + entry->child_id - entry->parent_id;
111 /* No entry is found. */
115 static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
116 struct inode_params *params)
119 uint64_t capabilities = 0;
120 struct ext2_inode inode;
121 struct vfs_cap_data cap_data;
122 unsigned int uid = 0, gid = 0, imode = 0;
124 retval = ext2fs_read_inode(fs, ino, &inode);
126 com_err(__func__, retval, _("while reading inode %u"), ino);
131 if (params->fs_config_func != NULL) {
132 params->fs_config_func(params->filename, S_ISDIR(inode.i_mode),
133 params->target_out, &uid, &gid, &imode,
135 uid = resolve_ugid(params->uid_map, uid);
136 gid = resolve_ugid(params->gid_map, gid);
137 inode.i_uid = (__u16) uid;
138 inode.i_gid = (__u16) gid;
139 ext2fs_set_i_uid_high(inode, (__u16) (uid >> 16));
140 ext2fs_set_i_gid_high(inode, (__u16) (gid >> 16));
141 inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
142 retval = ext2fs_write_inode(fs, ino, &inode);
144 com_err(__func__, retval,
145 _("while writing inode %u"), ino);
153 memset(&cap_data, 0, sizeof(cap_data));
154 cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
155 cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
156 cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
157 return ino_add_xattr(fs, ino, "security." XATTR_CAPS_SUFFIX,
158 &cap_data, sizeof(cap_data));
161 static errcode_t set_timestamp(ext2_filsys fs, ext2_ino_t ino,
162 struct inode_params *params)
165 struct ext2_inode inode;
167 char *src_filename = NULL;
169 retval = ext2fs_read_inode(fs, ino, &inode);
171 com_err(__func__, retval,
172 _("while reading inode %u"), ino);
176 if (params->fixed_time == -1 && params->src_dir) {
177 /* replace mountpoint from filename with src_dir */
178 if (asprintf(&src_filename, "%s/%s", params->src_dir,
179 params->filename + strlen(params->mountpoint)) < 0) {
182 retval = lstat(src_filename, &stat);
184 com_err(__func__, retval,
185 _("while lstat file %s"), src_filename);
188 inode.i_atime = inode.i_ctime = inode.i_mtime = stat.st_mtime;
190 inode.i_atime = inode.i_ctime = inode.i_mtime = params->fixed_time;
193 retval = ext2fs_write_inode(fs, ino, &inode);
195 com_err(__func__, retval,
196 _("while writing inode %u"), ino);
205 static int is_dir(ext2_filsys fs, ext2_ino_t ino)
207 struct ext2_inode inode;
209 if (ext2fs_read_inode(fs, ino, &inode))
211 return S_ISDIR(inode.i_mode);
214 static errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
215 struct inode_params *params)
219 retval = set_timestamp(fs, ino, params);
223 retval = set_selinux_xattr(fs, ino, params);
227 return set_perms_and_caps(fs, ino, params);
230 static int walk_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
231 int flags EXT2FS_ATTR((unused)),
232 struct ext2_dir_entry *de,
233 int offset EXT2FS_ATTR((unused)),
234 int blocksize EXT2FS_ATTR((unused)),
235 char *buf EXT2FS_ATTR((unused)), void *priv_data)
239 struct inode_params *params = (struct inode_params *)priv_data;
241 name_len = de->name_len & 0xff;
242 if (!strncmp(de->name, ".", name_len)
243 || (!strncmp(de->name, "..", name_len)))
246 if (asprintf(¶ms->filename, "%s/%.*s", params->path, name_len,
250 if (!strncmp(de->name, "lost+found", 10)) {
251 retval = set_selinux_xattr(params->fs, de->inode, params);
255 retval = androidify_inode(params->fs, de->inode, params);
258 if (is_dir(params->fs, de->inode)) {
259 char *cur_path = params->path;
260 char *cur_filename = params->filename;
261 params->path = params->filename;
262 ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
264 params->path = cur_path;
265 params->filename = cur_filename;
270 free(params->filename);
274 errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
277 fs_config_f fs_config_func,
278 struct selabel_handle *sehnd,
280 const struct ugid_map* uid_map,
281 const struct ugid_map* gid_map)
284 struct inode_params params = {
287 .target_out = target_out,
288 .fs_config_func = fs_config_func,
290 .fixed_time = fixed_time,
292 .filename = mountpoint,
293 .mountpoint = mountpoint,
298 /* walk_dir will add the "/". Don't add it twice. */
299 if (strlen(mountpoint) == 1 && mountpoint[0] == '/')
302 retval = set_selinux_xattr(fs, EXT2_ROOT_INO, ¶ms);
305 retval = set_timestamp(fs, EXT2_ROOT_INO, ¶ms);
309 return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
313 errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
315 struct selinux_opt *seopts EXT2FS_ATTR((unused)),
316 unsigned int nopt EXT2FS_ATTR((unused)),
317 char *fs_config_file, time_t fixed_time,
318 const struct ugid_map* uid_map,
319 const struct ugid_map* gid_map)
322 fs_config_f fs_config_func = NULL;
323 struct selabel_handle *sehnd = NULL;
325 /* Retrieve file contexts */
326 #if !defined(__ANDROID__)
328 sehnd = selabel_open(SELABEL_CTX_FILE, seopts, nopt);
330 com_err(__func__, -EINVAL,
331 _("while opening file contexts \"%s\""),
337 sehnd = selinux_android_file_context_handle();
339 com_err(__func__, -EINVAL,
340 _("while opening android file_contexts"));
345 /* Load the FS config */
346 if (fs_config_file) {
347 retval = load_canned_fs_config(fs_config_file);
349 com_err(__func__, retval,
350 _("while loading fs_config \"%s\""),
354 fs_config_func = canned_fs_config;
355 } else if (mountpoint)
356 fs_config_func = fs_config;
358 return __android_configure_fs(fs, src_dir, target_out, mountpoint,
359 fs_config_func, sehnd, fixed_time,