Commit 380a2a35 authored by Sridhar Samudrala's avatar Sridhar Samudrala

[IPV4/IPV6]: Fix to avoid overriding TCP/UDP with a new protocol of same type.

Registering a new protocol of type SOCK_STREAM with a protocol value other
than IPPROTO_TCP will override TCP if the application passes 0 as the protocol
to the socket() call.
socket(AF_INET, SOCK_STREAM, 0)
I guess many applications follow this syntax as they assume TCP is the default
protocol for SOCK_STREAM type.
The same holds true for SOCK_DGRAM type sockets assuing UDP as the default.

This is due to the insertion of a new inet_protosw entry into the inetsw list
of a particular type at the head of the list. inet_create() uses the first
entry in the list if a wild-card protocol is passed.

The following patch fixes the insertion of a new entry so that it is added
after the last permanent entry in the list. This makes sure that the new 
entries do not override any existing permanent entries.
parent 426d1b54
...@@ -976,6 +976,7 @@ void inet_register_protosw(struct inet_protosw *p) ...@@ -976,6 +976,7 @@ void inet_register_protosw(struct inet_protosw *p)
struct list_head *lh; struct list_head *lh;
struct inet_protosw *answer; struct inet_protosw *answer;
int protocol = p->protocol; int protocol = p->protocol;
struct list_head *last_perm;
br_write_lock_bh(BR_NETPROTO_LOCK); br_write_lock_bh(BR_NETPROTO_LOCK);
...@@ -984,24 +985,29 @@ void inet_register_protosw(struct inet_protosw *p) ...@@ -984,24 +985,29 @@ void inet_register_protosw(struct inet_protosw *p)
/* If we are trying to override a permanent protocol, bail. */ /* If we are trying to override a permanent protocol, bail. */
answer = NULL; answer = NULL;
last_perm = &inetsw[p->type];
list_for_each(lh, &inetsw[p->type]) { list_for_each(lh, &inetsw[p->type]) {
answer = list_entry(lh, struct inet_protosw, list); answer = list_entry(lh, struct inet_protosw, list);
/* Check only the non-wild match. */ /* Check only the non-wild match. */
if (protocol == answer->protocol && if (INET_PROTOSW_PERMANENT & answer->flags) {
(INET_PROTOSW_PERMANENT & answer->flags)) if (protocol == answer->protocol)
break; break;
last_perm = lh;
}
answer = NULL; answer = NULL;
} }
if (answer) if (answer)
goto out_permanent; goto out_permanent;
/* Add to the BEGINNING so that we override any existing /* Add the new entry after the last permanent entry if any, so that
* entry. This means that when we remove this entry, the * the new entry does not override a permanent entry when matched with
* a wild-card protocol. But it is allowed to override any existing
* non-permanent entry. This means that when we remove this entry, the
* system automatically returns to the old behavior. * system automatically returns to the old behavior.
*/ */
list_add(&p->list, &inetsw[p->type]); list_add(&p->list, last_perm);
out: out:
br_write_unlock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);
return; return;
......
...@@ -571,6 +571,7 @@ inet6_register_protosw(struct inet_protosw *p) ...@@ -571,6 +571,7 @@ inet6_register_protosw(struct inet_protosw *p)
struct list_head *lh; struct list_head *lh;
struct inet_protosw *answer; struct inet_protosw *answer;
int protocol = p->protocol; int protocol = p->protocol;
struct list_head *last_perm;
br_write_lock_bh(BR_NETPROTO_LOCK); br_write_lock_bh(BR_NETPROTO_LOCK);
...@@ -579,24 +580,29 @@ inet6_register_protosw(struct inet_protosw *p) ...@@ -579,24 +580,29 @@ inet6_register_protosw(struct inet_protosw *p)
/* If we are trying to override a permanent protocol, bail. */ /* If we are trying to override a permanent protocol, bail. */
answer = NULL; answer = NULL;
last_perm = &inetsw6[p->type];
list_for_each(lh, &inetsw6[p->type]) { list_for_each(lh, &inetsw6[p->type]) {
answer = list_entry(lh, struct inet_protosw, list); answer = list_entry(lh, struct inet_protosw, list);
/* Check only the non-wild match. */ /* Check only the non-wild match. */
if (protocol == answer->protocol && if (INET_PROTOSW_PERMANENT & answer->flags) {
(INET_PROTOSW_PERMANENT & answer->flags)) if (protocol == answer->protocol)
break; break;
last_perm = lh;
}
answer = NULL; answer = NULL;
} }
if (answer) if (answer)
goto out_permanent; goto out_permanent;
/* Add to the BEGINNING so that we override any existing /* Add the new entry after the last permanent entry if any, so that
* entry. This means that when we remove this entry, the * the new entry does not override a permanent entry when matched with
* a wild-card protocol. But it is allowed to override any existing
* non-permanent entry. This means that when we remove this entry, the
* system automatically returns to the old behavior. * system automatically returns to the old behavior.
*/ */
list_add(&p->list, &inetsw6[p->type]); list_add(&p->list, last_perm);
out: out:
br_write_unlock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment