summaryrefslogtreecommitdiff
authorerik <erik>2007-01-26 20:30:32 (UTC)
committer erik <erik>2007-01-26 20:30:32 (UTC)
commitf77da1ae08512b02a3c50a124f823ed77e53dd64 (patch) (unidiff)
treeac7e414aff95348e0bf2fba3f45b2a06a4eb4623
parent4688f98202f590ec6af6c2e66a49dd2f80536083 (diff)
downloadopie-f77da1ae08512b02a3c50a124f823ed77e53dd64.zip
opie-f77da1ae08512b02a3c50a124f823ed77e53dd64.tar.gz
opie-f77da1ae08512b02a3c50a124f823ed77e53dd64.tar.bz2
Both packageslave.cpp and textedit.cpp have instances of possibly exploitable
race conditions associated to files. The big deal is that it is quite typical to use strings of pathnames to track files. But because that does not leverage the filesystem would be attackers may be able to exploit time lags in uses of filesystem functions (like stat and chmod or open) to get files with suspect data into the files that the applications are working with. This commit closes that potential hole even though there are no known exploits. Better safe then sorry. There is no change in the behavior of the apps.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/apps/textedit/textedit.cpp45
-rw-r--r--core/launcher/packageslave.cpp48
2 files changed, 49 insertions, 44 deletions
diff --git a/core/apps/textedit/textedit.cpp b/core/apps/textedit/textedit.cpp
index 4bbc62b..1c81a55 100644
--- a/core/apps/textedit/textedit.cpp
+++ b/core/apps/textedit/textedit.cpp
@@ -735,153 +735,150 @@ void TextEdit::openFile( const QString &f ) {
735 735
736 showEditTools(); 736 showEditTools();
737 // Show filename in caption 737 // Show filename in caption
738 QString name = filer; 738 QString name = filer;
739 int sep = name.findRev( '/' ); 739 int sep = name.findRev( '/' );
740 if ( sep > 0 ) 740 if ( sep > 0 )
741 name = name.mid( sep+1 ); 741 name = name.mid( sep+1 );
742 updateCaption( name ); 742 updateCaption( name );
743} 743}
744 744
745void TextEdit::openFile( const DocLnk &f ) { 745void TextEdit::openFile( const DocLnk &f ) {
746// clear(); 746// clear();
747// bFromDocView = true; 747// bFromDocView = true;
748 FileManager fm; 748 FileManager fm;
749 QString txt; 749 QString txt;
750 currentFileName=f.file(); 750 currentFileName=f.file();
751 odebug << "openFile doclnk " + currentFileName << oendl; 751 odebug << "openFile doclnk " + currentFileName << oendl;
752 if ( !fm.loadFile( f, txt ) ) { 752 if ( !fm.loadFile( f, txt ) ) {
753 // ####### could be a new file 753 // ####### could be a new file
754 odebug << "Cannot open file" << oendl; 754 odebug << "Cannot open file" << oendl;
755 } 755 }
756// fileNew(); 756// fileNew();
757 if ( doc ) 757 if ( doc )
758 delete doc; 758 delete doc;
759 doc = new DocLnk(f); 759 doc = new DocLnk(f);
760 editor->setText(txt); 760 editor->setText(txt);
761 editor->setEdited( false); 761 editor->setEdited( false);
762 edited1=false; 762 edited1=false;
763 edited=false; 763 edited=false;
764 764
765 doc->setName(currentFileName); 765 doc->setName(currentFileName);
766 updateCaption(); 766 updateCaption();
767 setTimer(); 767 setTimer();
768} 768}
769 769
770void TextEdit::showEditTools() { 770void TextEdit::showEditTools() {
771 menu->show(); 771 menu->show();
772 editBar->show(); 772 editBar->show();
773 if(!useSearchBar) 773 if(!useSearchBar)
774 searchBar->hide(); 774 searchBar->hide();
775 else 775 else
776 searchBar->show(); 776 searchBar->show();
777 setWState (WState_Reserved1 ); 777 setWState (WState_Reserved1 );
778} 778}
779 779
780/*! 780/*!
781 unprompted save */ 781 unprompted save */
782bool TextEdit::save() { 782bool TextEdit::save() {
783 QString name, file; 783 QString name, file;
784 odebug << "saveAsFile " + currentFileName << oendl; 784 odebug << "saveAsFile " + currentFileName << oendl;
785 if(currentFileName.isEmpty()) { 785 if(currentFileName.isEmpty()) {
786 saveAs(); 786 saveAs();
787 return false; 787 return false;
788 } 788 }
789 name = currentFileName; 789 if(doc) {
790 if(doc) { 790 file = doc->file();
791 file = doc->file(); 791 odebug << "saver file "+file << oendl;
792 odebug << "saver file "+file << oendl; 792 name = doc->name();
793 name = doc->name(); 793 odebug << "File named "+name << oendl;
794 odebug << "File named "+name << oendl; 794 } else {
795 } else { 795 file = currentFileName;
796 file = currentFileName;
797 name = QFileInfo(currentFileName).baseName(); 796 name = QFileInfo(currentFileName).baseName();
798 } 797 }
799 798
800 QString rt = editor->text(); 799 QString rt = editor->text();
801 if( !rt.isEmpty() ) { 800 if( !rt.isEmpty() ) {
802 if(name.isEmpty()) { 801 if(name.isEmpty()) {
803 saveAs(); 802 saveAs();
804 } else { 803 } else {
805 currentFileName = name; 804 currentFileName = name;
806 odebug << "saveFile "+currentFileName << oendl; 805 odebug << "saveFile "+currentFileName << oendl;
807 806
808 struct stat buf; 807 struct stat buf;
809 mode_t mode; 808 mode_t mode;
810 stat(file.latin1(), &buf); 809 QFile f(file);
810 fstat(f.handle(), &buf);
811 mode = buf.st_mode; 811 mode = buf.st_mode;
812 812
813 if(!fileIs) { 813 if(!fileIs) {
814 doc->setName( name); 814 doc->setName( name);
815 FileManager fm; 815 FileManager fm;
816 if ( !fm.saveFile( *doc, rt ) ) { 816 if ( !fm.saveFile( *doc, rt ) ) {
817 QMessageBox::message(tr("Text Edit"),tr("Save Failed")); 817 QMessageBox::message(tr("Text Edit"),tr("Save Failed"));
818 return false; 818 return false;
819 } 819 }
820 } else { 820 } else {
821 odebug << "regular save file" << oendl; 821 odebug << "regular save file" << oendl;
822 QFile f(file); 822 if( f.open(IO_WriteOnly)) {
823 if( f.open(IO_WriteOnly)) { 823 QCString crt = rt.utf8();
824 QCString crt = rt.utf8(); 824 f.writeBlock(crt,crt.length());
825 f.writeBlock(crt,crt.length()); 825 } else {
826 } else { 826 QMessageBox::message(tr("Text Edit"),tr("Write Failed"));
827 QMessageBox::message(tr("Text Edit"),tr("Write Failed")); 827 return false;
828 return false; 828 }
829 }
830
831 } 829 }
832 editor->setEdited( false); 830 editor->setEdited( false);
833 edited1=false; 831 edited1=false;
834 edited=false; 832 edited=false;
835 if(caption().left(1)=="*") 833 if(caption().left(1)=="*")
836 setCaption(caption().right(caption().length()-1)); 834 setCaption(caption().right(caption().length()-1));
837
838 835
839 chmod( file.latin1(), mode); 836 fchmod( f.handle(), mode);
840 } 837 }
841 return true; 838 return true;
842 } 839 }
843 return false; 840 return false;
844} 841}
845 842
846/*! 843/*!
847 prompted save */ 844 prompted save */
848bool TextEdit::saveAs() { 845bool TextEdit::saveAs() {
849 846
850 if(caption() == tr("Text Editor")) 847 if(caption() == tr("Text Editor"))
851 return false; 848 return false;
852 odebug << "saveAsFile " + currentFileName << oendl; 849 odebug << "saveAsFile " + currentFileName << oendl;
853 850
854 QString rt = editor->text(); 851 QString rt = editor->text();
855 odebug << currentFileName << oendl; 852 odebug << currentFileName << oendl;
856 853
857 if( currentFileName.isEmpty() 854 if( currentFileName.isEmpty()
858 || currentFileName == tr("Unnamed") 855 || currentFileName == tr("Unnamed")
859 || currentFileName == tr("Text Editor")) 856 || currentFileName == tr("Text Editor"))
860 { 857 {
861 odebug << "do silly TT filename thing" << oendl; 858 odebug << "do silly TT filename thing" << oendl;
862 QString pt = rt.simplifyWhiteSpace(); 859 QString pt = rt.simplifyWhiteSpace();
863 int i = pt.find( ' ' ); 860 int i = pt.find( ' ' );
864 QString docname = pt; 861 QString docname = pt;
865 if ( i > 0 ) docname = pt.left( i ); 862 if ( i > 0 ) docname = pt.left( i );
866 863
867 while( docname.startsWith( "." ) ) 864 while( docname.startsWith( "." ) )
868 docname = docname.mid( 1 ); 865 docname = docname.mid( 1 );
869 docname.replace( QRegExp("/"), "_" ); 866 docname.replace( QRegExp("/"), "_" );
870 // Cut the length. Filenames longer than 40 are not helpful 867 // Cut the length. Filenames longer than 40 are not helpful
871 // and something goes wrong when they get too long. 868 // and something goes wrong when they get too long.
872 if ( docname.length() > 40 ) docname = docname.left(40); 869 if ( docname.length() > 40 ) docname = docname.left(40);
873 870
874 if ( docname.isEmpty() ) docname = tr("Unnamed"); 871 if ( docname.isEmpty() ) docname = tr("Unnamed");
875 872
876 if(doc) doc->setName(docname); 873 if(doc) doc->setName(docname);
877 874
878 currentFileName=docname; 875 currentFileName=docname;
879 } 876 }
880 877
881 878
882 QMap<QString, QStringList> map; 879 QMap<QString, QStringList> map;
883 map.insert(tr("All"), QStringList() ); 880 map.insert(tr("All"), QStringList() );
884 QStringList text; 881 QStringList text;
885 text << "text/*"; 882 text << "text/*";
886 map.insert(tr("Text"), text ); 883 map.insert(tr("Text"), text );
887 text << "*"; 884 text << "*";
diff --git a/core/launcher/packageslave.cpp b/core/launcher/packageslave.cpp
index abbc610..965020e 100644
--- a/core/launcher/packageslave.cpp
+++ b/core/launcher/packageslave.cpp
@@ -169,122 +169,130 @@ void PackageHandler::addPackageFiles( const QString &location,
169 s = ts.readLine(); // line of text excluding '\n' 169 s = ts.readLine(); // line of text excluding '\n'
170 // for s, do link/mkdir. 170 // for s, do link/mkdir.
171 if ( s.right(1) == "/" ) { 171 if ( s.right(1) == "/" ) {
172 odebug << "do mkdir for " << s.ascii() << "" << oendl; 172 odebug << "do mkdir for " << s.ascii() << "" << oendl;
173#ifndef Q_OS_WIN32 173#ifndef Q_OS_WIN32
174 mkdir( s.ascii(), 0777 ); 174 mkdir( s.ascii(), 0777 );
175 //possible optimization: symlink directories 175 //possible optimization: symlink directories
176 //that don't exist already. -- Risky. 176 //that don't exist already. -- Risky.
177#else 177#else
178 d.mkdir( s.ascii()); 178 d.mkdir( s.ascii());
179#endif 179#endif
180 180
181 } else { 181 } else {
182#ifndef Q_OS_WIN32 182#ifndef Q_OS_WIN32
183 odebug << "do symlink for " << s.ascii() << "" << oendl; 183 odebug << "do symlink for " << s.ascii() << "" << oendl;
184 symlink( (location + s).ascii(), s.ascii() ); 184 symlink( (location + s).ascii(), s.ascii() );
185#else 185#else
186 odebug << "Copy file instead of a symlink for WIN32" << oendl; 186 odebug << "Copy file instead of a symlink for WIN32" << oendl;
187 if (!CopyFile((TCHAR*)qt_winTchar((location + s), TRUE), (TCHAR*)qt_winTchar(s, TRUE), FALSE)) 187 if (!CopyFile((TCHAR*)qt_winTchar((location + s), TRUE), (TCHAR*)qt_winTchar(s, TRUE), FALSE))
188 owarn << "Unable to create symlinkfor " << (location + s).ascii() << oendl; 188 owarn << "Unable to create symlinkfor " << (location + s).ascii() << oendl;
189#endif 189#endif
190 } 190 }
191 } 191 }
192 f.close(); 192 f.close();
193 } 193 }
194} 194}
195 195
196void PackageHandler::addPackages( const QString &location ) 196void PackageHandler::addPackages( const QString &location )
197{ 197{
198 // get list of *.list in location/usr/lib/ipkg/info/*.list 198 // get list of *.list in location/usr/lib/ipkg/info/*.list
199 QDir dir(location + "/usr/lib/ipkg/info", "*.list", // No tr 199 QDir dir(location + "/usr/lib/ipkg/info", "*.list", // No tr
200 QDir::Name, QDir::Files); 200 QDir::Name, QDir::Files);
201 if ( !dir.exists() ) 201 if ( !dir.exists() )
202 return; 202 return;
203 203
204 QStringList packages = dir.entryList(); 204 QStringList packages = dir.entryList();
205 for ( QStringList::Iterator it = packages.begin(); 205 for ( QStringList::Iterator it = packages.begin();
206 it != packages.end(); ++it ) { 206 it != packages.end(); ++it ) {
207 addPackageFiles( location, *it ); 207 addPackageFiles( location, *it );
208 } 208 }
209} 209}
210 210
211 211
212void PackageHandler::cleanupPackageFiles( const QString &listfile ) 212void PackageHandler::cleanupPackageFiles( const QString &listfile )
213{ 213{
214 QFile f(listfile); 214 QFile f(listfile);
215 215
216 if ( f.open(IO_ReadOnly) ) { 216 if ( f.open(IO_ReadOnly) ) {
217 QTextStream ts(&f); 217 QTextStream ts(&f);
218 218
219 QString s; 219 QString s;
220 while ( !ts.eof() ) { // until end of file... 220 while ( !ts.eof() ) { // until end of file...
221 s = ts.readLine(); // line of text excluding '\n' 221 s = ts.readLine(); // line of text excluding '\n'
222 // for s, do link/mkdir. 222 // for s, do link/mkdir.
223 if ( s.right(1) == "/" ) { 223 // @todo Right now we just move on if the name of the file we
224 //should rmdir if empty, after all files have been removed 224 // find is actually a directory. What we ought to do is check
225 } else { 225 // to see if the directory is empty and if so remove it.
226 if ( s.right(1) != "/" ) {
226#ifndef Q_OS_WIN32 227#ifndef Q_OS_WIN32
227 odebug << "remove symlink for " << s.ascii() << "" << oendl; 228 odebug << "remove symlink for " << s << oendl;
228 //check if it is a symlink first (don't remove /etc/passwd...) 229 QFile symFile(s);
229 char buf[10]; //we don't care about the contents 230 QFileInfo symFileInfo(symFile);
230 if ( ::readlink( s.ascii(),buf, 10 >= 0 ) ) 231 //check if it is a symlink first (don't remove /etc/passwd...)
231 ::unlink( s.ascii() ); 232 if ( !symFileInfo.readLink().isNull())
233 if (!symFile.remove())
234 owarn << "Unable to remove symlink " << symFile.name()
235 << " " << __FILE__ << ":" << __LINE__ << oendl;
232#else 236#else
233 // ### revise 237 // @todo If we actually want to be portable to other operating
234 owarn << "Unable to remove symlink " << __FILE__ << ":" << __LINE__ << "" << oendl; 238 // systems we ought to at least have a portable way of removing
239 // their notion of symlinks.
240 owarn << "Unable to remove symlink " << s " " << __FILE__
241 << ":" << __LINE__ << oendl;
235#endif 242#endif
243 }
236 } 244 }
237 } 245 f.close();
238 f.close();
239 246
240 //remove the list file 247 //remove the list file
241 ::unlink( listfile.ascii() ); 248 if (!f.remove())
242 249 owarn << "Unable to remove list file " << f.name() << " "
250 << __FILE__ << ":" << __LINE__ << oendl;
243 } 251 }
244} 252}
245 253
246void PackageHandler::cleanupPackages( const QString &location ) 254void PackageHandler::cleanupPackages( const QString &location )
247{ 255{
248 // get list of *.list in location/usr/lib/ipkg/info/*.list 256 // get list of *.list in location/usr/lib/ipkg/info/*.list
249 QDir dir( "/usr/lib/ipkg/info/"+location, "*.list", // No tr 257 QDir dir( "/usr/lib/ipkg/info/"+location, "*.list", // No tr
250 QDir::Name, QDir::Files); 258 QDir::Name, QDir::Files);
251 if ( !dir.exists() ) 259 if ( !dir.exists() )
252 return; 260 return;
253 261
254 QStringList packages = dir.entryList(); 262 QStringList packages = dir.entryList();
255 for ( QStringList::Iterator it = packages.begin(); 263 for ( QStringList::Iterator it = packages.begin();
256 it != packages.end(); ++it ) { 264 it != packages.end(); ++it ) {
257 cleanupPackageFiles( *it ); 265 cleanupPackageFiles( *it );
258 } 266 }
259 267
260 //remove the backup directory 268 //remove the backup directory
261 //### 269 //###
262} 270}
263 271
264void PackageHandler::prepareInstall( const QString& size, const QString& path ) 272void PackageHandler::prepareInstall( const QString& size, const QString& path )
265{ 273{
266 // Check whether there will be enough space to install the next package. 274 // Check whether there will be enough space to install the next package.
267 bool ok; 275 bool ok;
268 unsigned int s = size.toUInt( &ok ); 276 unsigned int s = size.toUInt( &ok );
269 277
270 if ( !ok ) 278 if ( !ok )
271 return; 279 return;
272 280
273 // Shamelessly stolen from the sysinfo application (Werner) 281 // Shamelessly stolen from the sysinfo application (Werner)
274#if defined(_OS_LINUX_) || defined(Q_OS_LINUX) 282#if defined(_OS_LINUX_) || defined(Q_OS_LINUX)
275 struct statfs fs; 283 struct statfs fs;
276 if ( statfs( path.latin1(), &fs ) == 0 ) 284 if ( statfs( path.latin1(), &fs ) == 0 )
277 if ( s > fs.f_bsize * fs.f_bavail ) { 285 if ( s > fs.f_bsize * fs.f_bavail ) {
278 //odebug << "############### Not enough space left ###############" << oendl; 286 //odebug << "############### Not enough space left ###############" << oendl;
279 mNoSpaceLeft = TRUE; 287 mNoSpaceLeft = TRUE;
280 } 288 }
281#endif 289#endif
282} 290}
283 291
284void PackageHandler::iProcessExited() 292void PackageHandler::iProcessExited()
285{ 293{
286 if ( currentProcess->normalExit() && currentProcess->exitStatus() == 0 ) 294 if ( currentProcess->normalExit() && currentProcess->exitStatus() == 0 )
287 sendReply( "installDone(QString)", currentPackage ); 295 sendReply( "installDone(QString)", currentPackage );
288 else { 296 else {
289#ifndef QT_NO_COP 297#ifndef QT_NO_COP
290 QCopEnvelope e( "QPE/Desktop", "installFailed(QString,int,QString)" ); 298 QCopEnvelope e( "QPE/Desktop", "installFailed(QString,int,QString)" );