From d3f5a05e292f63ef285a1f0a458669f59bf179fc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 11 Mar 2013 12:32:21 +0100 Subject: [PATCH 1/7] When adding Netlink attributes, increase header length with potential alignment If the payload is unaligned, we must make sure the total netlink message length includes the added alignment for the first attribute. --- .../kernel_netlink/kernel_netlink_ipsec.c | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index e81e55c24..3231f8212 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1259,7 +1259,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_ALG_AEAD; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1291,7 +1292,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_ALG_CRYPT; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1344,8 +1346,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + int_key.len); - - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1364,8 +1366,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_ALG_AUTH; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len); - - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1394,7 +1396,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, ipcomp_transform_names, ipcomp); rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1414,8 +1416,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_ENCAP; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); - - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1446,7 +1447,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1464,8 +1465,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_TFCPAD; rthdr->rta_len = RTA_LENGTH(sizeof(u_int32_t)); - - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1487,8 +1487,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, rthdr->rta_type = XFRMA_REPLAY_ESN_VAL; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) + (this->replay_window + 7) / 8); - - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1580,7 +1580,7 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { return; @@ -1681,7 +1681,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { return FAILED; @@ -1784,7 +1784,7 @@ METHOD(kernel_ipsec_t, del_sa, status_t, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { return FAILED; @@ -1828,7 +1828,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, struct nlmsghdr *hdr, *out = NULL; struct xfrm_usersa_id *sa_id; struct xfrm_usersa_info *out_sa = NULL, *sa; - size_t len; + size_t len, newlen; struct rtattr *rta; size_t rtasize; struct xfrm_encap_tmpl* tmpl = NULL; @@ -1866,7 +1866,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { return FAILED; @@ -1956,8 +1956,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t, tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); } memcpy(pos, rta, rta->rta_len); - pos += RTA_ALIGN(rta->rta_len); - hdr->nlmsg_len += RTA_ALIGN(rta->rta_len); + newlen = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); + pos += newlen - hdr->nlmsg_len; + hdr->nlmsg_len = newlen; } rta = RTA_NEXT(rta, rtasize); } @@ -1967,8 +1968,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { /* add tmpl if we are enabling it */ rta->rta_type = XFRMA_ENCAP; rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); - - hdr->nlmsg_len += RTA_ALIGN(rta->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -1988,8 +1988,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta->rta_type = XFRMA_REPLAY_ESN_VAL; rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) + this->replay_bmp); - - hdr->nlmsg_len += RTA_ALIGN(rta->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -2003,8 +2002,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { rta->rta_type = XFRMA_REPLAY_VAL; rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state)); - - hdr->nlmsg_len += RTA_ALIGN(rta->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); if (hdr->nlmsg_len > sizeof(request)) { goto failed; @@ -2134,7 +2132,8 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, } rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); - hdr->nlmsg_len += RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl))); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + + RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl))); if (hdr->nlmsg_len > sizeof(request)) { this->mutex->unlock(this->mutex); @@ -2171,7 +2170,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { this->mutex->unlock(this->mutex); @@ -2414,8 +2413,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { return FAILED; @@ -2586,7 +2584,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, rthdr->rta_type = XFRMA_MARK; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { this->mutex->unlock(this->mutex); From 6ac601f543346ec75bcba0fc14fb7319663f37d8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 15 Mar 2013 14:01:15 +0100 Subject: [PATCH 2/7] Avoid unneeded termination of netlink algorithm name arrays with END_OF_LIST --- .../kernel_netlink/kernel_netlink_ipsec.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 3231f8212..47523160b 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -176,8 +176,6 @@ ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_REPLAY_ESN_VAL, "XFRMA_REPLAY_ESN_VAL", ); -#define END_OF_LIST -1 - /** * Algorithms for encryption */ @@ -208,7 +206,6 @@ static kernel_algorithm_t encryption_algs[] = { /* {ENCR_CAMELLIA_CCM_ICV16, "***" }, */ {ENCR_SERPENT_CBC, "serpent" }, {ENCR_TWOFISH_CBC, "twofish" }, - {END_OF_LIST, NULL } }; /** @@ -226,7 +223,6 @@ static kernel_algorithm_t integrity_algs[] = { /* {AUTH_DES_MAC, "***" }, */ /* {AUTH_KPDK_MD5, "***" }, */ {AUTH_AES_XCBC_96, "xcbc(aes)" }, - {END_OF_LIST, NULL } }; /** @@ -237,7 +233,6 @@ static kernel_algorithm_t compression_algs[] = { {IPCOMP_DEFLATE, "deflate" }, {IPCOMP_LZS, "lzs" }, {IPCOMP_LZJH, "lzjh" }, - {END_OF_LIST, NULL } }; /** @@ -246,33 +241,39 @@ static kernel_algorithm_t compression_algs[] = { static char* lookup_algorithm(transform_type_t type, int ikev2) { kernel_algorithm_t *list; - char *name = NULL; + int i, count; + char *name; switch (type) { case ENCRYPTION_ALGORITHM: list = encryption_algs; + count = countof(encryption_algs); break; case INTEGRITY_ALGORITHM: list = integrity_algs; + count = countof(integrity_algs); break; case COMPRESSION_ALGORITHM: list = compression_algs; + count = countof(compression_algs); break; default: return NULL; } - while (list->ikev2 != END_OF_LIST) + for (i = 0; i < count; i++) { - if (list->ikev2 == ikev2) + if (list[i].ikev2 == ikev2) { - return list->name; + return list[i].name; } - list++; } - hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, - type, NULL, &name); - return name; + if (hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, + ikev2, type, NULL, &name)) + { + return name; + } + return NULL; } typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t; From 53c98f098feed0dd779ab0426b6ab635a6e33c8f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 15 Mar 2013 14:32:25 +0100 Subject: [PATCH 3/7] Correctly check buffer length in netlink_add_attribute() --- .../plugins/kernel_netlink/kernel_netlink_shared.c | 2 +- .../plugins/kernel_netlink/kernel_netlink_shared.h | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c index 561e8529d..729e08d5a 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c @@ -292,7 +292,7 @@ void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, { struct rtattr *rta; - if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data.len) > buflen) + if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_LENGTH(data.len) > buflen) { DBG1(DBG_KNL, "unable to add attribute, buffer too small"); return; diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h index dfd27a21a..f5721dfbb 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h @@ -42,7 +42,8 @@ struct netlink_socket_t { * @param out received netlink message * @param out_len length of the received message */ - status_t (*send)(netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out, size_t *out_len); + status_t (*send)(netlink_socket_t *this, struct nlmsghdr *in, + struct nlmsghdr **out, size_t *out_len); /** * Send a netlink message and wait for its acknowledge. @@ -67,11 +68,12 @@ netlink_socket_t *netlink_socket_create(int protocol); /** * Creates an rtattr and adds it to the given netlink message. * - * @param hdr netlink message - * @param rta_type type of the rtattr - * @param data data to add to the rtattr - * @param buflen length of the netlink message buffer + * @param hdr netlink message + * @param rta_type type of the rtattr + * @param data data to add to the rtattr + * @param buflen length of the netlink message buffer */ -void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, size_t buflen); +void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, + size_t buflen); #endif /* KERNEL_NETLINK_SHARED_H_ */ From 6359ab04f410900fc355cdf1883097ae4704f9b8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 15 Mar 2013 14:32:51 +0100 Subject: [PATCH 4/7] Add a Netlink utility function to add a RTA header and reserve space for data --- .../kernel_netlink/kernel_netlink_shared.c | 21 +++++++++++++++++++ .../kernel_netlink/kernel_netlink_shared.h | 11 ++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c index 729e08d5a..fd00c23af 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c @@ -304,3 +304,24 @@ void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, memcpy(RTA_DATA(rta), data.ptr, data.len); hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len; } + +/** + * Described in header. + */ +void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len) +{ + struct rtattr *rta; + + if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_LENGTH(len) > buflen) + { + DBG1(DBG_KNL, "unable to add attribute, buffer too small"); + return NULL; + } + + rta = ((void*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len); + rta->rta_type = type; + rta->rta_len = RTA_LENGTH(len); + hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len; + + return RTA_DATA(rta); +} diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h index f5721dfbb..8be935bc3 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h @@ -76,4 +76,15 @@ netlink_socket_t *netlink_socket_create(int protocol); void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, size_t buflen); +/** + * Reserve space in a netlink message for given size and type, returning buffer. + * + * @param hdr netlink message + * @param buflen size of full netlink buffer + * @param type RTA type + * @param len length of RTA data + * @return buffer to len bytes of attribute data, NULL on error + */ +void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len); + #endif /* KERNEL_NETLINK_SHARED_H_ */ From 6dfc633927bedd5b162f6dbd26ccf168e6edd092 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 15 Mar 2013 15:05:00 +0100 Subject: [PATCH 5/7] Use netlink_reserve() helper function in XFRM to simplify message construction --- .../kernel_netlink/kernel_netlink_ipsec.c | 247 +++++------------- 1 file changed, 72 insertions(+), 175 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 47523160b..1c4b60317 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -94,12 +94,6 @@ */ #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + \ NLMSG_ALIGN(sizeof(x)))) -/** - * Returns a pointer to the next rtattr following rta. - * !!! Do not use this to parse messages. Use RTA_NEXT and RTA_OK instead !!! - */ -#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + \ - RTA_ALIGN((rta)->rta_len))) /** * Returns the total size of attached rta data * (after 'usual' netlink data x like 'struct xfrm_usersa_info') @@ -1223,8 +1217,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->lft.soft_use_expires_seconds = 0; sa->lft.hard_use_expires_seconds = 0; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info); - switch (enc_alg) { case ENCR_UNDEFINED: @@ -1257,24 +1249,17 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", encryption_algorithm_names, enc_alg, enc_key.len * 8); - rthdr->rta_type = XFRMA_ALG_AEAD; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + - enc_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AEAD, + sizeof(*algo) + enc_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr); algo->alg_key_len = enc_key.len * 8; algo->alg_icv_len = icv_size; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, enc_key.ptr, enc_key.len); - - rthdr = XFRM_RTA_NEXT(rthdr); break; } default: @@ -1291,22 +1276,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", encryption_algorithm_names, enc_alg, enc_key.len * 8); - rthdr->rta_type = XFRMA_ALG_CRYPT; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_CRYPT, + sizeof(*algo) + enc_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = enc_key.len * 8; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, enc_key.ptr, enc_key.len); - - rthdr = XFRM_RTA_NEXT(rthdr); } } @@ -1344,17 +1323,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, /* the kernel uses SHA256 with 96 bit truncation by default, * use specified truncation size supported by newer kernels. * also use this for untruncated MD5 and SHA1. */ - rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + - int_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC, + sizeof(*algo) + int_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; algo->alg_trunc_len = trunc_len; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); @@ -1365,27 +1339,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo* algo; - rthdr->rta_type = XFRMA_ALG_AUTH; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH, + sizeof(*algo) + int_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, int_key.ptr, int_key.len); } - rthdr = XFRM_RTA_NEXT(rthdr); } if (ipcomp != IPCOMP_NONE) { - rthdr->rta_type = XFRMA_ALG_COMP; + struct xfrm_algo* algo; + alg_name = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); if (alg_name == NULL) { @@ -1396,34 +1366,26 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using compression algorithm %N", ipcomp_transform_names, ipcomp); - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_COMP, + sizeof(*algo)); + if (!algo) { goto failed; } - - struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = 0; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; - - rthdr = XFRM_RTA_NEXT(rthdr); } if (encap) { struct xfrm_encap_tmpl *tmpl; - rthdr->rta_type = XFRMA_ENCAP; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); + if (!tmpl) { goto failed; } - - tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); tmpl->encap_type = UDP_ENCAP_ESPINUDP; tmpl->encap_sport = htons(src->get_port(src)); tmpl->encap_dport = htons(dst->get_port(dst)); @@ -1438,43 +1400,32 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * No. The reason the kernel ignores NAT-OA is that it recomputes * (or, rather, just ignores) the checksum. If packets pass the IPsec * checks it marks them "checksum ok" so OA isn't needed. */ - rthdr = XFRM_RTA_NEXT(rthdr); } if (mark.value) { struct xfrm_mark *mrk; - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { goto failed; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; - rthdr = XFRM_RTA_NEXT(rthdr); } if (tfc) { u_int32_t *tfcpad; - rthdr->rta_type = XFRMA_TFCPAD; - rthdr->rta_len = RTA_LENGTH(sizeof(u_int32_t)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + tfcpad = netlink_reserve(hdr, sizeof(request), XFRMA_TFCPAD, + sizeof(*tfcpad)); + if (!tfcpad) { goto failed; } - - tfcpad = (u_int32_t*)RTA_DATA(rthdr); *tfcpad = tfc; - rthdr = XFRM_RTA_NEXT(rthdr); } if (protocol != IPPROTO_COMP) @@ -1485,24 +1436,18 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */ struct xfrm_replay_state_esn *replay; - rthdr->rta_type = XFRMA_REPLAY_ESN_VAL; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) + - (this->replay_window + 7) / 8); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + replay = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL, + sizeof(*replay) + (this->replay_window + 7) / 8); + if (!replay) { goto failed; } - - replay = (struct xfrm_replay_state_esn*)RTA_DATA(rthdr); /* bmp_len contains number uf __u32's */ replay->bmp_len = this->replay_bmp; replay->replay_window = this->replay_window; DBG2(DBG_KNL, " using replay window of %u packets", this->replay_window); - rthdr = XFRM_RTA_NEXT(rthdr); if (esn) { DBG2(DBG_KNL, " using extended sequence numbers (ESN)"); @@ -1577,17 +1522,12 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1678,17 +1618,12 @@ METHOD(kernel_ipsec_t, query_sa, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1781,17 +1716,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1863,17 +1793,12 @@ METHOD(kernel_ipsec_t, update_sa, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1945,7 +1870,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = XFRM_RTA(out, struct xfrm_usersa_info); rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info); - while(RTA_OK(rta, rtasize)) + while (RTA_OK(rta, rtasize)) { /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ if (rta->rta_type != XFRMA_ENCAP || new_encap) @@ -1964,53 +1889,42 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = RTA_NEXT(rta, rtasize); } - rta = (struct rtattr*)pos; if (tmpl == NULL && new_encap) { /* add tmpl if we are enabling it */ - rta->rta_type = XFRMA_ENCAP; - rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); + if (!tmpl) { goto failed; } - - tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); tmpl->encap_type = UDP_ENCAP_ESPINUDP; tmpl->encap_sport = ntohs(new_src->get_port(new_src)); tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); - - rta = XFRM_RTA_NEXT(rta); } if (replay_esn) { - rta->rta_type = XFRMA_REPLAY_ESN_VAL; - rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) + - this->replay_bmp); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + struct xfrm_replay_state_esn *state; + + state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL, + sizeof(*state) + this->replay_bmp); + if (!state) { goto failed; } - memcpy(RTA_DATA(rta), replay_esn, - sizeof(struct xfrm_replay_state_esn) + this->replay_bmp); - - rta = XFRM_RTA_NEXT(rta); + memcpy(state, replay_esn, sizeof(*state) + this->replay_bmp); } else if (replay) { - rta->rta_type = XFRMA_REPLAY_VAL; - rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + struct xfrm_replay_state *state; + + state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_VAL, + sizeof(*state)); + if (!state) { goto failed; } - memcpy(RTA_DATA(rta), replay, sizeof(struct xfrm_replay_state)); - - rta = XFRM_RTA_NEXT(rta); + memcpy(state, replay, sizeof(*state)); } else { @@ -2107,11 +2021,9 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, policy_info->lft.soft_use_expires_seconds = 0; policy_info->lft.hard_use_expires_seconds = 0; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info); - if (mapping->type == POLICY_IPSEC) { - struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr); + struct xfrm_user_tmpl *tmpl; struct { u_int8_t proto; bool use; @@ -2121,9 +2033,22 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, { IPPROTO_AH, ipsec->cfg.ah.use }, }; ipsec_mode_t proto_mode = ipsec->cfg.mode; + int count = 0; - rthdr->rta_type = XFRMA_TMPL; - rthdr->rta_len = 0; /* actual length is set below */ + for (i = 0; i < countof(protos); i++) + { + if (protos[i].use) + { + count++; + } + } + tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_TMPL, + count * sizeof(*tmpl)); + if (!tmpl) + { + this->mutex->unlock(this->mutex); + return FAILED; + } for (i = 0; i < countof(protos); i++) { @@ -2131,16 +2056,6 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, { continue; } - - rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl))); - if (hdr->nlmsg_len > sizeof(request)) - { - this->mutex->unlock(this->mutex); - return FAILED; - } - tmpl->reqid = ipsec->cfg.reqid; tmpl->id.proto = protos[i].proto; tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; @@ -2160,25 +2075,18 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, /* use transport mode for other SAs */ proto_mode = MODE_TRANSPORT; } - - rthdr = XFRM_RTA_NEXT(rthdr); } if (ipsec->mark.value) { struct xfrm_mark *mrk; - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { this->mutex->unlock(this->mutex); return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = ipsec->mark.value; mrk->m = ipsec->mark.mask; } @@ -2410,17 +2318,12 @@ METHOD(kernel_ipsec_t, query_policy, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -2581,18 +2484,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { - this->mutex->unlock(this->mutex); return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } From 0d9f31e1ed9be8dc933b6c28f0eb81b182d0a2b9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 15 Mar 2013 15:17:13 +0100 Subject: [PATCH 6/7] Use a helper function to add XFRM_MARK attribute --- .../kernel_netlink/kernel_netlink_ipsec.c | 118 ++++++------------ 1 file changed, 37 insertions(+), 81 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 1c4b60317..485a4d91d 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1145,6 +1145,26 @@ METHOD(kernel_ipsec_t, get_cpi, status_t, return SUCCESS; } +/** + * Add a XFRM mark to message if required + */ +static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark) +{ + if (mark.value) + { + struct xfrm_mark *xmrk; + + xmrk = netlink_reserve(hdr, buflen, XFRMA_MARK, sizeof(*xmrk)); + if (!xmrk) + { + return FALSE; + } + xmrk->v = mark.value; + xmrk->m = mark.mask; + } + return TRUE; +} + METHOD(kernel_ipsec_t, add_sa, status_t, private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark, @@ -1402,17 +1422,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * checks it marks them "checksum ok" so OA isn't needed. */ } - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - goto failed; - } - mrk->v = mark.value; - mrk->m = mark.mask; + goto failed; } if (tfc) @@ -1519,17 +1531,9 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, aevent_id->sa_id.proto = protocol; aevent_id->sa_id.family = dst->get_family(dst); - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - return; - } - mrk->v = mark.value; - mrk->m = mark.mask; + return; } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) @@ -1615,17 +1619,9 @@ METHOD(kernel_ipsec_t, query_sa, status_t, sa_id->proto = protocol; sa_id->family = dst->get_family(dst); - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - return FAILED; - } - mrk->v = mark.value; - mrk->m = mark.mask; + return FAILED; } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) @@ -1713,17 +1709,9 @@ METHOD(kernel_ipsec_t, del_sa, status_t, sa_id->proto = protocol; sa_id->family = dst->get_family(dst); - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - return FAILED; - } - mrk->v = mark.value; - mrk->m = mark.mask; + return FAILED; } switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr)) @@ -1790,17 +1778,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t, sa_id->proto = protocol; sa_id->family = dst->get_family(dst); - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - return FAILED; - } - mrk->v = mark.value; - mrk->m = mark.mask; + return FAILED; } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) @@ -2077,18 +2057,10 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, } } - if (ipsec->mark.value) + if (!add_mark(hdr, sizeof(request), ipsec->mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - this->mutex->unlock(this->mutex); - return FAILED; - } - mrk->v = ipsec->mark.value; - mrk->m = ipsec->mark.mask; + this->mutex->unlock(this->mutex); + return FAILED; } this->mutex->unlock(this->mutex); @@ -2315,17 +2287,9 @@ METHOD(kernel_ipsec_t, query_policy, status_t, policy_id->sel = ts2selector(src_ts, dst_ts); policy_id->dir = direction; - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - return FAILED; - } - mrk->v = mark.value; - mrk->m = mark.mask; + return FAILED; } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) @@ -2481,17 +2445,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, policy_id->sel = current->sel; policy_id->dir = direction; - if (mark.value) + if (!add_mark(hdr, sizeof(request), mark)) { - struct xfrm_mark *mrk; - - mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); - if (!mrk) - { - return FAILED; - } - mrk->v = mark.value; - mrk->m = mark.mask; + return FAILED; } if (current->route) From 94163816fad436423b6e6f0764ae582f0b8be9c1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 15 Mar 2013 16:01:32 +0100 Subject: [PATCH 7/7] Use netlink_add_attribute() to copy over attributes during update_sa() --- .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 485a4d91d..3e84d1699 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1743,11 +1743,10 @@ METHOD(kernel_ipsec_t, update_sa, status_t, bool old_encap, bool new_encap, mark_t mark) { netlink_buf_t request; - u_char *pos; struct nlmsghdr *hdr, *out = NULL; struct xfrm_usersa_id *sa_id; struct xfrm_usersa_info *out_sa = NULL, *sa; - size_t len, newlen; + size_t len; struct rtattr *rta; size_t rtasize; struct xfrm_encap_tmpl* tmpl = NULL; @@ -1831,11 +1830,11 @@ METHOD(kernel_ipsec_t, update_sa, status_t, ntohl(spi), src, dst, new_src, new_dst); /* copy over the SA from out to request */ hdr = (struct nlmsghdr*)request; - memcpy(hdr, out, min(out->nlmsg_len, sizeof(request))); hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; hdr->nlmsg_type = XFRM_MSG_NEWSA; hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa = NLMSG_DATA(hdr); + memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info)); sa->family = new_dst->get_family(new_dst); if (!src->ip_equals(src, new_src)) @@ -1849,7 +1848,6 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = XFRM_RTA(out, struct xfrm_usersa_info); rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); - pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info); while (RTA_OK(rta, rtasize)) { /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ @@ -1857,14 +1855,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { if (rta->rta_type == XFRMA_ENCAP) { /* update encap tmpl */ - tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); + tmpl = RTA_DATA(rta); tmpl->encap_sport = ntohs(new_src->get_port(new_src)); tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); } - memcpy(pos, rta, rta->rta_len); - newlen = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - pos += newlen - hdr->nlmsg_len; - hdr->nlmsg_len = newlen; + netlink_add_attribute(hdr, rta->rta_type, + chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), + sizeof(request)); } rta = RTA_NEXT(rta, rtasize); }