mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2024-11-23 18:14:25 +08:00
AOSP: Support UID/GID mapping
This reverts commit 797c9c47d8419f58f752a96ae972423ca32b4c30. with the fix. Signed-off-by: Theodore Ts'o <tytso@mit.edu> Google-Bug-Id: 78561186 Test: Ran on DUT. Change-Id: I0d903cb08373aa5e9d79a1601d2e5ea9a59573fe From AOSP commit: 5250966f2b7b7b4643235551b125ddbcfbd3d609
This commit is contained in:
parent
7c40d7bc9e
commit
32272a37d7
@ -13,6 +13,15 @@
|
||||
#include "basefs_allocator.h"
|
||||
#include "create_inode.h"
|
||||
|
||||
#ifndef UID_GID_MAP_MAX_EXTENTS
|
||||
/*
|
||||
* The value is defined in linux/user_namspace.h.
|
||||
* The value is (arbitrarily) 5 in 4.14 and earlier, or 340 in 4.15 and later.
|
||||
* Here, the bigger value is taken. See also man user_namespace(7).
|
||||
*/
|
||||
#define UID_GID_MAP_MAX_EXTENTS 340
|
||||
#endif
|
||||
|
||||
static char *prog_name = "e2fsdroid";
|
||||
static char *in_file;
|
||||
static char *block_list;
|
||||
@ -32,7 +41,8 @@ static void usage(int ret)
|
||||
{
|
||||
fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-T timestamp]\n"
|
||||
"\t[-C fs_config] [-S file_contexts] [-p product_out]\n"
|
||||
"\t[-a mountpoint] [-d basefs_in] [-f src_dir] [-e] [-s] image\n",
|
||||
"\t[-a mountpoint] [-d basefs_in] [-f src_dir] [-e] [-s]\n"
|
||||
"\t[-u uid-mapping] [-g gid-mapping] image\n",
|
||||
prog_name);
|
||||
exit(ret);
|
||||
}
|
||||
@ -55,6 +65,135 @@ static char *absolute_path(const char *file)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_ugid_map_entry(char* line, struct ugid_map_entry* result)
|
||||
{
|
||||
char *token, *token_saveptr;
|
||||
size_t num_tokens;
|
||||
unsigned int *parsed[] = {&result->child_id,
|
||||
&result->parent_id,
|
||||
&result->length};
|
||||
for (token = strtok_r(line, " ", &token_saveptr), num_tokens = 0;
|
||||
token && num_tokens < 3;
|
||||
token = strtok_r(NULL, " ", &token_saveptr), ++num_tokens) {
|
||||
char* endptr = NULL;
|
||||
*parsed[num_tokens] = strtoul(token, &endptr, 10);
|
||||
if ((*parsed[num_tokens] == ULONG_MAX && errno) || *endptr) {
|
||||
fprintf(stderr, "Malformed u/gid mapping line\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (num_tokens < 3 || strtok_r(NULL, " ", &token_saveptr) != NULL) {
|
||||
fprintf(stderr, "Malformed u/gid mapping line\n");
|
||||
return 0;
|
||||
}
|
||||
if (result->child_id + result->length < result->child_id ||
|
||||
result->parent_id + result->length < result->parent_id) {
|
||||
fprintf(stderr, "u/gid mapping overflow\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if [begin1, begin1+length1) and [begin2, begin2+length2) have
|
||||
* overlapping range. Otherwise 0.
|
||||
*/
|
||||
static int is_overlapping(unsigned int begin1, unsigned int length1,
|
||||
unsigned int begin2, unsigned int length2)
|
||||
{
|
||||
unsigned int end1 = begin1 + length1;
|
||||
unsigned int end2 = begin2 + length2;
|
||||
return !(end1 <= begin2 || end2 <= begin1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies if the given mapping works.
|
||||
* - Checks if the number of entries is less than or equals to
|
||||
* UID_GID_MAP_MAX_EXTENTS.
|
||||
* - Checks if there is no overlapped ranges.
|
||||
* Returns 1 if valid, otherwise 0.
|
||||
*/
|
||||
static int is_valid_ugid_map(const struct ugid_map* mapping)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
if (mapping->size > UID_GID_MAP_MAX_EXTENTS) {
|
||||
fprintf(stderr, "too many u/gid mapping entries\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < mapping->size; ++i) {
|
||||
const struct ugid_map_entry *entry1 = &mapping->entries[i];
|
||||
for (j = i + 1; j < mapping->size; ++j) {
|
||||
const struct ugid_map_entry *entry2 =
|
||||
&mapping->entries[j];
|
||||
if (is_overlapping(entry1->child_id, entry1->length,
|
||||
entry2->child_id, entry2->length)) {
|
||||
fprintf(stderr,
|
||||
"Overlapping child u/gid: [%d %d %d],"
|
||||
" [%d %d %d]\n",
|
||||
entry1->child_id, entry1->parent_id,
|
||||
entry1->length, entry2->child_id,
|
||||
entry2->parent_id, entry2->length);
|
||||
return 0;
|
||||
}
|
||||
if (is_overlapping(entry1->parent_id, entry1->length,
|
||||
entry2->parent_id, entry2->length)) {
|
||||
fprintf(stderr,
|
||||
"Overlapping parent u/gid: [%d %d %d],"
|
||||
" [%d %d %d]\n",
|
||||
entry1->child_id, entry1->parent_id,
|
||||
entry1->length, entry2->child_id,
|
||||
entry2->parent_id, entry2->length);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the UID/GID mapping argument. The argument could be a multi-line
|
||||
* string (separated by '\n', no trailing '\n' is allowed). Each line must
|
||||
* contain exact three integer tokens; the first token is |child_id|,
|
||||
* the second is |parent_id|, and the last is |length| of the mapping range.
|
||||
* See also user_namespace(7) man page.
|
||||
* On success, the parsed entries are stored in |result|, and it returns 1.
|
||||
* Otherwise, returns 0.
|
||||
*/
|
||||
static int parse_ugid_map(char* arg, struct ugid_map* result)
|
||||
{
|
||||
int i;
|
||||
char *line, *line_saveptr;
|
||||
size_t current_index;
|
||||
|
||||
/* Count the number of lines. */
|
||||
result->size = 1;
|
||||
for (i = 0; arg[i]; ++i) {
|
||||
if (arg[i] == '\n')
|
||||
++result->size;
|
||||
}
|
||||
|
||||
/* Allocate memory for entries. */
|
||||
result->entries = malloc(sizeof(struct ugid_map_entry) * result->size);
|
||||
if (!result->entries) {
|
||||
result->size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse each line */
|
||||
for (line = strtok_r(arg, "\n", &line_saveptr), current_index = 0;
|
||||
line;
|
||||
line = strtok_r(NULL, "\n", &line_saveptr), ++current_index) {
|
||||
if (!parse_ugid_map_entry(
|
||||
line, &result->entries[current_index])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return is_valid_ugid_map(result);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
@ -70,10 +209,11 @@ int main(int argc, char *argv[])
|
||||
ext2_ino_t free_inodes_count;
|
||||
blk64_t blocks_count;
|
||||
blk64_t free_blocks_count;
|
||||
struct ugid_map uid_map = { 0, NULL }, gid_map = { 0, NULL };
|
||||
|
||||
add_error_table(&et_ext2_error_table);
|
||||
|
||||
while ((c = getopt (argc, argv, "T:C:S:p:a:D:d:B:f:es")) != EOF) {
|
||||
while ((c = getopt (argc, argv, "T:C:S:p:a:D:d:B:f:esu:g:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'T':
|
||||
fixed_time = strtoul(optarg, &p, 0);
|
||||
@ -122,6 +262,14 @@ int main(int argc, char *argv[])
|
||||
case 's':
|
||||
flags |= EXT2_FLAG_SHARE_DUP;
|
||||
break;
|
||||
case 'u':
|
||||
if (!parse_ugid_map(optarg, &uid_map))
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
case 'g':
|
||||
if (!parse_ugid_map(optarg, &gid_map))
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
default:
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
@ -173,8 +321,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (android_configure) {
|
||||
retval = android_configure_fs(fs, src_dir, product_out, mountpoint,
|
||||
seopt_file, nr_opt, fs_config_file, fixed_time);
|
||||
retval = android_configure_fs(
|
||||
fs, src_dir, product_out, mountpoint, seopt_file,
|
||||
nr_opt, fs_config_file, fixed_time, &uid_map, &gid_map);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while configuring the file system");
|
||||
|
@ -23,6 +23,8 @@ struct inode_params {
|
||||
fs_config_f fs_config_func;
|
||||
struct selabel_handle *sehnd;
|
||||
time_t fixed_time;
|
||||
const struct ugid_map* uid_map;
|
||||
const struct ugid_map* gid_map;
|
||||
};
|
||||
|
||||
static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
|
||||
@ -90,6 +92,26 @@ static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns mapped UID/GID if there is a corresponding entry in |mapping|.
|
||||
* Otherwise |id| as is.
|
||||
*/
|
||||
static unsigned int resolve_ugid(const struct ugid_map* mapping,
|
||||
unsigned int id)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < mapping->size; ++i) {
|
||||
const struct ugid_map_entry* entry = &mapping->entries[i];
|
||||
if (entry->parent_id <= id &&
|
||||
id < entry->parent_id + entry->length) {
|
||||
return id + entry->child_id - entry->parent_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* No entry is found. */
|
||||
return id;
|
||||
}
|
||||
|
||||
static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct inode_params *params)
|
||||
{
|
||||
@ -110,8 +132,12 @@ static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
|
||||
params->fs_config_func(params->filename, S_ISDIR(inode.i_mode),
|
||||
params->target_out, &uid, &gid, &imode,
|
||||
&capabilities);
|
||||
inode.i_uid = uid & 0xffff;
|
||||
inode.i_gid = gid & 0xffff;
|
||||
uid = resolve_ugid(params->uid_map, uid);
|
||||
gid = resolve_ugid(params->gid_map, gid);
|
||||
inode.i_uid = (__u16) uid;
|
||||
inode.i_gid = (__u16) gid;
|
||||
ext2fs_set_i_uid_high(inode, (__u16) (uid >> 16));
|
||||
ext2fs_set_i_gid_high(inode, (__u16) (gid >> 16));
|
||||
inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
|
||||
retval = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
@ -250,7 +276,9 @@ errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
|
||||
char *mountpoint,
|
||||
fs_config_f fs_config_func,
|
||||
struct selabel_handle *sehnd,
|
||||
time_t fixed_time)
|
||||
time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugid_map* gid_map)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct inode_params params = {
|
||||
@ -263,6 +291,8 @@ errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
|
||||
.path = mountpoint,
|
||||
.filename = mountpoint,
|
||||
.mountpoint = mountpoint,
|
||||
.uid_map = uid_map,
|
||||
.gid_map = gid_map,
|
||||
};
|
||||
|
||||
/* walk_dir will add the "/". Don't add it twice. */
|
||||
@ -284,7 +314,9 @@ errcode_t 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)
|
||||
char *fs_config_file, time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugid_map* gid_map)
|
||||
{
|
||||
errcode_t retval;
|
||||
fs_config_f fs_config_func = NULL;
|
||||
@ -324,5 +356,6 @@ errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
|
||||
fs_config_func = fs_config;
|
||||
|
||||
return __android_configure_fs(fs, src_dir, target_out, mountpoint,
|
||||
fs_config_func, sehnd, fixed_time);
|
||||
fs_config_func, sehnd, fixed_time,
|
||||
uid_map, gid_map);
|
||||
}
|
||||
|
@ -9,6 +9,25 @@ typedef void (*fs_config_f)(const char *path, int dir,
|
||||
unsigned *uid, unsigned *gid,
|
||||
unsigned *mode, uint64_t *capabilities);
|
||||
|
||||
/*
|
||||
* Represents a range of UID/GID mapping.
|
||||
* This maps the id in [|parent_id|, |parent_id| + |length|) into
|
||||
* [|child_id|, |child_id| + |length|)
|
||||
*/
|
||||
struct ugid_map_entry {
|
||||
unsigned int child_id;
|
||||
unsigned int parent_id;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
struct ugid_map {
|
||||
/* The number of elements in |entries|. */
|
||||
size_t size;
|
||||
|
||||
/* An array of entries. If |size| is 0, this is a null pointer. */
|
||||
struct ugid_map_entry* entries;
|
||||
};
|
||||
|
||||
# ifdef _WIN32
|
||||
struct selabel_handle;
|
||||
static inline errcode_t android_configure_fs(ext2_filsys fs,
|
||||
@ -18,7 +37,9 @@ static inline errcode_t android_configure_fs(ext2_filsys fs,
|
||||
void *seopts,
|
||||
unsigned int nopt,
|
||||
char *fs_config_file,
|
||||
time_t fixed_time)
|
||||
time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugdi_map* gid_map)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -36,7 +57,9 @@ errcode_t android_configure_fs(ext2_filsys fs, char *src_dir,
|
||||
char *mountpoint,
|
||||
struct selinux_opt *seopts,
|
||||
unsigned int nopt,
|
||||
char *fs_config_file, time_t fixed_time);
|
||||
char *fs_config_file, time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugid_map* gid_map);
|
||||
|
||||
# endif
|
||||
#endif /* !ANDROID_PERMS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user