Approved, oprócz użycie RESTORE_ERRNO() do ustawiania errno.

Change the nvlist_recv() function to take additional argument that
specifies flags expected on the received nvlist. Receiving a nvlist with
different set of flags than the ones we expect might lead to undefined
behaviour, which might be potentially dangerous.

Update consumers of this and related functions and update the tests.

Approved by:	pjd (mentor)

Update man page for nvlist_unpack, nvlist_recv, nvlist_xfer, cap_recv_nvlist
and cap_xfer_nvlist.

Reviewed by:	AllanJude
Approved by:	pjd (mentor)
This commit is contained in:
Mariusz Zaborski 2015-05-02 17:45:52 +00:00
parent 1025d8e679
commit bd1da0a002
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=282346
19 changed files with 109 additions and 54 deletions

View File

@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 14, 2014
.Dd May 2, 2015
.Dt LIBCAPSICUM 3
.Os
.Sh NAME
@ -68,9 +68,9 @@
.Ft "int"
.Fn cap_send_nvlist "const cap_channel_t *chan" "const nvlist_t *nvl"
.Ft "nvlist_t *"
.Fn cap_recv_nvlist "const cap_channel_t *chan"
.Fn cap_recv_nvlist "const cap_channel_t *chan" "int flags"
.Ft "nvlist_t *"
.Fn cap_xfer_nvlist "const cap_channel_t *chan" "nvlist_t *nvl"
.Fn cap_xfer_nvlist "const cap_channel_t *chan" "nvlist_t *nvl" "int flags"
.In libcapsicum_service.h
.Ft "cap_channel_t *"
.Fn cap_service_open "const cap_channel_t *chan" "const char *name"
@ -171,11 +171,23 @@ Most services should provide higher level API.
The
.Fn cap_recv_nvlist
function receives the given nvlist over the given capability.
The
.Fa flags
argument defines what type the top nvlist is expected to be.
If the nvlist flags do not match the flags passed to
.Fn cap_recv_nvlist ,
the nvlist will not be returned.
.Pp
The
.Fn cap_xfer_nvlist
function sends the given nvlist, destroys it and receives new nvlist in
response over the given capability.
The
.Fa flags
argument defines what type the top nvlist is expected to be.
If the nvlist flags do not match the flags passed to
.Fn cap_xfer_nvlist ,
the nvlist will not be returned.
It does not matter if the function succeeds or fails, the nvlist given
for sending will always be destroyed once the function returns.
.Pp

View File

@ -142,7 +142,7 @@ cap_clone(const cap_channel_t *chan)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "clone");
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (NULL);
if (nvlist_get_number(nvl, "error") != 0) {
@ -195,7 +195,7 @@ cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
nvlmsg = nvlist_create(0);
nvlist_add_string(nvlmsg, "cmd", "limit_set");
nvlist_add_nvlist(nvlmsg, "limits", limits);
nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
if (nvlmsg == NULL) {
nvlist_destroy(limits);
return (-1);
@ -218,7 +218,7 @@ cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
nvlmsg = nvlist_create(0);
nvlist_add_string(nvlmsg, "cmd", "limit_get");
nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
if (nvlmsg == NULL)
return (-1);
error = (int)nvlist_get_number(nvlmsg, "error");
@ -246,21 +246,21 @@ cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
}
nvlist_t *
cap_recv_nvlist(const cap_channel_t *chan)
cap_recv_nvlist(const cap_channel_t *chan, int flags)
{
assert(chan != NULL);
assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
return (nvlist_recv(chan->cch_sock));
return (nvlist_recv(chan->cch_sock, flags));
}
nvlist_t *
cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl)
cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
{
assert(chan != NULL);
assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
return (nvlist_xfer(chan->cch_sock, nvl));
return (nvlist_xfer(chan->cch_sock, nvl, flags));
}

View File

@ -105,11 +105,11 @@ int cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl);
/*
* Function receives nvlist over the given capability.
*/
nvlist_t *cap_recv_nvlist(const cap_channel_t *chan);
nvlist_t *cap_recv_nvlist(const cap_channel_t *chan, int flags);
/*
* Function sends the given nvlist, destroys it and receives new nvlist in
* response over the given capability.
*/
nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl);
nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags);
#endif /* !_LIBCAPSICUM_H_ */

View File

