On 6/27/17, 11:04 AM, "Joe Stringer" <[email protected]> wrote:

    On 27 June 2017 at 10:51, Darrell Ball <[email protected]> wrote:
    >
    >
    > On 6/27/17, 10:47 AM, "Joe Stringer" <[email protected]> wrote:
    >
    >     On 27 June 2017 at 10:42, Darrell Ball <[email protected]> wrote:
    >     >
    >     >
    >     > On 6/27/17, 10:40 AM, "Joe Stringer" <[email protected]> wrote:
    >     >
    >     >     On 26 June 2017 at 18:19, Darrell Ball <[email protected]> wrote:
    >     >     >
    >     >     >
    >     >     > On 6/26/17, 4:49 PM, "Joe Stringer" <[email protected]> wrote:
    >     >     >
    >     >     >     On 26 June 2017 at 13:22, Joe Stringer <[email protected]> 
wrote:
    >     >     >     > On 26 June 2017 at 11:45, Darrell Ball 
<[email protected]> wrote:
    >     >     >     >> On 6/26/17, 10:22 AM, "Joe Stringer" <[email protected]> 
wrote:
    >     >     >     >>     On 23 June 2017 at 18:57, Darrell Ball 
<[email protected]> wrote:
    >     >     >     >>     > On 6/23/17, 4:08 PM, 
"[email protected] on behalf of Joe Stringer" 
<[email protected] on behalf of [email protected]> wrote:
    >     >     >     >>     >     On 17 June 2017 at 15:53, Darrell Ball 
<[email protected]> wrote:
    >     >     >     >>     >     > @@ -554,34 +681,50 @@ 
