lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080829052211.GA3557@gerrit.erg.abdn.ac.uk>
Date:	Fri, 29 Aug 2008 07:22:11 +0200
From:	Gerrit Renker <gerrit@....abdn.ac.uk>
To:	Arnaldo Carvalho de Melo <acme@...hat.com>, dccp@...r.kernel.org,
	netdev@...r.kernel.org
Subject: Re: [PATCH 03/37] dccp: List management for new feature negotiation

| > +/*
| > + *	List management functions
| > + */
| > +
| > +/**
| > + * dccp_feat_entry_new  -  Central list update routine (called by all others)
| > + * @fn: list to add to
| > + * @feat: feature number
| > + * @is_local: whether the local (1) or remote feature with number @feat is meant
| > + * The function maintains and relies on the following invariants:
| > + *  - each feat_num in the list is known, ie. we know its type and default value
| > + *  - each feat_num/is_local combination is unique (old entries are overwritten)
| > + *  - SP values are always freshly allocated
| > + *  - list is sorted in increasing order of feature number (faster lookup)
| > + */
| > +static struct dccp_feat_entry *
| > +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +	struct list_head *pos_head = fn;
| > +
| > +	list_for_each(pos_head, fn) {
| > +		entry = list_entry(pos_head, struct dccp_feat_entry, node);
| 
| Why not use list_for_each_entry()?
As I recall (and that is now over a year ago), there were reasons for doing
it this way, but at the moment I can not figure out which. It is too
long ago, one of the disadvantages of keeping patches out for so long.


| > +		if (feat < entry->feat_num)
| > +			break;
| > +		if (entry->feat_num == feat && entry->is_local == is_local) {
| > +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
| 
| <first reaction>
| You call dccp_feat_val_destructor on entry->val, that kfrees a field and
| then return it? I havent checked, but would it be safer to set the field
| kfree'ed in dccp_feat_val_destructor to NULL since
| dccp_feat_val_destructor is not a destructor (i.e. its not the last
| function in the life of dccp_feat_val)?
| 
| Humm, and shouldn't this entry be removed from the list?
| </>
Please refer to the comments above the function: 
 | > + *  - each feat_num/is_local combination is unique (old entries are overwritten)
A user is free to call setsocktopt as many times as s/he wants. To avoid
ending up with different values for the same feature in the same list,
there is one a single entry for each {feature, remote|local}
combination. Hence the list is searched first:
	 * if an entry already exists, its entry->val is deallocated
	 * and later filled in new
This is necessary since a user may first allocate {3,2} for a CCID and
then decide to overwrite later with {3}.

If there is no entry yet, a new list entry is kmalloced. Each {feature,	local|remote}
combination is allocated at most once, due to the uniqueness requirement.

| I got confused with a _new routine that ends up not being a constructor
| and _destructor being called on an object, then not setting what it
| frees to NULL and then reusing it somehow
|
It seems that the web server (www.erg.abdn.ac.uk/users/gerrit) is still
down, but this discussion would be much easier with the documentation at
hand. But the purpose of the function should be clear from the comments
above it - it is not a "standard" _new routine, due to the specific
requirements of performing feature negotiation safely.


| > +static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
| > +						     u8 feat_num, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +
| > +	list_for_each_entry(entry, fn_list, node)
| 
| cool, here you use list_for_each_entry :-)
| 
What is "cool" about it?

| > +		if (entry->feat_num == feat_num && entry->is_local == is_local)
| > +			return entry;
| > +		else if (entry->feat_num > feat_num)
| > +			break;
| > +	return NULL;
| > +}
| 
| Humm, wouldn't it be better to make the users of dccp_feat_entry_new
| call dccp_feat_list_lookup and if it returns NULL call
| dccp_feat_entry_new that now would just be what its name implies, i.e. a
| constructor, doing just the kmalloc + member init?
| 
This conflicts with the other requirement
 | > + *  - list is sorted in increasing order of feature number (faster lookup)
I agree, the code may look similar, but in feat_entry_new, the purpose
of the list search is to advance to the position within the sorted list
where to put a new feature. When returning NULL, feat_entry_new would
need to start the same search again.

| > +/**
| > + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
| > + * @fn_list: feature-negotiation list to update
| > + * @feat: one of %dccp_feature_numbers
| > + * @local: whether local (1) or remote (0) @feat_num is meant
| > + * @needs_mandatory: whether to use Mandatory feature negotiation options
| > + * @fval: pointer to NN/SP value to be inserted (will be copied)
| > + */
| > +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
| > +				 u8 mandatory, dccp_feat_val *fval)
| > +{
| > +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
| > +
| > +	if (new == NULL)
| > +		return -ENOMEM;
| > +
| > +	new->feat_num	     = feat;
| > +	new->is_local	     = local;
| > +	new->state	     = FEAT_INITIALISING;
| > +	new->needs_confirm   = 0;
| > +	new->empty_confirm   = 0;
| > +	new->val	     = *fval;
| > +	new->needs_mandatory = mandatory;
| > +
| > +	return 0;
| > +}
| > +
| > +/**
| > + * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
| > + * @fn_list: feature-negotiation list to add to
| > + * @feat: one of %dccp_feature_numbers
| > + * @local: whether local (1) or remote (0) @feat_num is being confirmed
| > + * @fval: pointer to NN/SP value to be inserted or NULL
| > + * Returns 0 on success, a Reset code for further processing otherwise.
| > + */
| > +static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
| > +				  dccp_feat_val *fval)
| > +{
| > +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
| > +
| > +	if (new == NULL)
| > +		return DCCP_RESET_CODE_TOO_BUSY;
| > +
| > +	new->feat_num	     = feat;
| > +	new->is_local	     = local;
| > +	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
| > +	new->needs_confirm   = 1;
| > +	new->empty_confirm   = (fval == NULL);
| > +	new->val.nn	     = 0;		/* zeroes the whole structure */
| > +	if (!new->empty_confirm)
| > +		new->val     = *fval;
| > +	new->needs_mandatory = 0;
| > +
| > +	return 0;
| > +}
| > +
| > +static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
| > +{
| > +	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
| > +}
| > +
| > +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
| > +{
| > +	list_del(&entry->node);
| > +	dccp_feat_entry_destructor(entry);
| > +}
| 
| So dccp_feat_entry will always be embedded on other structs? i.e.
| dccp_feat_entry_destructor doesn't frees its space, only fields that
| points to memory allocated elsewhere
| 
Please note that there is a "val destructor" and an "entry destructor",
whose definition is (from the other patch) below:       

static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
{
        if (entry != NULL) {
                dccp_feat_val_destructor(entry->feat_num, &entry->val);
                kfree(entry);
        }
}

So this takes care of freeing the value first and then de-allocating the
list entry.

| > +void dccp_feat_list_purge(struct list_head *fn_list)
| > +{
| > +	struct dccp_feat_entry *entry, *next;
| > +
| > +	list_for_each_entry_safe(entry, next, fn_list, node)
| > +		dccp_feat_entry_destructor(entry);
| > +	INIT_LIST_HEAD(fn_list);
| > +}
| 
| Ditto, who frees the struct dccp_feat_entry instances?
| 
Please see above.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