Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/emc/sai/driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,31 @@ int main (int argc, char ** argv)
tool_nml_register((CANON_TOOL_TABLE*)& _sai._tools);
#else //}{
const int random_toolchanger = 0;
// sai gets its OWN mmap. tool_mmap_creator() opens the file O_TRUNC, and it
// runs before getopt() below, so every rs274 invocation -- including --help,
// and including one given -t -- emptied $HOME/.tool.mmap. That file is the
// live tool table, shared MAP_SHARED with io/milltask/halui, so an offline
// parse silently replaced the tool table of a running machine.
//
// mkstemp(), not a name built from the pid: TMPDIR is world-writable and a
// pid is guessable, so a predictable name can be pre-created as a symlink
// and the victim's rs274 then truncates the attacker's chosen file.
// mkstemp() creates it atomically with O_EXCL and mode 0600.
char sai_mmap_fname[LINELEN];
Comment thread
grandixximo marked this conversation as resolved.
const char *tmpdir = getenv("TMPDIR");
if (!tmpdir || !*tmpdir) tmpdir = "/tmp";
snprintf(sai_mmap_fname,sizeof(sai_mmap_fname),
"%s/rs274.tool.mmap.XXXXXX",tmpdir);
int sai_fd = mkstemp(sai_mmap_fname);
if (sai_fd < 0) {
perror("rs274: mkstemp for the tool mmap failed");
exit(EXIT_FAILURE);
}
close(sai_fd); // tool_mmap_creator() opens it by name; O_NOFOLLOW guards
// the gap, and the file already exists and is ours
tool_mmap_set_fname(sai_mmap_fname);
tool_mmap_creator((EMC_TOOL_STAT*)NULL,random_toolchanger);
atexit(tool_mmap_close); // tool_mmap_close() unlinks the file
/* Notes:
Comment thread
BsAtHome marked this conversation as resolved.
** 1) sai does not use toolInSpindle,pocketPrepped
** 2) sai does not distinguish changer type
Expand Down
1 change: 1 addition & 0 deletions src/emc/tooldata/tooldata.hh
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ int tooldata_save(const char *filename,

//----------------------------------------------------------
//mmap specific
void tool_mmap_set_fname(const char* fname);
int tool_mmap_creator(EMC_TOOL_STAT const *ptr,int random_toolchanger);
int tool_mmap_user(void);
void tool_mmap_close(void);
Expand Down
45 changes: 38 additions & 7 deletions src/emc/tooldata/tooldata_mmap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@

#define TOOL_MMAP_FILENAME ".tool.mmap"
#define TOOL_MMAP_MODE 0600
#define TOOL_MMAP_CREATOR_OPEN_FLAGS O_RDWR | O_CREAT | O_TRUNC
// O_NOFOLLOW: refuse to follow a symlink at the mmap path. Without it a
// pre-placed symlink is followed and the target truncated.
#define TOOL_MMAP_CREATOR_OPEN_FLAGS O_RDWR | O_CREAT | O_TRUNC | O_NOFOLLOW
#define TOOL_MMAP_USER_OPEN_FLAGS O_RDWR

static int creator_fd;
// The descriptor actually backing the mapping, and whether THIS process
// created the file. tool_mmap_user() previously dropped its fd on the
// floor: it was neither closed nor recorded, so it leaked for the life of
// the process and tool_mmap_close() had nothing to close but creator_fd --
// which a user process never sets, so it is 0, i.e. stdin.
static int mmap_fd = -1;
static bool mmap_is_creator = false;
static char filename[LINELEN] = {};
static char* tool_mmap_base = 0;
static EMC_TOOL_STAT const *toolstat;
Expand Down Expand Up @@ -71,6 +80,13 @@ typedef struct {
** DEFAULT_EMC_IO_CYCLE_TIME 0.100
*/

void tool_mmap_set_fname(const char* fname) {
// Let a standalone user of the tooldata mmap (sai/rs274) choose a private
// file. Without this every process uses $HOME/.tool.mmap, so an offline
// parse truncates the tool table of a session that is already running.
snprintf(filename,sizeof(filename),"%s",fname);
}

static char* tool_mmap_fname(void) {
if (*filename) {return filename;}
char* hdir = secure_getenv("HOME");
Expand Down Expand Up @@ -159,6 +175,8 @@ int tool_mmap_creator(EMC_TOOL_STAT const * ptr,int random_toolchanger)
hptr->is_random_toolchanger = random_toolchanger;
hptr->last_index = 0;

mmap_fd = creator_fd;
mmap_is_creator = true;
inited = 1;
tool_mmap_mutex_give(); return 0;
} // tool_mmap_creator();
Expand All @@ -179,7 +197,7 @@ int tool_mmap_user()
** So print message and return fail indicator.
*/
fprintf(stderr,"tool_mmap_user(): tool mmap not available\n");
tool_mmap_base = (char*)0;
tool_mmap_base = nullptr;
return(-1);
}
tool_mmap_base = (char*)mmap(0, TOOL_MMAP_SIZE, PROT_READ|PROT_WRITE,
Expand All @@ -190,6 +208,7 @@ int tool_mmap_user()
perror("tool_mmap_user(): mmap fail");
exit(EXIT_FAILURE);
}
mmap_fd = fd;
return 0;
} //tool_mmap_user()

Expand All @@ -201,14 +220,26 @@ void tool_mmap_close()
perror("tool_mmap_close(): msync fail");
}
if (munmap(tool_mmap_base, TOOL_MMAP_SIZE) < 0) {
close(creator_fd);
perror("tool_mmap_close(): munmapfail");
exit(EXIT_FAILURE);
// NO exit() HERE. This function is usable as an atexit() handler,
// and calling exit() from within one is undefined behaviour.
// Report and FALL THROUGH: a failed munmap is exactly when the
// unlink and close below matter most, so returning here would leave
// the file on disk and the descriptor open.
perror("tool_mmap_close(): munmap fail");
}
if( unlink(tool_mmap_fname() )) {
// Only the creator removes the file. A user process unlinking it would
// delete the running session's tool table out from under io.
if (mmap_is_creator && unlink(tool_mmap_fname())) {
perror("tool_mmap_close(): unlink fail");
Comment thread
BsAtHome marked this conversation as resolved.
}
close(creator_fd);
if (mmap_fd >= 0) {
close(mmap_fd);
mmap_fd = -1;
}
// Idempotent from here: a second call, or an atexit after an explicit
// close, returns at the tool_mmap_base guard above.
tool_mmap_base = nullptr;
mmap_is_creator = false;
} //tool_mmap_close()
Comment thread
BsAtHome marked this conversation as resolved.

void tooldata_last_index_set(int idx) //force last_index
Expand Down