"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
close-on-exec
To:
gameoftrees@openbsd.org
Date:
Wed, 29 Dec 2021 12:56:09 +0100

Download raw body.

Thread
  • Stefan Sperling:

    close-on-exec

We recently disabled closefrom() return value checks because closefrom()
returns void on some non-OpenBSD platforms. During discussion of this
change, millert@ suggested use of the close-on-exec flag to avoid leaking
open files into a child process without a need for closefrom().

This patch adds the "e" flag to all fopen() calls, and the O_CLOEXEC
flag to all open() and openat() calls. Is this sufficient or do we need
to cover any other variants of fopen() and/or open()?

Do all of the various C libraries in use on Linux systems support the
close-on-exec flag? The linux kernel supports O_CLOEXEC since 2.6.23,
glibc supports the fopen "e" flag since 2.7. I have not checked other
libc, and I do not even know which libc are important to people running
got-portable.

Our use of closefrom() could now be deleted but we would then need to use
close-on-exec consistently in new code. I would rather keep both mechanisms
in place, such that closefrom() acts as a safety net which should close any
file descriptors that were accidentally not marked close-on-exec.

These changes affect the main process only since none of the libexec
helpers are able to open files. All files used by libexec helpers are
passed from the main process via imsg.

Regression tests are still passing on OpenBSD.

ok?


