Re: restorecon and symbolic links

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 01/09/09 14:43, Martin Orr wrote:
> On 31/08/09 21:27, Stephen Smalley wrote:
>> On Mon, 2009-08-31 at 14:21 +0100, Martin Orr wrote:
>>> On 31/08/09 13:17, Stephen Smalley wrote:
>>>> On Sat, 2009-08-29 at 18:19 -0500, Manoj Srivastava wrote:
>>>>> On Sat, Aug 29 2009, Martin Orr wrote:
>>>>>
>>>>>> With policycoreutils 2.0.71, "restorecon /dev/stdin" fails if stdin is a pipe:
>>>>>> martin@caligula:~$ echo hi | sudo restorecon /dev/stdin
>>>>>> realpath(/dev/stdin) failed No such file or directory
>>>>>>
>>>>>> The intention here (and what happened with policycoreutils 2.0.69) is to
>>>>>> relabel the symbolic link.  But the recent realpath patch changed this, and
>>>>>> I don't think there is a way now to ask restorecon to relabel an individual
>>>>>> symlink.
>>>> The particular commit was:
>>>>
>>>> commit 37c5c30998b73d9c6efe53fd0534256463991c5e
>>>> Author: Stephen Smalley <sds@xxxxxxxxxxxxx>
>>>> Date:   Mon Aug 3 09:34:52 2009 -0400
>>>>
>>>>     setfiles: only call realpath() on user-supplied pathnames
>>>>     
>>>>     Change setfiles/restorecon to only call realpath() on the user-supplied
>>>>     pathnames prior to invoking fts_open().  This ensures that commands such
>>>>     as restorecon -R /etc/init.d and (cd /etc && restorecon shadow gshadow)
>>>>     will work as expected while avoiding the overhead of calling realpath()
>>>>     on each file during a file tree walk.
>>>>     
>>>>     Since we are now only acting on user-supplied pathnames, drop the
>>>>     special case handling of symlinks (when a user invokes restorecon
>>>>     -R /etc/init.d he truly wants it to descend /etc/rc.d/init.d).  We can
>>>>     also defer allocation of the pathname buffer to libc by passing NULL
>>>>     (freeing on the out path) and we can drop the redundant exclude() check
>>>>     as it will now get handled on the normal path.
>>>>     
>>>>     Signed-off-by: Stephen Smalley <sds@xxxxxxxxxxxxx>
>>>>
>>>> What behavior would you like instead?  I'd still like to have restorecon
>>>> -R /etc/init.d to do what the user expects, which isn't just relabel the
>>>> symlink.
>>> True, but I would expect restorecon -R /etc/init.d to relabel the symlink as
>>> well as descend into the directory.  On the whole I would expect it not to
>>> relabel the target of the symlink itself but I don't have a strong opinion
>>> on that, as long as it doesn't fail if the symlink is broken.
>> How about this for a compromise?
>>
>> Add a -h option to restorecon so that the user can explicitly ask to
>> relabel a symlink (as with chcon), but also fall back to proceeding with
>> the original path if realpath() fails, in which case we will relabel the
>> symlink if the path was a broken symlink.
> 
> I think that this is pretty complicated and the fallback behaviour is
> potentially confusing.  I still think that restorecon -R /etc/init.d should
> by default change the context on the symlink as well as descending into the
> directory.
> 
> Also, I think it is necessary to restore the code to compute the real path
> of all but the last component of a symlink when relabelling the link itself.
> 
> The following patch shows approximately the behaviour I would like, except
> that it doesn't work, because apply_spec needs an FTSENT:

Here's a patch that works, and does what I want.

It moves most of process_one into process_one_realpath, which assumes that
the path it is given requires no further expansion.
Now if given a symlink, call symlink_realpath to get the real path ignoring
the last component, and give that to process_one_realpath; tell
process_one_realpath not to recurse so this acts on the symlink only.
Then call process_one_realpath again with the real path of the target, to
recurse into it.

diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c
index 4c47f21..c84cd6f 100644
--- a/policycoreutils/setfiles/setfiles.c
+++ b/policycoreutils/setfiles/setfiles.c
@@ -545,7 +545,47 @@ int canoncon(char **contextp)
 	return rc;
 }
 
