Skip to content
Snippets Groups Projects
Commit e507fb11 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman
Browse files

xdp-gun: use safer alternative of popen because being root

parent b8f48e97
No related branches found
No related tags found
1 merge request!1149Xdp gun popen fix
......@@ -73,6 +73,8 @@ src/contrib/openbsd/strlcat.c
src/contrib/openbsd/strlcat.h
src/contrib/openbsd/strlcpy.c
src/contrib/openbsd/strlcpy.h
src/contrib/popenve.c
src/contrib/popenve.h
src/contrib/qp-trie/trie.c
src/contrib/qp-trie/trie.h
src/contrib/semaphore.c
......
......@@ -43,6 +43,8 @@ libcontrib_la_SOURCES = \
contrib/mempattern.h \
contrib/net.c \
contrib/net.h \
contrib/popenve.c \
contrib/popenve.h \
contrib/qp-trie/trie.c \
contrib/qp-trie/trie.h \
contrib/semaphore.c \
......
/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "popenve.h"
int kpopenve(const char *binfile, char *const args[], char *const env[])
{
int pipefds[2];
if (pipe(pipefds) < 0) {
return -errno;
}
if (fcntl(pipefds[0], F_SETFD, FD_CLOEXEC) < 0) {
int fcntlerrno = errno;
close(pipefds[0]);
close(pipefds[1]);
return -fcntlerrno;
}
pid_t forkpid = fork();
if (forkpid < 0) {
int forkerrno = errno;
close(pipefds[0]);
close(pipefds[1]);
return -forkerrno;
}
if (forkpid == 0) {
dup_stdout:
if (dup2(pipefds[1], STDOUT_FILENO) < 0) {
if (errno == EINTR) {
goto dup_stdout;
}
perror("dup_stdout");
close(pipefds[0]);
close(pipefds[1]);
exit(98);
}
close(pipefds[1]);
execve(binfile, args, env);
perror("execve");
exit(99);
}
close(pipefds[1]);
return pipefds[0];
}
FILE *kpopenve2(const char *binfile, char *const args[], char *const env[])
{
int p = kpopenve(binfile, args, env);
if (p < 0) {
errno = -p;
return NULL;
}
FILE *res = fdopen(p, "r");
if (res == NULL) {
int fdoerrno = errno;
close(p);
errno = fdoerrno;
}
return res;
}
/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdio.h>
/*!
* \brief Hybrid of popen() and execve().
*
* This function is a safer altervative to popen(), it is the same to
* popen() as execve() is to system().
*
* \param binfile Executable file to be executed.
* \param args NULL-terminated arguments; first shall be the prog name!
* \param env NULL-terminated environment variables "key=value"
*
* \retval < 0 Error occured, set to -errno.
* \return > 0 File descriptor of the pipe reading end.
*/
int kpopenve(const char *binfile, char *const args[], char *const env[]);
/*!
* \brief Variant of kpopenve() returning FILE*
*
* \param binfile Executable file to be executed.
* \param args NULL-terminated arguments; first shall be the prog name!
* \param env NULL-terminated environment variables "key=value"
*
* \retval NULL Error occured, see errno.
* \return Pointer to open file descriptor.
*/
FILE *kpopenve2(const char *binfile, char *const args[], char *const env[]);
......@@ -37,6 +37,7 @@
#include "libknot/libknot.h"
#include "contrib/openbsd/strlcpy.h"
#include "contrib/popenve.h"
#include "utils/common/params.h"
#include "load_queries.h"
......@@ -342,34 +343,41 @@ static bool str2mac(const char *str, uint8_t mac[])
return true;
}
static int ip_route_get(const char *ip_str, const char *what, char **res)
static FILE *popen_ip(char *arg1, char *arg2, char *arg3)
{
char cmd[50 + strlen(ip_str) + strlen(what)];
(void)snprintf(cmd, sizeof(cmd), "ip route get %s | grep -o ' %s [^ ]* '", ip_str, what);
char *args[5] = { "ip", arg1, arg2, arg3, NULL };
char *env[] = { NULL };
return kpopenve2("/sbin/ip", args, env);
}
static int ip_route_get(const char *ip_str, const char *what, char **res)
{
errno = 0;
FILE *p = popen(cmd, "r");
FILE *p = popen_ip("route", "get", (char *)ip_str); // hope ip_str gets not broken
if (p == NULL) {
return (errno != 0) ? knot_map_errno() : KNOT_ENOMEM;
}
char check[16] = { 0 }, got[256] = { 0 };
if (fscanf(p, "%15s%255s", check, got) != 2 ||
strcmp(check, what) != 0) {
int ret = feof(p) ? KNOT_ENOENT : KNOT_EMALF;
pclose(p);
return ret;
char buf[256] = { 0 };
bool hit = false;
while (fscanf(p, "%255s", buf) == 1) {
if (hit) {
*res = strdup(buf);
fclose(p);
return *res == NULL ? KNOT_ENOMEM : KNOT_EOK;
}
if (strcmp(buf, what) == 0) {
hit = true;
}
}
pclose(p);
*res = strdup(got);
return *res == NULL ? KNOT_ENOMEM : KNOT_EOK;
fclose(p);
return KNOT_ENOENT;
}
static int remoteIP2MAC(const char *ip_str, bool ipv6, char devname[], uint8_t remote_mac[])
{
errno = 0;
FILE *p = popen(ipv6 ? "ip -6 neigh" : "arp -ne", "r");
FILE *p = popen_ip(ipv6 ? "-6" : "-4", "neigh", NULL);
if (p == NULL) {
return (errno != 0) ? knot_map_errno() : KNOT_ENOMEM;
}
......@@ -384,14 +392,14 @@ static int remoteIP2MAC(const char *ip_str, bool ipv6, char devname[], uint8_t r
if (strcmp(fields[0], ip_str) != 0) {
continue;
}
if (!str2mac(fields[ipv6 ? 4 : 2], remote_mac)) {
if (!str2mac(fields[4], remote_mac)) {
ret = KNOT_EMALF;
} else {
strlcpy(devname, fields[ipv6 ? 2 : 4], IFNAMSIZ);
strlcpy(devname, fields[2], IFNAMSIZ);
ret = KNOT_EOK;
}
}
pclose(p);
fclose(p);
return ret;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment