Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
New lua validation script for Keywords
Baptiste Daroussin committed 5 years ago
commit ebeeab11e672e04afb3d62d5aecb9ec5f18f8857
parent 9caf48c
4 files changed +166 -1
modified libpkg/lua.c
@@ -325,6 +325,20 @@ lua_stat(lua_State *L)
	return (1);
}

+
/* stolen from lua.c */
+
void
+
lua_args_table(lua_State *L, char **argv, int argc)
+
{
+
	lua_createtable(L, argc, 1);
+
	for (int i = 0; i < argc; i++) {
+
		lua_pushstring(L, argv[i]);
+
		/* lua starts counting by 1 */
+
		lua_rawseti(L, -2, i + 1);
+
	}
+
	lua_setglobal(L, "arg");
+
}
+

+

/*
 * this is a copy of lua code to be able to override open
 * merge of newprefile and newfile
modified libpkg/pkg_ports.c
@@ -26,7 +26,15 @@
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

+
#include "pkg_config.h"
+

+
#ifdef HAVE_CAPSICUM
+
#include <sys/capsicum.h>
+
#endif
+

#include <sys/stat.h>
+
#include <sys/types.h>
+
#include <sys/wait.h>

#include <assert.h>
#include <ctype.h>
@@ -39,11 +47,13 @@
#include <fcntl.h>
#include <unistd.h>
#include <uthash.h>
+
#include <err.h>

#include "pkg.h"
#include "private/utils.h"
#include "private/event.h"
#include "private/pkg.h"
+
#include "private/lua.h"

static ucl_object_t *keyword_schema = NULL;

@@ -884,6 +894,7 @@ apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, struct file_a
	struct file_attr *freeattr = NULL;
	int spaces, argc = 0;
	int ret = EPKG_FATAL;
+
	int pstat;

	if ((o = ucl_object_find_key(obj,  "arguments")) && ucl_object_toboolean(o)) {
		spaces = pkg_utils_count_spaces(line);
@@ -894,6 +905,52 @@ apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, struct file_a
		}
	}

+
	if ((o = ucl_object_find_key(obj, "validation"))) {
+
		pid_t pid = fork();
+
		if (pid == 0) {
+
			lua_State *L = luaL_newstate();
+
			luaL_openlibs(L);
+
			lua_pushlightuserdata(L, p->pkg);
+
			lua_setglobal(L, "package");
+
			lua_pushstring(L, line);
+
			lua_setglobal(L, "line");
+
			lua_args_table(L, args, argc);
+
			lua_override_ios(L);
+
#ifdef HAVE_CAPSICUM
+
			if (cap_enter() < 0 && errno != ENOSYS) {
+
				err(1, "cap_enter failed");
+
			}
+
#endif
+
			pkg_debug(3, "Scripts: executing lua\n--- BEGIN ---"
+
			    "\n%s\nScripts: --- END ---", ucl_object_tostring(o));
+
			if (luaL_dostring(L, ucl_object_tostring(o))) {
+
				pkg_emit_error("Failed to execute lua script: "
+
				    "%s", lua_tostring(L, -1));
+
				lua_close(L);
+
				exit(1);
+
			}
+

+
			lua_close(L);
+
			exit(0);
+
		} else if (pid < 0) {
+
			pkg_emit_errno("Cannot fork", "lua validation script");
+
			ret = EPKG_FATAL;
+
			goto keywords_cleanup;
+
		}
+
		while (waitpid(pid, &pstat, 0) == -1) {
+
			if (errno != EINTR) {
+
				pkg_emit_error("waitpid() failed: %s",
+
				    strerror(errno));
+
			}
+
		}
+
		if (WEXITSTATUS(pstat) != 0) {
+
			pkg_emit_error("lua validation script failed for '%s'",
+
			    line);
+
			ret = EPKG_FATAL;
+
			goto keywords_cleanup;
+
		}
+
	}
+

	if ((o = ucl_object_find_key(obj,  "attributes")))
		parse_attributes(o, attr != NULL ? &attr : &freeattr);

modified libpkg/private/lua.h
@@ -34,3 +34,4 @@ int lua_pkg_filecmp(lua_State *L);
int lua_prefix_path(lua_State *L);
void lua_override_ios(lua_State *L);
int lua_stat(lua_State *L);
+
void lua_args_table(lua_State *L, char **argv, int argc);
modified tests/frontend/create.sh
@@ -20,7 +20,8 @@ tests_init \
	create_from_plist_include \
	create_with_hardlink \
	create_no_clobber \
-
	time
+
	time \
+
	create_from_plist_keyword_validation \

genmanifest() {
	cat << EOF >> +MANIFEST
@@ -244,6 +245,98 @@ create_from_plist_bad_fflags_body() {
		pkg create -o ${TMPDIR} -m . -p test.plist -r .
}

+
create_from_plist_keyword_validation_body()
+
{
+
	preparetestcredentials "test"
+

+
cat << EOF > test.ucl
+
actions: []
+
validation: <<EOS
+
io.stderr:write("meh\n")
+
os.exit(1)
+
EOS
+
EOF
+
	atf_check \
+
		-o empty \
+
		-e inline:"meh\n${PROGNAME}: lua validation script failed for 'file1'\n" \
+
		-s exit:1 \
+
		pkg -o PLIST_KEYWORDS_DIR=. create -o ${TMPDIR} -m . -p test.plist -r .
+

+
cat << EOF > test.ucl
+
actions: []
+
validation: <<EOS
+
print(line)
+
io.stderr:write("meh\n")
+
os.exit(1)
+
EOS
+
EOF
+
	atf_check \
+
		-o inline:"file1\n" \
+
		-e inline:"meh\n${PROGNAME}: lua validation script failed for 'file1'\n" \
+
		-s exit:1 \
+
		pkg -o PLIST_KEYWORDS_DIR=. create -o ${TMPDIR} -m . -p test.plist -r .
+

+
cat << EOF > test.ucl
+
actions: []
+
validation: <<EOS
+
print(#arg)
+
io.stderr:write("meh\n")
+
os.exit(1)
+
EOS
+
EOF
+
	atf_check \
+
		-o inline:"0\n" \
+
		-e inline:"meh\n${PROGNAME}: lua validation script failed for 'file1'\n" \
+
		-s exit:1 \
+
		pkg -o PLIST_KEYWORDS_DIR=. create -o ${TMPDIR} -m . -p test.plist -r .
+

+
cat << EOF > test.ucl
+
actions: []
+
arguments: true
+
validation: <<EOS
+
print(#arg)
+
io.stderr:write("meh\n")
+
os.exit(1)
+
EOS
+
EOF
+
	atf_check \
+
		-o inline:"1\n" \
+
		-e inline:"meh\n${PROGNAME}: lua validation script failed for 'file1'\n" \
+
		-s exit:1 \
+
		pkg -o PLIST_KEYWORDS_DIR=. create -o ${TMPDIR} -m . -p test.plist -r .
+

+
	genplist "@test A B"
+
	genplist "@test A A"
+
	genplist "@test A B C"
+
cat << EOF > test.ucl
+
actions: []
+
arguments: true
+
validation: <<EOS
+
if #arg == 1 then
+
   os.exit(0)
+
end
+
if #arg == 2 then
+
  if arg[1] == arg[2] then
+
    io.stderr:write("The first and the second argument are identical\n")
+
    os.exit(1)
+
  end
+
  os.exit(0)
+
end
+
io.stderr:write("Invalid number of arguments '".. #arg .. "' expecting 1 or 2\n")
+
os.exit(1)
+
EOS
+
EOF
+
output="The first and the second argument are identical
+
${PROGNAME}: lua validation script failed for 'A A'
+
Invalid number of arguments '3' expecting 1 or 2
+
${PROGNAME}: lua validation script failed for 'A B C'
+
"
+
	atf_check \
+
		-e inline:"${output}" \
+
		-s exit:1 \
+
		pkg -o PLIST_KEYWORDS_DIR=. create -o ${TMPDIR} -m . -p test.plist -r .
+
}
+

create_from_plist_with_keyword_arguments_body() {
	preparetestcredentials "testkeyword"