Re: capget() overflows buffers.

From: Chris Wright
Date: Fri May 23 2008 - 14:34:57 EST


* Andrew G. Morgan (morgan@xxxxxxxxxx) wrote:
> diff --git a/include/linux/capability.h b/include/linux/capability.h
> index f4ea0dd..f88b4db 100644
> --- a/include/linux/capability.h
> +++ b/include/linux/capability.h
> @@ -34,9 +34,6 @@ struct task_struct;
> #define _LINUX_CAPABILITY_VERSION_2 0x20071026
> #define _LINUX_CAPABILITY_U32S_2 2
>
> -#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2
> -#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2
> -
> typedef struct __user_cap_header_struct {
> __u32 version;
> int pid;
> @@ -77,10 +74,23 @@ struct vfs_cap_data {
> } data[VFS_CAP_U32];
> };
>
> -#ifdef __KERNEL__
> +#ifndef __KERNEL__
> +
> +/*
> + * Backwardly compatible definition for source code - trapped in a
> + * 32-bit world. If you find you need this, please consider using
> + * libcap to untrap yourself...
> + */
> +#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
> +#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1

I'm sure you're painfully aware, but this will need some change
to libcap as well (to let it handle 64bit caps again).

That's what I meant earlier by "And use another mechanism to
signal the availability of 64bit caps."

All looks good. I think we need to issue some warnings, because
at least Fedora 9 and openSUSE 11 are/will be 2.6.25 based.

Something like this:


--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -31,9 +31,13 @@ struct task_struct;
#define _LINUX_CAPABILITY_VERSION_1 0x19980330
#define _LINUX_CAPABILITY_U32S_1 1

+/* v2 should be considered broken */
#define _LINUX_CAPABILITY_VERSION_2 0x20071026
#define _LINUX_CAPABILITY_U32S_2 2

+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#define _LINUX_CAPABILITY_U32S_3 2
+
typedef struct __user_cap_header_struct {
__u32 version;
int pid;
@@ -86,8 +90,8 @@ struct vfs_cap_data {

#else

-#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2
-#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2
+#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3
+#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3

typedef struct kernel_cap_struct {
__u32 cap[_KERNEL_CAPABILITY_U32S];
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -39,6 +39,19 @@ EXPORT_SYMBOL(__cap_init_eff_set);
* http://www.kernel.org/pub/linux/libs/security/linux-privs/
*/

+static void warn_broken_capability_use(void)
+{
+ static int warned;
+ if (!warned) {
+ char name[sizeof(current->comm)];
+
+ printk(KERN_INFO "warning: `%s' uses a capabilities version"
+ " which could be broken if it is not using libcap.\n",
+ get_task_comm(name, current));
+ warned = 1;
+ }
+}
+
static void warn_legacy_capability_use(void)
{
static int warned;
@@ -85,8 +98,12 @@ asmlinkage long sys_capget(cap_user_head
tocopy = _LINUX_CAPABILITY_U32S_1;
break;
case _LINUX_CAPABILITY_VERSION_2:
+ warn_broken_capability_use();
tocopy = _LINUX_CAPABILITY_U32S_2;
break;
+ case _LINUX_CAPABILITY_VERSION_3:
+ tocopy = _LINUX_CAPABILITY_U32S_3;
+ break;
default:
if (put_user(_KERNEL_CAPABILITY_VERSION, &header->version))
return -EFAULT;
@@ -257,8 +274,12 @@ asmlinkage long sys_capset(cap_user_head
tocopy = _LINUX_CAPABILITY_U32S_1;
break;
case _LINUX_CAPABILITY_VERSION_2:
+ warn_broken_capability_use();
tocopy = _LINUX_CAPABILITY_U32S_2;
break;
+ case _LINUX_CAPABILITY_VERSION_3:
+ tocopy = _LINUX_CAPABILITY_U32S_3;
+ break;
default:
if (put_user(_KERNEL_CAPABILITY_VERSION, &header->version))
return -EFAULT;

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/