dccp: allow probing of CCID-array length

This fixes a problem in the DCCP getsockopt() API: currently there is no way
for a user to a priori know the number of built-in CCIDs, other than trying
DCCP_SOCKOPT_AVAILABLE_CCIDS in a loop, incrementing the option length until
EINVAL is no longer returned.

This patch truncates the array to the user-provided length. No copy is made
when the length is <= 0.

Due to the length restriction in do_dccp_getsockopt() to sizeof(int), the
minimum array length remains 4, which is a reasonable default (only 3
CCIDs, CCID-2..4, are currently defined).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Gerrit Renker 2010-02-07 20:20:28 +00:00 коммит произвёл David S. Miller
Родитель 7455a76f17
Коммит 69a6a0b38a
2 изменённых файлов: 8 добавлений и 7 удалений

Просмотреть файл

@ -58,8 +58,10 @@ DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
size (application payload size) in bytes, see RFC 4340, section 14. size (application payload size) in bytes, see RFC 4340, section 14.
DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
supported by the endpoint (see include/linux/dccp.h for symbolic constants). supported by the endpoint. The option value is an array of type uint8_t whose
The caller needs to provide a sufficiently large (> 2) array of type uint8_t. size is passed as option length. The minimum array size is 4 elements, the
value returned in the optlen argument always reflects the true number of
built-in CCIDs.
DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
time, combining the operation of the next two socket options. This option is time, combining the operation of the next two socket options. This option is

Просмотреть файл

@ -63,14 +63,13 @@ int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
u8 *ccid_array, array_len; u8 *ccid_array, array_len;
int err = 0; int err = 0;
if (len < ARRAY_SIZE(ccids))
return -EINVAL;
if (ccid_get_builtin_ccids(&ccid_array, &array_len)) if (ccid_get_builtin_ccids(&ccid_array, &array_len))
return -ENOBUFS; return -ENOBUFS;
if (put_user(array_len, optlen) || if (put_user(array_len, optlen))
copy_to_user(optval, ccid_array, array_len)) err = -EFAULT;
else if (len > 0 && copy_to_user(optval, ccid_array,
len > array_len ? array_len : len))
err = -EFAULT; err = -EFAULT;
kfree(ccid_array); kfree(ccid_array);