summaryrefslogtreecommitdiff
path: root/net/socket.c
diff options
context:
space:
mode:
authorFrank Filz <ffilzlnx@us.ibm.com>2005-09-28 02:23:38 +0400
committerDavid S. Miller <davem@davemloft.net>2005-09-28 02:23:38 +0400
commita79af59efd20990473d579b1d8d70bb120f0920c (patch)
tree763cc7f083cf922e30537c89d92765415ada78e4 /net/socket.c
parent9356b8fc07dc126cd91d2b12f314d760ab48996e (diff)
downloadlinux-a79af59efd20990473d579b1d8d70bb120f0920c.tar.xz
[NET]: Fix module reference counts for loadable protocol modules
I have been experimenting with loadable protocol modules, and ran into several issues with module reference counting. The first issue was that __module_get failed at the BUG_ON check at the top of the routine (checking that my module reference count was not zero) when I created the first socket. When sk_alloc() is called, my module reference count was still 0. When I looked at why sctp didn't have this problem, I discovered that sctp creates a control socket during module init (when the module ref count is not 0), which keeps the reference count non-zero. This section has been updated to address the point Stephen raised about checking the return value of try_module_get(). The next problem arose when my socket init routine returned an error. This resulted in my module reference count being decremented below 0. My socket ops->release routine was also being called. The issue here is that sock_release() calls the ops->release routine and decrements the ref count if sock->ops is not NULL. Since the socket probably didn't get correctly initialized, this should not be done, so we will set sock->ops to NULL because we will not call try_module_get(). While searching for another bug, I also noticed that sys_accept() has a possibility of doing a module_put() when it did not do an __module_get so I re-ordered the call to security_socket_accept(). Signed-off-by: Frank Filz <ffilzlnx@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/net/socket.c b/net/socket.c
index dbd1a6851edd..3145103cdf54 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1145,8 +1145,11 @@ static int __sock_create(int family, int type, int protocol, struct socket **res
if (!try_module_get(net_families[family]->owner))
goto out_release;
- if ((err = net_families[family]->create(sock, protocol)) < 0)
+ if ((err = net_families[family]->create(sock, protocol)) < 0) {
+ sock->ops = NULL;
goto out_module_put;
+ }
+
/*
* Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt.
@@ -1360,16 +1363,16 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
newsock->type = sock->type;
newsock->ops = sock->ops;
- err = security_socket_accept(sock, newsock);
- if (err)
- goto out_release;
-
/*
* We don't need try_module_get here, as the listening socket (sock)
* has the protocol module (sock->ops->owner) held.
*/
__module_get(newsock->ops->owner);
+ err = security_socket_accept(sock, newsock);
+ if (err)
+ goto out_release;
+
err = sock->ops->accept(sock, newsock, sock->file->f_flags);
if (err < 0)
goto out_release;