Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
tempfile: improve the filename creation to reduce ENAMETOOLONG risks
Baptiste Daroussin committed 4 years ago
commit ce75303c613f2f5d04fdd7c9edd6f4cd40eb9dac
parent ed16961
5 files changed +152 -54
modified libpkg/pkg_add.c
@@ -63,54 +63,6 @@ typedef tll(struct store_hardlinks *) hls;
#define NOCHANGESFLAGS	(UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
#endif

-
static const unsigned char litchar[] =
-
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-

-
static void
-
pkg_add_file_random_suffix(char *buf, int buflen, int suflen)
-
{
-
	int nchars = strlen(buf);
-
	char *pos;
-
	int r;
-

-
	if (nchars + suflen > buflen - 1) {
-
		suflen = buflen - nchars - 1;
-
		if (suflen <= 0)
-
			return;
-
	}
-

-
	buf[nchars++] = '.';
-
	pos = buf + nchars;
-

-
	while(suflen --) {
-
#ifndef HAVE_ARC4RANDOM
-
		r = rand() % (sizeof(litchar) - 1);
-
#else
-
		r = arc4random_uniform(sizeof(litchar) - 1);
-
#endif
-
		*pos++ = litchar[r];
-
	}
-

-
	*pos = '\0';
-
}
-

-
static void
-
pkg_hidden_tempfile(char *buf, int buflen, const char *path)
-
{
-
	const char *fname;
-

-
	fname = strrchr(path, '/');
-
	if (fname != NULL)
-
		fname++;
-

-
	if (fname != NULL)
-
		snprintf(buf, buflen, "%.*s.pkgtemp.%s", (int)(fname - path), path, fname);
-
	else
-
		snprintf(buf, buflen, ".pkgtemp.%s", path);
-

-
	pkg_add_file_random_suffix(buf, buflen, 12);
-
}
-

static void
attempt_to_merge(int rootfd, struct pkg_config_file *rcf, struct pkg *local,
    bool merge)