@ -132,7 +132,7 @@ cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
nvlist_add_string(nvl, "cmd", "gethostbyname");
nvlist_add_number(nvl, "family", (uint64_t)type);
nvlist_add_string(nvl, "name", name);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
@ -159,7 +159,7 @@ cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
nvlist_add_string(nvl, "cmd", "gethostbyaddr");
nvlist_add_binary(nvl, "addr", addr, (size_t)len);
nvlist_add_number(nvl, "family", (uint64_t)type);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
@ -233,7 +233,7 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
nvlist_add_number(nvl, "hints.ai_protocol",
(uint64_t)hints->ai_protocol);
}
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
@ -283,7 +283,7 @@ cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
nvlist_add_number(nvl, "flags", (uint64_t)flags);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {

View File

@ -195,7 +195,7 @@ cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name,
} else {
abort();
}
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
assert(errno != 0);
*result = NULL;
@ -319,7 +319,7 @@ cap_setgroupent(cap_channel_t *chan, int stayopen)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setgroupent");
nvlist_add_bool(nvl, "stayopen", stayopen != 0);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
@ -339,7 +339,7 @@ cap_setgrent(cap_channel_t *chan)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setgrent");
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
@ -360,7 +360,7 @@ cap_endgrent(cap_channel_t *chan)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "endgrent");
/* Ignore any errors, we have no way to report them. */
nvlist_destroy(cap_xfer_nvlist(chan, nvl));
nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
}
int

View File

@ -154,7 +154,7 @@ cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
} else {
abort();
}
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
assert(errno != 0);
*result = NULL;
@ -278,7 +278,7 @@ cap_setpassent(cap_channel_t *chan, int stayopen)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setpassent");
nvlist_add_bool(nvl, "stayopen", stayopen != 0);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
@ -299,7 +299,7 @@ cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", cmd);
/* Ignore any errors, we have no way to report them. */
nvlist_destroy(cap_xfer_nvlist(chan, nvl));
nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
}
void

View File

