aboutsummaryrefslogtreecommitdiffstats
path: root/src/fcopy/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fcopy/main.c')
-rw-r--r--src/fcopy/main.c65
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
54static void selinux_relabel_path(const char *path, const char *inside_path) 54static 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
176static 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
216done:
217 if (proc_pid)
218 free(proc_pid);
219 return use_target;
220}
175 221
176void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { 222void 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 308out:
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
297errexit: 341errexit:
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}