@@ -436,7 +388,7 @@ create_symlinks(struct pkg *pkg, struct pkg_file *f, const char *target)
{
	bool tried_mkdir = false;

-
	pkg_hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
+
	hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
retry:
	if (symlinkat(target, pkg->rootfd, RELATIVE_PATH(f->temppath)) == -1) {
		if (!tried_mkdir) {
@@ -495,7 +447,7 @@ create_hardlink(struct pkg *pkg, struct pkg_file *f, const char *path)
	bool tried_mkdir = false;
	struct pkg_file *fh;

-
	pkg_hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
+
	hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
	fh = pkg_get_file(pkg, path);
	if (fh == NULL) {
		pkg_emit_error("Can't find the file %s is supposed to be"
@@ -555,7 +507,7 @@ create_regfile(struct pkg *pkg, struct pkg_file *f, struct archive *a,
	size_t len;
	char buf[32768];

-
	pkg_hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
+
	hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);

retry:
	/* Create the new temp file */
modified libpkg/private/utils.h
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2014 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * All rights reserved.
 * 
@@ -114,5 +114,7 @@ bool match_ucl_lists(const char *buffer, const ucl_object_t *globs, const ucl_ob
char *get_dirname(char *dir);
char *rtrimspace(char *buf);
bool copy_file(int from, int to);
+
void hidden_tempfile(char *buf, int buflen, const char *path);
+
void append_random_suffix(char *buf, int buflen, int suffixlen);

#endif
modified libpkg/utils.c
@@ -917,3 +917,71 @@ copy_file(int from, int to)

	return (r >= 0);
}
+

+
static const unsigned char litchar[] =
+
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+

+
void
+
append_random_suffix(char *buf, int buflen, int suflen)
+
{
+
	int nchars = strlen(buf);
+
	char *pos;
+
	int r;
+

+
	if (nchars + suflen > buflen - 1) {
+
		suflen = buflen - nchars - 1;
+
		if (suflen <= 0)
+
			return;
+
	}
+

+
	buf[nchars++] = '.';
+
	pos = buf + nchars;
+

+
	while(suflen --) {
+
#ifndef HAVE_ARC4RANDOM
+
		r = rand() % (sizeof(litchar) - 1);
+
#else
+
		r = arc4random_uniform(sizeof(litchar) - 1);
+
#endif
+
		*pos++ = litchar[r];
+
	}
+

+
	*pos = '\0';
+
}
+

+
void
+
hidden_tempfile(char *buf, int buflen, const char *path)
+
{
+
	const char *fname;
+
	int suffixlen = 12;
+
	int nbuflen;
+
	const char *prefix = ".pkgtemp.";
+

+
	fname = strrchr(path, '/');
+
	if (fname != NULL)
+
		fname++;
+

+
	/* 
+
	 * try to reduce the temporary name as much as possible to fit with very
+
	 * long file names if possible. by default
+
	 * .pkgtemp. fname . <suffix>
+
	 * otherwise
+
	 * . fname . <suffix>
+
	 * keep if suffix of at least 5 if possible
+
	 */
+
	if (fname != NULL) {
+
		if (strlen(fname) > (NAME_MAX - 15))
+
			prefix = ".";
+
		snprintf(buf, buflen, "%.*s%s%s", (int)(fname - path), path, prefix, fname);
+
		nbuflen = buflen;
+
	} else {
+
		if (strlen(path) > NAME_MAX - 15)
+
			prefix = ".";
+
		snprintf(buf, buflen, "%s%s", prefix, path);
+
		nbuflen = NAME_MAX;
+
	}
+

+

+
	append_random_suffix(buf, nbuflen, suffixlen);
+
}
+

modified tests/Makefile.autosetup
@@ -10,7 +10,8 @@ TESTS= \
	pkg_validation \
	plist \
	lua \
-
	ssh
+
	ssh \
+
	utils

TESTS_SH= \
	frontend/pkg.sh \
@@ -73,6 +74,7 @@ pkg_add_dir_to_del_OBJS= lib/pkg_add_dir_to_del.o
pkg_validation_OBJS=	lib/pkg_validation.o
packing_OBJS=	lib/packing.o
ssh_OBJS=	lib/ssh.o
+
utils_OBJS=	lib/utils.o

SRCS=	\
	$(packing_OBJS:.o=.c) \
@@ -84,7 +86,8 @@ SRCS= \
	$(deps_formula_OBJS:.o=.c) \
	$(pkg_add_dir_to_del_OBJS:.o=.c) \
	$(pkg_validation_OBJS:.o=.c) \
-
	$(ssh_OBJS:.o=.c)
+
	$(ssh_OBJS:.o=.c) \
+
	$(utils_OBJS:.o=.c)

include $(MK)/common.mk

added tests/lib/utils.c
@@ -0,0 +1,73 @@
+
/*-
+
 * Copyright (c) 2022 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *~
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions
+
 * are met:
+
 * 1. Redistributions of source code must retain the above copyright
+
 *    notice, this list of conditions and the following disclaimer
+
 *    in this position and unchanged.
+
 * 2. Redistributions in binary form must reproduce the above copyright
+
 *    notice, this list of conditions and the following disclaimer in the
+
 *    documentation and/or other materials provided with the distribution.
+
 *~
+
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include <atf-c.h>
+
#include <err.h>
+
#include <private/utils.h>
+

+
ATF_TC(hidden_tempfile);
+
ATF_TC(random_suffix);
+

+
ATF_TC_HEAD(hidden_tempfile, tc) {}
+
ATF_TC_HEAD(random_suffix, tc) {}
+

+
ATF_TC_BODY(hidden_tempfile, tc) {
+
	const char *filename = "plop";
+
	const char *longfile = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif";
+
	const char *pathfn = "/tmp/plop";
+
	const char *pathlongfn = "/tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif";
+
	char buf[MAXPATHLEN];
+

+
	hidden_tempfile(buf, MAXPATHLEN, filename);
+
	ATF_REQUIRE_EQ_MSG(strncmp(buf, ".pkgtemp.plop.", 14), 0, "bad filename '%s'", buf);
+
	hidden_tempfile(buf, MAXPATHLEN, longfile);
+
	ATF_REQUIRE_EQ_MSG(strncmp(buf, ".AAA", 4), 0, "bad filename '%s'", buf);
+

+
	hidden_tempfile(buf, MAXPATHLEN, pathfn);
+
	ATF_REQUIRE_EQ_MSG(strncmp(buf, "/tmp/.pkgtemp.plop.", 19), 0, "bad filename '%s'", buf);
+

+
	hidden_tempfile(buf, MAXPATHLEN, pathlongfn);
+
	ATF_REQUIRE_EQ_MSG(strncmp(buf, "/tmp/.AAA", 9), 0, "bad filename '%s'", buf);
+

+

+
}
+
ATF_TC_BODY(random_suffix, tc) {
+
	char buf[14];
+

+
	buf[0] = '\0';
+
	append_random_suffix(buf, sizeof(buf), 12);
+
	ATF_REQUIRE_EQ_MSG(strlen(buf), 13, "suffix not long enough %lu", strlen(buf));
+
	snprintf(buf, sizeof(buf), "filename");
+
	append_random_suffix(buf, sizeof(buf), 12);
+
	ATF_REQUIRE_EQ_MSG(strlen(buf), 14, "suffix not long enough %lu", strlen(buf));
+
}
+

+
ATF_TP_ADD_TCS(tp)
+
{
+
	ATF_TP_ADD_TC(tp, hidden_tempfile);
+
	ATF_TP_ADD_TC(tp, random_suffix);
+

+
	return (atf_no_error());
+
}