Skip to content

Commit 1151a72

Browse files
committed
If the system supports the syscalls to get and set Linux capabilities then apply currently effective Linux capabilities to the Inheritable set and then apply all the capabilities in both the Effective and Inheritable sets to the Ambient set, so that the child process (which can be unaware of capabilities) can have its capabilities set accordingly.
Note: a failure to set these capabilities will not be considered as a total failure as the application might still be able to work for the intended use case (otherwise the user simply needs to start it as root).
1 parent 2df896e commit 1151a72

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

src/runtime/runtime.c

+110
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ extern int sqfs_opt_proc(void* data, const char* arg, int key, struct fuse_args*
6464
#include <libgen.h>
6565
#include <dirent.h>
6666
#include <ctype.h>
67+
#include <sys/syscall.h>
68+
69+
#if defined(SYS_capget) && defined(SYS_capset)
70+
#define USE_CAPABILITIES
71+
#endif
72+
73+
#ifdef USE_CAPABILITIES
74+
#include <sys/prctl.h>
75+
#include <linux/capability.h>
76+
#endif
6777

6878
const char* fusermountPath = NULL;
6979

@@ -1459,6 +1469,97 @@ void set_portable_home_and_config(char* basepath) {
14591469
}
14601470
}
14611471

1472+
#ifdef USE_CAPABILITIES
1473+
int appimage_adjust_capabilities()
1474+
{
1475+
struct __user_cap_header_struct hdr;
1476+
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
1477+
int res, datacnt;
1478+
1479+
hdr.version = 0;
1480+
hdr.pid = 0;
1481+
res = syscall(SYS_capget, &hdr, NULL);
1482+
if (res)
1483+
{
1484+
if (errno != EINVAL || hdr.version == 0)
1485+
{
1486+
fprintf(stderr, "SYS_capget syscall failed with %d\n", errno);
1487+
return -1;
1488+
}
1489+
}
1490+
else if (hdr.version == 0)
1491+
{
1492+
fprintf(stderr, "Failed to query capability version\n");
1493+
return -1;
1494+
}
1495+
1496+
//fprintf(stderr, "Linux capability version: %x\n", hdr.version);
1497+
1498+
switch (hdr.version)
1499+
{
1500+
case _LINUX_CAPABILITY_VERSION_1:
1501+
datacnt = _LINUX_CAPABILITY_U32S_1;
1502+
break;
1503+
case _LINUX_CAPABILITY_VERSION_2:
1504+
datacnt = _LINUX_CAPABILITY_U32S_2;
1505+
break;
1506+
case _LINUX_CAPABILITY_VERSION_3:
1507+
datacnt = _LINUX_CAPABILITY_U32S_3;
1508+
break;
1509+
default:
1510+
fprintf(stderr, "Unknown Linux capability version: %x; forcing version 3\n", hdr.version);
1511+
datacnt = _LINUX_CAPABILITY_U32S_3;
1512+
hdr.version = _LINUX_CAPABILITY_VERSION_3;
1513+
}
1514+
1515+
res = syscall(SYS_capget, &hdr, &data);
1516+
if (res)
1517+
{
1518+
fprintf(stderr, "Failed to query capabilities; error: %d\n", errno);
1519+
return -1;
1520+
}
1521+
1522+
//for (int i = 0; i < datacnt; ++i)
1523+
//{
1524+
// fprintf(stderr, "Set %d: eff = %08x, perm = %08x, inh = %08x\n", i, data[i].effective, data[i].permitted, data[i].inheritable);
1525+
//}
1526+
1527+
for (int i = 0; i < datacnt; ++i)
1528+
{
1529+
data[i].inheritable |= data[i].permitted;
1530+
}
1531+
1532+
res = syscall(SYS_capset, &hdr, &data);
1533+
if (res)
1534+
{
1535+
fprintf(stderr, "Failed to set capabilities; error: %d\n", errno);
1536+
return -1;
1537+
}
1538+
1539+
/* now we can set up the ambient set */
1540+
for (int i = 0; i < datacnt; ++i)
1541+
{
1542+
for (int j = 0; j < 32; ++j)
1543+
{
1544+
int capval = i * 32 + j;
1545+
int capbit = 1 << j;
1546+
1547+
if ((data[i].permitted & capbit) && (data[i].inheritable & capbit))
1548+
{
1549+
res = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, capval, 0, 0);
1550+
if (res)
1551+
{
1552+
fprintf(stderr, "Failed to set ambient capability %d; error: %d\n", capval, errno);
1553+
return -1;
1554+
}
1555+
}
1556+
}
1557+
}
1558+
1559+
return 0;
1560+
}
1561+
#endif
1562+
14621563
int main(int argc, char* argv[]) {
14631564
const bool verbose = (getenv("VERBOSE") != NULL);
14641565
if (verbose) {
@@ -1832,6 +1933,15 @@ int main(int argc, char* argv[]) {
18321933

18331934
set_portable_home_and_config(fullpath);
18341935

1936+
#ifdef USE_CAPABILITIES
1937+
/* Ensure that capabilities for the AppImage are applied to the children (Note: we won't consider
1938+
this failing as an error as the application might still work for the usecase intended by the user) */
1939+
if (appimage_adjust_capabilities())
1940+
{
1941+
fprintf(stderr, "Warning: failed to forward capabilities\n");
1942+
}
1943+
#endif
1944+
18351945
/* Original working directory */
18361946
char cwd[1024];
18371947
if (getcwd(cwd, sizeof(cwd)) != NULL) {

0 commit comments

Comments
 (0)