pcp/0012-src-pmpost-pmpost.c-guard-against-possible-symlink-a.patch

132 lines
3.9 KiB
Diff
Raw Permalink Normal View History

From 58ac1989fe64377b66af4090b10c807656237430 Mon Sep 17 00:00:00 2001
From: Ken McDonell <kenj@kenj.id.au>
Date: Tue, 13 Aug 2024 11:45:20 +1000
Subject: [PATCH 12/19] src/pmpost/pmpost.c: guard against possible symlink
attack
If $PCP_LOG_DIR/NOTICES is a symlink don't trust it.
Note that $PCP_LOG_DIR is owned pcp:pcp, so this would need a
prior root penetration or compromise of the pcp account which has a
/usr/sbin/nologin shell and no password by default.
Addresses SUSE Issue G.
Extend qa/640 to explore this possible attack vector.
(cherry picked from commit 22505f9a43c212217d4d53200dcf2f0e94febc8f)
[ddiss: rebase qa/1370 without 39d434c0a ("libpcp et. al.: derived
metric saga continues")]
Acked-by: David Disseldorp <ddiss@suse.de>
---
qa/640 | 51 ++++++++++++++++++++++++++++++++++++++++++---
qa/640.out | 3 +++
src/pmpost/pmpost.c | 8 +++++--
3 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/qa/640 b/qa/640
index c36018e0f..44088d75f 100755
--- a/qa/640
+++ b/qa/640
@@ -6,6 +6,10 @@
# years; so we now simply check the right permissions are in place
# and move right along...
#
+# Aug 2024 update
+# SuSE Issue G identifies another possible exploit, so try that
+# as well.
+#
# Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved.
#
@@ -17,13 +21,54 @@ echo "QA output created by $seq"
. ./common.filter
. ./common.check
-status=0 # success is the default!
-trap "$sudo rm -f $tmp.*; exit \$status" 0 1 2 3 15
+rm -f $seq.full
+ls -li $PCP_LOG_DIR/NOTICES $tmp/badness >>$seq.full 2>&1
+
+_cleanup()
+{
+ if [ -f $PCP_LOG_DIR/NOTICES.$seq ]
+ then
+ $sudo rm -f $PCP_LOG_DIR/NOTICES
+ $sudo mv $PCP_LOG_DIR/NOTICES.$seq $PCP_LOG_DIR/NOTICES
+ fi
+ ls -li $PCP_LOG_DIR/NOTICES $tmp/badness >>$seq.full 2>&1
+ $sudo rm -rf $tmp $tmp.*
+}
+
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_filter()
+{
+ sed \
+ -e "s@$PCP_LOG_DIR@PCP_LOG_DIR@g" \
+ -e '/^pmpost:/s/\[.*]/[DATE]/' \
+ # end
+}
# real QA test starts here
pmpost=$PCP_BINADM_DIR/pmpost
-echo "Using pmpost binary: $pmpost" > $seq.full
+echo "Using pmpost binary: $pmpost" >>$seq.full
test -u "$pmpost" && echo "FAIL: pmpost has setuid bit set"
test -g "$pmpost" && echo "FAIL: pmpost has setgid bit set"
+
+$sudo mkdir $tmp || exit
+$sudo chmod 700 $tmp || exit
+$sudo -u $PCP_USER mv $PCP_LOG_DIR/NOTICES $PCP_LOG_DIR/NOTICES.$seq
+
+$sudo -u $PCP_USER ln -s $tmp/badness $PCP_LOG_DIR/NOTICES >>$seq.full
+$pmpost ordinary user 2>&1 | _filter
+$sudo ls -li $PCP_LOG_DIR/NOTICES $tmp/badness >>$seq.full 2>&1
+$sudo -u pcp $pmpost pcp user 2>&1 | _filter
+$sudo ls -li $PCP_LOG_DIR/NOTICES $tmp/badness >>$seq.full 2>&1
+$sudo $pmpost root user 2>&1 | _filter
+$sudo ls -li $PCP_LOG_DIR/NOTICES $tmp/badness >>$seq.full 2>&1
+if $sudo test -f $tmp/badness
+then
+ $sudo cat $tmp/badness
+fi
+
echo "Test complete"
+
+status=0
exit
diff --git a/qa/640.out b/qa/640.out
index f8a70b72d..3de815cd2 100644
--- a/qa/640.out
+++ b/qa/640.out
@@ -1,2 +1,5 @@
QA output created by 640
+pmpost: unposted message: [DATE] ordinary user
+pmpost: unposted message: [DATE] pcp user
+pmpost: unposted message: [DATE] root user
Test complete
diff --git a/src/pmpost/pmpost.c b/src/pmpost/pmpost.c
index 4036baa41..398c104e5 100644
--- a/src/pmpost/pmpost.c
+++ b/src/pmpost/pmpost.c
@@ -144,8 +144,12 @@ main(int argc, char **argv)
goto oops;
}
- if ((fd = open(notices, O_WRONLY|O_APPEND, 0)) < 0) {
- if ((fd = open(notices, O_WRONLY|O_CREAT|O_APPEND, 0664)) < 0) {
+ if ((fd = open(notices, O_WRONLY|O_APPEND|O_NOFOLLOW, 0)) < 0) {
+ if (oserror() == ELOOP) {
+ /* last component is symlink => attack? ... bail! */
+ goto oops;
+ }
+ if ((fd = open(notices, O_WRONLY|O_CREAT|O_APPEND|O_NOFOLLOW, 0664)) < 0) {
fprintf(stderr, "pmpost: cannot open or create file \"%s\": %s\n",
notices, osstrerror());
goto oops;
--
2.43.0