GNOME Bugzilla – Bug 477070
gedit cannot copy xattr's when saving and indicates an error
Last modified: 2010-02-03 22:10:23 UTC
Please describe the problem: When I try to edit existing documents and save them I get the following error: "Could not create a temporary backup file while saving /home/dennis/url.txt gedit could not backup the old copy of the file before saving the new one. You can ignore this warning and save the file anyway, but if an error occurs while saving, you could lose the old copy of the file. Save anyway?" Setting GEDIT_DEBUG to 1 results in the following output: ... [-1189617724.590221 (0.000031)] gedit-local-document-saver.c:797 (save_file) [-1189617724.590197 (0.000024)] gedit-document.c:1173 (document_saver_saving) [-1189617724.590178 (0.000019)] gedit-document.c:1219 (document_saver_saving) save progress: 0 of 0 [-1189617724.590157 (0.000021)] gedit-tab.c:1085 (document_saving) 0/0 [-1189617724.590011 (0.000146)] gedit-local-document-saver.c:294 (save_existing_local_file) [-1189617724.589909 (0.000102)] gedit-local-document-saver.c:391 (save_existing_local_file) tmp file moving strategy [-1189617724.589561 (0.000348)] gedit-local-document-saver.c:443 (save_existing_local_file) could not set xattrs [-1189617724.589461 (0.000100)] gedit-local-document-saver.c:553 (save_existing_local_file) fallback strategy [-1189617724.589446 (0.000015)] gedit-local-document-saver.c:563 (save_existing_local_file) copying to backup [-1189617724.589309 (0.000137)] gedit-local-document-saver.c:650 (save_existing_local_file) could not set xattrs [-1189617724.589211 (0.000098)] gedit-document.c:1173 (document_saver_saving) ... So I checked if I can set xattrs on the files manually: [dennis@nexus ~]$ getfattr -d url.txt [dennis@nexus ~]$ setfattr -n user.foo -v bar url.txt [dennis@nexus ~]$ getfattr -d url.txt # file: url.txt user.foo="bar" The problem is that the following call to attr_copy_fd() in gedit-local-document-saver.c fails: /* copy the xattrs, like user.mime_type, over. Also ACLs and * SELinux context. */ if ((attr_copy_fd (lsaver->priv->local_path, lsaver->priv->fd, tmp_filename, tmpfd, all_xattrs, NULL) == -1) && (errno != EOPNOTSUPP) && (errno != ENOSYS)) { gedit_debug_message (DEBUG_SAVER, "could not set xattrs"); close (tmpfd); unlink (tmp_filename); g_free (tmp_filename); goto fallback_strategy; } Adding some debug code shows that the call fails with an errno code of EPERM and that is where I'm stuck and don't know why this could possibly fail with this error. I've seen this for a while now but now got annoyed enough to investigate. All of this is happening on an up-to-date Fedora rawhide system. Steps to reproduce: 1. Edit a local file and save it Actual results: I get the described error. Expected results: Gedit should save the file without a message. Does this happen every time? yes Other information:
To debug this further, we should figure out the root cause of when EPERM can be returned by xattr_copy_fd. Could it happen when /home is a separate partition without user_xattr option? But overall, I think it makes sense to ignore errors returned by the xattr copy; or maybe just print a warning to the session error console. Currently the main users of xattrs are SELinux security contexts (these have sane defaults for new files), and Beagle metadata (which is just a cache); therefore errors during copying may be safely ignored, especially if the cost is to not write a backup of the user's data.
Unfortunately I have no idea about xattr stuff, since support for it is disabled on my system. In general it seems to me that if the copy of the xattrs fails with EPERM the warning message is legitimate. However I'd like to understand how common this problem is, since it's the first time we get this kind of report. Do you have any special configuration in your system? I am CC'ing the original author of xattr support in case he has any ideas... (the xattr support bugreport is bug #350805)
There's really nothing special about my system. I has two partitions on a software raid-1, one for / and one for swap so no individual ones for /home, /var, etc. The full fstab line for / looks like this: /dev/md2 / ext3 defaults,noatime 1 1 As for the defaults, dumpe2fs has this to say: ... Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery sparse_super large_file Filesystem flags: signed directory hash Default mount options: user_xattr acl Filesystem state: clean ... The kernel package is a fairly recent "kernel-2.6.23-0.164.rc5.fc8".
I tried to come up with a simple test program to make playing around with the attr_copy_fd() call easier and encountered a strange behavior. Here is the program: #include <attr/libattr.h> #include <stdio.h> #include <errno.h> static int all_xattrs( const char *xattr, struct error_context *err ) { return 1; } int main( int argc, char *argv[] ) { int ret; int infile,outfile; infile = open("a","r"); outfile = open("b","w"); ret = attr_copy_fd( "a", infile, "b", outfile, all_xattrs, NULL); printf("error = %d\n",ret); // printf("error = %d, errno = %d\n",ret,errno); close(outfile); close(infile); return 0; } Compile with "gcc -o test test.c -lattr" and create two files "a" and "b" and set an xattr on "a" with "setfattr -n user.foo -v bar". Here is what's weird: If I run the above here it fails and ret is set to -1. So far so good. Now when I comment out the printf the call and comment in the other...the call succeeds. I have no idea why changing the printf() call would have any influence on the attr_copy_fd() call especially since that output happens after the call happened. The whole reason I wanted to output the errno value was to find out why attr_copy_fd() failed but that doesn't work if the error disappears the moment I try to output errno :)
Dennis, you should try compiling with warnings :). open("a", "r") is very wrong. You want open("a", O_RDONLY) likwise open("b", O_RDWR | O_CREAT, 0644) ...as for the issue itself, we _could_ just ignore it, and that would probably be the right thing "most" of the time ... however it is possible for people to use ACLs, so if we just ignore it's possible the file will have different permissions after we ignore it == bad. Also the selinux context changing could be a bad thing ... think of editing /etc/resolve.conf in /etc and it reverting to etc_t (or CGIs in /var/www outside a CGI directory). The other thing is that AIUI if this fails it just means that the file will be overwritten, using the same inode ... which is only a problem if you crash. My guess on the issue itself would be the SELinux context, if SELinux is enabled ... otherwise I'm not sure. Note to be "userfriendly" getfattr only outputs "user" xattrs by default, so you want: getfattr -d -m . <filename> ...to get all the xattrs for a file.
Also note that if you strace gedit and look for which setxattr() call is failing. Tiny output would be (on x86_64, you probably need to add 64 to the end for i386): strace -e trace=fgetxattr,fsetxattr,flistxattr gedit url.txt
> Also the selinux context changing could be a bad thing ... think of editing /etc/resolve.conf in /etc and it reverting to etc_t (or CGIs in /var/www outside a CGI directory). It is bad, but in the case of these security contexts it should generally be making access more restrictive if they fall back to the context computed from the directory and process domain. > so if we just ignore it's possible the file will have different permissions after we ignore it == bad. As above, I think for most sane uses of ACLs, losing them will make access *more* restrictive, not less. Though anyways, we still need to figure out why this EPERM happens on his computer...
> It is bad, but in the case of these security contexts it should generally be > making access more restrictive if they fall back to the context computed from > the directory and process domain. It's a really bad idea to talk about "more" or "less" restrictive with regard to security contexts ... it won't be, it'll just be _differently_ restrictive. If you lose context X, and so that file gets default context Y then some applications might only be able to do things to the X context and some only to the Y context. > Though anyways, we still need to figure out why this EPERM happens on his > computer... I completely agree, if the reporter could run the strace command and the getfattr command ... that should point us very close to the source of the problem.
(In reply to comment #5) > Dennis, you should try compiling with warnings :). > > open("a", "r") is very wrong. You want open("a", O_RDONLY) > likwise open("b", O_RDWR | O_CREAT, 0644) I'm a bit surprised that I was able to compile this without the compiler complaining. GCC should really balk at this even without explicitly enabling warnings. If I'd have to venture a guess I'd say silently and implicitly defining a function is the wrong thing to do for GCC in 99% of cases. > My guess on the issue itself would be the SELinux context, if SELinux is > enabled ... otherwise I'm not sure. Nope. SELinux is not enabled at all on this system. Anyway, it seems the problem solved itself in the latest rawhide updates. I can no longer reproduce this problem.
(In reply to comment #8) > It's a really bad idea to talk about "more" or "less" restrictive with regard > to security contexts ... it won't be, it'll just be _differently_ restrictive. > If you lose context X, and so that file gets default context Y then some > applications might only be able to do things to the X context and some only to > the Y context. I understand the theory behind type enforcement; I'm saying that *in practice*, at least on the systems where people will be running gedit, it will almost certainly be more restrictive. The main reason being that you can't always be sure that someone will be using an application patched to preserve xattrs; so the policy usually needs to have a sane default.
I had the same problem, SELinux was disabled on my system but libattr installed. The corrected version of the test program written by Dennis gave error = -1 and errno = 1 (Operation not permitted). Then I enabled SELinux, rebooted the system and gedit saves without warnings and the test program ends with success. So it's the combination SELinux disabled & libattr installed that causes the problem with attr_copy_fd().
We now switched to gio for saving files so if the problem persist with the upcoming major release you should poke to the gio guys. Closing this as WONTFIX. Thanks for reporting it.