diff options
Diffstat (limited to 'src/fcopy/main.c')
-rw-r--r-- | src/fcopy/main.c | 65 |
1 files changed, 55 insertions, 10 deletions
diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 01633be59..572e9f601 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c | |||
@@ -51,8 +51,9 @@ static int selinux_enabled = -1; | |||
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | // copy from firejail/selinux.c | 53 | // copy from firejail/selinux.c |
54 | static void selinux_relabel_path(const char *path, const char *inside_path) | 54 | static void selinux_relabel_path(const char *path, const char *inside_path) { |
55 | { | 55 | assert(path); |
56 | assert(inside_path); | ||
56 | #if HAVE_SELINUX | 57 | #if HAVE_SELINUX |
57 | char procfs_path[64]; | 58 | char procfs_path[64]; |
58 | char *fcon = NULL; | 59 | char *fcon = NULL; |
@@ -172,6 +173,51 @@ static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { | |||
172 | } | 173 | } |
173 | } | 174 | } |
174 | 175 | ||
176 | static char *proc_pid_to_self(const char *target) { | ||
177 | assert(target); | ||
178 | char *use_target = 0; | ||
179 | char *proc_pid = 0; | ||
180 | |||
181 | if (!(use_target = realpath(target, NULL))) | ||
182 | goto done; | ||
183 | |||
184 | // target is under /proc/<PID>? | ||
185 | static const char proc[] = "/proc/"; | ||
186 | if (strncmp(use_target, proc, sizeof(proc) - 1)) | ||
187 | goto done; | ||
188 | |||
189 | int digit = use_target[sizeof(proc) - 1]; | ||
190 | if (digit < '1' || digit > '9') | ||
191 | goto done; | ||
192 | |||
193 | // check where /proc/self points to | ||
194 | static const char proc_self[] = "/proc/self"; | ||
195 | if (!(proc_pid = realpath(proc_self, NULL))) | ||
196 | goto done; | ||
197 | |||
198 | // redirect /proc/PID/xxx -> /proc/self/XXX | ||
199 | size_t pfix = strlen(proc_pid); | ||
200 | if (strncmp(use_target, proc_pid, pfix)) | ||
201 | goto done; | ||
202 | |||
203 | if (use_target[pfix] != 0 && use_target[pfix] != '/') | ||
204 | goto done; | ||
205 | |||
206 | char *tmp; | ||
207 | if (asprintf(&tmp, "%s%s", proc_self, use_target + pfix) != -1) { | ||
208 | if (arg_debug) | ||
209 | fprintf(stderr, "SYMLINK %s\n --> %s\n", use_target, tmp); | ||
210 | free(use_target); | ||
211 | use_target = tmp; | ||
212 | } | ||
213 | else | ||
214 | errExit("asprintf"); | ||
215 | |||
216 | done: | ||
217 | if (proc_pid) | ||
218 | free(proc_pid); | ||
219 | return use_target; | ||
220 | } | ||
175 | 221 | ||
176 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { | 222 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { |
177 | (void) mode; | 223 | (void) mode; |
@@ -183,7 +229,7 @@ void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, | |||
183 | if (lstat(linkpath, &s) == 0) | 229 | if (lstat(linkpath, &s) == 0) |
184 | return; | 230 | return; |
185 | 231 | ||
186 | char *rp = realpath(target, NULL); | 232 | char *rp = proc_pid_to_self(target); |
187 | if (rp) { | 233 | if (rp) { |
188 | if (symlink(rp, linkpath) == -1) { | 234 | if (symlink(rp, linkpath) == -1) { |
189 | free(rp); | 235 | free(rp); |
@@ -227,16 +273,14 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
227 | first = 0; | 273 | first = 0; |
228 | else if (!arg_quiet) | 274 | else if (!arg_quiet) |
229 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); | 275 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); |
230 | free(outfname); | 276 | goto out; |
231 | return 0; | ||
232 | } | 277 | } |
233 | 278 | ||
234 | // extract mode and ownership | 279 | // extract mode and ownership |
235 | if (stat(infname, &s) != 0) { | 280 | if (stat(infname, &s) != 0) { |
236 | if (!arg_quiet) | 281 | if (!arg_quiet) |
237 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); | 282 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); |
238 | free(outfname); | 283 | goto out; |
239 | return 0; | ||
240 | } | 284 | } |
241 | uid_t uid = s.st_uid; | 285 | uid_t uid = s.st_uid; |
242 | gid_t gid = s.st_gid; | 286 | gid_t gid = s.st_gid; |
@@ -246,8 +290,7 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
246 | if ((s.st_size + size_cnt) > copy_limit) { | 290 | if ((s.st_size + size_cnt) > copy_limit) { |
247 | fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024); | 291 | fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024); |
248 | size_limit_reached = 1; | 292 | size_limit_reached = 1; |
249 | free(outfname); | 293 | goto out; |
250 | return 0; | ||
251 | } | 294 | } |
252 | 295 | ||
253 | file_cnt++; | 296 | file_cnt++; |
@@ -262,7 +305,8 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
262 | else if (ftype == FTW_SL) { | 305 | else if (ftype == FTW_SL) { |
263 | copy_link(infname, outfname, mode, uid, gid); | 306 | copy_link(infname, outfname, mode, uid, gid); |
264 | } | 307 | } |
265 | 308 | out: | |
309 | free(outfname); | ||
266 | return(0); | 310 | return(0); |
267 | } | 311 | } |
268 | 312 | ||
@@ -295,6 +339,7 @@ static char *check(const char *src) { | |||
295 | return rsrc; // normal exit from the function | 339 | return rsrc; // normal exit from the function |
296 | 340 | ||
297 | errexit: | 341 | errexit: |
342 | free(rsrc); | ||
298 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); | 343 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); |
299 | exit(1); | 344 | exit(1); |
300 | } | 345 | } |