Skip to content

Commit 824bd0c

Browse files
authored
Merge pull request #5702 from craigcomstock/CFE-3429/master
CFE-3429: Use current process ID to investigate proc filesystem to workaround in-container non-root owned symlinks
2 parents 5981b18 + 9fa16cd commit 824bd0c

File tree

7 files changed

+122
-15
lines changed

7 files changed

+122
-15
lines changed

INSTALL

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ See docs/BSD.md
150150

151151
sudo zypper install gdb gcc make lmdb autoconf automake libtool git python3 pcre2-devel libopenssl-devel pam-devel
152152

153-
* AlpineOS (3.11.3 x86_64 2020-04-13)
153+
* Alpine Linux (3.21.3 2025-02-25)
154154

155-
sudo apk add alpine-sdk lmdb-dev openssl-dev bison flex-dev acl-dev pcre2-dev autoconf automake libtool git python3 gdb
155+
sudo apk add alpine-sdk lmdb-dev openssl-dev bison flex-dev acl-dev pcre2-dev autoconf automake libtool git python3 gdb librsync-dev
156156
./autogen.sh --without-pam
157157

158158
* Termux (2020-04-24)

libenv/unix_iface.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <ip_address.h>
4040
#include <file_lib.h>
4141
#include <cleanup.h>
42+
#include <unix.h> /* GetRelocatedProcdirRoot() and GetProcdirPid() */
4243

4344
#ifdef HAVE_SYS_JAIL_H
4445
# include <sys/jail.h>
@@ -1283,6 +1284,10 @@ static JsonElement* GetNetworkingStatsInfo(const char *filename)
12831284

12841285
fclose(fin);
12851286
}
1287+
else
1288+
{
1289+
Log(LOG_LEVEL_VERBOSE, "netstat file not found at '%s'", filename);
1290+
}
12861291

12871292
return stats;
12881293
}
@@ -1390,20 +1395,21 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char*
13901395
void GetNetworkingInfo(EvalContext *ctx)
13911396
{
13921397
const char *procdir_root = GetRelocatedProcdirRoot();
1398+
int promiser_pid = GetProcdirPid();
13931399

13941400
Buffer *pbuf = BufferNew();
13951401

13961402
JsonElement *inet = JsonObjectCreate(2);
13971403

1398-
BufferPrintf(pbuf, "%s/proc/net/netstat", procdir_root);
1404+
BufferPrintf(pbuf, "%s/proc/%d/net/netstat", procdir_root, promiser_pid);
13991405
JsonElement *inet_stats = GetNetworkingStatsInfo(BufferData(pbuf));
14001406

14011407
if (inet_stats != NULL)
14021408
{
14031409
JsonObjectAppendElement(inet, "stats", inet_stats);
14041410
}
14051411

1406-
BufferPrintf(pbuf, "%s/proc/net/route", procdir_root);
1412+
BufferPrintf(pbuf, "%s/proc/%d/net/route", procdir_root, promiser_pid);
14071413
JsonElement *routes = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingRoutesPostProcessInfo, NULL,
14081414
// format: Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
14091415
// eth0 00000000 0102A8C0 0003 0 0 1024 00000000 0 0 0
@@ -1451,7 +1457,7 @@ void GetNetworkingInfo(EvalContext *ctx)
14511457

14521458
JsonElement *inet6 = JsonObjectCreate(3);
14531459

1454-
BufferPrintf(pbuf, "%s/proc/net/snmp6", procdir_root);
1460+
BufferPrintf(pbuf, "%s/proc/%d/net/snmp6", procdir_root, promiser_pid);
14551461
JsonElement *inet6_stats = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, NULL, NULL,
14561462
"^\\s*(?<key>\\S+)\\s+(?<value>\\d+)");
14571463

@@ -1477,7 +1483,7 @@ void GetNetworkingInfo(EvalContext *ctx)
14771483
JsonDestroy(inet6_stats);
14781484
}
14791485

1480-
BufferPrintf(pbuf, "%s/proc/net/ipv6_route", procdir_root);
1486+
BufferPrintf(pbuf, "%s/proc/%d/net/ipv6_route", procdir_root, promiser_pid);
14811487
JsonElement *inet6_routes = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingIPv6RoutesPostProcessInfo, NULL,
14821488
// format: dest dest_prefix source source_prefix next_hop metric refcnt use flags interface
14831489
// fe800000000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth0
@@ -1492,7 +1498,7 @@ void GetNetworkingInfo(EvalContext *ctx)
14921498
JsonObjectAppendElement(inet6, "routes", inet6_routes);
14931499
}
14941500

