Index: usr.bin/sort/Makefile =================================================================== --- usr.bin/sort/Makefile +++ usr.bin/sort/Makefile @@ -32,6 +32,14 @@ MAN_SUB+= -e 's|%%NLS%%|\.\\"|g' .endif +.if ${MK_CASPER} != "no" +LIBADD+= casper +LIBADD+= cap_fileargs +LIBADD+= cap_exec +LIBADD+= nv +CFLAGS+=-DWITH_CASPER +.endif + #HAS_TESTS= #SUBDIR.${MK_TESTS}+= tests Index: usr.bin/sort/file.h =================================================================== --- usr.bin/sort/file.h +++ usr.bin/sort/file.h @@ -85,6 +85,7 @@ /* temporary file dir */ extern const char *tmpdir; +extern int tmpdir_fd; /* * Max number of simultaneously open files (including the output file). Index: usr.bin/sort/file.c =================================================================== --- usr.bin/sort/file.c +++ usr.bin/sort/file.c @@ -35,8 +35,10 @@ #include #include +#include #include #include +#include #if defined(SORT_THREADS) #include #endif @@ -58,6 +60,7 @@ bool use_mmap; const char *tmpdir = "/var/tmp"; +int tmpdir_fd; const char *compress_program; size_t max_open_files = 16; @@ -160,7 +163,7 @@ sem_wait(&tmp_files_sem); LIST_FOREACH(item,&tmp_files,files) { if ((item) && (item->fn)) - unlink(item->fn); + unlinkat(tmpdir_fd, basename(item->fn), 0); } sem_post(&tmp_files_sem); } @@ -270,8 +273,12 @@ for (i = 0; i < fl->count; i++) { if (fl->fns[i]) { - if (fl->tmp) - unlink(fl->fns[i]); + if (fl->tmp) { + char *buf = sort_malloc(strlen(fl->fns[i]) + 1); + strcpy(buf, fl->fns[i]); + unlinkat(tmpdir_fd, basename(buf), 0); + sort_free(buf); + } sort_free(fl->fns[i]); fl->fns[i] = 0; } @@ -559,23 +566,46 @@ fflush(stdout); if (mode[0] == 'r') - snprintf(cmd, cmdsz - 1, "cat %s | %s -d", - fn, compress_program); + snprintf(cmd, cmdsz - 1, "%s -d < %s", + compress_program, fn); else if (mode[0] == 'w') snprintf(cmd, cmdsz - 1, "%s > %s", compress_program, fn); else err(2, "%s", getstr(7)); - if ((file = popen(cmd, mode)) == NULL) + if ((file = cap_exec_open(capexec, cmd, mode)) == NULL) err(2, NULL); sort_free(cmd); + } else if (is_tmp) { + char *tmp = sort_malloc(strlen(fn) + 1); + strcpy(tmp, fn); - } else - if ((file = fopen(fn, mode)) == NULL) + int fd = openat(tmpdir_fd, basename(tmp), O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) err(2, NULL); - + if ((file = fdopen(fd, mode)) == NULL) + err(2, NULL); + sort_free(tmp); + } else { + /* + * fa_in and fa_out contain the input and output files + * respectively. For input files we only read, and for + * output files we only write, so we can tell which fa + * to use based on the mode. + */ + fileargs_t *fa; + if (mode[0] == 'w') + fa = fa_out; + else if (mode[0] == 'r') + fa = fa_in; + else + err(2, NULL); + if ((file = fileargs_fopen(fa, fn, mode)) == NULL) + err(2, NULL); + } if (is_tmp && (mode[0] == 'w')) umask(orig_file_mask); } @@ -597,8 +627,8 @@ fflush(f); } else { if (file_is_tmp(fn) && compress_program != NULL) { - if(pclose(f)<0) - err(2,NULL); + if (cap_exec_close(capexec, f) < 0) + err(2, NULL); } else fclose(f); } @@ -1170,9 +1200,14 @@ merge_files_array(num, fl->fns + indx, fnew); if (fl->tmp) { size_t i; + char *buf; - for (i = 0; i < num; i++) - unlink(fl->fns[indx + i]); + for (i = 0; i < num; i++) { + buf = sort_malloc(strlen(fl->fns[indx + i]) + 1); + strcpy(buf, fl->fns[indx + i]); + unlinkat(tmpdir_fd, basename(buf), 0); + sort_free(buf); + } } file_list_add(&new_fl, fnew, false); indx += num; @@ -1198,7 +1233,6 @@ if (fl && fn_out) { while (shrink_file_list(fl)); - merge_files_array(fl->count, fl->fns, fn_out); } } Index: usr.bin/sort/sort.h =================================================================== --- usr.bin/sort/sort.h +++ usr.bin/sort/sort.h @@ -32,6 +32,10 @@ #if !defined(__BSD_SORT_H__) #define __BSD_SORT_H__ +#include +#include +#include + #include #include #include @@ -70,6 +74,13 @@ */ extern MD5_CTX md5_ctx; +/* + * For accessing files, executing compression program in Capability mode + */ +extern fileargs_t *fa_in; +extern fileargs_t *fa_out; +extern cap_exec_t *capexec; + /* * sort.c */ Index: usr.bin/sort/sort.c =================================================================== --- usr.bin/sort/sort.c +++ usr.bin/sort/sort.c @@ -30,14 +30,21 @@ #include __FBSDID("$FreeBSD$"); +#include +#include #include #include #include +#include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -117,6 +124,10 @@ static size_t argc_from_file0 = (size_t)-1; static char **argv_from_file0; +fileargs_t *fa_in; +fileargs_t *fa_out; +cap_exec_t *capexec; + /* * Placeholder symbols for options which have no single-character equivalent */ @@ -981,9 +992,12 @@ int main(int argc, char **argv) { + char *argv_out[2]; + cap_rights_t rights; + cap_channel_t *capcas; char *outfile, *real_outfile; char *random_source = NULL; - int c, result; + int argc_out, c, outdir, result; bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = { false, false, false, false, false, false }; @@ -1185,6 +1199,73 @@ argv = argv_from_file0; } + /* Case when the outfile equals one of the input files: */ + if (strcmp(outfile, "-")) { + + for(int i = 0; i < argc; ++i) { + if (strcmp(argv[i], outfile) == 0) { + real_outfile = sort_strdup(outfile); + for(;;) { + char* tmp = sort_malloc(strlen(outfile) + + strlen(".tmp") + 1); + + strcpy(tmp, outfile); + strcpy(tmp + strlen(tmp), ".tmp"); + sort_free(outfile); + outfile = tmp; + if (access(outfile, F_OK) < 0) + break; + } + } + } + } + + argc_out = 1; + argv_out[0] = outfile; + if (real_outfile) { + ++argc_out; + argv_out[1] = real_outfile; + + /* Open the output directory now, as we will later rename/delete files there */ + char* tmp = sort_malloc(strlen(real_outfile) + 1); + strcpy(tmp, real_outfile); + if ((outdir = open(dirname(tmp), O_DIRECTORY)) < 0) + err(1, NULL); + sort_free(tmp); + + cap_rights_init(&rights, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET, CAP_UNLINKAT); + caph_rights_limit(outdir, &rights); + } + + /* Open the temporary files directory */ + if ((tmpdir_fd = open(tmpdir, O_DIRECTORY)) == -1) + err(1, NULL); + cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, CAP_LOOKUP, + CAP_PWRITE, CAP_READ, CAP_UNLINKAT, CAP_FSTAT); + caph_rights_limit(tmpdir_fd, &rights); + + capcas = cap_init(); + + /* Initialize input and output fileargs */ + cap_rights_init(&rights, CAP_FCNTL, CAP_READ, CAP_FSTAT); + fa_in = fileargs_cinit(capcas, argc, argv, O_RDONLY, 0, &rights, FA_OPEN); + + cap_rights_init(&rights, CAP_FCNTL, CAP_WRITE, CAP_FSTAT); + fa_out = fileargs_cinit(capcas, argc_out, argv_out, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &rights, FA_OPEN); + + if (fa_in == NULL || fa_out == NULL) + err(1, "unable to set limits"); + + /* Open cap_exec service, if needed */ + if (compress_program != NULL) { + capexec = cap_exec_init(capcas, 1, &compress_program); + } + + cap_close(capcas); + + caph_limit_stdio(); + #ifndef WITHOUT_NLS catalog = catopen("sort", NL_CAT_LOCALE); #endif @@ -1196,6 +1277,9 @@ catclose(catalog); #endif + if (caph_enter_casper() < 0) + err(1, "cap_enter"); + if (keys_num == 0) { keys_num = 1; keys = sort_realloc(keys, sizeof(struct key_specs)); @@ -1245,28 +1329,6 @@ if (need_random) get_random_seed(random_source); - /* Case when the outfile equals one of the input files: */ - if (strcmp(outfile, "-")) { - - for(int i = 0; i < argc; ++i) { - if (strcmp(argv[i], outfile) == 0) { - real_outfile = sort_strdup(outfile); - for(;;) { - char* tmp = sort_malloc(strlen(outfile) + - strlen(".tmp") + 1); - - strcpy(tmp, outfile); - strcpy(tmp + strlen(tmp), ".tmp"); - sort_free(outfile); - outfile = tmp; - if (access(outfile, F_OK) < 0) - break; - } - tmp_file_atexit(outfile); - } - } - } - #if defined(SORT_THREADS) if ((argc < 1) || (strcmp(outfile, "-") == 0) || (*outfile == 0)) nthreads = 1; @@ -1326,13 +1388,17 @@ } if (real_outfile) { - unlink(real_outfile); - if (rename(outfile, real_outfile) < 0) + unlinkat(outdir, real_outfile, 0); + if (renameat(outdir, outfile, outdir, real_outfile) < 0) err(2, NULL); sort_free(real_outfile); } sort_free(outfile); + fileargs_free(fa_in); + fileargs_free(fa_out); + cap_exec_free(capexec); + return (result); }