diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-07-10 02:17:14 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-07-10 02:17:14 -0400 |
| commit | 9e4144abf8a30ae221311368bbb10690ebdb4b76 (patch) | |
| tree | 032289d5b7d87976675c1a1a32d512a44d234fa2 /kernel/capability.c | |
| parent | e17ba73b0ee6c0f24393c48b455e0d8db761782c (diff) | |
| parent | 6329d3021bcfa9038621e6e917d98929421d8ec8 (diff) | |
Merge branch 'linus' into core/printk
Conflicts:
kernel/printk.c
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/capability.c')
| -rw-r--r-- | kernel/capability.c | 132 |
1 files changed, 94 insertions, 38 deletions
diff --git a/kernel/capability.c b/kernel/capability.c index 39e8193b41ea..901e0fdc3fff 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
| @@ -53,11 +53,95 @@ static void warn_legacy_capability_use(void) | |||
| 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 | * For sys_getproccap() and sys_setproccap(), any of the three | 119 | * For sys_getproccap() and sys_setproccap(), any of the three |
| 57 | * capability set pointers may be NULL -- indicating that that set is | 120 | * capability set pointers may be NULL -- indicating that that set is |
| 58 | * uninteresting and/or not to be changed. | 121 | * uninteresting and/or not to be changed. |
| 59 | */ | 122 | */ |
| 60 | 123 | ||
| 124 | /* | ||
| 125 | * Atomically modify the effective capabilities returning the original | ||
| 126 | * value. No permission check is performed here - it is assumed that the | ||
| 127 | * caller is permitted to set the desired effective capabilities. | ||
| 128 | */ | ||
| 129 | kernel_cap_t cap_set_effective(const kernel_cap_t pE_new) | ||
| 130 | { | ||
| 131 | kernel_cap_t pE_old; | ||
| 132 | |||
| 133 | spin_lock(&task_capability_lock); | ||
| 134 | |||
| 135 | pE_old = current->cap_effective; | ||
| 136 | current->cap_effective = pE_new; | ||
| 137 | |||
| 138 | spin_unlock(&task_capability_lock); | ||
| 139 | |||
| 140 | return pE_old; | ||
| 141 | } | ||
| 142 | |||
| 143 | EXPORT_SYMBOL(cap_set_effective); | ||
| 144 | |||
| 61 | /** | 145 | /** |
| 62 | * sys_capget - get the capabilities of a given process. | 146 | * sys_capget - get the capabilities of a given process. |
| 63 | * @header: pointer to struct that contains capability version and | 147 | * @header: pointer to struct that contains capability version and |
| @@ -71,27 +155,13 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) | |||
| 71 | { | 155 | { |
| 72 | int ret = 0; | 156 | int ret = 0; |
| 73 | pid_t pid; | 157 | pid_t pid; |
| 74 | __u32 version; | ||
| 75 | struct task_struct *target; | 158 | struct task_struct *target; |
| 76 | unsigned tocopy; | 159 | unsigned tocopy; |
| 77 | kernel_cap_t pE, pI, pP; | 160 | kernel_cap_t pE, pI, pP; |
| 78 | 161 | ||
| 79 | if (get_user(version, &header->version)) | 162 | ret = cap_validate_magic(header, &tocopy); |
| 80 | return -EFAULT; | 163 | if (ret != 0) |
| 81 | 164 | return ret; | |
| 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 | 165 | ||
| 96 | if (get_user(pid, &header->pid)) | 166 | if (get_user(pid, &header->pid)) |
| 97 | return -EFAULT; | 167 | return -EFAULT; |
| @@ -118,7 +188,7 @@ out: | |||
| 118 | spin_unlock(&task_capability_lock); | 188 | spin_unlock(&task_capability_lock); |
| 119 | 189 | ||
| 120 | if (!ret) { | 190 | if (!ret) { |
| 121 | struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S]; | 191 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; |
| 122 | unsigned i; | 192 | unsigned i; |
| 123 | 193 | ||
| 124 | for (i = 0; i < tocopy; i++) { | 194 | for (i = 0; i < tocopy; i++) { |
| @@ -128,7 +198,7 @@ out: | |||
| 128 | } | 198 | } |
| 129 | 199 | ||
| 130 | /* | 200 | /* |
| 131 | * Note, in the case, tocopy < _LINUX_CAPABILITY_U32S, | 201 | * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S, |
| 132 | * we silently drop the upper capabilities here. This | 202 | * we silently drop the upper capabilities here. This |
| 133 | * has the effect of making older libcap | 203 | * has the effect of making older libcap |
| 134 | * implementations implicitly drop upper capability | 204 | * implementations implicitly drop upper capability |
| @@ -240,30 +310,16 @@ static inline int cap_set_all(kernel_cap_t *effective, | |||
| 240 | */ | 310 | */ |
| 241 | asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | 311 | asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) |
| 242 | { | 312 | { |
| 243 | struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S]; | 313 | struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; |
| 244 | unsigned i, tocopy; | 314 | unsigned i, tocopy; |
| 245 | kernel_cap_t inheritable, permitted, effective; | 315 | kernel_cap_t inheritable, permitted, effective; |
| 246 | __u32 version; | ||
| 247 | struct task_struct *target; | 316 | struct task_struct *target; |
| 248 | int ret; | 317 | int ret; |
| 249 | pid_t pid; | 318 | pid_t pid; |
| 250 | 319 | ||
| 251 | if (get_user(version, &header->version)) | 320 | ret = cap_validate_magic(header, &tocopy); |
| 252 | return -EFAULT; | 321 | if (ret != 0) |
| 253 | 322 | return ret; | |
| 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 | 323 | ||
| 268 | if (get_user(pid, &header->pid)) | 324 | if (get_user(pid, &header->pid)) |
| 269 | return -EFAULT; | 325 | return -EFAULT; |
| @@ -281,7 +337,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) | |||
| 281 | permitted.cap[i] = kdata[i].permitted; | 337 | permitted.cap[i] = kdata[i].permitted; |
| 282 | inheritable.cap[i] = kdata[i].inheritable; | 338 | inheritable.cap[i] = kdata[i].inheritable; |
| 283 | } | 339 | } |
| 284 | while (i < _LINUX_CAPABILITY_U32S) { | 340 | while (i < _KERNEL_CAPABILITY_U32S) { |
| 285 | effective.cap[i] = 0; | 341 | effective.cap[i] = 0; |
| 286 | permitted.cap[i] = 0; | 342 | permitted.cap[i] = 0; |
| 287 | inheritable.cap[i] = 0; | 343 | inheritable.cap[i] = 0; |
