On Mon, Oct 09, 2023 at 12:29:43AM +0200, Tobias Heider wrote:
> The diff below adds pledge("stdio") calls for the pfkey dump subset
> of ipsecctl commands.
>
> In particular ipsecctl -s which prints all SAs or flows in the kernel
> and more importantly ipsecctl -m which contiously parses and prints every
> pfkey message forwarded by the kernel don't seem to need any additional
> privileges after setting up pfkey sockets and sysctls.
>
> ok?
New diff after some contstructive feedback from mbuhl@.
ipsecctl -m stays the same, ipsecctl -s is a bit more complicated.
I moved SA and flow printing to the new common function ipsecctl_show()
which first does all the setup, then drops priviledges and finally
parses and prints the messages.
With this all of -sa -ssa and -sf should work properly.
diff /home/user/got/co/src
commit - 6d4ae77d67512ff88b0f7db1a1f3f79dda95dead
path + /home/user/got/co/src
blob - 51858d1a404c26e8c23259910dc399905909ef22
file + sbin/ipsecctl/ipsecctl.c
--- sbin/ipsecctl/ipsecctl.c
+++ sbin/ipsecctl/ipsecctl.c
@@ -57,10 +57,10 @@ void ipsecctl_print_flow(struct ipsec_rule
*, int);
void ipsecctl_print_sa(struct ipsec_rule *, int);
void ipsecctl_print_sabundle(struct ipsec_rule *, int);
int ipsecctl_flush(int);
-void ipsecctl_get_rules(struct ipsecctl *);
+char *ipsecctl_get_rules(struct ipsecctl *, size_t *);
+void ipsecctl_parse_rules(struct ipsecctl *, char *, size_t);
void ipsecctl_print_title(char *);
-void ipsecctl_show_flows(int);
-void ipsecctl_show_sas(int);
+void ipsecctl_show(int);
int ipsecctl_monitor(int);
void usage(void);
const char *ipsecctl_lookup_option(char *, const char **);
@@ -595,30 +595,37 @@ ipsecctl_flush(int opts)
return (0);
}
-void
-ipsecctl_get_rules(struct ipsecctl *ipsec)
+char *
+ipsecctl_get_rules(struct ipsecctl *ipsec, size_t *need)
{
- struct sadb_msg *msg;
- struct ipsec_rule *rule, *last = NULL;
int mib[4];
- size_t need;
- char *buf, *lim, *next;
+ char *buf;
mib[0] = CTL_NET;
mib[1] = PF_KEY;
mib[2] = PF_KEY_V2;
mib[3] = NET_KEY_SPD_DUMP;
- if (sysctl(mib, 4, NULL, &need, NULL, 0) == -1)
+ if (sysctl(mib, 4, NULL, need, NULL, 0) == -1)
err(1, "ipsecctl_get_rules: sysctl");
- if (need == 0)
- return;
- if ((buf = malloc(need)) == NULL)
+ if (*need == 0)
+ return NULL;
+ if ((buf = malloc(*need)) == NULL)
err(1, "ipsecctl_get_rules: malloc");
- if (sysctl(mib, 4, buf, &need, NULL, 0) == -1)
+ if (sysctl(mib, 4, buf, need, NULL, 0) == -1)
err(1, "ipsecctl_get_rules: sysctl");
+
+ return buf;
+}
+
+void
+ipsecctl_parse_rules(struct ipsecctl *ipsec, char *buf, size_t need)
+{
+ struct sadb_msg *msg;
+ struct ipsec_rule *rule, *last = NULL;
+ char *lim, *next;
+
lim = buf + need;
-
for (next = buf; next < lim; next += msg->sadb_msg_len *
PFKEYV2_CHUNK) {
msg = (struct sadb_msg *)next;
@@ -627,13 +634,13 @@ ipsecctl_get_rules(struct ipsecctl *ipsec)
rule = calloc(1, sizeof(struct ipsec_rule));
if (rule == NULL)
- err(1, "ipsecctl_get_rules: calloc");
+ err(1, "ipsecctl_parse_rules: calloc");
rule->nr = ipsec->rule_nr++;
rule->type |= RULE_FLOW;
TAILQ_INIT(&rule->collapsed_rules);
if (pfkey_parse(msg, rule))
- errx(1, "ipsecctl_get_rules: "
+ errx(1, "ipsecctl_parse_rules: "
"failed to parse PF_KEY message");
/*
@@ -663,108 +670,116 @@ ipsecctl_print_title(char *title)
}
void
-ipsecctl_show_flows(int opts)
+ipsecctl_show(int opts)
{
struct ipsecctl ipsec;
struct ipsec_rule *rp;
-
- bzero(&ipsec, sizeof(ipsec));
- ipsec.opts = opts;
- TAILQ_INIT(&ipsec.rule_queue);
-
- ipsecctl_get_rules(&ipsec);
-
- if (opts & IPSECCTL_OPT_SHOWALL)
- ipsecctl_print_title("FLOWS:");
-
- if (TAILQ_FIRST(&ipsec.rule_queue) == 0) {
- if (opts & IPSECCTL_OPT_SHOWALL)
- printf("No flows\n");
- return;
- }
-
- while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
- TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
-
- ipsecctl_print_rule(rp, ipsec.opts);
-
- free(rp->src->name);
- free(rp->src);
- free(rp->dst->name);
- free(rp->dst);
- if (rp->local) {
- free(rp->local->name);
- free(rp->local);
- }
- if (rp->peer) {
- free(rp->peer->name);
- free(rp->peer);
- }
- if (rp->auth) {
- free(rp->auth->srcid);
- free(rp->auth->dstid);
- free(rp->auth);
- }
- free(rp);
- }
-}
-
-void
-ipsecctl_show_sas(int opts)
-{
struct sadb_msg *msg;
struct sad *sad;
int mib[5], sacount, i;
- size_t need = 0;
- char *buf, *lim, *next;
+ size_t need = 0, rlen;
+ char *sbuf = NULL, *rbuf = NULL, *lim, *next;
- mib[0] = CTL_NET;
- mib[1] = PF_KEY;
- mib[2] = PF_KEY_V2;
- mib[3] = NET_KEY_SADB_DUMP;
- mib[4] = SADB_SATYPE_UNSPEC;
+ if (opts & IPSECCTL_OPT_SHOWFLOWS) {
+ bzero(&ipsec, sizeof(ipsec));
+ ipsec.opts = opts;
+ TAILQ_INIT(&ipsec.rule_queue);
+ rbuf = ipsecctl_get_rules(&ipsec, &rlen);
+ }
- if (opts & IPSECCTL_OPT_SHOWALL)
- ipsecctl_print_title("SAD:");
+ if (opts & IPSECCTL_OPT_SHOWSAS) {
+ mib[0] = CTL_NET;
+ mib[1] = PF_KEY;
+ mib[2] = PF_KEY_V2;
+ mib[3] = NET_KEY_SADB_DUMP;
+ mib[4] = SADB_SATYPE_UNSPEC;
- /* When the SAD is empty we get ENOENT, no need to err(). */
- if (sysctl(mib, 5, NULL, &need, NULL, 0) == -1 && errno != ENOENT)
- err(1, "ipsecctl_show_sas: sysctl");
- if (need == 0) {
+ /* When the SAD is empty we get ENOENT, no need to err(). */
+ if (sysctl(mib, 5, NULL, &need, NULL, 0) == -1 &&
+ errno != ENOENT)
+ err(1, "ipsecctl_show: sysctl");
+ if (need > 0) {
+ if ((sbuf = malloc(need)) == NULL)
+ err(1, "ipsecctl_show: malloc");
+ if (sysctl(mib, 5, sbuf, &need, NULL, 0) == -1)
+ err(1, "ipsecctl_show: sysctl");
+ } else {
+ if (opts & IPSECCTL_OPT_SHOWALL)
+ printf("No entries\n");
+ }
+ }
+
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+
+ if (rbuf != NULL) {
+ ipsecctl_parse_rules(&ipsec, rbuf, rlen);
+
if (opts & IPSECCTL_OPT_SHOWALL)
- printf("No entries\n");
- return;
+ ipsecctl_print_title("FLOWS:");
+
+ if (TAILQ_FIRST(&ipsec.rule_queue) != NULL) {
+ while ((rp = TAILQ_FIRST(&ipsec.rule_queue))) {
+ TAILQ_REMOVE(&ipsec.rule_queue, rp, rule_entry);
+
+ ipsecctl_print_rule(rp, ipsec.opts);
+
+ free(rp->src->name);
+ free(rp->src);
+ free(rp->dst->name);
+ free(rp->dst);
+ if (rp->local) {
+ free(rp->local->name);
+ free(rp->local);
+ }
+ if (rp->peer) {
+ free(rp->peer->name);
+ free(rp->peer);
+ }
+ if (rp->auth) {
+ free(rp->auth->srcid);
+ free(rp->auth->dstid);
+ free(rp->auth);
+ }
+ free(rp);
+ }
+ } else {
+ if (opts & IPSECCTL_OPT_SHOWALL)
+ printf("No flows\n");
+ }
}
- if ((buf = malloc(need)) == NULL)
- err(1, "ipsecctl_show_sas: malloc");
- if (sysctl(mib, 5, buf, &need, NULL, 0) == -1)
- err(1, "ipsecctl_show_sas: sysctl");
- sacount = 0;
- lim = buf + need;
- for (next = buf; next < lim;
- next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
- msg = (struct sadb_msg *)next;
- if (msg->sadb_msg_len == 0)
- break;
- sacount++;
+
+ if (sbuf != NULL) {
+ if (opts & IPSECCTL_OPT_SHOWALL)
+ ipsecctl_print_title("SAD:");
+
+ sacount = 0;
+ lim = sbuf + need;
+ for (next = sbuf; next < lim;
+ next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
+ msg = (struct sadb_msg *)next;
+ if (msg->sadb_msg_len == 0)
+ break;
+ sacount++;
+ }
+ if ((sad = calloc(sacount, sizeof(*sad))) == NULL)
+ err(1, "ipsecctl_show: calloc");
+ i = 0;
+ for (next = sbuf; next < lim;
+ next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
+ msg = (struct sadb_msg *)next;
+ if (msg->sadb_msg_len == 0)
+ break;
+ sad[i].sad_spi = pfkey_get_spi(msg);
+ sad[i].sad_msg = msg;
+ i++;
+ }
+ qsort(sad, sacount, sizeof(*sad), sacompare);
+ for (i = 0; i < sacount; i++)
+ pfkey_print_sa(sad[i].sad_msg, opts);
+ free(sad);
+ free(sbuf);
}
- if ((sad = calloc(sacount, sizeof(*sad))) == NULL)
- err(1, "ipsecctl_show_sas: calloc");
- i = 0;
- for (next = buf; next < lim;
- next += msg->sadb_msg_len * PFKEYV2_CHUNK) {
- msg = (struct sadb_msg *)next;
- if (msg->sadb_msg_len == 0)
- break;
- sad[i].sad_spi = pfkey_get_spi(msg);
- sad[i].sad_msg = msg;
- i++;
- }
- qsort(sad, sacount, sizeof(*sad), sacompare);
- for (i = 0; i < sacount; i++)
- pfkey_print_sa(sad[i].sad_msg, opts);
- free(sad);
- free(buf);
}
int
@@ -882,16 +897,18 @@ main(int argc, char *argv[])
if (showopt != NULL) {
switch (*showopt) {
case 'f':
- ipsecctl_show_flows(opts);
+ opts |= IPSECCTL_OPT_SHOWFLOWS;
break;
case 's':
- ipsecctl_show_sas(opts);
+ opts |= IPSECCTL_OPT_SHOWSAS;
break;
case 'a':
+ opts |= IPSECCTL_OPT_SHOWFLOWS;
+ opts |= IPSECCTL_OPT_SHOWSAS;
opts |= IPSECCTL_OPT_SHOWALL;
- ipsecctl_show_flows(opts);
- ipsecctl_show_sas(opts);
+ break;
}
+ ipsecctl_show(opts);
}
if (opts & IPSECCTL_OPT_MONITOR)
blob - c7f92d7d41c3db71a6be686413c46a1b3d304892
file + sbin/ipsecctl/ipsecctl.h
--- sbin/ipsecctl/ipsecctl.h
+++ sbin/ipsecctl/ipsecctl.h
@@ -30,6 +30,8 @@
#define IPSECCTL_OPT_MONITOR 0x0400
#define IPSECCTL_OPT_SHOWKEY 0x0800
#define IPSECCTL_OPT_COLLAPSE 0x1000
+#define IPSECCTL_OPT_SHOWFLOWS 0x2000
+#define IPSECCTL_OPT_SHOWSAS 0x4000
enum {
ACTION_ADD, ACTION_DELETE
@@ -244,7 +246,6 @@ int parse_rules(const char *, struct ipsecctl *);
int cmdline_symset(char *);
int ipsecctl_add_rule(struct ipsecctl *, struct ipsec_rule *);
void ipsecctl_free_rule(struct ipsec_rule *);
-void ipsecctl_get_rules(struct ipsecctl *);
void ipsecctl_print_rule(struct ipsec_rule *, int);
int ike_print_config(struct ipsec_rule *, int);
int ike_ipsec_establish(int, struct ipsec_rule *, const char *);
blob - 388b3663e3b4762acbcea9afb83a8a0998d49a3b
file + sbin/ipsecctl/pfkey.c
--- sbin/ipsecctl/pfkey.c
+++ sbin/ipsecctl/pfkey.c
@@ -1324,6 +1324,9 @@ pfkey_monitor(int opts)
if (pfkey_promisc() < 0)
return -1;
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+
pfd[0].fd = fd;
pfd[0].events = POLLIN;
for (;;) {