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(¶ms->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, ¶ms); 278 if (retval) 279 return retval; 280 retval = set_timestamp(fs, EXT2_ROOT_INO, ¶ms); 281 if (retval) 282 return retval; 283 284 return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir, 285 ¶ms); 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