A response is represented by the task_diag_creds structure: struct task_diag_creds { struct task_diag_caps cap_inheritable; struct task_diag_caps cap_permitted; struct task_diag_caps cap_effective; struct task_diag_caps cap_bset; __u32 uid; __u32 euid; __u32 suid; __u32 fsuid; __u32 gid; __u32 egid; __u32 sgid; __u32 fsgid; }; This group is optional and it's filled only if show_flags contains TASK_DIAG_SHOW_CRED. Signed-off-by: Andrey Vagin <avagin@xxxxxxxxxx> --- include/uapi/linux/task_diag.h | 22 ++++++++++++++++++ kernel/taskdiag.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/include/uapi/linux/task_diag.h b/include/uapi/linux/task_diag.h index 3a1e6c4..0e659d6 100644 --- a/include/uapi/linux/task_diag.h +++ b/include/uapi/linux/task_diag.h @@ -7,6 +7,7 @@ enum { /* optional attributes which can be specified in show_flags */ TASK_DIAG_BASE = 0, + TASK_DIAG_CRED, /* other attributes */ TASK_DIAG_PID = 64, /* u32 */ @@ -16,6 +17,7 @@ enum { }; #define TASK_DIAG_SHOW_BASE (1ULL << TASK_DIAG_BASE) +#define TASK_DIAG_SHOW_CRED (1ULL << TASK_DIAG_CRED) enum { TASK_DIAG_RUNNING, @@ -40,6 +42,26 @@ struct task_diag_base { char comm[TASK_DIAG_COMM_LEN]; }; +struct task_diag_caps { + __u32 cap[_LINUX_CAPABILITY_U32S_3]; +}; + +struct task_diag_creds { + struct task_diag_caps cap_inheritable; + struct task_diag_caps cap_permitted; + struct task_diag_caps cap_effective; + struct task_diag_caps cap_bset; + + __u32 uid; + __u32 euid; + __u32 suid; + __u32 fsuid; + __u32 gid; + __u32 egid; + __u32 sgid; + __u32 fsgid; +}; + #define TASK_DIAG_DUMP_ALL 0 struct task_diag_pid { diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c index 5771baf..5123e12 100644 --- a/kernel/taskdiag.c +++ b/kernel/taskdiag.c @@ -16,6 +16,9 @@ static size_t taskdiag_packet_size(u64 show_flags) if (show_flags & TASK_DIAG_SHOW_BASE) size += nla_total_size(sizeof(struct task_diag_base)); + if (show_flags & TASK_DIAG_SHOW_CRED) + size += nla_total_size(sizeof(struct task_diag_creds)); + return size; } @@ -83,6 +86,48 @@ static int fill_task_base(struct task_struct *p, struct sk_buff *skb) return 0; } +static inline void caps2diag(struct task_diag_caps *diag, const kernel_cap_t *cap) +{ + int i; + + for (i = 0; i < _LINUX_CAPABILITY_U32S_3; i++) + diag->cap[i] = cap->cap[i]; +} + +static int fill_creds(struct task_struct *p, struct sk_buff *skb) +{ + struct user_namespace *user_ns = current_user_ns(); + struct task_diag_creds *diag_cred; + const struct cred *cred; + struct nlattr *attr; + + attr = nla_reserve(skb, TASK_DIAG_CRED, sizeof(struct task_diag_creds)); + if (!attr) + return -EMSGSIZE; + + diag_cred = nla_data(attr); + + cred = get_task_cred(p); + + caps2diag(&diag_cred->cap_inheritable, &cred->cap_inheritable); + caps2diag(&diag_cred->cap_permitted, &cred->cap_permitted); + caps2diag(&diag_cred->cap_effective, &cred->cap_effective); + caps2diag(&diag_cred->cap_bset, &cred->cap_bset); + + diag_cred->uid = from_kuid_munged(user_ns, cred->uid); + diag_cred->euid = from_kuid_munged(user_ns, cred->euid); + diag_cred->suid = from_kuid_munged(user_ns, cred->suid); + diag_cred->fsuid = from_kuid_munged(user_ns, cred->fsuid); + diag_cred->gid = from_kgid_munged(user_ns, cred->gid); + diag_cred->egid = from_kgid_munged(user_ns, cred->egid); + diag_cred->sgid = from_kgid_munged(user_ns, cred->sgid); + diag_cred->fsgid = from_kgid_munged(user_ns, cred->fsgid); + + put_cred(cred); + + return 0; +} + static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb, u64 show_flags, u32 portid, u32 seq, struct netlink_callback *cb) @@ -115,6 +160,14 @@ static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb, i++; } + if (show_flags & TASK_DIAG_SHOW_CRED) { + if (i >= n) + err = fill_creds(tsk, skb); + if (err) + goto err; + i++; + } + genlmsg_end(skb, reply); if (cb) cb->args[2] = 0; -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html