diff options
author | Dean Jenkins <Dean_Jenkins@mentor.com> | 2013-02-28 09:21:55 -0500 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-03-08 08:40:24 -0500 |
commit | 8ff52f7d04d9cc31f1e81dcf9a2ba6335ed34905 (patch) | |
tree | 681a2468209aff5c83cd7c3bafe1eb6c38123c63 /net/bluetooth/rfcomm | |
parent | c06f7d532aa6f78b2847e3b651c0da27fc3296c0 (diff) |
Bluetooth: Return RFCOMM session ptrs to avoid freed session
Unfortunately, the design retains local copies of the s RFCOMM
session pointer in various code blocks and this invites the erroneous
access to a freed RFCOMM session structure.
Therefore, return the RFCOMM session pointer back up the call stack
to avoid accessing a freed RFCOMM session structure. When the RFCOMM
session is deleted, NULL is passed up the call stack.
If active DLCs exist when the rfcomm session is terminating,
avoid a memory leak of rfcomm_dlc structures by ensuring that
rfcomm_session_close() is used instead of rfcomm_session_del().
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/rfcomm')
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 106 |
1 files changed, 56 insertions, 50 deletions
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index d9e97cf1792b..2b5c543638ba 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -69,7 +69,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, | |||
69 | u8 sec_level, | 69 | u8 sec_level, |
70 | int *err); | 70 | int *err); |
71 | static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); | 71 | static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); |
72 | static void rfcomm_session_del(struct rfcomm_session *s); | 72 | static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s); |
73 | 73 | ||
74 | /* ---- RFCOMM frame parsing macros ---- */ | 74 | /* ---- RFCOMM frame parsing macros ---- */ |
75 | #define __get_dlci(b) ((b & 0xfc) >> 2) | 75 | #define __get_dlci(b) ((b & 0xfc) >> 2) |
@@ -108,10 +108,12 @@ static void rfcomm_schedule(void) | |||
108 | wake_up_process(rfcomm_thread); | 108 | wake_up_process(rfcomm_thread); |
109 | } | 109 | } |
110 | 110 | ||
111 | static void rfcomm_session_put(struct rfcomm_session *s) | 111 | static struct rfcomm_session *rfcomm_session_put(struct rfcomm_session *s) |
112 | { | 112 | { |
113 | if (atomic_dec_and_test(&s->refcnt)) | 113 | if (s && atomic_dec_and_test(&s->refcnt)) |
114 | rfcomm_session_del(s); | 114 | s = rfcomm_session_del(s); |
115 | |||
116 | return s; | ||
115 | } | 117 | } |
116 | 118 | ||
117 | /* ---- RFCOMM FCS computation ---- */ | 119 | /* ---- RFCOMM FCS computation ---- */ |
@@ -631,7 +633,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) | |||
631 | return s; | 633 | return s; |
632 | } | 634 | } |
633 | 635 | ||
634 | static void rfcomm_session_del(struct rfcomm_session *s) | 636 | static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s) |
635 | { | 637 | { |
636 | int state = s->state; | 638 | int state = s->state; |
637 | 639 | ||
@@ -648,6 +650,8 @@ static void rfcomm_session_del(struct rfcomm_session *s) | |||
648 | 650 | ||
649 | if (state != BT_LISTEN) | 651 | if (state != BT_LISTEN) |
650 | module_put(THIS_MODULE); | 652 | module_put(THIS_MODULE); |
653 | |||
654 | return NULL; | ||
651 | } | 655 | } |
652 | 656 | ||
653 | static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) | 657 | static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) |
@@ -666,7 +670,8 @@ static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) | |||
666 | return NULL; | 670 | return NULL; |
667 | } | 671 | } |
668 | 672 | ||
669 | static void rfcomm_session_close(struct rfcomm_session *s, int err) | 673 | static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s, |
674 | int err) | ||
670 | { | 675 | { |
671 | struct rfcomm_dlc *d; | 676 | struct rfcomm_dlc *d; |
672 | struct list_head *p, *n; | 677 | struct list_head *p, *n; |
@@ -685,7 +690,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err) | |||
685 | } | 690 | } |
686 | 691 | ||
687 | rfcomm_session_clear_timer(s); | 692 | rfcomm_session_clear_timer(s); |
688 | rfcomm_session_put(s); | 693 | return rfcomm_session_put(s); |
689 | } | 694 | } |
690 | 695 | ||
691 | static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, | 696 | static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, |
@@ -737,8 +742,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, | |||
737 | if (*err == 0 || *err == -EINPROGRESS) | 742 | if (*err == 0 || *err == -EINPROGRESS) |
738 | return s; | 743 | return s; |
739 | 744 | ||
740 | rfcomm_session_del(s); | 745 | return rfcomm_session_del(s); |
741 | return NULL; | ||
742 | 746 | ||
743 | failed: | 747 | failed: |
744 | sock_release(sock); | 748 | sock_release(sock); |
@@ -1127,7 +1131,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) | |||
1127 | } | 1131 | } |
1128 | 1132 | ||
1129 | /* ---- RFCOMM frame reception ---- */ | 1133 | /* ---- RFCOMM frame reception ---- */ |
1130 | static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) | 1134 | static struct rfcomm_session *rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) |
1131 | { | 1135 | { |
1132 | BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); | 1136 | BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); |
1133 | 1137 | ||
@@ -1136,7 +1140,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) | |||
1136 | struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); | 1140 | struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); |
1137 | if (!d) { | 1141 | if (!d) { |
1138 | rfcomm_send_dm(s, dlci); | 1142 | rfcomm_send_dm(s, dlci); |
1139 | return 0; | 1143 | return s; |
1140 | } | 1144 | } |
1141 | 1145 | ||
1142 | switch (d->state) { | 1146 | switch (d->state) { |
@@ -1172,25 +1176,14 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) | |||
1172 | break; | 1176 | break; |
1173 | 1177 | ||
1174 | case BT_DISCONN: | 1178 | case BT_DISCONN: |
1175 | /* rfcomm_session_put is called later so don't do | 1179 | s = rfcomm_session_close(s, ECONNRESET); |
1176 | * anything here otherwise we will mess up the session | ||
1177 | * reference counter: | ||
1178 | * | ||
1179 | * (a) when we are the initiator dlc_unlink will drive | ||
1180 | * the reference counter to 0 (there is no initial put | ||
1181 | * after session_add) | ||
1182 | * | ||
1183 | * (b) when we are not the initiator rfcomm_rx_process | ||
1184 | * will explicitly call put to balance the initial hold | ||
1185 | * done after session add. | ||
1186 | */ | ||
1187 | break; | 1180 | break; |
1188 | } | 1181 | } |
1189 | } | 1182 | } |
1190 | return 0; | 1183 | return s; |
1191 | } | 1184 | } |
1192 | 1185 | ||
1193 | static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) | 1186 | static struct rfcomm_session *rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) |
1194 | { | 1187 | { |
1195 | int err = 0; | 1188 | int err = 0; |
1196 | 1189 | ||
@@ -1215,12 +1208,13 @@ static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) | |||
1215 | err = ECONNRESET; | 1208 | err = ECONNRESET; |
1216 | 1209 | ||
1217 | s->state = BT_CLOSED; | 1210 | s->state = BT_CLOSED; |
1218 | rfcomm_session_close(s, err); | 1211 | s = rfcomm_session_close(s, err); |
1219 | } | 1212 | } |
1220 | return 0; | 1213 | return s; |
1221 | } | 1214 | } |
1222 | 1215 | ||
1223 | static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) | 1216 | static struct rfcomm_session *rfcomm_recv_disc(struct rfcomm_session *s, |
1217 | u8 dlci) | ||
1224 | { | 1218 | { |
1225 | int err = 0; | 1219 | int err = 0; |
1226 | 1220 | ||
@@ -1250,10 +1244,9 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) | |||
1250 | err = ECONNRESET; | 1244 | err = ECONNRESET; |
1251 | 1245 | ||
1252 | s->state = BT_CLOSED; | 1246 | s->state = BT_CLOSED; |
1253 | rfcomm_session_close(s, err); | 1247 | s = rfcomm_session_close(s, err); |
1254 | } | 1248 | } |
1255 | 1249 | return s; | |
1256 | return 0; | ||
1257 | } | 1250 | } |
1258 | 1251 | ||
1259 | void rfcomm_dlc_accept(struct rfcomm_dlc *d) | 1252 | void rfcomm_dlc_accept(struct rfcomm_dlc *d) |
@@ -1674,11 +1667,18 @@ drop: | |||
1674 | return 0; | 1667 | return 0; |
1675 | } | 1668 | } |
1676 | 1669 | ||
1677 | static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) | 1670 | static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s, |
1671 | struct sk_buff *skb) | ||
1678 | { | 1672 | { |
1679 | struct rfcomm_hdr *hdr = (void *) skb->data; | 1673 | struct rfcomm_hdr *hdr = (void *) skb->data; |
1680 | u8 type, dlci, fcs; | 1674 | u8 type, dlci, fcs; |
1681 | 1675 | ||
1676 | if (!s) { | ||
1677 | /* no session, so free socket data */ | ||
1678 | kfree_skb(skb); | ||
1679 | return s; | ||
1680 | } | ||
1681 | |||
1682 | dlci = __get_dlci(hdr->addr); | 1682 | dlci = __get_dlci(hdr->addr); |
1683 | type = __get_type(hdr->ctrl); | 1683 | type = __get_type(hdr->ctrl); |
1684 | 1684 | ||
@@ -1689,7 +1689,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) | |||
1689 | if (__check_fcs(skb->data, type, fcs)) { | 1689 | if (__check_fcs(skb->data, type, fcs)) { |
1690 | BT_ERR("bad checksum in packet"); | 1690 | BT_ERR("bad checksum in packet"); |
1691 | kfree_skb(skb); | 1691 | kfree_skb(skb); |
1692 | return -EILSEQ; | 1692 | return s; |
1693 | } | 1693 | } |
1694 | 1694 | ||
1695 | if (__test_ea(hdr->len)) | 1695 | if (__test_ea(hdr->len)) |
@@ -1705,22 +1705,23 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) | |||
1705 | 1705 | ||
1706 | case RFCOMM_DISC: | 1706 | case RFCOMM_DISC: |
1707 | if (__test_pf(hdr->ctrl)) | 1707 | if (__test_pf(hdr->ctrl)) |
1708 | rfcomm_recv_disc(s, dlci); | 1708 | s = rfcomm_recv_disc(s, dlci); |
1709 | break; | 1709 | break; |
1710 | 1710 | ||
1711 | case RFCOMM_UA: | 1711 | case RFCOMM_UA: |
1712 | if (__test_pf(hdr->ctrl)) | 1712 | if (__test_pf(hdr->ctrl)) |
1713 | rfcomm_recv_ua(s, dlci); | 1713 | s = rfcomm_recv_ua(s, dlci); |
1714 | break; | 1714 | break; |
1715 | 1715 | ||
1716 | case RFCOMM_DM: | 1716 | case RFCOMM_DM: |
1717 | rfcomm_recv_dm(s, dlci); | 1717 | s = rfcomm_recv_dm(s, dlci); |
1718 | break; | 1718 | break; |
1719 | 1719 | ||
1720 | case RFCOMM_UIH: | 1720 | case RFCOMM_UIH: |
1721 | if (dlci) | 1721 | if (dlci) { |
1722 | return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb); | 1722 | rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb); |
1723 | 1723 | return s; | |
1724 | } | ||
1724 | rfcomm_recv_mcc(s, skb); | 1725 | rfcomm_recv_mcc(s, skb); |
1725 | break; | 1726 | break; |
1726 | 1727 | ||
@@ -1729,7 +1730,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) | |||
1729 | break; | 1730 | break; |
1730 | } | 1731 | } |
1731 | kfree_skb(skb); | 1732 | kfree_skb(skb); |
1732 | return 0; | 1733 | return s; |
1733 | } | 1734 | } |
1734 | 1735 | ||
1735 | /* ---- Connection and data processing ---- */ | 1736 | /* ---- Connection and data processing ---- */ |
@@ -1866,7 +1867,7 @@ static void rfcomm_process_dlcs(struct rfcomm_session *s) | |||
1866 | } | 1867 | } |
1867 | } | 1868 | } |
1868 | 1869 | ||
1869 | static void rfcomm_process_rx(struct rfcomm_session *s) | 1870 | static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s) |
1870 | { | 1871 | { |
1871 | struct socket *sock = s->sock; | 1872 | struct socket *sock = s->sock; |
1872 | struct sock *sk = sock->sk; | 1873 | struct sock *sk = sock->sk; |
@@ -1878,17 +1879,20 @@ static void rfcomm_process_rx(struct rfcomm_session *s) | |||
1878 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | 1879 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { |
1879 | skb_orphan(skb); | 1880 | skb_orphan(skb); |
1880 | if (!skb_linearize(skb)) | 1881 | if (!skb_linearize(skb)) |
1881 | rfcomm_recv_frame(s, skb); | 1882 | s = rfcomm_recv_frame(s, skb); |
1882 | else | 1883 | else |
1883 | kfree_skb(skb); | 1884 | kfree_skb(skb); |
1884 | } | 1885 | } |
1885 | 1886 | ||
1886 | if (sk->sk_state == BT_CLOSED) { | 1887 | if (s && (sk->sk_state == BT_CLOSED)) { |
1887 | if (!s->initiator) | 1888 | if (!s->initiator) |
1888 | rfcomm_session_put(s); | 1889 | s = rfcomm_session_put(s); |
1889 | 1890 | ||
1890 | rfcomm_session_close(s, sk->sk_err); | 1891 | if (s) |
1892 | s = rfcomm_session_close(s, sk->sk_err); | ||
1891 | } | 1893 | } |
1894 | |||
1895 | return s; | ||
1892 | } | 1896 | } |
1893 | 1897 | ||
1894 | static void rfcomm_accept_connection(struct rfcomm_session *s) | 1898 | static void rfcomm_accept_connection(struct rfcomm_session *s) |
@@ -1925,7 +1929,7 @@ static void rfcomm_accept_connection(struct rfcomm_session *s) | |||
1925 | sock_release(nsock); | 1929 | sock_release(nsock); |
1926 | } | 1930 | } |
1927 | 1931 | ||
1928 | static void rfcomm_check_connection(struct rfcomm_session *s) | 1932 | static struct rfcomm_session *rfcomm_check_connection(struct rfcomm_session *s) |
1929 | { | 1933 | { |
1930 | struct sock *sk = s->sock->sk; | 1934 | struct sock *sk = s->sock->sk; |
1931 | 1935 | ||
@@ -1944,9 +1948,10 @@ static void rfcomm_check_connection(struct rfcomm_session *s) | |||
1944 | 1948 | ||
1945 | case BT_CLOSED: | 1949 | case BT_CLOSED: |
1946 | s->state = BT_CLOSED; | 1950 | s->state = BT_CLOSED; |
1947 | rfcomm_session_close(s, sk->sk_err); | 1951 | s = rfcomm_session_close(s, sk->sk_err); |
1948 | break; | 1952 | break; |
1949 | } | 1953 | } |
1954 | return s; | ||
1950 | } | 1955 | } |
1951 | 1956 | ||
1952 | static void rfcomm_process_sessions(void) | 1957 | static void rfcomm_process_sessions(void) |
@@ -1975,15 +1980,16 @@ static void rfcomm_process_sessions(void) | |||
1975 | 1980 | ||
1976 | switch (s->state) { | 1981 | switch (s->state) { |
1977 | case BT_BOUND: | 1982 | case BT_BOUND: |
1978 | rfcomm_check_connection(s); | 1983 | s = rfcomm_check_connection(s); |
1979 | break; | 1984 | break; |
1980 | 1985 | ||
1981 | default: | 1986 | default: |
1982 | rfcomm_process_rx(s); | 1987 | s = rfcomm_process_rx(s); |
1983 | break; | 1988 | break; |
1984 | } | 1989 | } |
1985 | 1990 | ||
1986 | rfcomm_process_dlcs(s); | 1991 | if (s) |
1992 | rfcomm_process_dlcs(s); | ||
1987 | 1993 | ||
1988 | rfcomm_session_put(s); | 1994 | rfcomm_session_put(s); |
1989 | } | 1995 | } |