ip xfrm state show currently dumps keys unconditionally. This limits its use in logging, as security information can be leaked.
This patch adds a nokeys option to ip xfrm ( state show | monitor ), which prevents the printing of keys. This allows ip xfrm state show to be used in logging without exposing keys. Signed-off-by: Benedict Wong <benedictw...@google.com> --- ip/ipxfrm.c | 49 +++++++++++++++++++++++++--------------------- ip/xfrm.h | 5 +++-- ip/xfrm_monitor.c | 7 +++++-- ip/xfrm_state.c | 27 ++++++++++++++++++++----- man/man8/ip-xfrm.8 | 15 +++++++++++++- 5 files changed, 71 insertions(+), 32 deletions(-) diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 2dea4e37..b153b863 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -497,7 +497,8 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family, } static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len, - FILE *fp, const char *prefix, int newline) + FILE *fp, const char *prefix, int newline, + bool nokeys) { int keylen; int i; @@ -521,7 +522,9 @@ static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len, goto fin; } - if (keylen > 0) { + if (nokeys) + fprintf(fp, "<<Keys hidden>>"); + else if (keylen > 0) { fprintf(fp, "0x"); for (i = 0; i < keylen; i++) fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]); @@ -536,13 +539,13 @@ static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len, } static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len, - FILE *fp, const char *prefix) + FILE *fp, const char *prefix, bool nokeys) { - return __xfrm_algo_print(algo, type, len, fp, prefix, 1); + return __xfrm_algo_print(algo, type, len, fp, prefix, 1, nokeys); } static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len, - FILE *fp, const char *prefix) + FILE *fp, const char *prefix, bool nokeys) { struct xfrm_algo *base_algo = alloca(sizeof(*base_algo) + algo->alg_key_len / 8); @@ -550,7 +553,8 @@ static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len, base_algo->alg_key_len = algo->alg_key_len; memcpy(base_algo->alg_key, algo->alg_key, algo->alg_key_len / 8); - __xfrm_algo_print(base_algo, XFRMA_ALG_AEAD, len, fp, prefix, 0); + __xfrm_algo_print(base_algo, XFRMA_ALG_AEAD, len, fp, prefix, 0, + nokeys); fprintf(fp, " %d", algo->alg_icv_len); @@ -558,7 +562,7 @@ static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len, } static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len, - FILE *fp, const char *prefix) + FILE *fp, const char *prefix, bool nokeys) { struct xfrm_algo *base_algo = alloca(sizeof(*base_algo) + algo->alg_key_len / 8); @@ -566,7 +570,8 @@ static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len, base_algo->alg_key_len = algo->alg_key_len; memcpy(base_algo->alg_key, algo->alg_key, algo->alg_key_len / 8); - __xfrm_algo_print(base_algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0); + __xfrm_algo_print(base_algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0, + nokeys); fprintf(fp, " %d", algo->alg_trunc_len); @@ -679,7 +684,7 @@ done: } void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, - FILE *fp, const char *prefix) + FILE *fp, const char *prefix, bool nokeys) { if (tb[XFRMA_MARK]) { struct rtattr *rta = tb[XFRMA_MARK]; @@ -700,36 +705,36 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) { struct rtattr *rta = tb[XFRMA_ALG_AUTH]; - xfrm_algo_print(RTA_DATA(rta), - XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix); + xfrm_algo_print(RTA_DATA(rta), XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), + fp, prefix, nokeys); } if (tb[XFRMA_ALG_AUTH_TRUNC]) { struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC]; - xfrm_auth_trunc_print(RTA_DATA(rta), - RTA_PAYLOAD(rta), fp, prefix); + xfrm_auth_trunc_print(RTA_DATA(rta), RTA_PAYLOAD(rta), fp, + prefix, nokeys); } if (tb[XFRMA_ALG_AEAD]) { struct rtattr *rta = tb[XFRMA_ALG_AEAD]; - xfrm_aead_print(RTA_DATA(rta), - RTA_PAYLOAD(rta), fp, prefix); + xfrm_aead_print(RTA_DATA(rta), RTA_PAYLOAD(rta), fp, prefix, + nokeys); } if (tb[XFRMA_ALG_CRYPT]) { struct rtattr *rta = tb[XFRMA_ALG_CRYPT]; - xfrm_algo_print(RTA_DATA(rta), - XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix); + xfrm_algo_print(RTA_DATA(rta), XFRMA_ALG_CRYPT, + RTA_PAYLOAD(rta), fp, prefix, nokeys); } if (tb[XFRMA_ALG_COMP]) { struct rtattr *rta = tb[XFRMA_ALG_COMP]; - xfrm_algo_print(RTA_DATA(rta), - XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix); + xfrm_algo_print(RTA_DATA(rta), XFRMA_ALG_COMP, RTA_PAYLOAD(rta), + fp, prefix, nokeys); } if (tb[XFRMA_ENCAP]) { @@ -897,7 +902,7 @@ static int xfrm_selector_iszero(struct xfrm_selector *s) void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo, struct rtattr *tb[], FILE *fp, const char *prefix, - const char *title) + const char *title, bool nokeys) { char buf[STRBUF_SIZE] = {}; int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto); @@ -943,7 +948,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo, fprintf(fp, " (0x%s)", strxf_mask8(xsinfo->flags)); fprintf(fp, "%s", _SL_); - xfrm_xfrma_print(tb, xsinfo->family, fp, buf); + xfrm_xfrma_print(tb, xsinfo->family, fp, buf, nokeys); if (!xfrm_selector_iszero(&xsinfo->sel)) { char sbuf[STRBUF_SIZE]; @@ -1071,7 +1076,7 @@ void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo, if (show_stats > 0) xfrm_lifetime_print(&xpinfo->lft, &xpinfo->curlft, fp, buf); - xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf); + xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf, false); } int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, diff --git a/ip/xfrm.h b/ip/xfrm.h index 72390d79..9ba5ca61 100644 --- a/ip/xfrm.h +++ b/ip/xfrm.h @@ -105,6 +105,7 @@ struct xfrm_filter { extern struct xfrm_filter filter; int xfrm_state_print(struct nlmsghdr *n, void *arg); +int xfrm_state_print_nokeys(struct nlmsghdr *n, void *arg); int xfrm_policy_print(struct nlmsghdr *n, void *arg); int do_xfrm_state(int argc, char **argv); int do_xfrm_policy(int argc, char **argv); @@ -124,10 +125,10 @@ const char *strxf_ptype(__u8 ptype); void xfrm_selector_print(struct xfrm_selector *sel, __u16 family, FILE *fp, const char *prefix); void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, - FILE *fp, const char *prefix); + FILE *fp, const char *prefix, bool nokeys); void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo, struct rtattr *tb[], FILE *fp, const char *prefix, - const char *title); + const char *title, bool nokeys); void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo, struct rtattr *tb[], FILE *fp, const char *prefix, const char *title); diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c index 76905ed3..17117f41 100644 --- a/ip/xfrm_monitor.c +++ b/ip/xfrm_monitor.c @@ -35,10 +35,11 @@ static void usage(void) __attribute__((noreturn)); static int listen_all_nsid; +static bool nokeys; static void usage(void) { - fprintf(stderr, "Usage: ip xfrm monitor [all-nsid] [ all | OBJECTS | help ]\n"); + fprintf(stderr, "Usage: ip xfrm monitor [ nokeys ] [ all-nsid ] [ all | OBJECTS | help ]\n"); fprintf(stderr, "OBJECTS := { acquire | expire | SA | aevent | policy | report }\n"); exit(-1); } @@ -197,7 +198,7 @@ static int xfrm_report_print(struct nlmsghdr *n, void *arg) parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len); - xfrm_xfrma_print(tb, family, fp, " "); + xfrm_xfrma_print(tb, family, fp, " ", nokeys); if (oneline) fprintf(fp, "\n"); @@ -352,6 +353,8 @@ int do_xfrm_monitor(int argc, char **argv) if (matches(*argv, "file") == 0) { NEXT_ARG(); file = *argv; + } else if (strcmp(*argv, "nokeys") == 0) { + nokeys = true; } else if (strcmp(*argv, "all") == 0) { /* fall out */ } else if (matches(*argv, "all-nsid") == 0) { diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index e8c01746..09292da9 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -65,7 +65,9 @@ static void usage(void) fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n"); fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n"); fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n"); - fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n"); + fprintf(stderr, "Usage: ip xfrm state deleteall [ ID ] [ mode MODE ] [ reqid REQID ]\n"); + fprintf(stderr, " [ flag FLAG-LIST ]\n"); + fprintf(stderr, "Usage: ip xfrm state list [ nokeys ] [ ID ] [ mode MODE ] [ reqid REQID ]\n"); fprintf(stderr, " [ flag FLAG-LIST ]\n"); fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n"); fprintf(stderr, "Usage: ip xfrm state count\n"); @@ -908,7 +910,7 @@ static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo) return 1; } -int xfrm_state_print(struct nlmsghdr *n, void *arg) +static int __do_xfrm_state_print(struct nlmsghdr *n, void *arg, bool nokeys) { FILE *fp = (FILE *)arg; struct rtattr *tb[XFRMA_MAX+1]; @@ -979,7 +981,7 @@ int xfrm_state_print(struct nlmsghdr *n, void *arg) xsinfo = RTA_DATA(tb[XFRMA_SA]); } - xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL); + xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL, nokeys); if (n->nlmsg_type == XFRM_MSG_EXPIRE) { fprintf(fp, "\t"); @@ -994,6 +996,16 @@ int xfrm_state_print(struct nlmsghdr *n, void *arg) return 0; } +int xfrm_state_print(struct nlmsghdr *n, void *arg) +{ + return __do_xfrm_state_print(n, arg, false); +} + +int xfrm_state_print_nokeys(struct nlmsghdr *n, void *arg) +{ + return __do_xfrm_state_print(n, arg, true); +} + static int xfrm_state_get_or_delete(int argc, char **argv, int delete) { struct rtnl_handle rth; @@ -1145,13 +1157,16 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall) { char *idp = NULL; struct rtnl_handle rth; + bool nokeys = false; if (argc > 0) filter.use = 1; filter.xsinfo.family = preferred_family; while (argc > 0) { - if (strcmp(*argv, "mode") == 0) { + if (strcmp(*argv, "nokeys") == 0) { + nokeys = true; + } else if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv); @@ -1267,7 +1282,9 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall) exit(1); } - if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) { + rtnl_filter_t filter = nokeys ? + xfrm_state_print_nokeys : xfrm_state_print; + if (rtnl_dump_filter(&rth, filter, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8 index 839e06aa..95478085 100644 --- a/man/man8/ip-xfrm.8 +++ b/man/man8/ip-xfrm.8 @@ -89,7 +89,7 @@ ip-xfrm \- transform configuration .IR MASK " ] ]" .ti -8 -.BR "ip xfrm state" " { " deleteall " | " list " } [" +.BR "ip xfrm state " deleteall " [" .IR ID " ]" .RB "[ " mode .IR MODE " ]" @@ -98,6 +98,17 @@ ip-xfrm \- transform configuration .RB "[ " flag .IR FLAG-LIST " ]" +.ti -8 +.BR "ip xfrm state " list " [" +.IR ID " ]" +.RB "[ " nokeys " ]" +.RB "[ " mode +.IR MODE " ]" +.RB "[ " reqid +.IR REQID " ]" +.RB "[ " flag +.IR FLAG-LIST " ]" + .ti -8 .BR "ip xfrm state flush" " [ " proto .IR XFRM-PROTO " ]" @@ -381,6 +392,8 @@ ip-xfrm \- transform configuration .BR "ip xfrm monitor" " [" .BI all-nsid ] [ +.BI nokeys +] [ .BI all | .IR LISTofXFRM-OBJECTS " ]" -- 2.20.1.321.g9e740568ce-goog