diff refs/heads/main refs/heads/close-on-exec
blob - 9e4617d2d22bb0cc089b03f64f1d2bca3d19ab51
blob + 0b61ca99747d4d1bde47a50eecd572ce88c838f8
--- got/got.c
+++ got/got.c
@@ -504,7 +504,7 @@ edit_logmsg(char **logmsg, const char *editor, const c
 		return got_error_from_errno("malloc");
 	(*logmsg)[0] = '\0';
 
-	fp = fopen(logmsg_path, "r");
+	fp = fopen(logmsg_path, "re");
 	if (fp == NULL) {
 		err = got_error_from_errno("fopen");
 		goto done;
@@ -1236,7 +1236,7 @@ create_gotconfig(const char *proto, const char *host, 
 		err = got_error_from_errno("got_repo_get_path_gotconfig");
 		goto done;
 	}
-	gotconfig_file = fopen(gotconfig_path, "a");
+	gotconfig_file = fopen(gotconfig_path, "ae");
 	if (gotconfig_file == NULL) {
 		err = got_error_from_errno2("fopen", gotconfig_path);
 		goto done;
@@ -1296,7 +1296,7 @@ create_gitconfig(const char *git_url, const char *defa
 		err = got_error_from_errno("got_repo_get_path_gitconfig");
 		goto done;
 	}
-	gitconfig_file = fopen(gitconfig_path, "a");
+	gitconfig_file = fopen(gitconfig_path, "ae");
 	if (gitconfig_file == NULL) {
 		err = got_error_from_errno2("fopen", gitconfig_path);
 		goto done;
@@ -4435,7 +4435,8 @@ print_diff(void *arg, unsigned char status, unsigned c
 		}
 
 		if (dirfd != -1) {
-			fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
+			fd = openat(dirfd, de_name,
+			    O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 			if (fd == -1) {
 				if (!got_err_open_nofollow_on_symlink()) { 
 					err = got_error_from_errno2("openat",
@@ -4448,7 +4449,7 @@ print_diff(void *arg, unsigned char status, unsigned c
 					goto done;
 			}
 		} else {
-			fd = open(abspath, O_RDONLY | O_NOFOLLOW);
+			fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 			if (fd == -1) {
 				if (!got_err_open_nofollow_on_symlink()) {
 					err = got_error_from_errno2("open",
@@ -7296,7 +7297,7 @@ cmd_revert(int argc, char *argv[])
 		goto done;
 
 	if (patch_script_path) {
-		patch_script_file = fopen(patch_script_path, "r");
+		patch_script_file = fopen(patch_script_path, "re");
 		if (patch_script_file == NULL) {
 			error = got_error_from_errno2("fopen",
 			    patch_script_path);
@@ -7392,7 +7393,7 @@ read_prepared_logmsg(char **logmsg, const char *path)
 	*logmsg = NULL;
 	memset(&sb, 0, sizeof(sb));
 
-	f = fopen(path, "r");
+	f = fopen(path, "re");
 	if (f == NULL)
 		return got_error_from_errno2("fopen", path);
 
@@ -9824,7 +9825,7 @@ histedit_run_editor(struct got_histedit_list *histedit
 		goto done;
 	}
 
-	f = fopen(path, "r");
+	f = fopen(path, "re");
 	if (f == NULL) {
 		err = got_error_from_errno("fopen");
 		goto done;
@@ -9910,7 +9911,7 @@ histedit_save_list(struct got_histedit_list *histedit_
 	if (err)
 		return err;
 
-	f = fopen(path, "w");
+	f = fopen(path, "we");
 	if (f == NULL) {
 		err = got_error_from_errno2("fopen", path);
 		goto done;
@@ -9957,7 +9958,7 @@ histedit_load_list(struct got_histedit_list *histedit_
 	const struct got_error *err = NULL;
 	FILE *f = NULL;
 
-	f = fopen(path, "r");
+	f = fopen(path, "re");
 	if (f == NULL) {
 		err = got_error_from_errno2("fopen", path);
 		goto done;
@@ -11241,7 +11242,7 @@ cmd_stage(int argc, char *argv[])
 		goto done;
 
 	if (patch_script_path) {
-		patch_script_file = fopen(patch_script_path, "r");
+		patch_script_file = fopen(patch_script_path, "re");
 		if (patch_script_file == NULL) {
 			error = got_error_from_errno2("fopen",
 			    patch_script_path);
@@ -11361,7 +11362,7 @@ cmd_unstage(int argc, char *argv[])
 		goto done;
 
 	if (patch_script_path) {
-		patch_script_file = fopen(patch_script_path, "r");
+		patch_script_file = fopen(patch_script_path, "re");
 		if (patch_script_file == NULL) {
 			error = got_error_from_errno2("fopen",
 			    patch_script_path);
blob - eeaf4cbd73e78bea7a719194a8223f1826901821
blob + 6363042469cbd22c9740556448d1cc20c5eafdab
--- gotweb/gotweb.c
+++ gotweb/gotweb.c
@@ -2670,7 +2670,7 @@ gw_get_repo_description(char **description, struct gw_
 	if (asprintf(&d_file, "%s/description", dir) == -1)
 		return got_error_from_errno("asprintf");
 
-	f = fopen(d_file, "r");
+	f = fopen(d_file, "re");
 	if (f == NULL) {
 		if (errno == ENOENT || errno == EACCES)
 			return NULL;
@@ -2973,7 +2973,7 @@ gw_get_clone_url(char **url, struct gw_trans *gw_trans
 	if (asprintf(&d_file, "%s/cloneurl", dir) == -1)
 		return got_error_from_errno("asprintf");
 
-	f = fopen(d_file, "r");
+	f = fopen(d_file, "re");
 	if (f == NULL) {
 		if (errno != ENOENT && errno != EACCES)
 			error = got_error_from_errno2("fopen", d_file);
blob - 1d91c1f05c748a155769cbfd96cb8871ffd0c8cc
blob + dac1eae40679c47137747bc4f1d9aa0f054e8f59
--- gotweb/parse.y
+++ gotweb/parse.y
@@ -503,7 +503,7 @@ pushfile(struct file **nfile, const char *name)
 		free(nfile);
 		return got_error_from_errno2(__func__, "strdup");
 	}
-	if (((*nfile)->stream = fopen((*nfile)->name, "r")) == NULL) {
+	if (((*nfile)->stream = fopen((*nfile)->name, "re")) == NULL) {
 		char *msg = NULL;
 		if (asprintf(&msg, "%s", (*nfile)->name) == -1)
 			return got_error_from_errno("asprintf");
blob - f17dddcabf8aa19fd01c17dec68dc1a8ec2dd748
blob + 05d16ce90ea867ddc912cd1321d68b0262228307
--- lib/buf.c
+++ lib/buf.c
@@ -280,7 +280,7 @@ buf_write(BUF *b, const char *path, mode_t mode)
 	const struct got_error *err = NULL;
 	int fd;
  open:
-	if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
+	if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, mode)) == -1) {
 		err = got_error_from_errno2("open", path);
 		if (errno == EACCES && unlink(path) != -1)
 			goto open;
blob - 95fdb0726bce1615a82c90e53763702fa49bc139
blob + ec933af31517a8e95d2772b7199c7efcb9064c82
--- lib/diff3.c
+++ lib/diff3.c
@@ -207,12 +207,12 @@ diffreg(BUF **d, const char *path1, const char *path2,
 
 	*d = NULL;
 
-	f1 = fopen(path1, "r");
+	f1 = fopen(path1, "re");
 	if (f1 == NULL) {
 		err = got_error_from_errno2("fopen", path1);
 		goto done;
 	}
-	f2 = fopen(path2, "r");
+	f2 = fopen(path2, "re");
 	if (f1 == NULL) {
 		err = got_error_from_errno2("fopen", path2);
 		goto done;
@@ -460,11 +460,11 @@ diff3_internal(char *dp13, char *dp23, char *path1, ch
 	if (err)
 		return err;
 
-	if ((d3s->fp[0] = fopen(path1, "r")) == NULL)
+	if ((d3s->fp[0] = fopen(path1, "re")) == NULL)
 		return got_error_from_errno2("fopen", path1);
-	if ((d3s->fp[1] = fopen(path2, "r")) == NULL)
+	if ((d3s->fp[1] = fopen(path2, "re")) == NULL)
 		return got_error_from_errno2("fopen", path2);
-	if ((d3s->fp[2] = fopen(path3, "r")) == NULL)
+	if ((d3s->fp[2] = fopen(path3, "re")) == NULL)
 		return got_error_from_errno2("fopen", path3);
 
 	return merge(m, n, d3s);
@@ -604,7 +604,7 @@ readin(size_t *n, char *name, struct diff **dd, struct
 
 	*n = 0;
 
-	f = fopen(name, "r");
+	f = fopen(name, "re");
 	if (f == NULL)
 		return got_error_from_errno2("fopen", name);
 	err = getchange(&p, f, d3s);
blob - 91a35e46fce2547ae0c44ba7edf82da9edd9e097
blob + 60539f2a09b85e1abbc55e1e6fb94f7210db3b14
--- lib/fileindex.c
+++ lib/fileindex.c
@@ -1059,7 +1059,7 @@ walk_dir(struct got_pathlist_entry **next, struct got_
 		}
 
 		subdirfd = openat(fd, de->d_name,
-		    O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
+		    O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
 		if (subdirfd == -1) {
 			if (errno == EACCES) {
 				*next = TAILQ_NEXT(dle, entry);
blob - 7133ec58bdbaf535f13ad65c71428d7eb891a975
blob + 664f170821f75b4356a1f141c1aebcf860ac1868
--- lib/gotconfig.c
+++ lib/gotconfig.c
@@ -51,7 +51,7 @@ got_gotconfig_read(struct got_gotconfig **conf, const 
 	if (*conf == NULL)
 		return got_error_from_errno("calloc");
 
-	fd = open(gotconfig_path, O_RDONLY);
+	fd = open(gotconfig_path, O_RDONLY | O_CLOEXEC);
 	if (fd == -1) {
 		if (errno == ENOENT)
 			return NULL;
blob - 846038c091fec21e8c028ab14a6fcdb0ea52c913
blob + e1a1870147bfefcb7e3caaaedf16d6b92e78a5c1
--- lib/lockfile.c
+++ lib/lockfile.c
@@ -55,11 +55,11 @@ got_lockfile_lock(struct got_lockfile **lf, const char
 	do {
 		if (dir_fd != -1) {
 			(*lf)->fd = openat(dir_fd, (*lf)->path,
-			    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK,
+			    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK | O_CLOEXEC,
 			    GOT_DEFAULT_FILE_MODE);
 		} else {
 			(*lf)->fd = open((*lf)->path,
-			    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK,
+			    O_RDONLY | O_CREAT | O_EXCL | O_EXLOCK | O_CLOEXEC,
 			    GOT_DEFAULT_FILE_MODE);
 		}
 		if ((*lf)->fd != -1)
blob - 5cfc0aee3892c25a4378b608302c31ca629fcabd
blob + a4cf395476aee75f57a0281a2184b91a09e360e3
--- lib/object.c
+++ lib/object.c
@@ -136,7 +136,7 @@ got_object_open_loose_fd(int *fd, struct got_object_id
 	err = got_object_get_path(&path, id, repo);
 	if (err)
 		return err;
-	*fd = open(path, O_RDONLY | O_NOFOLLOW);
+	*fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 	if (*fd == -1) {
 		err = got_error_from_errno2("open", path);
 		goto done;
blob - 1092bb03e5e276167684b61088c369b208953167
blob + 687f6f051b8fd962cbc58e0415b5cd3d2d385fcf
--- lib/object_create.c
+++ lib/object_create.c
@@ -127,7 +127,7 @@ got_object_blob_file_create(struct got_object_id **id,
 
 	SHA1Init(&sha1_ctx);
 
-	fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW);
+	fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 	if (fd == -1) {
 		if (!got_err_open_nofollow_on_symlink())
 			return got_error_from_errno2("open", ondisk_path);
blob - b29f6d25ce45802ebffcccce90ca9975efdbf260
blob + cda2a94c06d5421f629332f0997eca5ce2c66c5c
--- lib/pack.c
+++ lib/pack.c
@@ -368,7 +368,7 @@ got_packidx_open(struct got_packidx **packidx,
 		goto done;
 	}
 
-	p->fd = openat(dir_fd, relpath, O_RDONLY | O_NOFOLLOW);
+	p->fd = openat(dir_fd, relpath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 	if (p->fd == -1) {
 		err = got_error_from_errno2("openat", relpath);
 		free(p);
blob - d94d085c6a81b1232aacfe54421d5ffa740b8393
blob + a00402e5edffaefb92ba18770b49fc07c8826c58
--- lib/path.c
+++ lib/path.c
@@ -500,7 +500,7 @@ got_path_create_file(const char *path, const char *con
 	const struct got_error *err = NULL;
 	int fd = -1;
 
-	fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW,
+	fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
 	    GOT_DEFAULT_FILE_MODE);
 	if (fd == -1) {
 		err = got_error_from_errno2("open", path);
blob - eff4b9a3e9d57466366fd04d73b1eeb8d92bd371
blob + b7336cfa9779d26b5bc510b4bb45c1f5f64df5c1
--- lib/reference.c
+++ lib/reference.c
@@ -189,7 +189,7 @@ parse_ref_file(struct got_reference **ref, const char 
 		}
 	}
 
-	f = fopen(abspath, "rb");
+	f = fopen(abspath, "rbe");
 	if (f == NULL) {
 		if (errno != ENOTDIR && errno != ENOENT)
 			err = got_error_from_errno2("fopen", abspath);
@@ -495,7 +495,7 @@ got_ref_open(struct got_reference **ref, struct got_re
 			if (err)
 				goto done;
 		}
-		f = fopen(packed_refs_path, "rb");
+		f = fopen(packed_refs_path, "rbe");
 		free(packed_refs_path);
 		if (f != NULL) {
 			struct stat sb;
@@ -1088,7 +1088,7 @@ got_ref_list(struct got_reflist_head *refs, struct got
 		goto done;
 	}
 
-	f = fopen(packed_refs_path, "r");
+	f = fopen(packed_refs_path, "re");
 	free(packed_refs_path);
 	if (f) {
 		size_t linesize = 0;
@@ -1342,7 +1342,7 @@ delete_packed_ref(struct got_reference *delref, struct
 			goto done;
 	}
 
-	f = fopen(packed_refs_path, "r");
+	f = fopen(packed_refs_path, "re");
 	if (f == NULL) {
 		err = got_error_from_errno2("fopen", packed_refs_path);
 		goto done;
blob - 3c4b83d77f6d8a35b74a2aeaffe36f60f8f0a7c3
blob + 41da7b15ca61d79a06862f1f0a9534002c2cdfca
--- lib/repository.c
+++ lib/repository.c
@@ -391,7 +391,8 @@ open_repo(struct got_repository *repo, const char *pat
 			err = got_error_from_errno("strdup");
 			goto done;
 		}
-		repo->gitdir_fd = open(repo->path_git_dir, O_DIRECTORY);
+		repo->gitdir_fd = open(repo->path_git_dir,
+		    O_DIRECTORY | O_CLOEXEC);
 		if (repo->gitdir_fd == -1) {
 			err = got_error_from_errno2("open",
 			    repo->path_git_dir);
@@ -413,7 +414,8 @@ open_repo(struct got_repository *repo, const char *pat
 			err = got_error_from_errno("strdup");
 			goto done;
 		}
-		repo->gitdir_fd = open(repo->path_git_dir, O_DIRECTORY);
+		repo->gitdir_fd = open(repo->path_git_dir,
+		    O_DIRECTORY | O_CLOEXEC);
 		if (repo->gitdir_fd == -1) {
 			err = got_error_from_errno2("open",
 			    repo->path_git_dir);
@@ -464,7 +466,7 @@ parse_gitconfig_file(int *gitconfig_repository_format_
 	if (gitconfig_owner)
 		*gitconfig_owner = NULL;
 
-	fd = open(gitconfig_path, O_RDONLY);
+	fd = open(gitconfig_path, O_RDONLY | O_CLOEXEC);
 	if (fd == -1) {
 		if (errno == ENOENT)
 			return NULL;
@@ -1123,7 +1125,7 @@ got_repo_search_packidx(struct got_packidx **packidx, 
 	/* No luck. Search the filesystem. */
 
 	packdir_fd = openat(got_repo_get_fd(repo),
-	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY);
+	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY | O_CLOEXEC);
 	if (packdir_fd == -1) {
 		if (errno == ENOENT)
 			err = got_error_no_obj(id);
@@ -1231,7 +1233,8 @@ open_packfile(int *fd, struct got_repository *repo,
 {
 	const struct got_error *err = NULL;
 
-	*fd = openat(got_repo_get_fd(repo), relpath, O_RDONLY | O_NOFOLLOW);
+	*fd = openat(got_repo_get_fd(repo), relpath,
+	    O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 	if (*fd == -1)
 		return got_error_from_errno_fmt("openat: %s/%s",
 		    got_repo_get_path_git_dir(repo), relpath);
@@ -1405,7 +1408,7 @@ match_packed_object(struct got_object_id **unique_id,
 	STAILQ_INIT(&matched_ids);
 
 	packdir_fd = openat(got_repo_get_fd(repo),
-	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY);
+	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY | O_CLOEXEC);
 	if (packdir_fd == -1) {
 		if (errno != ENOENT)
 			err = got_error_from_errno2("openat", GOT_OBJECTS_PACK_DIR);
blob - d7d0ab9f80f5bc272b6a81a901c3647364c3e962
blob + 4e1253bcafe34044a40c52250b6a96a552b4b609
--- lib/repository_admin.c
+++ lib/repository_admin.c
@@ -483,7 +483,7 @@ got_repo_find_pack(FILE **packfile, struct got_object_
 		goto done;
 	}
 
-	packfd = open(packfile_path, O_RDONLY | O_NOFOLLOW);
+	packfd = open(packfile_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 	if (packfd == -1) {
 		err = got_error_from_errno2("open", packfile_path);
 		goto done;
@@ -1215,7 +1215,7 @@ got_repo_remove_lonely_packidx(struct got_repository *
 	struct stat sb;
 
 	packdir_fd = openat(got_repo_get_fd(repo),
-	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY);
+	    GOT_OBJECTS_PACK_DIR, O_DIRECTORY | O_CLOEXEC);
 	if (packdir_fd == -1) {
 		if (errno == ENOENT)
 			return NULL;
blob - 08a1d596cc47c30cfb0e5dd2c6118178530bdd72
blob + 87959af131f11571b21d37fe9087acd551dd9250
--- lib/worktree.c
+++ lib/worktree.c
@@ -1044,7 +1044,7 @@ merge_blob(int *local_changes_subsumed, struct got_wor
 			goto done;
 	} else {
 		int fd;
-		fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW);
+		fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 		if (fd == -1) {
 			err = got_error_from_errno2("open", ondisk_path);
 			goto done;
@@ -1159,7 +1159,7 @@ replace_existing_symlink(int *did_something, const cha
 	 * caller. If we can successfully open a regular file then we simply
 	 * replace this file with a symlink below.
 	 */
-	fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW);
+	fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW | O_CLOEXEC);
 	if (fd == -1) {
 		if (!got_err_open_nofollow_on_symlink())
 			return got_error_from_errno2("open", ondisk_path);
@@ -1389,8 +1389,8 @@ install_blob(struct got_worktree *worktree, const char
 	int update = 0;
 	char *tmppath = NULL;
 
-	fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW,
-	    GOT_DEFAULT_FILE_MODE);
+	fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW |
+	    O_CLOEXEC, GOT_DEFAULT_FILE_MODE);
 	if (fd == -1) {
 		if (errno == ENOENT) {
 			char *parent;
@@ -1402,7 +1402,7 @@ install_blob(struct got_worktree *worktree, const char
 			if (err)
 				return err;
 			fd = open(ondisk_path,
-			    O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW,
+			    O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
 			    GOT_DEFAULT_FILE_MODE);
 			if (fd == -1)
 				return got_error_from_errno2("open",
@@ -1657,7 +1657,7 @@ get_file_status(unsigned char *status, struct stat *sb
 			goto done;
 		}
 	} else {
-		fd = open(abspath, O_RDONLY | O_NOFOLLOW);
+		fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 		if (fd == -1 && errno != ENOENT &&
 		    !got_err_open_nofollow_on_symlink())
 			return got_error_from_errno2("open", abspath);
@@ -1717,7 +1717,7 @@ get_file_status(unsigned char *status, struct stat *sb
 	}
 
 	if (dirfd != -1) {
-		fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
+		fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 		if (fd == -1) {
 			err = got_error_from_errno2("openat", abspath);
 			goto done;
@@ -2342,7 +2342,7 @@ open_fileindex(struct got_fileindex **fileindex, char 
 	if (err)
 		goto done;
 
-	index = fopen(*fileindex_path, "rb");
+	index = fopen(*fileindex_path, "rbe");
 	if (index == NULL) {
 		if (errno != ENOENT)
 			err = got_error_from_errno2("fopen", *fileindex_path);
@@ -2816,7 +2816,7 @@ merge_file_cb(void *arg, struct got_blob_object *blob1
 			if (err)
 				goto done;
 
-			fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW);
+			fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 			if (fd == -1) {
 				err = got_error_from_errno2("open",
 				    ondisk_path);
@@ -3460,7 +3460,8 @@ add_ignores(struct got_pathlist_head *ignores, const c
 		return got_error_from_errno("asprintf");
 
 	if (dirfd != -1) {
-		fd = openat(dirfd, ignores_filename, O_RDONLY | O_NOFOLLOW);
+		fd = openat(dirfd, ignores_filename,
+		    O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 		if (fd == -1) {
 			if (errno != ENOENT && errno != EACCES)
 				err = got_error_from_errno2("openat",
@@ -3476,7 +3477,7 @@ add_ignores(struct got_pathlist_head *ignores, const c
 			}
 		}
 	} else {
-		ignoresfile = fopen(ignorespath, "r");
+		ignoresfile = fopen(ignorespath, "re");
 		if (ignoresfile == NULL) {
 			if (errno != ENOENT && errno != EACCES)
 				err = got_error_from_errno2("fopen",
@@ -3649,7 +3650,7 @@ worktree_status(struct got_worktree *worktree, const c
 	    worktree->root_path, path[0] ? "/" : "", path) == -1)
 		return got_error_from_errno("asprintf");
 
-	fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
+	fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
 	if (fd == -1) {
 		if (errno != ENOTDIR && errno != ENOENT && errno != EACCES &&
 		    !got_err_open_nofollow_on_symlink())
@@ -4356,7 +4357,8 @@ create_patched_content(char **path_outfile, int revers
 		return err;
 
 	if (dirfd2 != -1) {
-		fd2 = openat(dirfd2, de_name2, O_RDONLY | O_NOFOLLOW);
+		fd2 = openat(dirfd2, de_name2,
+		    O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 		if (fd2 == -1) {
 			if (!got_err_open_nofollow_on_symlink()) {
 				err = got_error_from_errno2("openat", path2);
@@ -4370,7 +4372,7 @@ create_patched_content(char **path_outfile, int revers
 			sb2.st_size = link_len;
 		}
 	} else {
-		fd2 = open(path2, O_RDONLY | O_NOFOLLOW);
+		fd2 = open(path2, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 		if (fd2 == -1) {
 			if (!got_err_open_nofollow_on_symlink()) {
 				err = got_error_from_errno2("open", path2);
@@ -8286,7 +8288,7 @@ unstage_hunks(struct got_object_id *staged_blob_id,
 			goto done;
 	}
 
-	f = fopen(path_unstaged_content, "r");
+	f = fopen(path_unstaged_content, "re");
 	if (f == NULL) {
 		err = got_error_from_errno2("fopen",
 		    path_unstaged_content);
@@ -8347,7 +8349,8 @@ unstage_hunks(struct got_object_id *staged_blob_id,
 				goto done;
 		} else {
 			int fd;
-			fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW);
+			fd = open(ondisk_path,
+			    O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 			if (fd == -1) {
 				err = got_error_from_errno2("open", ondisk_path);
 				goto done;
blob - 4a589cf5ece62d780a9e4fac1215b2df6a5ea5cc
blob + 965700c2ad7edf85000a045f92b3727fc9ebc460
--- lib/worktree_open.c
+++ lib/worktree_open.c
@@ -56,7 +56,7 @@ read_meta_file(char **content, const char *path_got, c
 		goto done;
 	}
 
-	fd = open(path, O_RDONLY | O_NOFOLLOW);
+	fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
 	if (fd == -1) {
 		if (errno == ENOENT)
 			err = got_error_path(path, GOT_ERR_WORKTREE_META);
@@ -131,7 +131,7 @@ open_worktree(struct got_worktree **worktree, const ch
 		goto done;
 	}
 
-	fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK);
+	fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK | O_CLOEXEC);
 	if (fd == -1) {
 		err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY)
 		    : got_error_from_errno2("open", path_lock));
@@ -213,7 +213,8 @@ open_worktree(struct got_worktree **worktree, const ch
 	err = got_gotconfig_read(&(*worktree)->gotconfig,
 	    (*worktree)->gotconfig_path);
 
-	(*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY);
+	(*worktree)->root_fd = open((*worktree)->root_path,
+	    O_DIRECTORY | O_CLOEXEC);
 	if ((*worktree)->root_fd == -1) {
 		err = got_error_from_errno2("open", (*worktree)->root_path);
 		goto done;