summaryrefslogtreecommitdiff
authorerik <erik>2007-01-26 20:30:32 (UTC)
committer erik <erik>2007-01-26 20:30:32 (UTC)
commitf77da1ae08512b02a3c50a124f823ed77e53dd64 (patch) (side-by-side diff)
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) (show whitespace changes)
-rw-r--r--core/apps/textedit/textedit.cpp9
-rw-r--r--core/launcher/packageslave.cpp30
2 files changed, 22 insertions, 17 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
@@ -693,243 +693,240 @@ void TextEdit::openFile( const QString &f ) {
switch ( QMessageBox::warning(this,tr("Text Editor"),tr("Text Editor has detected<BR>you selected a <B>.desktop</B>file.<BR>Open<B>.desktop</B> file or <B>linked</B> file?"),tr(".desktop File"),tr("Linked Document"),0,1,1) )
{
case 0: //desktop
filer = f;
break;
case 1: //linked
DocLnk sf(f);
filer = sf.file();
break;
};
}
else if(fi.baseName().left(1) == "")
{
odebug << "opening dotfile" << oendl;
currentFileName=f;
openDotFile(currentFileName);
return;
}
/*
* The problem is a file where Config(f).isValid() and it does not
* end with .desktop will be treated as desktop file
*/
else if (f.find(".desktop",0,true) != -1 )
{
DocLnk sf(f);
filer = sf.file();
if(filer.right(1) == "/")
filer = f;
}
else
filer = f;
DocLnk nf;
nf.setType("text/plain");
nf.setFile(filer);
currentFileName=filer;
nf.setName(fi.baseName());
openFile(nf);
odebug << "openFile string "+currentFileName << oendl;
showEditTools();
// Show filename in caption
QString name = filer;
int sep = name.findRev( '/' );
if ( sep > 0 )
name = name.mid( sep+1 );
updateCaption( name );
}
void TextEdit::openFile( const DocLnk &f ) {
// clear();
// bFromDocView = true;
FileManager fm;
QString txt;
currentFileName=f.file();
odebug << "openFile doclnk " + currentFileName << oendl;
if ( !fm.loadFile( f, txt ) ) {
// ####### could be a new file
odebug << "Cannot open file" << oendl;
}
// fileNew();
if ( doc )
delete doc;
doc = new DocLnk(f);
editor->setText(txt);
editor->setEdited( false);
edited1=false;
edited=false;
doc->setName(currentFileName);
updateCaption();
setTimer();
}
void TextEdit::showEditTools() {
menu->show();
editBar->show();
if(!useSearchBar)
searchBar->hide();
else
searchBar->show();
setWState (WState_Reserved1 );
}
/*!
unprompted save */
bool TextEdit::save() {
QString name, file;
odebug << "saveAsFile " + currentFileName << oendl;
if(currentFileName.isEmpty()) {
saveAs();
return false;
}
- name = currentFileName;
if(doc) {
file = doc->file();
odebug << "saver file "+file << oendl;
name = doc->name();
odebug << "File named "+name << oendl;
} else {
file = currentFileName;
name = QFileInfo(currentFileName).baseName();
}
QString rt = editor->text();
if( !rt.isEmpty() ) {
if(name.isEmpty()) {
saveAs();
} else {
currentFileName = name;
odebug << "saveFile "+currentFileName << oendl;
struct stat buf;
mode_t mode;
- stat(file.latin1(), &buf);
+ QFile f(file);
+ fstat(f.handle(), &buf);
mode = buf.st_mode;
if(!fileIs) {
doc->setName( name);
FileManager fm;
if ( !fm.saveFile( *doc, rt ) ) {
QMessageBox::message(tr("Text Edit"),tr("Save Failed"));
return false;
}
} else {
odebug << "regular save file" << oendl;
- QFile f(file);
if( f.open(IO_WriteOnly)) {
QCString crt = rt.utf8();
f.writeBlock(crt,crt.length());
} else {
QMessageBox::message(tr("Text Edit"),tr("Write Failed"));
return false;
}
-
}
editor->setEdited( false);
edited1=false;
edited=false;
if(caption().left(1)=="*")
setCaption(caption().right(caption().length()-1));
-
- chmod( file.latin1(), mode);
+ fchmod( f.handle(), mode);
}
return true;
}
return false;
}
/*!
prompted save */
bool TextEdit::saveAs() {
if(caption() == tr("Text Editor"))
return false;
odebug << "saveAsFile " + currentFileName << oendl;
QString rt = editor->text();
odebug << currentFileName << oendl;
if( currentFileName.isEmpty()
|| currentFileName == tr("Unnamed")
|| currentFileName == tr("Text Editor"))
{
odebug << "do silly TT filename thing" << oendl;
QString pt = rt.simplifyWhiteSpace();
int i = pt.find( ' ' );
QString docname = pt;
if ( i > 0 ) docname = pt.left( i );
while( docname.startsWith( "." ) )
docname = docname.mid( 1 );
docname.replace( QRegExp("/"), "_" );
// Cut the length. Filenames longer than 40 are not helpful
// and something goes wrong when they get too long.
if ( docname.length() > 40 ) docname = docname.left(40);
if ( docname.isEmpty() ) docname = tr("Unnamed");
if(doc) doc->setName(docname);
currentFileName=docname;
}
QMap<QString, QStringList> map;
map.insert(tr("All"), QStringList() );
QStringList text;
text << "text/*";
map.insert(tr("Text"), text );
text << "*";
map.insert(tr("All"), text );
QFileInfo cuFi( currentFileName);
QString filee = cuFi.fileName();
QString dire = cuFi.dirPath();
if(dire==".")
dire = QPEApplication::documentDir();
QString str;
if( !featureAutoSave) {
str = OFileDialog::getSaveFileName( 2, dire, filee, map);
} else
str = currentFileName;
if(!str.isEmpty()) {
QString fileNm=str;
odebug << "saving filename "+fileNm << oendl;
QFileInfo fi(fileNm);
currentFileName=fi.fileName();
if(doc)
delete doc;
DocLnk nf;
nf.setType("text/plain");
nf.setFile( fileNm);
doc = new DocLnk(nf);
odebug << "Saving file as "+currentFileName << oendl;
doc->setName( fi.baseName() );
updateCaption( currentFileName);
FileManager fm;
if ( !fm.saveFile( *doc, rt ) ) {
QMessageBox::message(tr("Text Edit"),tr("Save Failed"));
return false;
}
if( filePerms ) {
filePermissions *filePerm;
filePerm = new filePermissions(this, tr("Permissions"),true, 0,
(const QString &)fileNm);
QPEApplication::execDialog( filePerm );
delete filePerm;
}
editor->setEdited( false);
edited1 = false;
edited = false;
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
@@ -127,212 +127,220 @@ void PackageHandler::removePackage( const QString &package )
{
currentProcess = new QProcess( QStringList() << "ipkg" << "remove" << package ); // No tr
connect( currentProcess, SIGNAL( processExited() ), SLOT( rmProcessExited() ) );
connect( currentProcess, SIGNAL( readyReadStdout() ), SLOT( readyReadStdout() ) );
connect( currentProcess, SIGNAL( readyReadStderr() ), SLOT( readyReadStderr() ) );
currentPackage = package;
currentProcessError="";
sendReply( "removeStarted(QString)", package );
currentProcess->start();
}
void PackageHandler::sendReply( const QCString& msg, const QString& arg )
{
#ifndef QT_NO_COP
QCopEnvelope e( "QPE/Desktop", msg );
e << arg;
#endif
}
void PackageHandler::addPackageFiles( const QString &location,
const QString &listfile )
{
QFile f(listfile);
#ifndef Q_OS_WIN32
//make a copy so we can remove the symlinks later
mkdir( ("/usr/lib/ipkg/info/"+location).ascii(), 0777 );
system(("cp " + f.name() + " /usr/lib/ipkg/info/"+location).ascii());
#else
QDir d;
//#### revise
odebug << "Copy file at " << __FILE__ << ": " << __LINE__ << "" << oendl;
d.mkdir(("/usr/lib/ipkg/info/" + location).ascii());
system(("copy " + f.name() + " /usr/lib/ipkg/info/"+location).ascii());
#endif
if ( f.open(IO_ReadOnly) ) {
QTextStream ts(&f);
QString s;
while ( !ts.eof() ) { // until end of file...
s = ts.readLine(); // line of text excluding '\n'
// for s, do link/mkdir.
if ( s.right(1) == "/" ) {
odebug << "do mkdir for " << s.ascii() << "" << oendl;
#ifndef Q_OS_WIN32
mkdir( s.ascii(), 0777 );
//possible optimization: symlink directories
//that don't exist already. -- Risky.
#else
d.mkdir( s.ascii());
#endif
} else {
#ifndef Q_OS_WIN32
odebug << "do symlink for " << s.ascii() << "" << oendl;
symlink( (location + s).ascii(), s.ascii() );
#else
odebug << "Copy file instead of a symlink for WIN32" << oendl;
if (!CopyFile((TCHAR*)qt_winTchar((location + s), TRUE), (TCHAR*)qt_winTchar(s, TRUE), FALSE))
owarn << "Unable to create symlinkfor " << (location + s).ascii() << oendl;
#endif
}
}
f.close();
}
}
void PackageHandler::addPackages( const QString &location )
{
// get list of *.list in location/usr/lib/ipkg/info/*.list
QDir dir(location + "/usr/lib/ipkg/info", "*.list", // No tr
QDir::Name, QDir::Files);
if ( !dir.exists() )
return;
QStringList packages = dir.entryList();
for ( QStringList::Iterator it = packages.begin();
it != packages.end(); ++it ) {
addPackageFiles( location, *it );
}
}
void PackageHandler::cleanupPackageFiles( const QString &listfile )
{
QFile f(listfile);
if ( f.open(IO_ReadOnly) ) {
QTextStream ts(&f);
QString s;
while ( !ts.eof() ) { // until end of file...
s = ts.readLine(); // line of text excluding '\n'
// for s, do link/mkdir.
- if ( s.right(1) == "/" ) {
- //should rmdir if empty, after all files have been removed
- } else {
+ // @todo Right now we just move on if the name of the file we
+ // find is actually a directory. What we ought to do is check
+ // to see if the directory is empty and if so remove it.
+ if ( s.right(1) != "/" ) {
#ifndef Q_OS_WIN32
- odebug << "remove symlink for " << s.ascii() << "" << oendl;
+ odebug << "remove symlink for " << s << oendl;
+ QFile symFile(s);
+ QFileInfo symFileInfo(symFile);
//check if it is a symlink first (don't remove /etc/passwd...)
- char buf[10]; //we don't care about the contents
- if ( ::readlink( s.ascii(),buf, 10 >= 0 ) )
- ::unlink( s.ascii() );
+ if ( !symFileInfo.readLink().isNull())
+ if (!symFile.remove())
+ owarn << "Unable to remove symlink " << symFile.name()
+ << " " << __FILE__ << ":" << __LINE__ << oendl;
#else
- // ### revise
- owarn << "Unable to remove symlink " << __FILE__ << ":" << __LINE__ << "" << oendl;
+ // @todo If we actually want to be portable to other operating
+ // systems we ought to at least have a portable way of removing
+ // their notion of symlinks.
+ owarn << "Unable to remove symlink " << s " " << __FILE__
+ << ":" << __LINE__ << oendl;
#endif
}
}
f.close();
//remove the list file
- ::unlink( listfile.ascii() );
-
+ if (!f.remove())
+ owarn << "Unable to remove list file " << f.name() << " "
+ << __FILE__ << ":" << __LINE__ << oendl;
}
}
void PackageHandler::cleanupPackages( const QString &location )
{
// get list of *.list in location/usr/lib/ipkg/info/*.list
QDir dir( "/usr/lib/ipkg/info/"+location, "*.list", // No tr
QDir::Name, QDir::Files);
if ( !dir.exists() )
return;
QStringList packages = dir.entryList();
for ( QStringList::Iterator it = packages.begin();
it != packages.end(); ++it ) {
cleanupPackageFiles( *it );
}
//remove the backup directory
//###
}
void PackageHandler::prepareInstall( const QString& size, const QString& path )
{
// Check whether there will be enough space to install the next package.
bool ok;
unsigned int s = size.toUInt( &ok );
if ( !ok )
return;
// Shamelessly stolen from the sysinfo application (Werner)
#if defined(_OS_LINUX_) || defined(Q_OS_LINUX)
struct statfs fs;
if ( statfs( path.latin1(), &fs ) == 0 )
if ( s > fs.f_bsize * fs.f_bavail ) {
//odebug << "############### Not enough space left ###############" << oendl;
mNoSpaceLeft = TRUE;
}
#endif
}
void PackageHandler::iProcessExited()
{
if ( currentProcess->normalExit() && currentProcess->exitStatus() == 0 )
sendReply( "installDone(QString)", currentPackage );
else {
#ifndef QT_NO_COP
QCopEnvelope e( "QPE/Desktop", "installFailed(QString,int,QString)" );
e << currentPackage << currentProcess->exitStatus()
<< currentProcessError;
#endif
}
delete currentProcess;
currentProcess = 0;
#ifndef QT_NO_COP
QCopEnvelope e("QPE/System", "linkChanged(QString)");
QString lf = QString::null;
e << lf;
#endif
unlink( currentPackage );
}
void PackageHandler::rmProcessExited()
{
if ( currentProcess->normalExit() && currentProcess->exitStatus() == 0 )
sendReply( "removeDone(QString)", currentPackage );
else
sendReply( "removeFailed(QString)", currentPackage );
#ifndef QT_NO_COP
QCopEnvelope e("QPE/System", "linkChanged(QString)");
QString lf = QString::null;
e << lf;
#endif
}
void PackageHandler::readyReadStdout()
{
while ( currentProcess->canReadLineStdout() ) {
QString line = currentProcess->readLineStdout();
currentProcessError.append("OUT:"+line);
if ( line.contains( "Unpacking" ) ) // No tr
sendReply( "installStep(QString)", "one" ); // No tr
else if ( line.contains( "Configuring" ) ) // No tr
sendReply( "installStep(QString)", "two" ); // No tr
}
}
void PackageHandler::readyReadStderr()
{
while ( currentProcess->canReadLineStderr() ) {
QString line = currentProcess->readLineStderr();
currentProcessError.append("ERR:"+line);
}