When adding Netlink attributes, increase header length with potential alignment
authorMartin Willi <martin@revosec.ch>
Mon, 11 Mar 2013 11:32:21 +0000 (12:32 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 11 Mar 2013 11:32:21 +0000 (12:32 +0100)
If the payload is unaligned, we must make sure the total netlink message
length includes the added alignment for the first attribute.

src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c

index e81e55c..3231f82 100644 (file)
@@ -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);