Commit ca05a99a54db1db5bca72eccb5866d2a86f8517f

Authored by Andrew G. Morgan
Committed by Chris Wright
1 parent cc94bc37d5

capabilities: remain source compatible with 32-bit raw legacy capability support.

Source code out there hard-codes a notion of what the
_LINUX_CAPABILITY_VERSION #define means in terms of the semantics of the
raw capability system calls capget() and capset().  Its unfortunate, but
true.

Since the confusing header file has been in a released kernel, there is
software that is erroneously using 64-bit capabilities with the semantics
of 32-bit compatibilities.  These recently compiled programs may suffer
corruption of their memory when sys_getcap() overwrites more memory than
they are coded to expect, and the raising of added capabilities when using
sys_capset().

As such, this patch does a number of things to clean up the situation
for all. It

  1. forces the _LINUX_CAPABILITY_VERSION define to always retain its
     legacy value.

  2. adopts a new #define strategy for the kernel's internal
     implementation of the preferred magic.

  3. deprecates v2 capability magic in favor of a new (v3) magic
     number. The functionality of v3 is entirely equivalent to v2,
     the only difference being that the v2 magic causes the kernel
     to log a "deprecated" warning so the admin can find applications
     that may be using v2 inappropriately.

[User space code continues to be encouraged to use the libcap API which
protects the application from details like this.  libcap-2.10 is the first
to support v3 capabilities.]

Fixes issue reported in https://bugzilla.redhat.com/show_bug.cgi?id=447518.
Thanks to Bojan Smojver for the report.

[akpm@linux-foundation.org: s/depreciate/deprecate/g]
[akpm@linux-foundation.org: be robust about put_user size]
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
Cc: Serge E. Hallyn <serue@us.ibm.com>
Cc: Bojan Smojver <bojan@rexursive.com>
Cc: stable@kernel.org
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>

Showing 3 changed files with 95 additions and 47 deletions Side-by-side Diff

... ... @@ -288,7 +288,7 @@
288 288 seq_printf(m, "%s", header);
289 289 CAP_FOR_EACH_U32(__capi) {
290 290 seq_printf(m, "%08x",
291   - a->cap[(_LINUX_CAPABILITY_U32S-1) - __capi]);
  291 + a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]);
292 292 }
293 293 seq_printf(m, "\n");
294 294 }
include/linux/capability.h
... ... @@ -31,11 +31,11 @@
31 31 #define _LINUX_CAPABILITY_VERSION_1 0x19980330
32 32 #define _LINUX_CAPABILITY_U32S_1 1
33 33  
34   -#define _LINUX_CAPABILITY_VERSION_2 0x20071026
  34 +#define _LINUX_CAPABILITY_VERSION_2 0x20071026 /* deprecated - use v3 */
35 35 #define _LINUX_CAPABILITY_U32S_2 2
36 36  
37   -#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2
38   -#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2
  37 +#define _LINUX_CAPABILITY_VERSION_3 0x20080522
  38 +#define _LINUX_CAPABILITY_U32S_3 2
39 39  
40 40 typedef struct __user_cap_header_struct {
41 41 __u32 version;
42 42  
43 43  
... ... @@ -77,10 +77,23 @@
77 77 } data[VFS_CAP_U32];
78 78 };
79 79  
80   -#ifdef __KERNEL__
  80 +#ifndef __KERNEL__
81 81  
  82 +/*
  83 + * Backwardly compatible definition for source code - trapped in a
  84 + * 32-bit world. If you find you need this, please consider using
  85 + * libcap to untrap yourself...
  86 + */
  87 +#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
  88 +#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1
  89 +
  90 +#else
  91 +
  92 +#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3
  93 +#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3
  94 +
82 95 typedef struct kernel_cap_struct {
83   - __u32 cap[_LINUX_CAPABILITY_U32S];
  96 + __u32 cap[_KERNEL_CAPABILITY_U32S];
84 97 } kernel_cap_t;
85 98  
86 99 #define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
... ... @@ -351,7 +364,7 @@
351 364 */
352 365  
353 366 #define CAP_FOR_EACH_U32(__capi) \
354   - for (__capi = 0; __capi < _LINUX_CAPABILITY_U32S; ++__capi)
  367 + for (__capi = 0; __capi < _KERNEL_CAPABILITY_U32S; ++__capi)
355 368  
356 369 # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
357 370 | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
... ... @@ -361,7 +374,7 @@
361 374  
362 375 # define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
363 376  
364   -#if _LINUX_CAPABILITY_U32S != 2
  377 +#if _KERNEL_CAPABILITY_U32S != 2
365 378 # error Fix up hand-coded capability macro initializers
366 379 #else /* HAND-CODED capability initializers */
367 380  
... ... @@ -372,7 +385,7 @@
372 385 # define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), \
373 386 CAP_FS_MASK_B1 } })
374 387  
375   -#endif /* _LINUX_CAPABILITY_U32S != 2 */
  388 +#endif /* _KERNEL_CAPABILITY_U32S != 2 */
