1 /*
2 * Copyright (c) 2000 Wichert Akkerman <wakkerma@debian.org>
3 * Copyright (c) 2011 Denys Vlasenko <dvlasenk@redhat.com>
4 * Copyright (c) 2005-2015 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2014-2022 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: LGPL-2.1-or-later
9 */
10
11 #include "defs.h"
12
13 /* these constants are the same as in <linux/capability.h> */
14 enum {
15 #include "caps0.h"
16 };
17
18 #include "xlat/cap_mask0.h"
19
20 /* these constants are CAP_TO_INDEX'ed constants from <linux/capability.h> */
21 enum {
22 #include "caps1.h"
23 };
24
25 #include "xlat/cap_mask1.h"
26
27 /* these constants are the same as in <linux/capability.h> */
28 enum {
29 _LINUX_CAPABILITY_VERSION_1 = 0x19980330,
30 _LINUX_CAPABILITY_VERSION_2 = 0x20071026,
31 _LINUX_CAPABILITY_VERSION_3 = 0x20080522
32 };
33
34 #include "xlat/cap_version.h"
35
36 struct user_cap_header_struct {
37 uint32_t version;
38 int pid;
39 };
40
41 struct user_cap_data_struct {
42 uint32_t effective;
43 uint32_t permitted;
44 uint32_t inheritable;
45 };
46
47 static const struct user_cap_header_struct *
48 get_cap_header(struct tcb *const tcp, const kernel_ulong_t addr)
49 {
50 static struct user_cap_header_struct header;
51
52 if (!addr || !verbose(tcp))
53 return NULL;
54
55 if (umove(tcp, addr, &header) < 0)
56 return NULL;
57
58 return &header;
59 }
60
61 static void
62 print_cap_header(struct tcb *const tcp, const kernel_ulong_t addr,
63 const struct user_cap_header_struct *const h)
64 {
65 if (!addr || !h) {
66 printaddr(addr);
67 return;
68 }
69
70 tprint_struct_begin();
71 PRINT_FIELD_XVAL(*h, version, cap_version,
72 "_LINUX_CAPABILITY_VERSION_???");
73 tprint_struct_next();
74 PRINT_FIELD_TGID(*h, pid, tcp);
75 tprint_struct_end();
76 }
77
78 static void
79 print_cap_bits(const uint32_t lo, const uint32_t hi)
80 {
81 tprint_flags_begin();
82 if (lo || !hi)
83 printflags_in(cap_mask0, lo, "CAP_???");
84
85 if (hi) {
86 if (lo)
87 tprint_flags_or();
88 printflags_in(cap_mask1, hi, "CAP_???");
89 }
90 tprint_flags_end();
91 }
92
93 static void
94 print_cap_data(struct tcb *const tcp, const kernel_ulong_t addr,
95 const struct user_cap_header_struct *const h)
96 {
97 struct user_cap_data_struct data[2];
98 unsigned int len;
99
100 if (!addr || !h) {
101 printaddr(addr);
102 return;
103 }
104
105 if (_LINUX_CAPABILITY_VERSION_2 == h->version ||
106 _LINUX_CAPABILITY_VERSION_3 == h->version)
107 len = 2;
108 else
109 len = 1;
110
111 if (umoven_or_printaddr(tcp, addr, len * sizeof(data[0]), data))
112 return;
113
114 tprint_struct_begin();
115 tprints_field_name("effective");
116 print_cap_bits(data[0].effective, len > 1 ? data[1].effective : 0);
117 tprint_struct_next();
118 tprints_field_name("permitted");
119 print_cap_bits(data[0].permitted, len > 1 ? data[1].permitted : 0);
120 tprint_struct_next();
121 tprints_field_name("inheritable");
122 print_cap_bits(data[0].inheritable, len > 1 ? data[1].inheritable : 0);
123 tprint_struct_end();
124 }
125
126 SYS_FUNC(capget)
127 {
128 const struct user_cap_header_struct *h;
129
130 if (entering(tcp)) {
131 /* hdrp */
132 h = get_cap_header(tcp, tcp->u_arg[0]);
133 print_cap_header(tcp, tcp->u_arg[0], h);
134 tprint_arg_next();
135 } else {
136 /* datap */
137 h = syserror(tcp) ? NULL : get_cap_header(tcp, tcp->u_arg[0]);
138 print_cap_data(tcp, tcp->u_arg[1], h);
139 }
140 return 0;
141 }
142
143 SYS_FUNC(capset)
144 {
145 /* hdrp */
146 const struct user_cap_header_struct *const h =
147 get_cap_header(tcp, tcp->u_arg[0]);
148 print_cap_header(tcp, tcp->u_arg[0], h);
149 tprint_arg_next();
150
151 /* datap */
152 print_cap_data(tcp, tcp->u_arg[1], h);
153
154 return RVAL_DECODED;
155 }