diff options
author | Paul Moore <paul@paul-moore.com> | 2017-05-02 10:16:05 -0400 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2017-05-02 10:16:05 -0400 |
commit | b6c7c115c2ce679ac536f0adf0ff518fcd939196 (patch) | |
tree | 0c7671fe200ec777495bec8c830ef17c12e76255 /kernel | |
parent | 45a0642b4d021a2f50d5db9c191b5bfe60bfa1c7 (diff) |
audit: store the auditd PID as a pid struct instead of pid_t
This is arguably the right thing to do, and will make it easier when
we start supporting multiple audit daemons in different namespaces.
Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.c | 84 | ||||
-rw-r--r-- | kernel/audit.h | 2 |
2 files changed, 58 insertions, 28 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index b40f3c4727e1..a2f7803a68d0 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/rcupdate.h> | 58 | #include <linux/rcupdate.h> |
59 | #include <linux/mutex.h> | 59 | #include <linux/mutex.h> |
60 | #include <linux/gfp.h> | 60 | #include <linux/gfp.h> |
61 | #include <linux/pid.h> | ||
61 | 62 | ||
62 | #include <linux/audit.h> | 63 | #include <linux/audit.h> |
63 | 64 | ||
@@ -117,7 +118,7 @@ struct audit_net { | |||
117 | * or the included spinlock for writing. | 118 | * or the included spinlock for writing. |
118 | */ | 119 | */ |
119 | static struct auditd_connection { | 120 | static struct auditd_connection { |
120 | int pid; | 121 | struct pid *pid; |
121 | u32 portid; | 122 | u32 portid; |
122 | struct net *net; | 123 | struct net *net; |
123 | spinlock_t lock; | 124 | spinlock_t lock; |
@@ -220,18 +221,41 @@ struct audit_reply { | |||
220 | * Description: | 221 | * Description: |
221 | * Return 1 if the task is a registered audit daemon, 0 otherwise. | 222 | * Return 1 if the task is a registered audit daemon, 0 otherwise. |
222 | */ | 223 | */ |
223 | int auditd_test_task(const struct task_struct *task) | 224 | int auditd_test_task(struct task_struct *task) |
224 | { | 225 | { |
225 | int rc; | 226 | int rc; |
226 | 227 | ||
227 | rcu_read_lock(); | 228 | rcu_read_lock(); |
228 | rc = (auditd_conn.pid && task->tgid == auditd_conn.pid ? 1 : 0); | 229 | rc = (auditd_conn.pid && auditd_conn.pid == task_tgid(task) ? 1 : 0); |
229 | rcu_read_unlock(); | 230 | rcu_read_unlock(); |
230 | 231 | ||
231 | return rc; | 232 | return rc; |
232 | } | 233 | } |
233 | 234 | ||
234 | /** | 235 | /** |
236 | * auditd_pid_vnr - Return the auditd PID relative to the namespace | ||
237 | * @auditd: the auditd connection | ||
238 | * | ||
239 | * Description: | ||
240 | * Returns the PID in relation to the namespace, 0 on failure. This function | ||
241 | * takes the RCU read lock internally, but if the caller needs to protect the | ||
242 | * auditd_connection pointer it should take the RCU read lock as well. | ||
243 | */ | ||
244 | static pid_t auditd_pid_vnr(const struct auditd_connection *auditd) | ||
245 | { | ||
246 | pid_t pid; | ||
247 | |||
248 | rcu_read_lock(); | ||
249 | if (!auditd || !auditd->pid) | ||
250 | pid = 0; | ||
251 | else | ||
252 | pid = pid_vnr(auditd->pid); | ||
253 | rcu_read_unlock(); | ||
254 | |||
255 | return pid; | ||
256 | } | ||
257 | |||
258 | /** | ||
235 | * audit_get_sk - Return the audit socket for the given network namespace | 259 | * audit_get_sk - Return the audit socket for the given network namespace |
236 | * @net: the destination network namespace | 260 | * @net: the destination network namespace |
237 | * | 261 | * |
@@ -428,12 +452,17 @@ static int audit_set_failure(u32 state) | |||
428 | * This function will obtain and drop network namespace references as | 452 | * This function will obtain and drop network namespace references as |
429 | * necessary. | 453 | * necessary. |
430 | */ | 454 | */ |
431 | static void auditd_set(int pid, u32 portid, struct net *net) | 455 | static void auditd_set(struct pid *pid, u32 portid, struct net *net) |
432 | { | 456 | { |
433 | unsigned long flags; | 457 | unsigned long flags; |
434 | 458 | ||
435 | spin_lock_irqsave(&auditd_conn.lock, flags); | 459 | spin_lock_irqsave(&auditd_conn.lock, flags); |
436 | auditd_conn.pid = pid; | 460 | if (auditd_conn.pid) |
461 | put_pid(auditd_conn.pid); | ||
462 | if (pid) | ||
463 | auditd_conn.pid = get_pid(pid); | ||
464 | else | ||
465 | auditd_conn.pid = NULL; | ||
437 | auditd_conn.portid = portid; | 466 | auditd_conn.portid = portid; |
438 | if (auditd_conn.net) | 467 | if (auditd_conn.net) |
439 | put_net(auditd_conn.net); | 468 | put_net(auditd_conn.net); |
@@ -1059,11 +1088,13 @@ static int audit_set_feature(struct sk_buff *skb) | |||
1059 | return 0; | 1088 | return 0; |
1060 | } | 1089 | } |
1061 | 1090 | ||
1062 | static int audit_replace(pid_t pid) | 1091 | static int audit_replace(struct pid *pid) |
1063 | { | 1092 | { |
1093 | pid_t pvnr; | ||
1064 | struct sk_buff *skb; | 1094 | struct sk_buff *skb; |
1065 | 1095 | ||
1066 | skb = audit_make_reply(0, AUDIT_REPLACE, 0, 0, &pid, sizeof(pid)); | 1096 | pvnr = pid_vnr(pid); |
1097 | skb = audit_make_reply(0, AUDIT_REPLACE, 0, 0, &pvnr, sizeof(pvnr)); | ||
1067 | if (!skb) | 1098 | if (!skb) |
1068 | return -ENOMEM; | 1099 | return -ENOMEM; |
1069 | return auditd_send_unicast_skb(skb); | 1100 | return auditd_send_unicast_skb(skb); |
@@ -1093,9 +1124,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1093 | memset(&s, 0, sizeof(s)); | 1124 | memset(&s, 0, sizeof(s)); |
1094 | s.enabled = audit_enabled; | 1125 | s.enabled = audit_enabled; |
1095 | s.failure = audit_failure; | 1126 | s.failure = audit_failure; |
1096 | rcu_read_lock(); | 1127 | /* NOTE: use pid_vnr() so the PID is relative to the current |
1097 | s.pid = auditd_conn.pid; | 1128 | * namespace */ |
1098 | rcu_read_unlock(); | 1129 | s.pid = auditd_pid_vnr(&auditd_conn); |
1099 | s.rate_limit = audit_rate_limit; | 1130 | s.rate_limit = audit_rate_limit; |
1100 | s.backlog_limit = audit_backlog_limit; | 1131 | s.backlog_limit = audit_backlog_limit; |
1101 | s.lost = atomic_read(&audit_lost); | 1132 | s.lost = atomic_read(&audit_lost); |
@@ -1121,36 +1152,36 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1121 | return err; | 1152 | return err; |
1122 | } | 1153 | } |
1123 | if (s.mask & AUDIT_STATUS_PID) { | 1154 | if (s.mask & AUDIT_STATUS_PID) { |
1124 | /* NOTE: we are using task_tgid_vnr() below because | 1155 | /* NOTE: we are using the vnr PID functions below |
1125 | * the s.pid value is relative to the namespace | 1156 | * because the s.pid value is relative to the |
1126 | * of the caller; at present this doesn't matter | 1157 | * namespace of the caller; at present this |
1127 | * much since you can really only run auditd | 1158 | * doesn't matter much since you can really only |
1128 | * from the initial pid namespace, but something | 1159 | * run auditd from the initial pid namespace, but |
1129 | * to keep in mind if this changes */ | 1160 | * something to keep in mind if this changes */ |
1130 | int new_pid = s.pid; | 1161 | pid_t new_pid = s.pid; |
1131 | pid_t auditd_pid; | 1162 | pid_t auditd_pid; |
1132 | pid_t requesting_pid = task_tgid_vnr(current); | 1163 | struct pid *req_pid = task_tgid(current); |
1164 | |||
1165 | /* sanity check - PID values must match */ | ||
1166 | if (new_pid != pid_vnr(req_pid)) | ||
1167 | return -EINVAL; | ||
1133 | 1168 | ||
1134 | /* test the auditd connection */ | 1169 | /* test the auditd connection */ |
1135 | audit_replace(requesting_pid); | 1170 | audit_replace(req_pid); |
1136 | 1171 | ||
1137 | rcu_read_lock(); | 1172 | auditd_pid = auditd_pid_vnr(&auditd_conn); |
1138 | auditd_pid = auditd_conn.pid; | ||
1139 | /* only the current auditd can unregister itself */ | 1173 | /* only the current auditd can unregister itself */ |
1140 | if ((!new_pid) && (requesting_pid != auditd_pid)) { | 1174 | if ((!new_pid) && (new_pid != auditd_pid)) { |
1141 | rcu_read_unlock(); | ||
1142 | audit_log_config_change("audit_pid", new_pid, | 1175 | audit_log_config_change("audit_pid", new_pid, |
1143 | auditd_pid, 0); | 1176 | auditd_pid, 0); |
1144 | return -EACCES; | 1177 | return -EACCES; |
1145 | } | 1178 | } |
1146 | /* replacing a healthy auditd is not allowed */ | 1179 | /* replacing a healthy auditd is not allowed */ |
1147 | if (auditd_pid && new_pid) { | 1180 | if (auditd_pid && new_pid) { |
1148 | rcu_read_unlock(); | ||
1149 | audit_log_config_change("audit_pid", new_pid, | 1181 | audit_log_config_change("audit_pid", new_pid, |
1150 | auditd_pid, 0); | 1182 | auditd_pid, 0); |
1151 | return -EEXIST; | 1183 | return -EEXIST; |
1152 | } | 1184 | } |
1153 | rcu_read_unlock(); | ||
1154 | 1185 | ||
1155 | if (audit_enabled != AUDIT_OFF) | 1186 | if (audit_enabled != AUDIT_OFF) |
1156 | audit_log_config_change("audit_pid", new_pid, | 1187 | audit_log_config_change("audit_pid", new_pid, |
@@ -1158,8 +1189,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1158 | 1189 | ||
1159 | if (new_pid) { | 1190 | if (new_pid) { |
1160 | /* register a new auditd connection */ | 1191 | /* register a new auditd connection */ |
1161 | auditd_set(new_pid, | 1192 | auditd_set(req_pid, NETLINK_CB(skb).portid, |
1162 | NETLINK_CB(skb).portid, | ||
1163 | sock_net(NETLINK_CB(skb).sk)); | 1193 | sock_net(NETLINK_CB(skb).sk)); |
1164 | /* try to process any backlog */ | 1194 | /* try to process any backlog */ |
1165 | wake_up_interruptible(&kauditd_wait); | 1195 | wake_up_interruptible(&kauditd_wait); |
diff --git a/kernel/audit.h b/kernel/audit.h index 18f3c2deeccf..4987ea2a4702 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
@@ -218,7 +218,7 @@ extern void audit_log_name(struct audit_context *context, | |||
218 | struct audit_names *n, const struct path *path, | 218 | struct audit_names *n, const struct path *path, |
219 | int record_num, int *call_panic); | 219 | int record_num, int *call_panic); |
220 | 220 | ||
221 | extern int auditd_test_task(const struct task_struct *task); | 221 | extern int auditd_test_task(struct task_struct *task); |
222 | 222 | ||
223 | #define AUDIT_INODE_BUCKETS 32 | 223 | #define AUDIT_INODE_BUCKETS 32 |
224 | extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; | 224 | extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; |