diff options
author | Eric Paris <eparis@redhat.com> | 2008-11-11 05:48:10 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-11 05:48:10 -0500 |
commit | c0b004413a46a0a5744e6d2b85220fe9d2c33d48 (patch) | |
tree | f66ee9e4cf14ce961e42a9dd356927478bab4574 /security/commoncap.c | |
parent | 9d36be76c55ad2c2bb29683b752b0d9ad2e4eeef (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>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r-- | security/commoncap.c | 129 |
1 files changed, 71 insertions, 58 deletions
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 | ||
205 | static inline int cap_from_disk(struct vfs_cap_data *caps, | 205 | static 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 | |||
243 | int 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 | ||
310 | out: | 323 | out: |
311 | dput(dentry); | 324 | dput(dentry); |