blob: bbd5544afefb509e7a789a2737af161068b1a936 [file] [log] [blame]
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +00001#include "defs.h"
2
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +00003/* these constants are the same as in <linux/capability.h> */
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +00004enum {
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +00005#include "caps0.h"
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +00006};
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +00007
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +00008#include "xlat/cap_mask0.h"
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +00009
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000010/* these constants are CAP_TO_INDEX'ed constants from <linux/capability.h> */
11enum {
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000012#include "caps1.h"
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000013};
14
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000015#include "xlat/cap_mask1.h"
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000016
17/* these constants are the same as in <linux/capability.h> */
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +000018enum {
19 _LINUX_CAPABILITY_VERSION_1 = 0x19980330,
20 _LINUX_CAPABILITY_VERSION_2 = 0x20071026,
21 _LINUX_CAPABILITY_VERSION_3 = 0x20080522
22};
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000023
24#include "xlat/cap_version.h"
25
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +000026typedef struct user_cap_header_struct {
27 uint32_t version;
28 int pid;
29} *cap_user_header_t;
30
31typedef struct user_cap_data_struct {
32 uint32_t effective;
33 uint32_t permitted;
34 uint32_t inheritable;
35} *cap_user_data_t;
36
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000037static cap_user_header_t
38get_cap_header(struct tcb *tcp, unsigned long addr)
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000039{
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000040 static struct user_cap_header_struct header;
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000041
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000042 if (!addr || !verbose(tcp))
43 return NULL;
44
45 if (umove(tcp, addr, &header) < 0)
46 return NULL;
47
48 return &header;
49}
50
51static void
52print_cap_header(struct tcb *tcp, unsigned long addr, cap_user_header_t h)
53{
54 if (!addr) {
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000055 tprints("NULL");
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000056 return;
57 }
58
59 if (!h) {
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000060 tprintf("%#lx", addr);
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000061 return;
62 }
63
64 tprints("{");
65 printxval(cap_version, h->version,
66 "_LINUX_CAPABILITY_VERSION_???");
67 tprintf(", %d}", h->pid);
68}
69
70static void
71print_cap_bits(const uint32_t lo, const uint32_t hi)
72{
73 if (lo || !hi)
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000074 printflags(cap_mask0, lo, "CAP_???");
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000075
76 if (hi) {
77 if (lo)
78 tprints("|");
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000079 printflags(cap_mask1, hi, "CAP_???");
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000080 }
81}
82
83static void
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000084print_cap_data(struct tcb *tcp, unsigned long addr, const cap_user_header_t h)
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000085{
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000086 struct user_cap_data_struct data[2];
87 unsigned int len;
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000088
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000089 if (!addr) {
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000090 tprints("NULL");
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000091 return;
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000092 }
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000093
94 if (!h || !verbose(tcp) ||
95 (exiting(tcp) && syserror(tcp))) {
96 tprintf("%#lx", addr);
97 return;
98 }
99
100 if (_LINUX_CAPABILITY_VERSION_2 == h->version ||
101 _LINUX_CAPABILITY_VERSION_3 == h->version)
102 len = 2;
103 else
104 len = 1;
105
106 if (umoven(tcp, addr, len * sizeof(data[0]), (char *) data) < 0) {
107 tprintf("%#lx", addr);
108 return;
109 }
110
111 tprints("{");
112 print_cap_bits(data[0].effective, len > 1 ? data[1].effective : 0);
113 tprints(", ");
114 print_cap_bits(data[0].permitted, len > 1 ? data[1].permitted : 0);
115 tprints(", ");
116 print_cap_bits(data[0].inheritable, len > 1 ? data[1].inheritable : 0);
117 tprints("}");
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000118}
119
120int
121sys_capget(struct tcb *tcp)
122{
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000123 cap_user_header_t h;
124
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000125 if (entering(tcp)) {
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000126 h = get_cap_header(tcp, tcp->u_arg[0]);
127 print_cap_header(tcp, tcp->u_arg[0], h);
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000128 tprints(", ");
129 } else {
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000130 h = syserror(tcp) ? NULL : get_cap_header(tcp, tcp->u_arg[0]);
131 print_cap_data(tcp, tcp->u_arg[1], h);
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000132 }
133 return 0;
134}
135
136int
137sys_capset(struct tcb *tcp)
138{
139 if (entering(tcp)) {
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000140 cap_user_header_t h = get_cap_header(tcp, tcp->u_arg[0]);
141 print_cap_header(tcp, tcp->u_arg[0], h);
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000142 tprints(", ");
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000143 print_cap_data(tcp, tcp->u_arg[1], h);
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000144 }
145 return 0;
146}