blob: 421649d57c682c191881322c82341a00666dc406 [file] [log] [blame]
Dmitry V. Levin38a34c92015-12-17 17:56:48 +00001/*
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@altlinux.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000030#include "defs.h"
31
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000032/* these constants are the same as in <linux/capability.h> */
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +000033enum {
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000034#include "caps0.h"
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +000035};
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000036
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000037#include "xlat/cap_mask0.h"
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000038
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000039/* these constants are CAP_TO_INDEX'ed constants from <linux/capability.h> */
40enum {
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000041#include "caps1.h"
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000042};
43
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000044#include "xlat/cap_mask1.h"
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000045
46/* these constants are the same as in <linux/capability.h> */
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +000047enum {
48 _LINUX_CAPABILITY_VERSION_1 = 0x19980330,
49 _LINUX_CAPABILITY_VERSION_2 = 0x20071026,
50 _LINUX_CAPABILITY_VERSION_3 = 0x20080522
51};
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000052
53#include "xlat/cap_version.h"
54
Dmitry V. Levinbf7fdfa2014-12-03 20:39:20 +000055typedef struct user_cap_header_struct {
56 uint32_t version;
57 int pid;
58} *cap_user_header_t;
59
60typedef struct user_cap_data_struct {
61 uint32_t effective;
62 uint32_t permitted;
63 uint32_t inheritable;
64} *cap_user_data_t;
65
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000066static cap_user_header_t
67get_cap_header(struct tcb *tcp, unsigned long addr)
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000068{
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000069 static struct user_cap_header_struct header;
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +000070
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000071 if (!addr || !verbose(tcp))
72 return NULL;
73
74 if (umove(tcp, addr, &header) < 0)
75 return NULL;
76
77 return &header;
78}
79
80static void
81print_cap_header(struct tcb *tcp, unsigned long addr, cap_user_header_t h)
82{
Dmitry V. Levinc70da7c2015-07-20 17:50:56 +000083 if (!addr || !h) {
84 printaddr(addr);
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000085 return;
86 }
87
88 tprints("{");
89 printxval(cap_version, h->version,
90 "_LINUX_CAPABILITY_VERSION_???");
91 tprintf(", %d}", h->pid);
92}
93
94static void
95print_cap_bits(const uint32_t lo, const uint32_t hi)
96{
97 if (lo || !hi)
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +000098 printflags(cap_mask0, lo, "CAP_???");
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +000099
100 if (hi) {
101 if (lo)
102 tprints("|");
Dmitry V. Levin2f0808b2015-02-18 23:59:50 +0000103 printflags(cap_mask1, hi, "CAP_???");
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000104 }
105}
106
107static void
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000108print_cap_data(struct tcb *tcp, unsigned long addr, const cap_user_header_t h)
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000109{
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000110 struct user_cap_data_struct data[2];
111 unsigned int len;
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000112
Dmitry V. Levinc70da7c2015-07-20 17:50:56 +0000113 if (!addr || !h) {
114 printaddr(addr);
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000115 return;
116 }
117
118 if (_LINUX_CAPABILITY_VERSION_2 == h->version ||
119 _LINUX_CAPABILITY_VERSION_3 == h->version)
120 len = 2;
121 else
122 len = 1;
123
Dmitry V. Levinc70da7c2015-07-20 17:50:56 +0000124 if (umoven_or_printaddr(tcp, addr, len * sizeof(data[0]), data))
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000125 return;
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000126
127 tprints("{");
128 print_cap_bits(data[0].effective, len > 1 ? data[1].effective : 0);
129 tprints(", ");
130 print_cap_bits(data[0].permitted, len > 1 ? data[1].permitted : 0);
131 tprints(", ");
132 print_cap_bits(data[0].inheritable, len > 1 ? data[1].inheritable : 0);
133 tprints("}");
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000134}
135
Dmitry V. Levina0bd3742015-04-07 01:36:50 +0000136SYS_FUNC(capget)
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000137{
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000138 cap_user_header_t h;
139
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000140 if (entering(tcp)) {
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000141 h = get_cap_header(tcp, tcp->u_arg[0]);
142 print_cap_header(tcp, tcp->u_arg[0], h);
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000143 tprints(", ");
144 } else {
Dmitry V. Levin4b9c68b2014-12-05 00:21:23 +0000145 h = syserror(tcp) ? NULL : get_cap_header(tcp, tcp->u_arg[0]);
146 print_cap_data(tcp, tcp->u_arg[1], h);
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000147 }
148 return 0;
149}
150
Dmitry V. Levina0bd3742015-04-07 01:36:50 +0000151SYS_FUNC(capset)
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000152{
Dmitry V. Levinff33aac2015-07-20 17:54:02 +0000153 cap_user_header_t h = get_cap_header(tcp, tcp->u_arg[0]);
154 print_cap_header(tcp, tcp->u_arg[0], h);
155 tprints(", ");
156 print_cap_data(tcp, tcp->u_arg[1], h);
157
158 return RVAL_DECODED;
Dmitry V. Levin5e7987b2014-12-03 20:30:15 +0000159}