Home | History | Annotate | Download | only in android
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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