aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2008-11-11 05:48:10 -0500
committerJames Morris <jmorris@namei.org>2008-11-11 05:48:10 -0500
commitc0b004413a46a0a5744e6d2b85220fe9d2c33d48 (patch)
treef66ee9e4cf14ce961e42a9dd356927478bab4574
parent9d36be76c55ad2c2bb29683b752b0d9ad2e4eeef (diff)
This patch add a generic cpu endian caps structure and externally available
functions which retrieve fcaps information from disk. This information is necessary so fcaps information can be collected and recorded by the audit system. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
-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);