1495-
BufferPrintf(pbuf, "%s/proc/net/if_inet6", procdir_root);
1501+
BufferPrintf(pbuf, "%s/proc/%d/net/if_inet6", procdir_root, promiser_pid);
14961502
JsonElement *inet6_addresses = GetProcFileInfo(ctx, BufferData(pbuf), NULL, "interface", &NetworkingIPv6AddressesPostProcessInfo, &NetworkingIPv6AddressesTiebreaker,
14971503
// format: address device_number prefix_length scope flags interface_name
14981504
// 00000000000000000000000000000001 01 80 10 80 lo
@@ -1515,7 +1521,7 @@ void GetNetworkingInfo(EvalContext *ctx)
15151521
// face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
15161522
// eth0: 74850544807 75236137 0 0 0 0 0 1108775 63111535625 74696758 0 0 0 0 0 0
15171523

1518-
BufferPrintf(pbuf, "%s/proc/net/dev", procdir_root);
1524+
BufferPrintf(pbuf, "%s/proc/%d/net/dev", procdir_root, promiser_pid);
15191525
JsonElement *interfaces_data =
15201526
GetProcFileInfo(ctx, BufferData(pbuf), "interfaces_data", "device", NULL, NULL,
15211527
"^\\s*(?<device>[^:]+)\\s*:\\s*"
@@ -1543,34 +1549,35 @@ void GetNetworkingInfo(EvalContext *ctx)
15431549
JsonElement* GetNetworkingConnections(EvalContext *ctx)
15441550
{
15451551
const char *procdir_root = GetRelocatedProcdirRoot();
1552+
int promiser_pid = GetProcdirPid();
15461553
JsonElement *json = JsonObjectCreate(5);
15471554
const char* ports_regex = "^\\s*\\d+:\\s+(?<raw_local>[0-9A-F:]+)\\s+(?<raw_remote>[0-9A-F:]+)\\s+(?<raw_state>[0-9]+)";
15481555

15491556
JsonElement *data = NULL;
15501557
Buffer *pbuf = BufferNew();
15511558

1552-
BufferPrintf(pbuf, "%s/proc/net/tcp", procdir_root);
1559+
BufferPrintf(pbuf, "%s/proc/%d/net/tcp", procdir_root, promiser_pid);
15531560
data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex);
15541561
if (data != NULL)
15551562
{
15561563
JsonObjectAppendElement(json, "tcp", data);
15571564
}
15581565

1559-
BufferPrintf(pbuf, "%s/proc/net/tcp6", procdir_root);
1566+
BufferPrintf(pbuf, "%s/proc/%d/net/tcp6", procdir_root, promiser_pid);
15601567
data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex);
15611568
if (data != NULL)
15621569
{
15631570
JsonObjectAppendElement(json, "tcp6", data);
15641571
}
15651572

1566-
BufferPrintf(pbuf, "%s/proc/net/udp", procdir_root);
1573+
BufferPrintf(pbuf, "%s/proc/%d/net/udp", procdir_root, promiser_pid);
15671574
data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex);
15681575
if (data != NULL)
15691576
{
15701577
JsonObjectAppendElement(json, "udp", data);
15711578
}
15721579

1573-
BufferPrintf(pbuf, "%s/proc/net/udp6", procdir_root);
1580+
BufferPrintf(pbuf, "%s/proc/%d/net/udp6", procdir_root, promiser_pid);
15741581
data = GetProcFileInfo(ctx, BufferData(pbuf), NULL, NULL, &NetworkingPortsPostProcessInfo, NULL, ports_regex);
15751582
if (data != NULL)
15761583
{

libpromises/unix.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <unix.h>
2626
#include <exec_tools.h>
2727
#include <file_lib.h>
28+
#include <string_lib.h> /* StringToInt64() */
2829

2930
#ifdef HAVE_SYS_UIO_H
3031
# include <sys/uio.h>
@@ -527,4 +528,45 @@ bool GetGroupID(const char *group_name, gid_t *gid, LogLevel error_log_level)
527528
return true;
528529
}
529530