@ -57,7 +57,7 @@ cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes)
nvlist_add_string(nvl, "cmd", "generate");
nvlist_add_number(nvl, "size",
(uint64_t)(left > MAXSIZE ? MAXSIZE : left));
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_get_number(nvl, "error") != 0) {

View File

@ -56,7 +56,7 @@ cap_service_open(const cap_channel_t *chan, const char *name)
nvlist_add_string(nvl, "service", name);
if (fd_is_valid(STDERR_FILENO))
nvlist_add_descriptor(nvl, "stderrfd", STDERR_FILENO);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (NULL);
error = (int)nvlist_get_number(nvl, "error");

View File

@ -63,7 +63,7 @@ cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
if (newp != NULL)
nvlist_add_binary(nvl, "newp", newp, newlen);
nvl = cap_xfer_nvlist(chan, nvl);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_get_number(nvl, "error") != 0) {

View File

@ -279,7 +279,7 @@ casper_message(const cap_channel_t *capcas, struct service *service)
const char *cmd;
nvlist_t *nvl;
nvl = cap_recv_nvlist(capcas);
nvl = cap_recv_nvlist(capcas, 0);
if (nvl == NULL)
pjdlog_exit(1, "Unable to receive message from Casper");
cmd = nvlist_get_string(nvl, "cmd");
@ -297,7 +297,7 @@ service_message(struct service *service, struct service_connection *sconn)
const char *cmd;
int error;
nvlin = cap_recv_nvlist(service_connection_get_chan(sconn));
nvlin = cap_recv_nvlist(service_connection_get_chan(sconn), 0);
if (nvlin == NULL) {
if (errno == ENOTCONN) {
pjdlog_debug(1, "Connection closed by the client.");

View File

@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 1, 2015
.Dd May 2, 2015
.Dt NV 3
.Os
.Sh NAME
@ -85,14 +85,14 @@
.Ft "void *"
.Fn nvlist_pack "const nvlist_t *nvl" "size_t *sizep"
.Ft "nvlist_t *"
.Fn nvlist_unpack "const void *buf" "size_t size"
.Fn nvlist_unpack "const void *buf" "size_t size" "int flags"
.\"
.Ft int
.Fn nvlist_send "int sock" "const nvlist_t *nvl"
.Ft "nvlist_t *"
.Fn nvlist_recv "int sock"
.Fn nvlist_recv "int sock" "int flags"
.Ft "nvlist_t *"
.Fn nvlist_xfer "int sock" "nvlist_t *nvl"
.Fn nvlist_xfer "int sock" "nvlist_t *nvl" "int flags"
.\"
.Ft "const char *"
.Fn nvlist_next "const nvlist_t *nvl" "int *typep" "void **cookiep"
@ -325,6 +325,18 @@ The nvlist must not be in error state.
The
.Fn nvlist_unpack
function converts the given buffer to the nvlist.
The
.Fa flags
argument defines what type of the top level nvlist is expected to be.
Flags are set up using the
.Fn nvlist_create
function.
If the nvlist flags do not match the flags passed to
.Fn nvlist_unpack ,
the nvlist will not be returned.
Every nested nvlist list should be checked using
.Fn nvlist_flags
function.
The function returns
.Dv NULL
in case of an error.
@ -343,12 +355,36 @@ The
function receives nvlist over the socket given by the
.Fa sock
argument.
The
.Fa flags
argument defines what type of the top level nvlist is expected to be.
Flags are set up using the
.Fn nvlist_create
function.
If the nvlist flags do not match the flags passed to
.Fn nvlist_recv ,
the nvlist will not be returned.
Every nested nvlist list should be checked using
.Fn nvlist_flags
function.
.Pp
The
.Fn nvlist_xfer
function sends the given nvlist over the socket given by the
.Fa sock
argument and receives nvlist over the same socket.
The
.Fa flags
argument defines what type of the top level nvlist is expected to be.
Flags are set up using the
.Fn nvlist_create
function.
If the nvlist flags do not match the flags passed to
.Fn nvlist_xfer ,
the nvlist will not be returned.
Every nested nvlist list should be checked using
.Fn nvlist_flags
function.
The given nvlist is always destroyed.
.Pp
The
@ -559,7 +595,7 @@ const char *command;
char *filename;
int fd;
nvl = nvlist_recv(sock);
nvl = nvlist_recv(sock, 0);
if (nvl == NULL)
err(1, "nvlist_recv() failed");
@ -588,7 +624,7 @@ const char *name;
void *cookie;
int type;
nvl = nvlist_recv(sock);
nvl = nvlist_recv(sock, 0);
if (nvl == NULL)
err(1, "nvlist_recv() failed");
@ -617,7 +653,7 @@ const char *name;
void *cookie;
int type;
nvl = nvlist_recv(sock);
nvl = nvlist_recv(sock, 0);
if (nvl == NULL)
err(1, "nvlist_recv() failed");

View File

@ -440,7 +440,7 @@ ATF_TEST_CASE_BODY(nvlist_pack__empty_nvlist)
packed = nvlist_pack(nvl, &packed_size);
ATF_REQUIRE(packed != NULL);
unpacked = nvlist_unpack(packed, packed_size);
unpacked = nvlist_unpack(packed, packed_size, 0);
ATF_REQUIRE(unpacked != NULL);
ATF_REQUIRE(unpacked != nvl);
ATF_REQUIRE(nvlist_empty(unpacked));
@ -534,7 +534,7 @@ ATF_TEST_CASE_BODY(nvlist_pack__multiple_values)
packed = nvlist_pack(nvl, &packed_size);
ATF_REQUIRE(packed != NULL);
unpacked = nvlist_unpack(packed, packed_size);
unpacked = nvlist_unpack(packed, packed_size, 0);
ATF_REQUIRE(unpacked != 0);
it = NULL;
@ -614,7 +614,7 @@ ATF_TEST_CASE_BODY(nvlist_unpack__duplicate_key)
ATF_REQUIRE(keypos != NULL);
memcpy(keypos, key2, keylen);
unpacked = nvlist_unpack(packed, size);
unpacked = nvlist_unpack(packed, size, 0);
ATF_REQUIRE(nvlist_error(unpacked) != 0);
free(packed);

View File

@ -95,7 +95,7 @@ parent(int sock)
int type, ctype;
size_t size;
nvl = nvlist_recv(sock);
nvl = nvlist_recv(sock, 0);
CHECK(nvlist_error(nvl) == 0);
if (nvlist_error(nvl) != 0)
err(1, "nvlist_recv() failed");

View File

@ -357,7 +357,7 @@ service_external_execute(int chanfd)
int stderrfd, execfd, procfd;
nvlist_t *nvl;
nvl = nvlist_recv(chanfd);
nvl = nvlist_recv(chanfd, 0);
if (nvl == NULL)
pjdlog_exit(1, "Unable to receive nvlist");
service = nvlist_take_string(nvl, "service");

View File

@ -91,7 +91,7 @@ zygote_clone(zygote_func_t *func, int flags, int *chanfdp, int *procfdp)
nvl = nvlist_create(0);
nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func);
nvlist_add_number(nvl, "flags", (uint64_t)flags);
nvl = nvlist_xfer(zygote_sock, nvl);
nvl = nvlist_xfer(zygote_sock, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_exists_number(nvl, "error")) {
@ -134,7 +134,7 @@ zygote_main(int sock)
closefrom(sock + 1);
for (;;) {
nvlin = nvlist_recv(sock);
nvlin = nvlist_recv(sock, 0);
if (nvlin == NULL) {
if (errno == ENOTCONN) {
/* Casperd exited. */

View File

@ -386,7 +386,7 @@ pci_iov_parse_config(struct pcicfg_iov *iov, struct pci_iov_arg *arg,
if (error != 0)
goto out;
config = nvlist_unpack(packed_config, arg->len);
config = nvlist_unpack(packed_config, arg->len, NV_FLAG_IGNORE_CASE);
if (config == NULL) {
error = EINVAL;
goto out;

View File

@ -774,7 +774,8 @@ nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
}
static nvlist_t *
nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
int flags)
{
const unsigned char *ptr;
nvlist_t *nvl, *retnvl, *tmpnvl;
@ -782,6 +783,8 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
size_t left;
bool isbe;
PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
left = size;
ptr = buf;
@ -793,6 +796,10 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
if (ptr == NULL)
goto failed;
if (nvl->nvl_flags != flags) {
ERRNO_SET(EILSEQ);
goto failed;
}
while (left > 0) {
ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
@ -849,10 +856,10 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
}
nvlist_t *
nvlist_unpack(const void *buf, size_t size)
nvlist_unpack(const void *buf, size_t size, int flags)
{
return (nvlist_xunpack(buf, size, NULL, 0));
return (nvlist_xunpack(buf, size, NULL, 0, flags));
}
#ifndef _KERNEL
@ -900,7 +907,7 @@ nvlist_send(int sock, const nvlist_t *nvl)
}
nvlist_t *
nvlist_recv(int sock)
nvlist_recv(int sock, int flags)
{
struct nvlist_header nvlhdr;
nvlist_t *nvl, *ret;
@ -937,7 +944,7 @@ nvlist_recv(int sock)
goto out;
}
nvl = nvlist_xunpack(buf, size, fds, nfds);
nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
if (nvl == NULL) {
ERRNO_SAVE();
for (i = 0; i < nfds; i++)
@ -957,7 +964,7 @@ nvlist_recv(int sock)
}
nvlist_t *
nvlist_xfer(int sock, nvlist_t *nvl)
nvlist_xfer(int sock, nvlist_t *nvl, int flags)
{
if (nvlist_send(sock, nvl) < 0) {
@ -965,7 +972,7 @@ nvlist_xfer(int sock, nvlist_t *nvl)
return (NULL);
}
nvlist_destroy(nvl);
return (nvlist_recv(sock));
return (nvlist_recv(sock, flags));
}
#endif

View File

@ -87,11 +87,11 @@ void nvlist_fdump(const nvlist_t *nvl, FILE *fp);
size_t nvlist_size(const nvlist_t *nvl);
void *nvlist_pack(const nvlist_t *nvl, size_t *sizep);
nvlist_t *nvlist_unpack(const void *buf, size_t size);
nvlist_t *nvlist_unpack(const void *buf, size_t size, int flags);
int nvlist_send(int sock, const nvlist_t *nvl);
nvlist_t *nvlist_recv(int sock);
nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl);
nvlist_t *nvlist_recv(int sock, int flags);
nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl, int flags);
const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep);

View File

@ -80,7 +80,7 @@ get_schema(int fd)
err(1, "Could not fetch config schema");
}
schema = nvlist_unpack(arg.schema, arg.len);
schema = nvlist_unpack(arg.schema, arg.len, NV_FLAG_IGNORE_CASE);
if (schema == NULL)
err(1, "Could not unpack schema");