aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/capability.h7
-rw-r--r--security/commoncap.c129
2 files changed, 78 insertions, 58 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h
index b5750d0b96e0..d567af247ed8 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -99,6 +99,13 @@ typedef struct kernel_cap_struct {
99 __u32 cap[_KERNEL_CAPABILITY_U32S]; 99 __u32 cap[_KERNEL_CAPABILITY_U32S];
100} kernel_cap_t; 100} kernel_cap_t;
101 101
102/* exact same as vfs_cap_data but in cpu endian and always filled completely */
103struct cpu_vfs_cap_data {
104 __u32 magic_etc;
105 kernel_cap_t permitted;
106 kernel_cap_t inheritable;
107};
108
102#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct)) 109#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
103#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) 110#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
104 111
diff --git a/security/commoncap.c b/security/commoncap.c
index f88119cb2bc2..d7eff5797b91 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -202,17 +202,70 @@ int cap_inode_killpriv(struct dentry *dentry)
202 return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); 202 return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
203} 203}
204 204
205static inline int cap_from_disk(struct vfs_cap_data *caps, 205static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
206 struct linux_binprm *bprm, unsigned size) 206 struct linux_binprm *bprm)
207{ 207{
208 unsigned i;
209 int ret = 0;
210
211 if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
212 bprm->cap_effective = true;
213 else
214 bprm->cap_effective = false;
215
216 CAP_FOR_EACH_U32(i) {
217 __u32 permitted = caps->permitted.cap[i];
218 __u32 inheritable = caps->inheritable.cap[i];
219
220 /*
221 * pP' = (X & fP) | (pI & fI)
222 */
223 bprm->cap_post_exec_permitted.cap[i] =
224 (current->cap_bset.cap[i] & permitted) |
225 (current->cap_inheritable.cap[i] & inheritable);
226
227 if (permitted & ~bprm->cap_post_exec_permitted.cap[i]) {
228 /*
229 * insufficient to execute correctly
230 */
231 ret = -EPERM;
232 }
233 }
234
235 /*
236 * For legacy apps, with no internal support for recognizing they
237 * do not have enough capabilities, we return an error if they are
238 * missing some "forced" (aka file-permitted) capabilities.
239 */
240 return bprm->cap_effective ? ret : 0;
241}
242
243int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
244{
245 struct inode *inode = dentry->d_inode;
208 __u32 magic_etc; 246 __u32 magic_etc;
209 unsigned tocopy, i; 247 unsigned tocopy, i;
210 int ret; 248 int size;
249 struct vfs_cap_data caps;
250
251 memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
252
253 if (!inode || !inode->i_op || !inode->i_op->getxattr)
254 return -ENODATA;
255
256 size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
257 XATTR_CAPS_SZ);
258 if (size == -ENODATA || size == -EOPNOTSUPP) {
259 /* no data, that's ok */
260 return -ENODATA;
261 }
262 if (size < 0)
263 return size;
211 264
212 if (size < sizeof(magic_etc)) 265 if (size < sizeof(magic_etc))
213 return -EINVAL; 266 return -EINVAL;
214 267
215 magic_etc = le32_to_cpu(caps->magic_etc); 268 cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);
216 269
217 switch ((magic_etc & VFS_CAP_REVISION_MASK)) { 270 switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
218 case VFS_CAP_REVISION_1: 271 case VFS_CAP_REVISION_1:
@@ -229,46 +282,13 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
229 return -EINVAL; 282 return -EINVAL;
230 } 283 }
231 284
232 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
233 bprm->cap_effective = true;
234 } else {
235 bprm->cap_effective = false;
236 }
237
238 ret = 0;
239
240 CAP_FOR_EACH_U32(i) { 285 CAP_FOR_EACH_U32(i) {
241 __u32 value_cpu; 286 if (i >= tocopy)
242 287 break;
243 if (i >= tocopy) { 288 cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
244 /* 289 cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
245 * Legacy capability sets have no upper bits
246 */
247 bprm->cap_post_exec_permitted.cap[i] = 0;
248 continue;
249 }
250 /*
251 * pP' = (X & fP) | (pI & fI)
252 */
253 value_cpu = le32_to_cpu(caps->data[i].permitted);
254 bprm->cap_post_exec_permitted.cap[i] =
255 (current->cap_bset.cap[i] & value_cpu) |
256 (current->cap_inheritable.cap[i] &
257 le32_to_cpu(caps->data[i].inheritable));
258 if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
259 /*
260 * insufficient to execute correctly
261 */
262 ret = -EPERM;
263 }
264 } 290 }
265 291 return 0;
266 /*
267 * For legacy apps, with no internal support for recognizing they
268 * do not have enough capabilities, we return an error if they are
269 * missing some "forced" (aka file-permitted) capabilities.
270 */
271 return bprm->cap_effective ? ret : 0;
272} 292}
273 293
274/* Locate any VFS capabilities: */ 294/* Locate any VFS capabilities: */
@@ -276,8 +296,7 @@ static int get_file_caps(struct linux_binprm *bprm)
276{ 296{
277 struct dentry *dentry; 297 struct dentry *dentry;
278 int rc = 0; 298 int rc = 0;
279 struct vfs_cap_data vcaps; 299 struct cpu_vfs_cap_data vcaps;
280 struct inode *inode;
281 300
282 bprm_clear_caps(bprm); 301 bprm_clear_caps(bprm);
283 302
@@ -288,24 +307,18 @@ static int get_file_caps(struct linux_binprm *bprm)
288 return 0; 307 return 0;
289 308
290 dentry = dget(bprm->file->f_dentry); 309 dentry = dget(bprm->file->f_dentry);
291 inode = dentry->d_inode;
292 if (!inode->i_op || !inode->i_op->getxattr)
293 goto out;
294 310
295 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps, 311 rc = get_vfs_caps_from_disk(dentry, &vcaps);
296 XATTR_CAPS_SZ); 312 if (rc < 0) {
297 if (rc == -ENODATA || rc == -EOPNOTSUPP) { 313 if (rc == -EINVAL)
298 /* no data, that's ok */ 314 printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n",
299 rc = 0; 315 __func__, rc, bprm->filename);
316 else if (rc == -ENODATA)
317 rc = 0;
300 goto out; 318 goto out;
301 } 319 }
302 if (rc < 0)
303 goto out;
304 320
305 rc = cap_from_disk(&vcaps, bprm, rc); 321 rc = bprm_caps_from_vfs_caps(&vcaps, bprm);
306 if (rc == -EINVAL)
307 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
308 __func__, rc, bprm->filename);
309 322
310out: 323out:
311 dput(dentry); 324 dput(dentry);