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