-static int process_one(char *name)
+static int symlink_realpath(char *name, char *path)
+{
+	char *p = NULL, *file_sep;
+	char *tmp_path = strdupa(name);
+	size_t len = 0;
+
+	if (!tmp_path) {
+		fprintf(stderr, "strdupa on %s failed:  %s\n", name,
+			strerror(errno));
+		return -1;
+	}
+	file_sep = strrchr(tmp_path, '/');
+	if (file_sep == tmp_path) {
+		file_sep++;
+		p = strcpy(path, "");
+	} else if (file_sep) {
+		*file_sep = 0;
+		file_sep++;
+		p = realpath(tmp_path, path);
+	} else {
+		file_sep = tmp_path;
+		p = realpath("./", path);
+	}
+	if (p)
+		len = strlen(p);
+	if (!p || len + strlen(file_sep) + 2 > PATH_MAX) {
+		fprintf(stderr, "symlink_realpath(%s) failed %s\n", name,
+			strerror(errno));
+		return -1;
+	}
+	p += len;
+	/* ensure trailing slash of directory name */
+	if (len == 0 || *(p - 1) != '/') {
+		*p = '/';
+		p++;
+	}
+	strcpy(p, file_sep);
+	return 0;
+}
+
+static int process_one_realpath(char *name, int recurse_this_path)
 {
 	int rc = 0;
 	const char *namelist[2];
@@ -553,18 +593,6 @@ static int process_one(char *name)
 	FTS *fts_handle;
 	FTSENT *ftsent;
 
-	if (expand_realpath) {
-		char *p;
-		p = realpath(name, NULL);
-		if (!p) {
-			fprintf(stderr, "realpath(%s) failed %s\n", name,
-				strerror(errno));
-			return -1;
-		}
-		name = p;
-	}
-
-
 	if (!strcmp(name, "/"))
 		mass_relabel = 1;
 
@@ -604,7 +632,7 @@ static int process_one(char *name)
 			fts_set(fts_handle, ftsent, FTS_SKIP);
 		if (rc == ERR)
 			goto err;
-		if (!recurse)
+		if (!recurse_this_path)
 			break;
 	} while ((ftsent = fts_read(fts_handle)) != NULL);
 
@@ -619,8 +647,6 @@ out:
 	}
 	if (fts_handle)
 		fts_close(fts_handle);
-	if (expand_realpath)
-		free(name);
 	return rc;
 
 err:
@@ -630,6 +656,55 @@ err:
 	goto out;
 }
 
+static int process_one(char *name)
+{
+	int rc = 0;
+	char *p;
+	struct stat sb;
+
+	if (!expand_realpath) {
+		return process_one_realpath(name, recurse);
+	} else {
+		rc = lstat(name, &sb);
+		if (rc < 0) {
+			fprintf(stderr, "%s:  lstat(%s) failed:  %s\n",
+				progname, name,	strerror(errno));
+			return -1;
+		}
+
+		if (S_ISLNK(sb.st_mode)) {
+			char path[PATH_MAX + 1];
+
+			rc = symlink_realpath(name, path);
+			if (rc < 0)
+				return rc;
+			rc = process_one_realpath(path, 0);
+			if (rc < 0)
+				return rc;
+
+			p = realpath(name, NULL);
+			if (!p) {
+				fprintf(stderr, "Warning: %s: Broken symlink: %s\n",
+					name, strerror(errno));
+				return 0;
+			}
+			rc = process_one_realpath(p, recurse);
+			free(p);
+			return rc;
+		} else {
+			p = realpath(name, NULL);
+			if (!p) {
+				fprintf(stderr, "realpath(%s) failed %s\n", name,
+					strerror(errno));
+				return -1;
+			}
+			rc = process_one_realpath(p, recurse);
+			free(p);
+			return rc;
+		}
+	}
+}
+
 #ifndef USE_AUDIT
 static void maybe_audit_mass_relabel(void)
 {

-- 
Martin Orr

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with
the words "unsubscribe selinux" without quotes as the message.

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux