diff options
author | James Morris <james.l.morris@oracle.com> | 2017-12-11 01:01:08 -0500 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2017-12-11 01:01:08 -0500 |
commit | d21bd6898336a7892914d308d5e0868f0b863571 (patch) | |
tree | f5f756c25348b5a6c1ce9ddbaa7d1ecd1bef40b0 /security/selinux/hooks.c | |
parent | 34d8751fd4ffa34e85ee7e85d34168b3f3f62b42 (diff) | |
parent | 50c4c4e268a2d7a3e58ebb698ac74da0de40ae36 (diff) |
Sync to v4.15-rc3 for security subsystem developers to work against.
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 215 |
1 files changed, 183 insertions, 32 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f5d304736852..8644d864e3c1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -85,6 +85,7 @@ | |||
85 | #include <linux/export.h> | 85 | #include <linux/export.h> |
86 | #include <linux/msg.h> | 86 | #include <linux/msg.h> |
87 | #include <linux/shm.h> | 87 | #include <linux/shm.h> |
88 | #include <linux/bpf.h> | ||
88 | 89 | ||
89 | #include "avc.h" | 90 | #include "avc.h" |
90 | #include "objsec.h" | 91 | #include "objsec.h" |
@@ -1814,6 +1815,10 @@ static inline int file_path_has_perm(const struct cred *cred, | |||
1814 | return inode_has_perm(cred, file_inode(file), av, &ad); | 1815 | return inode_has_perm(cred, file_inode(file), av, &ad); |
1815 | } | 1816 | } |
1816 | 1817 | ||
1818 | #ifdef CONFIG_BPF_SYSCALL | ||
1819 | static int bpf_fd_pass(struct file *file, u32 sid); | ||
1820 | #endif | ||
1821 | |||
1817 | /* Check whether a task can use an open file descriptor to | 1822 | /* Check whether a task can use an open file descriptor to |
1818 | access an inode in a given way. Check access to the | 1823 | access an inode in a given way. Check access to the |
1819 | descriptor itself, and then use dentry_has_perm to | 1824 | descriptor itself, and then use dentry_has_perm to |
@@ -1844,6 +1849,12 @@ static int file_has_perm(const struct cred *cred, | |||
1844 | goto out; | 1849 | goto out; |
1845 | } | 1850 | } |
1846 | 1851 | ||
1852 | #ifdef CONFIG_BPF_SYSCALL | ||
1853 | rc = bpf_fd_pass(file, cred_sid(cred)); | ||
1854 | if (rc) | ||
1855 | return rc; | ||
1856 | #endif | ||
1857 | |||
1847 | /* av is zero if only checking access to the descriptor. */ | 1858 | /* av is zero if only checking access to the descriptor. */ |
1848 | rc = 0; | 1859 | rc = 0; |
1849 | if (av) | 1860 | if (av) |
@@ -2164,6 +2175,12 @@ static int selinux_binder_transfer_file(struct task_struct *from, | |||
2164 | return rc; | 2175 | return rc; |
2165 | } | 2176 | } |
2166 | 2177 | ||
2178 | #ifdef CONFIG_BPF_SYSCALL | ||
2179 | rc = bpf_fd_pass(file, sid); | ||
2180 | if (rc) | ||
2181 | return rc; | ||
2182 | #endif | ||
2183 | |||
2167 | if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) | 2184 | if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) |
2168 | return 0; | 2185 | return 0; |
2169 | 2186 | ||
@@ -2918,13 +2935,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2918 | { | 2935 | { |
2919 | const struct task_security_struct *tsec = current_security(); | 2936 | const struct task_security_struct *tsec = current_security(); |
2920 | struct superblock_security_struct *sbsec; | 2937 | struct superblock_security_struct *sbsec; |
2921 | u32 sid, newsid, clen; | 2938 | u32 newsid, clen; |
2922 | int rc; | 2939 | int rc; |
2923 | char *context; | 2940 | char *context; |
2924 | 2941 | ||
2925 | sbsec = dir->i_sb->s_security; | 2942 | sbsec = dir->i_sb->s_security; |
2926 | 2943 | ||
2927 | sid = tsec->sid; | ||
2928 | newsid = tsec->create_sid; | 2944 | newsid = tsec->create_sid; |
2929 | 2945 | ||
2930 | rc = selinux_determine_inode_label(current_security(), | 2946 | rc = selinux_determine_inode_label(current_security(), |
@@ -3124,27 +3140,6 @@ static int selinux_inode_getattr(const struct path *path) | |||
3124 | return path_has_perm(current_cred(), path, FILE__GETATTR); | 3140 | return path_has_perm(current_cred(), path, FILE__GETATTR); |
3125 | } | 3141 | } |
3126 | 3142 | ||
3127 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | ||
3128 | { | ||
3129 | const struct cred *cred = current_cred(); | ||
3130 | |||
3131 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | ||
3132 | sizeof XATTR_SECURITY_PREFIX - 1)) { | ||
3133 | if (!strcmp(name, XATTR_NAME_CAPS)) { | ||
3134 | if (!capable(CAP_SETFCAP)) | ||
3135 | return -EPERM; | ||
3136 | } else if (!capable(CAP_SYS_ADMIN)) { | ||
3137 | /* A different attribute in the security namespace. | ||
3138 | Restrict to administrator. */ | ||
3139 | return -EPERM; | ||
3140 | } | ||
3141 | } | ||
3142 | |||
3143 | /* Not an attribute we recognize, so just check the | ||
3144 | ordinary setattr permission. */ | ||
3145 | return dentry_has_perm(cred, dentry, FILE__SETATTR); | ||
3146 | } | ||
3147 | |||
3148 | static bool has_cap_mac_admin(bool audit) | 3143 | static bool has_cap_mac_admin(bool audit) |
3149 | { | 3144 | { |
3150 | const struct cred *cred = current_cred(); | 3145 | const struct cred *cred = current_cred(); |
@@ -3167,8 +3162,15 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
3167 | u32 newsid, sid = current_sid(); | 3162 | u32 newsid, sid = current_sid(); |
3168 | int rc = 0; | 3163 | int rc = 0; |
3169 | 3164 | ||
3170 | if (strcmp(name, XATTR_NAME_SELINUX)) | 3165 | if (strcmp(name, XATTR_NAME_SELINUX)) { |
3171 | return selinux_inode_setotherxattr(dentry, name); | 3166 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
3167 | if (rc) | ||
3168 | return rc; | ||
3169 | |||
3170 | /* Not an attribute we recognize, so just check the | ||
3171 | ordinary setattr permission. */ | ||
3172 | return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); | ||
3173 | } | ||
3172 | 3174 | ||
3173 | sbsec = inode->i_sb->s_security; | 3175 | sbsec = inode->i_sb->s_security; |
3174 | if (!(sbsec->flags & SBLABEL_MNT)) | 3176 | if (!(sbsec->flags & SBLABEL_MNT)) |
@@ -3191,18 +3193,17 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
3191 | if (!has_cap_mac_admin(true)) { | 3193 | if (!has_cap_mac_admin(true)) { |
3192 | struct audit_buffer *ab; | 3194 | struct audit_buffer *ab; |
3193 | size_t audit_size; | 3195 | size_t audit_size; |
3194 | const char *str; | ||
3195 | 3196 | ||
3196 | /* We strip a nul only if it is at the end, otherwise the | 3197 | /* We strip a nul only if it is at the end, otherwise the |
3197 | * context contains a nul and we should audit that */ | 3198 | * context contains a nul and we should audit that */ |
3198 | if (value) { | 3199 | if (value) { |
3199 | str = value; | 3200 | const char *str = value; |
3201 | |||
3200 | if (str[size - 1] == '\0') | 3202 | if (str[size - 1] == '\0') |
3201 | audit_size = size - 1; | 3203 | audit_size = size - 1; |
3202 | else | 3204 | else |
3203 | audit_size = size; | 3205 | audit_size = size; |
3204 | } else { | 3206 | } else { |
3205 | str = ""; | ||
3206 | audit_size = 0; | 3207 | audit_size = 0; |
3207 | } | 3208 | } |
3208 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); | 3209 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); |
@@ -3282,8 +3283,15 @@ static int selinux_inode_listxattr(struct dentry *dentry) | |||
3282 | 3283 | ||
3283 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) | 3284 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
3284 | { | 3285 | { |
3285 | if (strcmp(name, XATTR_NAME_SELINUX)) | 3286 | if (strcmp(name, XATTR_NAME_SELINUX)) { |
3286 | return selinux_inode_setotherxattr(dentry, name); | 3287 | int rc = cap_inode_removexattr(dentry, name); |
3288 | if (rc) | ||
3289 | return rc; | ||
3290 | |||
3291 | /* Not an attribute we recognize, so just check the | ||
3292 | ordinary setattr permission. */ | ||
3293 | return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); | ||
3294 | } | ||
3287 | 3295 | ||
3288 | /* No one is allowed to remove a SELinux security label. | 3296 | /* No one is allowed to remove a SELinux security label. |
3289 | You can change the label, but all data must be labeled. */ | 3297 | You can change the label, but all data must be labeled. */ |
@@ -3978,8 +3986,8 @@ static int selinux_task_getioprio(struct task_struct *p) | |||
3978 | PROCESS__GETSCHED, NULL); | 3986 | PROCESS__GETSCHED, NULL); |
3979 | } | 3987 | } |
3980 | 3988 | ||
3981 | int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, | 3989 | static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, |
3982 | unsigned int flags) | 3990 | unsigned int flags) |
3983 | { | 3991 | { |
3984 | u32 av = 0; | 3992 | u32 av = 0; |
3985 | 3993 | ||
@@ -6252,6 +6260,139 @@ static void selinux_ib_free_security(void *ib_sec) | |||
6252 | } | 6260 | } |
6253 | #endif | 6261 | #endif |
6254 | 6262 | ||
6263 | #ifdef CONFIG_BPF_SYSCALL | ||
6264 | static int selinux_bpf(int cmd, union bpf_attr *attr, | ||
6265 | unsigned int size) | ||
6266 | { | ||
6267 | u32 sid = current_sid(); | ||
6268 | int ret; | ||
6269 | |||
6270 | switch (cmd) { | ||
6271 | case BPF_MAP_CREATE: | ||
6272 | ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, | ||
6273 | NULL); | ||
6274 | break; | ||
6275 | case BPF_PROG_LOAD: | ||
6276 | ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, | ||
6277 | NULL); | ||
6278 | break; | ||
6279 | default: | ||
6280 | ret = 0; | ||
6281 | break; | ||
6282 | } | ||
6283 | |||
6284 | return ret; | ||
6285 | } | ||
6286 | |||
6287 | static u32 bpf_map_fmode_to_av(fmode_t fmode) | ||
6288 | { | ||
6289 | u32 av = 0; | ||
6290 | |||
6291 | if (fmode & FMODE_READ) | ||
6292 | av |= BPF__MAP_READ; | ||
6293 | if (fmode & FMODE_WRITE) | ||
6294 | av |= BPF__MAP_WRITE; | ||
6295 | return av; | ||
6296 | } | ||
6297 | |||
6298 | /* This function will check the file pass through unix socket or binder to see | ||
6299 | * if it is a bpf related object. And apply correspinding checks on the bpf | ||
6300 | * object based on the type. The bpf maps and programs, not like other files and | ||
6301 | * socket, are using a shared anonymous inode inside the kernel as their inode. | ||
6302 | * So checking that inode cannot identify if the process have privilege to | ||
6303 | * access the bpf object and that's why we have to add this additional check in | ||
6304 | * selinux_file_receive and selinux_binder_transfer_files. | ||
6305 | */ | ||
6306 | static int bpf_fd_pass(struct file *file, u32 sid) | ||
6307 | { | ||
6308 | struct bpf_security_struct *bpfsec; | ||
6309 | struct bpf_prog *prog; | ||
6310 | struct bpf_map *map; | ||
6311 | int ret; | ||
6312 | |||
6313 | if (file->f_op == &bpf_map_fops) { | ||
6314 | map = file->private_data; | ||
6315 | bpfsec = map->security; | ||
6316 | ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6317 | bpf_map_fmode_to_av(file->f_mode), NULL); | ||
6318 | if (ret) | ||
6319 | return ret; | ||
6320 | } else if (file->f_op == &bpf_prog_fops) { | ||
6321 | prog = file->private_data; | ||
6322 | bpfsec = prog->aux->security; | ||
6323 | ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6324 | BPF__PROG_RUN, NULL); | ||
6325 | if (ret) | ||
6326 | return ret; | ||
6327 | } | ||
6328 | return 0; | ||
6329 | } | ||
6330 | |||
6331 | static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) | ||
6332 | { | ||
6333 | u32 sid = current_sid(); | ||
6334 | struct bpf_security_struct *bpfsec; | ||
6335 | |||
6336 | bpfsec = map->security; | ||
6337 | return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6338 | bpf_map_fmode_to_av(fmode), NULL); | ||
6339 | } | ||
6340 | |||
6341 | static int selinux_bpf_prog(struct bpf_prog *prog) | ||
6342 | { | ||
6343 | u32 sid = current_sid(); | ||
6344 | struct bpf_security_struct *bpfsec; | ||
6345 | |||
6346 | bpfsec = prog->aux->security; | ||
6347 | return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6348 | BPF__PROG_RUN, NULL); | ||
6349 | } | ||
6350 | |||
6351 | static int selinux_bpf_map_alloc(struct bpf_map *map) | ||
6352 | { | ||
6353 | struct bpf_security_struct *bpfsec; | ||
6354 | |||
6355 | bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); | ||
6356 | if (!bpfsec) | ||
6357 | return -ENOMEM; | ||
6358 | |||
6359 | bpfsec->sid = current_sid(); | ||
6360 | map->security = bpfsec; | ||
6361 | |||
6362 | return 0; | ||
6363 | } | ||
6364 | |||
6365 | static void selinux_bpf_map_free(struct bpf_map *map) | ||
6366 | { | ||
6367 | struct bpf_security_struct *bpfsec = map->security; | ||
6368 | |||
6369 | map->security = NULL; | ||
6370 | kfree(bpfsec); | ||
6371 | } | ||
6372 | |||
6373 | static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) | ||
6374 | { | ||
6375 | struct bpf_security_struct *bpfsec; | ||
6376 | |||
6377 | bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); | ||
6378 | if (!bpfsec) | ||
6379 | return -ENOMEM; | ||
6380 | |||
6381 | bpfsec->sid = current_sid(); | ||
6382 | aux->security = bpfsec; | ||
6383 | |||
6384 | return 0; | ||
6385 | } | ||
6386 | |||
6387 | static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) | ||
6388 | { | ||
6389 | struct bpf_security_struct *bpfsec = aux->security; | ||
6390 | |||
6391 | aux->security = NULL; | ||
6392 | kfree(bpfsec); | ||
6393 | } | ||
6394 | #endif | ||
6395 | |||
6255 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | 6396 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { |
6256 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), | 6397 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), |
6257 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), | 6398 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), |
@@ -6471,6 +6612,16 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6471 | LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match), | 6612 | LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match), |
6472 | LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free), | 6613 | LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free), |
6473 | #endif | 6614 | #endif |
6615 | |||
6616 | #ifdef CONFIG_BPF_SYSCALL | ||
6617 | LSM_HOOK_INIT(bpf, selinux_bpf), | ||
6618 | LSM_HOOK_INIT(bpf_map, selinux_bpf_map), | ||
6619 | LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), | ||
6620 | LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), | ||
6621 | LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), | ||
6622 | LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), | ||
6623 | LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), | ||
6624 | #endif | ||
6474 | }; | 6625 | }; |
6475 | 6626 | ||
6476 | static __init int selinux_init(void) | 6627 | static __init int selinux_init(void) |