Commit 321fe6f8 authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] Use id to ptr translation service in lib/idr.c to assign and

validate ids of associations.

This patch avoids the use of virt_addr_valid() to validate the address
of associations passed by the user. Currently the address of an
association is used as its id. virt_addr_valid doesn't work as
expected when PAGEALLOC debugging is enabled.
parent 8843177d
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 Intel Corp.
......@@ -78,6 +78,7 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#include <linux/idr.h>
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/ipv6.h>
......@@ -223,24 +224,6 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
#define SCTP_DEC_STATS(field) SNMP_DEC_STATS(sctp_statistics, field)
/* Determine if this is a valid kernel address. */
static inline int sctp_is_valid_kaddr(unsigned long addr)
{
struct page *page;
/* Make sure the address is not in the user address space. */
if (addr < PAGE_OFFSET)
return 0;
page = virt_to_page(addr);
/* Is this page valid? */
if (!virt_addr_valid(addr) || PageReserved(page))
return 0;
return 1;
}
#endif /* !TEST_FRAME */
......@@ -357,7 +340,7 @@ static inline void sctp_v6_exit(void) { return; }
/* Map an association to an assoc_id. */
static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
{
return (sctp_assoc_t) asoc;
return (asoc?asoc->assoc_id:NULL);
}
/* Look up the association by its id. */
......@@ -519,6 +502,9 @@ extern struct proto sctp_prot;
extern struct proc_dir_entry *proc_net_sctp;
void sctp_put_port(struct sock *sk);
extern struct idr sctp_assocs_id;
extern spinlock_t sctp_assocs_id_lock;
/* Static inline functions. */
/* Convert from an IP version number to an Address Family symbol. */
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
......@@ -1282,11 +1282,8 @@ struct sctp_association {
/* Associations on the same socket. */
struct list_head asocs;
/* This is a signature that lets us know that this is a
* struct sctp_association data structure. Used for mapping an
* association id to an association.
*/
__u32 eyecatcher;
/* association id. */
sctp_assoc_t assoc_id;
/* This is our parent endpoint. */
struct sctp_endpoint *ep;
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
......@@ -276,7 +276,7 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->need_ecne = 0;
asoc->eyecatcher = SCTP_ASSOC_EYECATCHER;
asoc->assoc_id = (sctp_assoc_t)-1;
/* Assume that peer would support both address types unless we are
* told otherwise.
......@@ -360,8 +360,6 @@ void sctp_association_free(struct sctp_association *asoc)
sctp_transport_free(transport);
}
asoc->eyecatcher = 0;
/* Free any cached ASCONF_ACK chunk. */
if (asoc->addip_last_asconf_ack)
sctp_chunk_free(asoc->addip_last_asconf_ack);
......@@ -381,6 +379,12 @@ static void sctp_association_destroy(struct sctp_association *asoc)
sctp_endpoint_put(asoc->ep);
sock_put(asoc->base.sk);
if ((int)asoc->assoc_id != -1) {
spin_lock_bh(&sctp_assocs_id_lock);
idr_remove(&sctp_assocs_id, (int)asoc->assoc_id);
spin_unlock_bh(&sctp_assocs_id_lock);
}
if (asoc->base.malloced) {
kfree(asoc);
SCTP_DBG_OBJCNT_DEC(assoc);
......@@ -856,26 +860,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
return transport;
}
/* Is this a live association structure. */
int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc)
{
/* First, verify that this is a kernel address. */
if (!sctp_is_valid_kaddr((unsigned long) asoc))
return 0;
/* Verify that this _is_ an sctp_association
* data structure and if so, that the socket matches.
*/
if (SCTP_ASSOC_EYECATCHER != asoc->eyecatcher)
return 0;
if (asoc->base.sk != sk)
return 0;
/* The association is valid. */
return 1;
}
/* Do delayed input processing. This is scheduled by sctp_rcv(). */
static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
{
......@@ -891,6 +875,7 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
sk = asoc->base.sk;
inqueue = &asoc->base.inqueue;
sctp_association_hold(asoc);
while (NULL != (chunk = sctp_inq_pop(inqueue))) {
state = asoc->state;
subtype = chunk->chunk_hdr->type;
......@@ -913,14 +898,14 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
/* Check to see if the association is freed in response to
* the incoming chunk. If so, get out of the while loop.
*/
if (!sctp_assoc_valid(sk, asoc))
if (asoc->base.dead)
break;
/* If there is an error on chunk, discard this packet. */
if (error && chunk)
chunk->pdiscard = 1;
}
sctp_association_put(asoc);
}
/* This routine moves an association from its old sk to a new sk. */
......
......@@ -64,6 +64,9 @@ struct sctp_globals sctp_globals;
struct proc_dir_entry *proc_net_sctp;
DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
struct idr sctp_assocs_id;
spinlock_t sctp_assocs_id_lock = SPIN_LOCK_UNLOCKED;
/* This is the global socket data structure used for responding to
* the Out-of-the-blue (OOTB) packets. A control sock will be created
* for this socket at the initialization time.
......@@ -1049,6 +1052,9 @@ __init int sctp_init(void)
sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
/* Initialize handle used for association ids. */
idr_init(&sctp_assocs_id);
/* Size and allocate the association hash table.
* The methodology is similar to that of the tcp hash tables.
*/
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 Intel Corp.
......@@ -1817,10 +1817,23 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
/* Allocate storage for the negotiated streams if it is not a temporary * association.
*/
if (!asoc->temp) {
sctp_assoc_t assoc_id;
asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
asoc->c.sinit_num_ostreams, gfp);
if (!asoc->ssnmap)
goto nomem_ssnmap;
goto clean_up;
do {
if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
goto clean_up;
spin_lock_bh(&sctp_assocs_id_lock);
assoc_id = (sctp_assoc_t)idr_get_new(&sctp_assocs_id,
(void *)asoc);
spin_unlock_bh(&sctp_assocs_id_lock);
} while (unlikely((int)assoc_id == -1));
asoc->assoc_id = assoc_id;
}
/* ADDIP Section 4.1 ASCONF Chunk Procedures
......@@ -1836,7 +1849,6 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;
return 1;
nomem_ssnmap:
clean_up:
/* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
......
......@@ -135,8 +135,14 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
}
/* Otherwise this is a UDP-style socket. */
asoc = (struct sctp_association *)id;
if (!sctp_assoc_valid(sk, asoc))
if (!id || (id == (sctp_assoc_t)-1))
return NULL;
spin_lock_bh(&sctp_assocs_id_lock);
asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id);
spin_unlock_bh(&sctp_assocs_id_lock);
if (!asoc || (asoc->base.sk != sk) || asoc->base.dead)
return NULL;
return asoc;
......
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