aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2009-08-05 18:02:43 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-12-16 12:16:41 -0500
commit6b18662e239a032f908b7f6e164bdf7e2e0a32c9 (patch)
treeb63bf63d7d2b0d0fac2529a3c3bd906f85388c79 /net
parent7cbe66b6b53b6615f1033bd5b3dbad8162886373 (diff)
9p connect fixes
* if we fail in p9_conn_create(), we shouldn't leak references to struct file. Logics in ->close() doesn't help - ->trans is already gone by the time it's called. * sock_create_kern() can fail. * use of sock_map_fd() is all fscked up; I'd fixed most of that, but the rest will have to wait for a bit more work in net/socket.c (we still are violating the basic rule of working with descriptor table: "once the reference is installed there, don't rely on finding it there again"). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'net')
-rw-r--r--net/9p/trans_fd.c112
1 files changed, 46 insertions, 66 deletions
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 4dd873e3a1bb..be1cb909d8c0 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -42,6 +42,8 @@
42#include <net/9p/client.h> 42#include <net/9p/client.h>
43#include <net/9p/transport.h> 43#include <net/9p/transport.h>
44 44
45#include <linux/syscalls.h> /* killme */
46
45#define P9_PORT 564 47#define P9_PORT 564
46#define MAX_SOCK_BUF (64*1024) 48#define MAX_SOCK_BUF (64*1024)
47#define MAXPOLLWADDR 2 49#define MAXPOLLWADDR 2
@@ -788,24 +790,41 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
788 790
789static int p9_socket_open(struct p9_client *client, struct socket *csocket) 791static int p9_socket_open(struct p9_client *client, struct socket *csocket)
790{ 792{
791 int fd, ret; 793 struct p9_trans_fd *p;
794 int ret, fd;
795
796 p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
797 if (!p)
798 return -ENOMEM;
792 799
793 csocket->sk->sk_allocation = GFP_NOIO; 800 csocket->sk->sk_allocation = GFP_NOIO;
794 fd = sock_map_fd(csocket, 0); 801 fd = sock_map_fd(csocket, 0);
795 if (fd < 0) { 802 if (fd < 0) {
796 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); 803 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
804 sock_release(csocket);
805 kfree(p);
797 return fd; 806 return fd;
798 } 807 }
799 808
800 ret = p9_fd_open(client, fd, fd); 809 get_file(csocket->file);
801 if (ret < 0) { 810 get_file(csocket->file);
802 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); 811 p->wr = p->rd = csocket->file;
812 client->trans = p;
813 client->status = Connected;
814
815 sys_close(fd); /* still racy */
816
817 p->rd->f_flags |= O_NONBLOCK;
818
819 p->conn = p9_conn_create(client);
820 if (IS_ERR(p->conn)) {
821 ret = PTR_ERR(p->conn);
822 p->conn = NULL;
823 kfree(p);
824 sockfd_put(csocket);
803 sockfd_put(csocket); 825 sockfd_put(csocket);
804 return ret; 826 return ret;
805 } 827 }
806
807 ((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK;
808
809 return 0; 828 return 0;
810} 829}
811 830
@@ -883,7 +902,6 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
883 struct socket *csocket; 902 struct socket *csocket;
884 struct sockaddr_in sin_server; 903 struct sockaddr_in sin_server;
885 struct p9_fd_opts opts; 904 struct p9_fd_opts opts;
886 struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
887 905
888 err = parse_opts(args, &opts); 906 err = parse_opts(args, &opts);
889 if (err < 0) 907 if (err < 0)
@@ -897,12 +915,11 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
897 sin_server.sin_family = AF_INET; 915 sin_server.sin_family = AF_INET;
898 sin_server.sin_addr.s_addr = in_aton(addr); 916 sin_server.sin_addr.s_addr = in_aton(addr);
899 sin_server.sin_port = htons(opts.port); 917 sin_server.sin_port = htons(opts.port);
900 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); 918 err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
901 919
902 if (!csocket) { 920 if (err) {
903 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); 921 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
904 err = -EIO; 922 return err;
905 goto error;
906 } 923 }
907 924
908 err = csocket->ops->connect(csocket, 925 err = csocket->ops->connect(csocket,
@@ -912,30 +929,11 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
912 P9_EPRINTK(KERN_ERR, 929 P9_EPRINTK(KERN_ERR,
913 "p9_trans_tcp: problem connecting socket to %s\n", 930 "p9_trans_tcp: problem connecting socket to %s\n",
914 addr); 931 addr);
915 goto error;
916 }
917
918 err = p9_socket_open(client, csocket);
919 if (err < 0)
920 goto error;
921
922 p = (struct p9_trans_fd *) client->trans;
923 p->conn = p9_conn_create(client);
924 if (IS_ERR(p->conn)) {
925 err = PTR_ERR(p->conn);
926 p->conn = NULL;
927 goto error;
928 }
929
930 return 0;
931
932error:
933 if (csocket)
934 sock_release(csocket); 932 sock_release(csocket);
933 return err;
934 }
935 935
936 kfree(p); 936 return p9_socket_open(client, csocket);
937
938 return err;
939} 937}
940 938
941static int 939static int
@@ -944,49 +942,33 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
944 int err; 942 int err;
945 struct socket *csocket; 943 struct socket *csocket;
946 struct sockaddr_un sun_server; 944 struct sockaddr_un sun_server;
947 struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
948 945
949 csocket = NULL; 946 csocket = NULL;
950 947
951 if (strlen(addr) > UNIX_PATH_MAX) { 948 if (strlen(addr) > UNIX_PATH_MAX) {
952 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 949 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
953 addr); 950 addr);
954 err = -ENAMETOOLONG; 951 return -ENAMETOOLONG;
955 goto error;
956 } 952 }
957 953
958 sun_server.sun_family = PF_UNIX; 954 sun_server.sun_family = PF_UNIX;
959 strcpy(sun_server.sun_path, addr); 955 strcpy(sun_server.sun_path, addr);
960 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 956 err = sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
957 if (err < 0) {
958 P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n");
959 return err;
960 }
961 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 961 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
962 sizeof(struct sockaddr_un) - 1, 0); 962 sizeof(struct sockaddr_un) - 1, 0);
963 if (err < 0) { 963 if (err < 0) {
964 P9_EPRINTK(KERN_ERR, 964 P9_EPRINTK(KERN_ERR,
965 "p9_trans_unix: problem connecting socket: %s: %d\n", 965 "p9_trans_unix: problem connecting socket: %s: %d\n",
966 addr, err); 966 addr, err);
967 goto error;
968 }
969
970 err = p9_socket_open(client, csocket);
971 if (err < 0)
972 goto error;
973
974 p = (struct p9_trans_fd *) client->trans;
975 p->conn = p9_conn_create(client);
976 if (IS_ERR(p->conn)) {
977 err = PTR_ERR(p->conn);
978 p->conn = NULL;
979 goto error;
980 }
981
982 return 0;
983
984error:
985 if (csocket)
986 sock_release(csocket); 967 sock_release(csocket);
968 return err;
969 }
987 970
988 kfree(p); 971 return p9_socket_open(client, csocket);
989 return err;
990} 972}
991 973
992static int 974static int
@@ -994,7 +976,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
994{ 976{
995 int err; 977 int err;
996 struct p9_fd_opts opts; 978 struct p9_fd_opts opts;
997 struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */ 979 struct p9_trans_fd *p;
998 980
999 parse_opts(args, &opts); 981 parse_opts(args, &opts);
1000 982
@@ -1005,21 +987,19 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
1005 987
1006 err = p9_fd_open(client, opts.rfd, opts.wfd); 988 err = p9_fd_open(client, opts.rfd, opts.wfd);
1007 if (err < 0) 989 if (err < 0)
1008 goto error; 990 return err;
1009 991
1010 p = (struct p9_trans_fd *) client->trans; 992 p = (struct p9_trans_fd *) client->trans;
1011 p->conn = p9_conn_create(client); 993 p->conn = p9_conn_create(client);
1012 if (IS_ERR(p->conn)) { 994 if (IS_ERR(p->conn)) {
1013 err = PTR_ERR(p->conn); 995 err = PTR_ERR(p->conn);
1014 p->conn = NULL; 996 p->conn = NULL;
1015 goto error; 997 fput(p->rd);
998 fput(p->wr);
999 return err;
1016 } 1000 }
1017 1001
1018 return 0; 1002 return 0;
1019
1020error:
1021 kfree(p);
1022 return err;
1023} 1003}
1024 1004
1025static struct p9_trans_module p9_tcp_trans = { 1005static struct p9_trans_module p9_tcp_trans = {