376 389  
377 390 #define CAP_INIT_INH_SET CAP_EMPTY_SET
378 391  
... ... @@ -53,6 +53,69 @@
53 53 }
54 54  
55 55 /*
  56 + * Version 2 capabilities worked fine, but the linux/capability.h file
  57 + * that accompanied their introduction encouraged their use without
  58 + * the necessary user-space source code changes. As such, we have
  59 + * created a version 3 with equivalent functionality to version 2, but
  60 + * with a header change to protect legacy source code from using
  61 + * version 2 when it wanted to use version 1. If your system has code
  62 + * that trips the following warning, it is using version 2 specific
  63 + * capabilities and may be doing so insecurely.
  64 + *
  65 + * The remedy is to either upgrade your version of libcap (to 2.10+,
  66 + * if the application is linked against it), or recompile your
  67 + * application with modern kernel headers and this warning will go
  68 + * away.
  69 + */
  70 +
  71 +static void warn_deprecated_v2(void)
  72 +{
  73 + static int warned;
  74 +
  75 + if (!warned) {
  76 + char name[sizeof(current->comm)];
  77 +
  78 + printk(KERN_INFO "warning: `%s' uses deprecated v2"
  79 + " capabilities in a way that may be insecure.\n",
  80 + get_task_comm(name, current));
  81 + warned = 1;
  82 + }
  83 +}
  84 +
  85 +/*
  86 + * Version check. Return the number of u32s in each capability flag
  87 + * array, or a negative value on error.
  88 + */
  89 +static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
  90 +{
  91 + __u32 version;
  92 +
  93 + if (get_user(version, &header->version))
  94 + return -EFAULT;
  95 +
  96 + switch (version) {
  97 + case _LINUX_CAPABILITY_VERSION_1:
  98 + warn_legacy_capability_use();
  99 + *tocopy = _LINUX_CAPABILITY_U32S_1;
  100 + break;
  101 + case _LINUX_CAPABILITY_VERSION_2:
  102 + warn_deprecated_v2();
  103 + /*
  104 + * fall through - v3 is otherwise equivalent to v2.
  105 + */
  106 + case _LINUX_CAPABILITY_VERSION_3:
  107 + *tocopy = _LINUX_CAPABILITY_U32S_3;
  108 + break;
  109 + default:
  110 + if (put_user((u32)_KERNEL_CAPABILITY_VERSION, &header->version))
  111 + return -EFAULT;
  112 + return -EINVAL;
  113 + }
  114 +
  115 + return 0;
  116 +}
  117 +
  118 +/*
56 119 * For sys_getproccap() and sys_setproccap(), any of the three
57 120 * capability set pointers may be NULL -- indicating that that set is
58 121 * uninteresting and/or not to be changed.
59 122  
60 123  
... ... @@ -71,28 +134,14 @@
71 134 {
72 135 int ret = 0;
73 136 pid_t pid;
74   - __u32 version;
75 137 struct task_struct *target;
76 138 unsigned tocopy;
77 139 kernel_cap_t pE, pI, pP;
78 140  
79   - if (get_user(version, &header->version))
80   - return -EFAULT;
  141 + ret = cap_validate_magic(header, &tocopy);
  142 + if (ret != 0)
  143 + return ret;
81 144  
82   - switch (version) {
83   - case _LINUX_CAPABILITY_VERSION_1:
84   - warn_legacy_capability_use();
85   - tocopy = _LINUX_CAPABILITY_U32S_1;
86   - break;
87   - case _LINUX_CAPABILITY_VERSION_2:
88   - tocopy = _LINUX_CAPABILITY_U32S_2;
89   - break;
90   - default:
91   - if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
92   - return -EFAULT;
93   - return -EINVAL;
94   - }
95   -
96 145 if (get_user(pid, &header->pid))
97 146 return -EFAULT;
98 147  
... ... @@ -118,7 +167,7 @@
118 167 spin_unlock(&task_capability_lock);
119 168  
120 169 if (!ret) {
121   - struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S];
  170 + struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
122 171 unsigned i;
123 172  
124 173 for (i = 0; i < tocopy; i++) {
... ... @@ -128,7 +177,7 @@
128 177 }
129 178  
130 179 /*
131   - * Note, in the case, tocopy < _LINUX_CAPABILITY_U32S,
  180 + * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S,
132 181 * we silently drop the upper capabilities here. This
133 182 * has the effect of making older libcap
134 183 * implementations implicitly drop upper capability
135 184  
136 185  
137 186  
... ... @@ -240,31 +289,17 @@
240 289 */
241 290 asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
242 291 {
243   - struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S];
  292 + struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
244 293 unsigned i, tocopy;
245 294 kernel_cap_t inheritable, permitted, effective;
246   - __u32 version;
247 295 struct task_struct *target;
248 296 int ret;
249 297 pid_t pid;
250 298  
251   - if (get_user(version, &header->version))
252   - return -EFAULT;
  299 + ret = cap_validate_magic(header, &tocopy);
  300 + if (ret != 0)
  301 + return ret;
253 302  
254   - switch (version) {
255   - case _LINUX_CAPABILITY_VERSION_1:
256   - warn_legacy_capability_use();
257   - tocopy = _LINUX_CAPABILITY_U32S_1;
258   - break;
259   - case _LINUX_CAPABILITY_VERSION_2:
260   - tocopy = _LINUX_CAPABILITY_U32S_2;
261   - break;
262   - default:
263   - if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
264   - return -EFAULT;
265   - return -EINVAL;
266   - }
267   -
268 303 if (get_user(pid, &header->pid))
269 304 return -EFAULT;
270 305  
... ... @@ -281,7 +316,7 @@
281 316 permitted.cap[i] = kdata[i].permitted;
282 317 inheritable.cap[i] = kdata[i].inheritable;
283 318 }
284   - while (i < _LINUX_CAPABILITY_U32S) {
  319 + while (i < _KERNEL_CAPABILITY_U32S) {
285 320 effective.cap[i] = 0;
286 321 permitted.cap[i] = 0;
287 322 inheritable.cap[i] = 0;