2

I plan to run potentially dangerous applications (browser, etc.) on a separate X-server, but since each server has its own clipboard, it is impossible to copy the link / text from one window to another.

Most articles suggest doing this using scripts using xclip and other similar utilities.

But how to CORRECTLY create a common clipboard so as not to accidentally create a new vulnerability?

Dstart
  • 435
  • 4
  • 6

2 Answers2

0

NOTE: Updating answer to reflect change of strategy - instead of running Xephyr on a server/container, I am running it on host/main-use environment. The reason for that is that running Xephyr on the server/container is like putting a lock on an inside door instead of the front door - bad actors would go around the inside door and access the clipboard through the X pipe remote socket directly.

Facing the same problem of clipboard vulnerability, I approached it by running a Xephyr on the host (my personal workspace), and forwarding X from the server-on-container(s) to the local Xephyr.

The Xephyr is running on display ':2' while my personal workspace windows and browser are running on the default display ':0'. These two displays do not share a clipboard - each has it's own clipboard. That is the only way to prevent snooping of my personal workspace clipboard on display ':0'. Then I have hot keys set up (e.g., function keys), one to transfer the clipboard content from ':0' to ':2', and another for ':2' to ':0', so allowing complete control.

In shell script the code could look like

xsel --display :0 --clipboard -o |  xsel --display :2 --clipboard -i

although I am using javascript as shown at the bottom of this post.

Shell script to start up the X forwarding could look something like this

Xephyr <args> :2
DISPLAY=:2 ssh -X -R 44713:localhost:4713 user@container <<EOF
DISPLAY=:10 PULSE_SERVER=tcp:localhost:44713 openbox --startup firefox
EOF

although I am using a javascript program to do it.

Here is the javascript code for copying between ':0' and ":2" which is mapped to by hot keys. You can see it pops up a transient message box to confirm it worked.

#!/usr/bin/env node
`strict`;
const child_process = require('child_process');

// TODO: write unviewable error messasges to system log

function notifySend(title, msg){
  title = title.replace(/"/g, '\\"');
  msg = msg.replace(/"/g, '\\"');
  //msg = msg.replace(/'/g, '\\'')
  try {
    child_process.execSync(`notify-send "${title}" "${msg}"`);
  } catch(e) {
    console.log(`system call "notify-send" failed with ${e.message}`);
  }
}

async function clipXfer(fromDispNum,toDispNum){
  var clipValue;
  let cmd1 = `xsel --display :${fromDispNum} --clipboard --output`;
  let cmd2 = `xsel --display :${toDispNum} --clipboard --input`;
  try {
    clipValue = child_process.execSync(cmd1, { encoding: 'utf-8' });
  } catch(e) {
    throw Error(`Display ${fromDispNum} clipboard is empty`);
  }
  await new Promise((resolve, reject)=>{        
    // eslint-disable-next-line no-unused-vars
    var proc = child_process.exec(cmd2, (error, stdout, stderr) => {
      //if (stdout) console.log(stdout);
      //if (stderr) console.log(stderr);
      if (error) {
        reject(Error(`${error.message}`));
      }
      resolve();
    });
    if (!proc.stdin.write(clipValue))
      reject(Error('clipToCont(), pipe write failed'));
    proc.stdin.end();
  });                    
}


async function main()
{
  let argOff=2;
  if (process.argv.length-argOff<2)
    throw Error('clip-xfer requires two arguments: fromDispNum, toDispNum');
  let fromDispNum = process.argv[argOff];
  let toDispNum = process.argv[argOff+1];
  argOff+=2;
  let f = (outcome)=>{
    notifySend("clipXfer",  `${fromDispNum} => ${toDispNum} ${outcome}`);
  }; 
  await clipXfer(fromDispNum,toDispNum)
    .then(f('SUCCESS'))
    .catch((e)=>{f(`FAILURE, ${e.message}`); throw e;});
}

//console.log(process.argv);
//console.log(process.env);
main()
  .then(()=>{process.exitCode=0;})
  .catch((e)=>{
    console.log(e);
    process.exitCode=1;
  });
Craig Hicks
  • 644
  • 8
  • 13
0

I use xclipsync. It works in 98%. In 2% I'm doing this:

On dislpay :0 run copyq. On display :1 run parcellite. To sync clipboard i use

copyq add $(parcellite)

or to backward

copyq read | parcellite -c

It works 100%! :-)

MarrekNožka
  • 191
  • 1
  • 4
  • Better solution is maybe use two sessions copyq and this script https://gist.github.com/hluk/b1f69df944335f41242b#file-copyq-synchronize-clipboard-with-other-sessions-ini – MarrekNožka Feb 25 '21 at 14:00