File: 0003-BUILTIN-Fix-test-x-as-root-on-platforms-with-old-fash.diff

package info (click to toggle)
dash 0.5.8-2.4
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 1,264 kB
  • sloc: ansic: 13,040; sh: 1,398; makefile: 154
file content (60 lines) | stat: -rw-r--r-- 2,025 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
From e08afc373611ba3e7f2f90bd8e7ce022a1bebed9 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 26 Sep 2011 16:16:37 -0500
Subject: [PATCH 3/6] [BUILTIN] Fix "test -x" as root on platforms with
 old-fashioned faccessat()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When dash switched from its own emulation to the true faccessat in
v0.5.7~54 (2010-04-02), on some platforms (e.g., old versions of
glibc-bsd), "test -x <path>" started returning true on all files when
run as root.  This violates POSIX.1-2008 ยง4.4 "File Access
Permission", which says:

	If execute permission is requested, access shall be granted
	if execute permission is granted to at least one user by the
	file permission bits or by an alternate access control
	mechanism; otherwise, access shall be denied.

Unfortunately, for historical reasons, access() and faccessat() are
allowed by POSIX to return success for X_OK when the current process
is privileged even when the above condition is not fulfilled and
actual execution would fail.  Work around this by checking the
permissions bits when mode == X_OK and geteuid() == 0.

Reported-by: Christoph Egger <christoph@debian.org>
Analysis-by: Petr Salinger <Petr.Salinger@seznam.cz>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 src/bltin/test.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/bltin/test.c b/src/bltin/test.c
index baa91a5..ca29f40 100644
--- a/src/bltin/test.c
+++ b/src/bltin/test.c
@@ -489,8 +489,19 @@ equalf (const char *f1, const char *f2)
 }
 
 #ifdef HAVE_FACCESSAT
+static int has_exec_bit_set(const char *path)
+{
+	struct stat64 st;
+
+	if (stat64(path, &st))
+		return 0;
+	return st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH);
+}
+
 static int test_file_access(const char *path, int mode)
 {
+	if (mode == X_OK && geteuid() == 0 && !has_exec_bit_set(path))
+		return 0;
 	return !faccessat(AT_FDCWD, path, mode, AT_EACCESS);
 }
 #else	/* HAVE_FACCESSAT */
-- 
2.1.0