conn_not_found(struct conntrack *ct, struct dp_packet *pkt,
    >     >     >     >>     >     >          nc->rev_key = nc->key;
    >     >     >     >>     >     >          conn_key_reverse(&nc->rev_key);
    >     >     >     >>     >     >
    >     >     >     >>     >     > +        if (helper) {
    >     >     >     >>     >     > +            nc->alg = xstrdup(helper);
    >     >     >     >>     >     > +        }
    >     >     >     >>     >     > +
    >     >     >     >>     >     > +        if (alg_exp) {
    >     >     >     >>     >     > +            nc->alg_related = true;
    >     >     >     >>     >     > +            nc->mark = 
alg_exp->master_mark;
    >     >     >     >>     >     > +            nc->label = 
alg_exp->master_label;
    >     >     >     >>     >     > +            nc->master_key = 
alg_exp->master_key;
    >     >     >     >>     >     > +        }
    >     >     >     >>     >     > +
    >     >     >     >>     >     >          if (nat_action_info) {
    >     >     >     >>     >     >              nc->nat_info = 
xmemdup(nat_action_info, sizeof *nc->nat_info);
    >     >     >     >>     >     > -            
ct_rwlock_wrlock(&ct->nat_resources_lock);
    >     >     >     >>     >     > -
    >     >     >     >>     >     > -            bool nat_res = 
nat_select_range_tuple(ct, nc,
    >     >     >     >>     >     > -                                          
        conn_for_un_nat_copy);
    >     >     >     >>     >     >
    >     >     >     >>     >     > -            if (!nat_res) {
    >     >     >     >>     >     > -                free(nc->nat_info);
    >     >     >     >>     >     > -                nc->nat_info = NULL;
    >     >     >     >>     >     > -                free (nc);
    >     >     >     >>     >     > -                
ct_rwlock_unlock(&ct->nat_resources_lock);
    >     >     >     >>     >     > -                return NULL;
    >     >     >     >>     >     > -            }
    >     >     >     >>     >     > +            if (alg_exp) {
    >     >     >     >>     >     > +                nc->rev_key.src.addr = 
alg_nat_repl_addr;
    >     >     >     >>     >     > +                nc->nat_info->nat_action 
= NAT_ACTION_DST;
    >     >     >     >>     >     > +                *conn_for_un_nat_copy = 
*nc;
    >     >     >     >>     >     > +            } else {
    >     >     >     >>     >     > +                
ct_rwlock_wrlock(&ct->resources_lock);
    >     >     >     >>     >     > +                bool nat_res = 
nat_select_range_tuple(
    >     >     >     >>     >     > +                                   ct, 
nc, conn_for_un_nat_copy);
    >     >     >     >>     >     > +
    >     >     >     >>     >     > +                if (!nat_res) {
    >     >     >     >>     >     > +                    free(nc->nat_info);
    >     >     >     >>     >     > +                    nc->nat_info = NULL;
    >     >     >     >>     >     > +                    free (nc);
    >     >     >     >>     >
    >     >     >     >>     >     I think that nc->alg may be leaked here? any 
reason it doesn't use
    >     >     >     >>     >     delete_conn()?
    >     >     >     >>     >
    >     >     >     >>     > Good
    >     >     >     >>     > Yes, alg will leak in this rare error case and 
yes, delete_conn() should be used
    >     >     >     >>     > here, as everywhere.
    >     >     >     >>
    >     >     >     >>     OK.
    >     >     >     >>
    >     >     >     >>     >     > +                    
ct_rwlock_unlock(&ct->resources_lock);
    >     >     >     >>     >     > +                    return NULL;
    >     >     >     >>     >     > +                }
    >     >     >     >>     >     >
    >     >     >     >>     >     > -            if (conn_for_un_nat_copy &&
    >     >     >     >>     >     > -                nc->conn_type == 
CT_CONN_TYPE_DEFAULT) {
    >     >     >     >>     >     >                  *nc = 
*conn_for_un_nat_copy;
    >     >     >     >>     >
    >     >     >     >>     >     Perhaps nc->alg and/or nc->nat_info may be 
leaked here?
    >     >     >     >>     >
    >     >     >     >>     > No, the un_nat conn has no such allocations, so 
there is nothing to leak.
    >     >     >     >>
    >     >     >     >>     I don't mean conn_for_un_nat_copy, I mean *nc 
which could have had an
    >     >     >     >>     xstrdup()'d 'alg' attached. Won't this overwrite 
all fields in 'nc'?
    >     >     >     >>
    >     >     >     >> I see your question now.
    >     >     >     >> No, at this point, the copy gets the same pointers to 
the alg string and nat_info.
    >     >     >     >> Only nc needs them and the un_nat copy ptrs are nulled.
    >     >     >     >> There is only one allocation set.
    >     >     >     >
    >     >     >     > Hmm. Maybe I'm just missing something, let me walk 
through it step by
    >     >     >     > step below and let's see where it goes.
    >     >     >     >
    >     >     >     >        if (helper) {
    >     >     >     >            nc->alg = xstrdup(helper);
    >     >     >     > ^ nc->alg is set
    >     >     >     >        }
    >     >     >     >
    >     >     >     >        if (alg_exp) {
    >     >     >     > ^ false; do not execute this block
    >     >     >     >            nc->alg_related = true;
    >     >     >     >            nc->mark = alg_exp->master_mark;
    >     >     >     >            nc->label = alg_exp->master_label;
    >     >     >     >            nc->master_key = alg_exp->master_key;
    >     >     >     >        }
    >     >     >     >
    >     >     >     >        if (nat_action_info) {
    >     >     >     > ^ true, execute this part
    >     >     >     >            nc->nat_info = xmemdup(nat_action_info, 
sizeof *nc->nat_info);
    >     >     >     >
    >     >     >     >            if (alg_exp) {
    >     >     >     > ^ false; skip to else
    >     >     >     >                nc->rev_key.src.addr = alg_nat_repl_addr;
    >     >     >     >                nc->nat_info->nat_action = 
NAT_ACTION_DST;
    >     >     >     >                *conn_for_un_nat_copy = *nc;
    >     >     >     >            } else {
    >     >     >     > ^ We go through this condition
    >     >     >     >                ct_rwlock_wrlock(&ct->resources_lock);
    >     >     >     >                bool nat_res = nat_select_range_tuple(
    >     >     >     >                                   ct, nc, 
conn_for_un_nat_copy);
    >     >     >     >
    >     >     >     >                if (!nat_res) {
    >     >     >     > ^ false; do not execute this block
    >     >     >     >                    free(nc->nat_info);
    >     >     >     >                    nc->nat_info = NULL;
    >     >     >     >                    free (nc);
    >     >     >     >                    
ct_rwlock_unlock(&ct->resources_lock);
    >     >     >     >                    return NULL;
    >     >     >     >                }
    >     >     >     >
    >     >     >     >                *nc = *conn_for_un_nat_copy;
    >     >     >     > ^ Now:
    >     >     >     > nc->alg is overwritten by conn_for_un_nat_copy->alg
    >     >     >     > nc->nat_info is overwritten by 
conn_for_un_nat_copy->nat_info
    >     >     >     >
    >     >     >     > We don't free either of these.
    >     >     >
    >     >     >     As discussed offline, the copy of '*nc' into 
'*conn_for_un_nat_copy'
    >     >     >     nested inside nat_select_range_tuple() is very well 
hidden. This means
    >     >     >     that the above is not a problem... but what if (!nat_res) 
? Then
    >     >     >     conn_for_un_nat_copy() has a reference to these 
alg/nat_info
    >     >     >     parameters which are freed from 'nc' inside that block, 
then
    >     >     >     'conn_for_un_nat_copy' is returned. Could there be a 
use-after-free
    >     >     >     then?
    >     >     >
    >     >     > Nope, because there is no un_nat conn.
    >     >
    >     >     So you mean that dangling references are returned inside
    >     >     conn_for_un_nat_copy but they're just not used?
    >     >
    >     > JTBC, nothing can be used, since there is not even a connection.
    >
    >     So if nat_select_range_tuple() is called, and it runs the "*nat_conn =
    >     *conn;" line which updates conn_for_un_nat_copy, then
    >     nat_select_range_tuple() fails to select a tuple and returns false,
    >     then the if (!nat_res) cleanup / return NULL path is called, then what
    >     cleans up the dangling pointers that are now in conn_for_un_nat_copy?
    >
    > conn_for_un_nat_copy is a local variable in the caller
    
    Which is then potentially passed to another function,
    create_un_nat_conn(), which then does an xmemdup() to propagate those
    dangling pointers further.. seems like it would be safest to clear out
    the conn_for_un_nat_copy->alg and ->nat_info pointers before freeing
    'nc' in that path.

No, as I stated already, since the un_nat creation (and also conn) never 
completed
the conntype is not set and create_un_nat_conn() is not called.



    

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to