diff options
-rw-r--r-- | Documentation/admin-guide/LSM/index.rst | 13 | ||||
-rw-r--r-- | fs/proc/base.c | 64 | ||||
-rw-r--r-- | fs/proc/internal.h | 1 | ||||
-rw-r--r-- | include/linux/security.h | 15 | ||||
-rw-r--r-- | security/security.c | 24 |
5 files changed, 96 insertions, 21 deletions
diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst index c980dfe9abf1..9842e21afd4a 100644 --- a/Documentation/admin-guide/LSM/index.rst +++ b/Documentation/admin-guide/LSM/index.rst | |||
@@ -17,9 +17,8 @@ MAC extensions, other extensions can be built using the LSM to provide | |||
17 | specific changes to system operation when these tweaks are not available | 17 | specific changes to system operation when these tweaks are not available |
18 | in the core functionality of Linux itself. | 18 | in the core functionality of Linux itself. |
19 | 19 | ||
20 | Without a specific LSM built into the kernel, the default LSM will be the | 20 | The Linux capabilities modules will always be included. This may be |
21 | Linux capabilities system. Most LSMs choose to extend the capabilities | 21 | followed by any number of "minor" modules and at most one "major" module. |
22 | system, building their checks on top of the defined capability hooks. | ||
23 | For more details on capabilities, see ``capabilities(7)`` in the Linux | 22 | For more details on capabilities, see ``capabilities(7)`` in the Linux |
24 | man-pages project. | 23 | man-pages project. |
25 | 24 | ||
@@ -30,6 +29,14 @@ order in which checks are made. The capability module will always | |||
30 | be first, followed by any "minor" modules (e.g. Yama) and then | 29 | be first, followed by any "minor" modules (e.g. Yama) and then |
31 | the one "major" module (e.g. SELinux) if there is one configured. | 30 | the one "major" module (e.g. SELinux) if there is one configured. |
32 | 31 | ||
32 | Process attributes associated with "major" security modules should | ||
33 | be accessed and maintained using the special files in ``/proc/.../attr``. | ||
34 | A security module may maintain a module specific subdirectory there, | ||
35 | named after the module. ``/proc/.../attr/smack`` is provided by the Smack | ||
36 | security module and contains all its special files. The files directly | ||
37 | in ``/proc/.../attr`` remain as legacy interfaces for modules that provide | ||
38 | subdirectories. | ||
39 | |||
33 | .. toctree:: | 40 | .. toctree:: |
34 | :maxdepth: 1 | 41 | :maxdepth: 1 |
35 | 42 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 633a63462573..c9d775fd24ef 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -140,9 +140,13 @@ struct pid_entry { | |||
140 | #define REG(NAME, MODE, fops) \ | 140 | #define REG(NAME, MODE, fops) \ |
141 | NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) | 141 | NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) |
142 | #define ONE(NAME, MODE, show) \ | 142 | #define ONE(NAME, MODE, show) \ |
143 | NOD(NAME, (S_IFREG|(MODE)), \ | 143 | NOD(NAME, (S_IFREG|(MODE)), \ |
144 | NULL, &proc_single_file_operations, \ | 144 | NULL, &proc_single_file_operations, \ |
145 | { .proc_show = show } ) | 145 | { .proc_show = show } ) |
146 | #define ATTR(LSM, NAME, MODE) \ | ||
147 | NOD(NAME, (S_IFREG|(MODE)), \ | ||
148 | NULL, &proc_pid_attr_operations, \ | ||
149 | { .lsm = LSM }) | ||
146 | 150 | ||
147 | /* | 151 | /* |
148 | * Count the number of hardlinks for the pid_entry table, excluding the . | 152 | * Count the number of hardlinks for the pid_entry table, excluding the . |
@@ -2525,7 +2529,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, | |||
2525 | if (!task) | 2529 | if (!task) |
2526 | return -ESRCH; | 2530 | return -ESRCH; |
2527 | 2531 | ||
2528 | length = security_getprocattr(task, | 2532 | length = security_getprocattr(task, PROC_I(inode)->op.lsm, |
2529 | (char*)file->f_path.dentry->d_name.name, | 2533 | (char*)file->f_path.dentry->d_name.name, |
2530 | &p); | 2534 | &p); |
2531 | put_task_struct(task); | 2535 | put_task_struct(task); |
@@ -2574,7 +2578,9 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, | |||
2574 | if (rv < 0) | 2578 | if (rv < 0) |
2575 | goto out_free; | 2579 | goto out_free; |
2576 | 2580 | ||
2577 | rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count); | 2581 | rv = security_setprocattr(PROC_I(inode)->op.lsm, |
2582 | file->f_path.dentry->d_name.name, page, | ||
2583 | count); | ||
2578 | mutex_unlock(¤t->signal->cred_guard_mutex); | 2584 | mutex_unlock(¤t->signal->cred_guard_mutex); |
2579 | out_free: | 2585 | out_free: |
2580 | kfree(page); | 2586 | kfree(page); |
@@ -2588,13 +2594,53 @@ static const struct file_operations proc_pid_attr_operations = { | |||
2588 | .llseek = generic_file_llseek, | 2594 | .llseek = generic_file_llseek, |
2589 | }; | 2595 | }; |
2590 | 2596 | ||
2597 | #define LSM_DIR_OPS(LSM) \ | ||
2598 | static int proc_##LSM##_attr_dir_iterate(struct file *filp, \ | ||
2599 | struct dir_context *ctx) \ | ||
2600 | { \ | ||
2601 | return proc_pident_readdir(filp, ctx, \ | ||
2602 | LSM##_attr_dir_stuff, \ | ||
2603 | ARRAY_SIZE(LSM##_attr_dir_stuff)); \ | ||
2604 | } \ | ||
2605 | \ | ||
2606 | static const struct file_operations proc_##LSM##_attr_dir_ops = { \ | ||
2607 | .read = generic_read_dir, \ | ||
2608 | .iterate = proc_##LSM##_attr_dir_iterate, \ | ||
2609 | .llseek = default_llseek, \ | ||
2610 | }; \ | ||
2611 | \ | ||
2612 | static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \ | ||
2613 | struct dentry *dentry, unsigned int flags) \ | ||
2614 | { \ | ||
2615 | return proc_pident_lookup(dir, dentry, \ | ||
2616 | LSM##_attr_dir_stuff, \ | ||
2617 | ARRAY_SIZE(LSM##_attr_dir_stuff)); \ | ||
2618 | } \ | ||
2619 | \ | ||
2620 | static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ | ||
2621 | .lookup = proc_##LSM##_attr_dir_lookup, \ | ||
2622 | .getattr = pid_getattr, \ | ||
2623 | .setattr = proc_setattr, \ | ||
2624 | } | ||
2625 | |||
2626 | #ifdef CONFIG_SECURITY_SMACK | ||
2627 | static const struct pid_entry smack_attr_dir_stuff[] = { | ||
2628 | ATTR("smack", "current", 0666), | ||
2629 | }; | ||
2630 | LSM_DIR_OPS(smack); | ||
2631 | #endif | ||
2632 | |||
2591 | static const struct pid_entry attr_dir_stuff[] = { | 2633 | static const struct pid_entry attr_dir_stuff[] = { |
2592 | REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2634 | ATTR(NULL, "current", 0666), |
2593 | REG("prev", S_IRUGO, proc_pid_attr_operations), | 2635 | ATTR(NULL, "prev", 0444), |
2594 | REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2636 | ATTR(NULL, "exec", 0666), |
2595 | REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2637 | ATTR(NULL, "fscreate", 0666), |
2596 | REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2638 | ATTR(NULL, "keycreate", 0666), |
2597 | REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), | 2639 | ATTR(NULL, "sockcreate", 0666), |
2640 | #ifdef CONFIG_SECURITY_SMACK | ||
2641 | DIR("smack", 0555, | ||
2642 | proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), | ||
2643 | #endif | ||
2598 | }; | 2644 | }; |
2599 | 2645 | ||
2600 | static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) | 2646 | static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 5185d7f6a51e..d4f9989063d0 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -81,6 +81,7 @@ union proc_op { | |||
81 | int (*proc_show)(struct seq_file *m, | 81 | int (*proc_show)(struct seq_file *m, |
82 | struct pid_namespace *ns, struct pid *pid, | 82 | struct pid_namespace *ns, struct pid *pid, |
83 | struct task_struct *task); | 83 | struct task_struct *task); |
84 | const char *lsm; | ||
84 | }; | 85 | }; |
85 | 86 | ||
86 | struct proc_inode { | 87 | struct proc_inode { |
diff --git a/include/linux/security.h b/include/linux/security.h index dbfb5a66babb..b2c5333ed4b5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -366,8 +366,10 @@ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd); | |||
366 | int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, | 366 | int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, |
367 | unsigned nsops, int alter); | 367 | unsigned nsops, int alter); |
368 | void security_d_instantiate(struct dentry *dentry, struct inode *inode); | 368 | void security_d_instantiate(struct dentry *dentry, struct inode *inode); |
369 | int security_getprocattr(struct task_struct *p, char *name, char **value); | 369 | int security_getprocattr(struct task_struct *p, const char *lsm, char *name, |
370 | int security_setprocattr(const char *name, void *value, size_t size); | 370 | char **value); |
371 | int security_setprocattr(const char *lsm, const char *name, void *value, | ||
372 | size_t size); | ||
371 | int security_netlink_send(struct sock *sk, struct sk_buff *skb); | 373 | int security_netlink_send(struct sock *sk, struct sk_buff *skb); |
372 | int security_ismaclabel(const char *name); | 374 | int security_ismaclabel(const char *name); |
373 | int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); | 375 | int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); |
@@ -1112,15 +1114,18 @@ static inline int security_sem_semop(struct kern_ipc_perm *sma, | |||
1112 | return 0; | 1114 | return 0; |
1113 | } | 1115 | } |
1114 | 1116 | ||
1115 | static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode) | 1117 | static inline void security_d_instantiate(struct dentry *dentry, |
1118 | struct inode *inode) | ||
1116 | { } | 1119 | { } |
1117 | 1120 | ||
1118 | static inline int security_getprocattr(struct task_struct *p, char *name, char **value) | 1121 | static inline int security_getprocattr(struct task_struct *p, const char *lsm, |
1122 | char *name, char **value) | ||
1119 | { | 1123 | { |
1120 | return -EINVAL; | 1124 | return -EINVAL; |
1121 | } | 1125 | } |
1122 | 1126 | ||
1123 | static inline int security_setprocattr(char *name, void *value, size_t size) | 1127 | static inline int security_setprocattr(const char *lsm, char *name, |
1128 | void *value, size_t size) | ||
1124 | { | 1129 | { |
1125 | return -EINVAL; | 1130 | return -EINVAL; |
1126 | } | 1131 | } |
diff --git a/security/security.c b/security/security.c index 9411f659454b..60b39db95c2f 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -1485,14 +1485,30 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode) | |||
1485 | } | 1485 | } |
1486 | EXPORT_SYMBOL(security_d_instantiate); | 1486 | EXPORT_SYMBOL(security_d_instantiate); |
1487 | 1487 | ||
1488 | int security_getprocattr(struct task_struct *p, char *name, char **value) | 1488 | int security_getprocattr(struct task_struct *p, const char *lsm, char *name, |
1489 | char **value) | ||
1489 | { | 1490 | { |
1490 | return call_int_hook(getprocattr, -EINVAL, p, name, value); | 1491 | struct security_hook_list *hp; |
1492 | |||
1493 | hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) { | ||
1494 | if (lsm != NULL && strcmp(lsm, hp->lsm)) | ||
1495 | continue; | ||
1496 | return hp->hook.getprocattr(p, name, value); | ||
1497 | } | ||
1498 | return -EINVAL; | ||
1491 | } | 1499 | } |
1492 | 1500 | ||
1493 | int security_setprocattr(const char *name, void *value, size_t size) | 1501 | int security_setprocattr(const char *lsm, const char *name, void *value, |
1502 | size_t size) | ||
1494 | { | 1503 | { |
1495 | return call_int_hook(setprocattr, -EINVAL, name, value, size); | 1504 | struct security_hook_list *hp; |
1505 | |||
1506 | hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) { | ||
1507 | if (lsm != NULL && strcmp(lsm, hp->lsm)) | ||
1508 | continue; | ||
1509 | return hp->hook.setprocattr(name, value, size); | ||
1510 | } | ||
1511 | return -EINVAL; | ||
1496 | } | 1512 | } |
1497 | 1513 | ||
1498 | int security_netlink_send(struct sock *sk, struct sk_buff *skb) | 1514 | int security_netlink_send(struct sock *sk, struct sk_buff *skb) |