531+
const char* GetRelocatedProcdirRoot()
532+
{
533+
const char *procdir = getenv("CFENGINE_TEST_OVERRIDE_PROCDIR");
534+
if (procdir == NULL)
535+
{
536+
procdir = "";
537+
}
538+
else
539+
{
540+
Log(LOG_LEVEL_VERBOSE, "Overriding /proc location to be %s", procdir);
541+
}
542+
543+
return procdir;
544+
}
545+
546+
/**
547+
* With the addition of using the current PID when examining the proc filesystem for details
548+
* we need a test-override option for acceptance tests.
549+
*/
550+
int GetProcdirPid()
551+
{
552+
const char *procpid = getenv("CFENGINE_TEST_OVERRIDE_PROCPID");
553+
if (procpid != NULL)
554+
{
555+
int64_t pid_int;
556+
int rc;
557+
rc = StringToInt64(procpid, &pid_int);
558+
if (rc != 0)
559+
{
560+
Log(LOG_LEVEL_ERR, "Could not parse CFENGINE_TEST_OVERRIDE_PROCPID '%s' as integer: '%s'", procpid, strerror(errno));
561+
}
562+
else
563+
{
564+
Log(LOG_LEVEL_VERBOSE, "Overriding proc pid from env var CFENGINE_TEST_OVERRIDE_PROCPID with value %jd", (intmax_t) pid_int);
565+
return (int) pid_int;
566+
}
567+
}
568+
return (int) getpid();
569+
}
570+
571+
530572
#endif /* !__MINGW32__ */

libpromises/unix.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ void ProcessSignalTerminate(pid_t pid);
3333
bool GetCurrentUserName(char *userName, int userNameLen);
3434

3535
#ifndef __MINGW32__
36+
/**
37+
* @brief For testing things against /proc, uses env var CFENGINE_TEST_OVERRIDE_PROCDIR
38+
* @return the extra directory to add BEFORE /proc in the path
39+
*/
40+
const char* GetRelocatedProcdirRoot();
41+
/**
42+
* @brief For testing things against /proc, use env var CFENGINE_TEST_OVERRIDE_PROCPID
43+
* @return the fake pid to use in proc paths
44+
*/
45+
int GetProcdirPid();
46+
3647
/**
3748
* Get user name for the user with UID #uid
3849
*

tests/acceptance/00_basics/environment/proc-net-functions.cf

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,35 @@ body common control
77

88
###########################################################
99

10+
bundle agent init
11+
{
12+
vars:
13+
"pid_for_testing" int => "11";
14+
15+
methods:
16+
"" usebundle => dir_sync(
17+
"$(this.promise_dirname)/proc",
18+
"$(G.testdir)/proc"
19+
);
20+
21+
commands:
22+
"
23+
cd $(G.testdir)/proc/proc
24+
mkdir $(pid_for_testing)
25+
mv net $(pid_for_testing)/
26+
ln -s $(pid_for_testing) self
27+
ln -s self/net net
28+
"
29+
comment => "Create a semi-real structure with symlinks and a pid dir",
30+
contain => in_shell;
31+
}
32+
33+
1034
bundle agent test
1135
{
1236
meta:
1337
"test_skip_unsupported" string => "!linux";
1438

1539
commands:
16-
"$(G.env) CFENGINE_TEST_OVERRIDE_PROCDIR=$(this.promise_dirname)/proc $(sys.cf_agent) -DAUTO -f $(this.promise_filename).sub";
40+
"$(G.env) CFENGINE_TEST_OVERRIDE_PROCPID=$(init.pid_for_testing) CFENGINE_TEST_OVERRIDE_PROCDIR=$(G.testdir)/proc $(sys.cf_agent) -DAUTO -f $(this.promise_filename).sub";
1741
}

tests/acceptance/00_basics/environment/proc-net.cf

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,34 @@ body common control
77

88
###########################################################
99

10+
bundle agent init
11+
{
12+
vars:
13+
"pid_for_testing" int => "11";
14+
15+
methods:
16+
"" usebundle => dir_sync(
17+
"$(this.promise_dirname)/proc",
18+
"$(G.testdir)/proc"
19+
);
20+
21+
commands:
22+
"
23+
cd $(G.testdir)/proc/proc
24+
mkdir $(pid_for_testing)
25+
mv net $(pid_for_testing)/
26+
ln -s $(pid_for_testing) self
27+
ln -s self/net net
28+
"
29+
comment => "Create a semi-real structure with symlinks and a pid dir",
30+
contain => in_shell;
31+
}
32+
1033
bundle agent test
1134
{
1235
meta:
1336
"test_skip_unsupported" string => "!linux";
1437

1538
commands:
16-
"$(G.env) CFENGINE_TEST_OVERRIDE_PROCDIR=$(this.promise_dirname)/proc $(sys.cf_agent) -DAUTO -f $(this.promise_filename).sub";
39+
"$(G.env) CFENGINE_TEST_OVERRIDE_PROCPID=$(init.pid_for_testing) CFENGINE_TEST_OVERRIDE_PROCDIR=$(G.testdir)/proc $(sys.cf_agent) -DAUTO -f $(this.promise_filename).sub";
1740
}

0 commit comments

Comments
 (0)