diff options
-rw-r--r-- | src/firejail/main.c | 160 | ||||
-rw-r--r-- | src/firejail/util.c | 56 |
2 files changed, 124 insertions, 92 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c index 32c25c8d9..b4117bb70 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -3094,94 +3094,98 @@ int main(int argc, char **argv, char **envp) { | |||
3094 | } | 3094 | } |
3095 | EUID_ASSERT(); | 3095 | EUID_ASSERT(); |
3096 | 3096 | ||
3097 | // close each end of the unused pipes | 3097 | // close each end of the unused pipes |
3098 | close(parent_to_child_fds[0]); | 3098 | close(parent_to_child_fds[0]); |
3099 | close(child_to_parent_fds[1]); | 3099 | close(child_to_parent_fds[1]); |
3100 | 3100 | ||
3101 | // notify child that base setup is complete | 3101 | // notify child that base setup is complete |
3102 | notify_other(parent_to_child_fds[1]); | 3102 | notify_other(parent_to_child_fds[1]); |
3103 | 3103 | ||
3104 | // wait for child to create new user namespace with CLONE_NEWUSER | 3104 | // wait for child to create new user namespace with CLONE_NEWUSER |
3105 | wait_for_other(child_to_parent_fds[0]); | 3105 | wait_for_other(child_to_parent_fds[0]); |
3106 | close(child_to_parent_fds[0]); | 3106 | close(child_to_parent_fds[0]); |
3107 | 3107 | ||
3108 | if (arg_noroot) { | 3108 | if (arg_noroot) { |
3109 | // update the UID and GID maps in the new child user namespace | 3109 | // update the UID and GID maps in the new child user namespace |
3110 | // uid | 3110 | // uid |
3111 | char *map_path; | 3111 | char *map_path; |
3112 | if (asprintf(&map_path, "/proc/%d/uid_map", child) == -1) | 3112 | if (asprintf(&map_path, "/proc/%d/uid_map", child) == -1) |
3113 | errExit("asprintf"); | 3113 | errExit("asprintf"); |
3114 | 3114 | ||
3115 | char *map; | 3115 | char *map; |
3116 | uid_t uid = getuid(); | 3116 | uid_t uid = getuid(); |
3117 | if (asprintf(&map, "%d %d 1", uid, uid) == -1) | 3117 | if (asprintf(&map, "%d %d 1", uid, uid) == -1) |
3118 | errExit("asprintf"); | 3118 | errExit("asprintf"); |
3119 | EUID_ROOT(); | 3119 | EUID_ROOT(); |
3120 | update_map(map, map_path); | 3120 | update_map(map, map_path); |
3121 | EUID_USER(); | 3121 | EUID_USER(); |
3122 | free(map); | 3122 | free(map); |
3123 | free(map_path); | 3123 | free(map_path); |
3124 | 3124 | ||
3125 | // gid file | 3125 | // gid file |
3126 | if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) | 3126 | if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) |
3127 | errExit("asprintf"); | 3127 | errExit("asprintf"); |
3128 | char gidmap[1024]; | 3128 | char gidmap[1024]; |
3129 | char *ptr = gidmap; | 3129 | char *ptr = gidmap; |
3130 | *ptr = '\0'; | 3130 | *ptr = '\0'; |
3131 | 3131 | ||
3132 | // add user group | 3132 | // add user group |
3133 | gid_t gid = getgid(); | 3133 | gid_t gid = getgid(); |
3134 | sprintf(ptr, "%d %d 1\n", gid, gid); | 3134 | sprintf(ptr, "%d %d 1\n", gid, gid); |
3135 | ptr += strlen(ptr); | 3135 | ptr += strlen(ptr); |
3136 | 3136 | ||
3137 | if (!arg_nogroups) { | 3137 | if (!arg_nogroups) { |
3138 | // add firejail group | 3138 | // add firejail group |
3139 | gid_t g = get_group_id("firejail"); | 3139 | gid_t g = get_group_id("firejail"); |
3140 | if (g) { | 3140 | if (g) { |
3141 | sprintf(ptr, "%d %d 1\n", g, g); | 3141 | sprintf(ptr, "%d %d 1\n", g, g); |
3142 | ptr += strlen(ptr); | 3142 | ptr += strlen(ptr); |
3143 | } | 3143 | } |
3144 | 3144 | ||
3145 | // add tty group | 3145 | // add tty group |
3146 | g = get_group_id("tty"); | 3146 | g = get_group_id("tty"); |
3147 | if (g) { | 3147 | if (g) { |
3148 | sprintf(ptr, "%d %d 1\n", g, g); | 3148 | sprintf(ptr, "%d %d 1\n", g, g); |
3149 | ptr += strlen(ptr); | 3149 | ptr += strlen(ptr); |
3150 | } | 3150 | } |
3151 | 3151 | ||
3152 | // add audio group | 3152 | // add audio group |
3153 | g = get_group_id("audio"); | 3153 | if (!arg_nosound) { |
3154 | if (g) { | 3154 | g = get_group_id("audio"); |
3155 | sprintf(ptr, "%d %d 1\n", g, g); | 3155 | if (g) { |
3156 | ptr += strlen(ptr); | 3156 | sprintf(ptr, "%d %d 1\n", g, g); |
3157 | } | 3157 | ptr += strlen(ptr); |
3158 | 3158 | } | |
3159 | // add video group | 3159 | } |
3160 | g = get_group_id("video"); | 3160 | |
3161 | if (g) { | 3161 | // add video group |
3162 | sprintf(ptr, "%d %d 1\n", g, g); | 3162 | if (!arg_novideo) { |
3163 | ptr += strlen(ptr); | 3163 | g = get_group_id("video"); |
3164 | } | 3164 | if (g) { |
3165 | 3165 | sprintf(ptr, "%d %d 1\n", g, g); | |
3166 | // add games group | 3166 | ptr += strlen(ptr); |
3167 | g = get_group_id("games"); | 3167 | } |
3168 | if (g) { | 3168 | } |
3169 | sprintf(ptr, "%d %d 1\n", g, g); | 3169 | |
3170 | } | 3170 | // add games group |
3171 | } | 3171 | g = get_group_id("games"); |
3172 | 3172 | if (g) { | |
3173 | EUID_ROOT(); | 3173 | sprintf(ptr, "%d %d 1\n", g, g); |
3174 | update_map(gidmap, map_path); | 3174 | } |
3175 | EUID_USER(); | 3175 | } |
3176 | free(map_path); | 3176 | |
3177 | } | 3177 | EUID_ROOT(); |
3178 | update_map(gidmap, map_path); | ||
3179 | EUID_USER(); | ||
3180 | free(map_path); | ||
3181 | } | ||
3178 | EUID_ASSERT(); | 3182 | EUID_ASSERT(); |
3179 | 3183 | ||
3180 | // notify child that UID/GID mapping is complete | 3184 | // notify child that UID/GID mapping is complete |
3181 | notify_other(parent_to_child_fds[1]); | 3185 | notify_other(parent_to_child_fds[1]); |
3182 | close(parent_to_child_fds[1]); | 3186 | close(parent_to_child_fds[1]); |
3183 | 3187 | ||
3184 | EUID_ROOT(); | 3188 | EUID_ROOT(); |
3185 | if (lockfd_network != -1) { | 3189 | if (lockfd_network != -1) { |
3186 | flock(lockfd_network, LOCK_UN); | 3190 | flock(lockfd_network, LOCK_UN); |
3187 | close(lockfd_network); | 3191 | close(lockfd_network); |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 86977cecf..3bfb4435e 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -103,6 +103,36 @@ void errLogExit(char* fmt, ...) { | |||
103 | exit(1); | 103 | exit(1); |
104 | } | 104 | } |
105 | 105 | ||
106 | static int find_group(gid_t group, const gid_t *groups, int ngroups) { | ||
107 | int i; | ||
108 | for (i = 0; i < ngroups; i++) { | ||
109 | if (group == groups[i]) | ||
110 | return i; | ||
111 | } | ||
112 | |||
113 | return -1; | ||
114 | } | ||
115 | |||
116 | // Gets group from "groupname" and adds it to "new_groups" if it exists on | ||
117 | // "groups". Always returns the current value of new_ngroups. | ||
118 | static int copy_group_ifcont(const char *groupname, | ||
119 | const gid_t *groups, int ngroups, | ||
120 | gid_t *new_groups, int *new_ngroups, int new_sz) { | ||
121 | if (*new_ngroups >= new_sz) { | ||
122 | errno = ERANGE; | ||
123 | goto out; | ||
124 | } | ||
125 | |||
126 | gid_t g = get_group_id(groupname); | ||
127 | if (g && find_group(g, groups, ngroups) >= 0) { | ||
128 | new_groups[*new_ngroups] = g; | ||
129 | (*new_ngroups)++; | ||
130 | } | ||
131 | |||
132 | out: | ||
133 | return *new_ngroups; | ||
134 | } | ||
135 | |||
106 | static void clean_supplementary_groups(gid_t gid) { | 136 | static void clean_supplementary_groups(gid_t gid) { |
107 | assert(cfg.username); | 137 | assert(cfg.username); |
108 | gid_t groups[MAX_GROUPS]; | 138 | gid_t groups[MAX_GROUPS]; |
@@ -112,34 +142,32 @@ static void clean_supplementary_groups(gid_t gid) { | |||
112 | goto clean_all; | 142 | goto clean_all; |
113 | 143 | ||
114 | // clean supplementary group list | 144 | // clean supplementary group list |
115 | // allow only firejail, tty, audio, video, games | ||
116 | gid_t new_groups[MAX_GROUPS]; | 145 | gid_t new_groups[MAX_GROUPS]; |
117 | int new_ngroups = 0; | 146 | int new_ngroups = 0; |
118 | char *allowed[] = { | 147 | char *allowed[] = { |
119 | "firejail", | 148 | "firejail", |
120 | "tty", | 149 | "tty", |
121 | "audio", | ||
122 | "video", | ||
123 | "games", | 150 | "games", |
124 | NULL | 151 | NULL |
125 | }; | 152 | }; |
126 | 153 | ||
127 | int i = 0; | 154 | int i = 0; |
128 | while (allowed[i]) { | 155 | while (allowed[i]) { |
129 | gid_t g = get_group_id(allowed[i]); | 156 | copy_group_ifcont(allowed[i], groups, ngroups, |
130 | if (g) { | 157 | new_groups, &new_ngroups, MAX_GROUPS); |
131 | int j; | ||
132 | for (j = 0; j < ngroups; j++) { | ||
133 | if (g == groups[j]) { | ||
134 | new_groups[new_ngroups] = g; | ||
135 | new_ngroups++; | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | i++; | 158 | i++; |
141 | } | 159 | } |
142 | 160 | ||
161 | if (!arg_nosound) { | ||
162 | copy_group_ifcont("audio", groups, ngroups, | ||
163 | new_groups, &new_ngroups, MAX_GROUPS); | ||
164 | } | ||
165 | |||
166 | if (!arg_novideo) { | ||
167 | copy_group_ifcont("video", groups, ngroups, | ||
168 | new_groups, &new_ngroups, MAX_GROUPS); | ||
169 | } | ||
170 | |||
143 | if (new_ngroups) { | 171 | if (new_ngroups) { |
144 | rv = setgroups(new_ngroups, new_groups); | 172 | rv = setgroups(new_ngroups, new_groups); |
145 | if (rv) | 173 | if (rv) |