aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrea Corallo2021-04-13 12:06:23 +0200
committerAndrea Corallo2021-04-13 12:06:23 +0200
commitb064ddd3f600ed28e62b09d556ecced5f80d9883 (patch)
tree2ddf4889f385beb34cd064f245a7e59265377c37 /src
parent2d23f19e7d5ff8a1ec1a188dcd530c185029d1f8 (diff)
parent6de79542e43ece9a12ebc032c275a6c3fee0b73b (diff)
downloademacs-b064ddd3f600ed28e62b09d556ecced5f80d9883.tar.gz
emacs-b064ddd3f600ed28e62b09d556ecced5f80d9883.zip
Merge remote-tracking branch 'savannah/master' into native-comp
Diffstat (limited to 'src')
-rw-r--r--src/emacs.c208
-rw-r--r--src/xdisp.c147
2 files changed, 217 insertions, 138 deletions
diff --git a/src/emacs.c b/src/emacs.c
index d353679b0f0..e5940ce1de6 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -62,6 +62,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
62# include <sys/socket.h> 62# include <sys/socket.h>
63#endif 63#endif
64 64
65#if defined HAVE_LINUX_SECCOMP_H && defined HAVE_LINUX_FILTER_H \
66 && HAVE_DECL_SECCOMP_SET_MODE_FILTER \
67 && HAVE_DECL_SECCOMP_FILTER_FLAG_TSYNC
68# define SECCOMP_USABLE 1
69#else
70# define SECCOMP_USABLE 0
71#endif
72
73#if SECCOMP_USABLE
74# include <linux/seccomp.h>
75# include <linux/filter.h>
76# include <sys/prctl.h>
77# include <sys/syscall.h>
78#endif
79
65#ifdef HAVE_WINDOW_SYSTEM 80#ifdef HAVE_WINDOW_SYSTEM
66#include TERM_HEADER 81#include TERM_HEADER
67#endif /* HAVE_WINDOW_SYSTEM */ 82#endif /* HAVE_WINDOW_SYSTEM */
@@ -242,6 +257,11 @@ Initialization options:\n\
242--dump-file FILE read dumped state from FILE\n\ 257--dump-file FILE read dumped state from FILE\n\
243", 258",
244#endif 259#endif
260#if SECCOMP_USABLE
261 "\
262--sandbox=FILE read Seccomp BPF filter from FILE\n\
263"
264#endif
245 "\ 265 "\
246--no-build-details do not add build details such as time stamps\n\ 266--no-build-details do not add build details such as time stamps\n\
247--no-desktop do not load a saved desktop\n\ 267--no-desktop do not load a saved desktop\n\
@@ -977,12 +997,195 @@ load_pdump (int argc, char **argv, char const *original_pwd)
977} 997}
978#endif /* HAVE_PDUMPER */ 998#endif /* HAVE_PDUMPER */
979 999
1000#if SECCOMP_USABLE
1001
1002/* Wrapper function for the `seccomp' system call on GNU/Linux. This
1003 system call usually doesn't have a wrapper function. See the
1004 manual page of `seccomp' for the signature. */
1005
1006static int
1007emacs_seccomp (unsigned int operation, unsigned int flags, void *args)
1008{
1009#ifdef SYS_seccomp
1010 return syscall (SYS_seccomp, operation, flags, args);
1011#else
1012 errno = ENOSYS;
1013 return -1;
1014#endif
1015}
1016
1017/* Read SIZE bytes into BUFFER. Return the number of bytes read, or
1018 -1 if reading failed altogether. */
1019
1020static ptrdiff_t
1021read_full (int fd, void *buffer, ptrdiff_t size)
1022{
1023 eassert (0 <= fd);
1024 eassert (buffer != NULL);
1025 eassert (0 <= size);
1026 enum
1027 {
1028 /* See MAX_RW_COUNT in sysdep.c. */
1029#ifdef MAX_RW_COUNT
1030 max_size = MAX_RW_COUNT
1031#else
1032 max_size = INT_MAX >> 18 << 18
1033#endif
1034 };
1035 if (PTRDIFF_MAX < size || max_size < size)
1036 {
1037 errno = EFBIG;
1038 return -1;
1039 }
1040 char *ptr = buffer;
1041 ptrdiff_t read = 0;
1042 while (size != 0)
1043 {
1044 ptrdiff_t n = emacs_read (fd, ptr, size);
1045 if (n < 0)
1046 return -1;
1047 if (n == 0)
1048 break; /* Avoid infinite loop on encountering EOF. */
1049 eassert (n <= size);
1050 size -= n;
1051 ptr += n;
1052 read += n;
1053 }
1054 return read;
1055}
1056
1057/* Attempt to load Secure Computing filters from FILE. Return false
1058 if that doesn't work for some reason. */
1059
1060static bool
1061load_seccomp (const char *file)
1062{
1063 bool success = false;
1064 void *buffer = NULL;
1065 int fd
1066 = emacs_open_noquit (file, O_RDONLY | O_CLOEXEC | O_BINARY, 0);
1067 if (fd < 0)
1068 {
1069 emacs_perror ("open");
1070 goto out;
1071 }
1072 struct stat stat;
1073 if (fstat (fd, &stat) != 0)
1074 {
1075 emacs_perror ("fstat");
1076 goto out;
1077 }
1078 if (! S_ISREG (stat.st_mode))
1079 {
1080 fprintf (stderr, "seccomp file %s is not regular\n", file);
1081 goto out;
1082 }
1083 struct sock_fprog program;
1084 if (stat.st_size <= 0 || SIZE_MAX <= stat.st_size
1085 || PTRDIFF_MAX <= stat.st_size
1086 || stat.st_size % sizeof *program.filter != 0)
1087 {
1088 fprintf (stderr, "seccomp filter %s has invalid size %ld\n",
1089 file, (long) stat.st_size);
1090 goto out;
1091 }
1092 size_t size = stat.st_size;
1093 size_t count = size / sizeof *program.filter;
1094 eassert (0 < count && count < SIZE_MAX);
1095 if (USHRT_MAX < count)
1096 {
1097 fprintf (stderr, "seccomp filter %s is too big\n", file);
1098 goto out;
1099 }
1100 /* Try reading one more byte to detect file size changes. */
1101 buffer = malloc (size + 1);
1102 if (buffer == NULL)
1103 {
1104 emacs_perror ("malloc");
1105 goto out;
1106 }
1107 ptrdiff_t read = read_full (fd, buffer, size + 1);
1108 if (read < 0)
1109 {
1110 emacs_perror ("read");
1111 goto out;
1112 }
1113 eassert (read <= SIZE_MAX);
1114 if (read != size)
1115 {
1116 fprintf (stderr,
1117 "seccomp filter %s changed size while reading\n",
1118 file);
1119 goto out;
1120 }
1121 if (emacs_close (fd) != 0)
1122 emacs_perror ("close"); /* not a fatal error */
1123 fd = -1;
1124 program.len = count;
1125 program.filter = buffer;
1126
1127 /* See man page of `seccomp' why this is necessary. Note that we
1128 intentionally don't check the return value: a parent process
1129 might have made this call before, in which case it would fail;
1130 or, if enabling privilege-restricting mode fails, the `seccomp'
1131 syscall will fail anyway. */
1132 prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1133 /* Install the filter. Make sure that potential other threads can't
1134 escape it. */
1135 if (emacs_seccomp (SECCOMP_SET_MODE_FILTER,
1136 SECCOMP_FILTER_FLAG_TSYNC, &program)
1137 != 0)
1138 {
1139 emacs_perror ("seccomp");
1140 goto out;
1141 }
1142 success = true;
1143
1144 out:
1145 if (0 <= fd)
1146 emacs_close (fd);
1147 free (buffer);
1148 return success;
1149}
1150
1151/* Load Secure Computing filter from file specified with the --seccomp
1152 option. Exit if that fails. */
1153
1154static void
1155maybe_load_seccomp (int argc, char **argv)
1156{
1157 int skip_args = 0;
1158 char *file = NULL;
1159 while (skip_args < argc - 1)
1160 {
1161 if (argmatch (argv, argc, "-seccomp", "--seccomp", 9, &file,
1162 &skip_args)
1163 || argmatch (argv, argc, "--", NULL, 2, NULL, &skip_args))
1164 break;
1165 ++skip_args;
1166 }
1167 if (file == NULL)
1168 return;
1169 if (! load_seccomp (file))
1170 fatal ("cannot enable seccomp filter from %s", file);
1171}
1172
1173#endif /* SECCOMP_USABLE */
1174
980int 1175int
981main (int argc, char **argv) 1176main (int argc, char **argv)
982{ 1177{
983 /* Variable near the bottom of the stack, and aligned appropriately 1178 /* Variable near the bottom of the stack, and aligned appropriately
984 for pointers. */ 1179 for pointers. */
985 void *stack_bottom_variable; 1180 void *stack_bottom_variable;
1181
1182 /* First, check whether we should apply a seccomp filter. This
1183 should come at the very beginning to allow the filter to protect
1184 the initialization phase. */
1185#if SECCOMP_USABLE
1186 maybe_load_seccomp (argc, argv);
1187#endif
1188
986 bool no_loadup = false; 1189 bool no_loadup = false;
987 char *junk = 0; 1190 char *junk = 0;
988 char *dname_arg = 0; 1191 char *dname_arg = 0;
@@ -2179,12 +2382,15 @@ static const struct standard_args standard_args[] =
2179 { "-color", "--color", 5, 0}, 2382 { "-color", "--color", 5, 0},
2180 { "-no-splash", "--no-splash", 3, 0 }, 2383 { "-no-splash", "--no-splash", 3, 0 },
2181 { "-no-desktop", "--no-desktop", 3, 0 }, 2384 { "-no-desktop", "--no-desktop", 3, 0 },
2182 /* The following two must be just above the file-name args, to get 2385 /* The following three must be just above the file-name args, to get
2183 them out of our way, but without mixing them with file names. */ 2386 them out of our way, but without mixing them with file names. */
2184 { "-temacs", "--temacs", 1, 1 }, 2387 { "-temacs", "--temacs", 1, 1 },
2185#ifdef HAVE_PDUMPER 2388#ifdef HAVE_PDUMPER
2186 { "-dump-file", "--dump-file", 1, 1 }, 2389 { "-dump-file", "--dump-file", 1, 1 },
2187#endif 2390#endif
2391#if SECCOMP_USABLE
2392 { "-seccomp", "--seccomp", 1, 1 },
2393#endif
2188#ifdef HAVE_NS 2394#ifdef HAVE_NS
2189 { "-NSAutoLaunch", 0, 5, 1 }, 2395 { "-NSAutoLaunch", 0, 5, 1 },
2190 { "-NXAutoLaunch", 0, 5, 1 }, 2396 { "-NXAutoLaunch", 0, 5, 1 },
diff --git a/src/xdisp.c b/src/xdisp.c
index a405d51f803..50d9040057a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -13607,8 +13607,9 @@ redisplay_tab_bar (struct frame *f)
13607 13607
13608/* Get information about the tab-bar item which is displayed in GLYPH 13608/* Get information about the tab-bar item which is displayed in GLYPH
13609 on frame F. Return in *PROP_IDX the index where tab-bar item 13609 on frame F. Return in *PROP_IDX the index where tab-bar item
13610 properties start in F->tab_bar_items. Value is false if 13610 properties start in F->tab_bar_items. Return in CLOSE_P an
13611 GLYPH doesn't display a tab-bar item. */ 13611 indication whether the click was on the close-tab icon of the tab.
13612 Value is false if GLYPH doesn't display a tab-bar item. */
13612 13613
13613static bool 13614static bool
13614tab_bar_item_info (struct frame *f, struct glyph *glyph, 13615tab_bar_item_info (struct frame *f, struct glyph *glyph,
@@ -13654,7 +13655,6 @@ static int
13654get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, 13655get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
13655 int *hpos, int *vpos, int *prop_idx, bool *close_p) 13656 int *hpos, int *vpos, int *prop_idx, bool *close_p)
13656{ 13657{
13657 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
13658 struct window *w = XWINDOW (f->tab_bar_window); 13658 struct window *w = XWINDOW (f->tab_bar_window);
13659 int area; 13659 int area;
13660 13660
@@ -13668,18 +13668,7 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
13668 if (!tab_bar_item_info (f, *glyph, prop_idx, close_p)) 13668 if (!tab_bar_item_info (f, *glyph, prop_idx, close_p))
13669 return -1; 13669 return -1;
13670 13670
13671 /* Is mouse on the highlighted item? */ 13671 return *prop_idx == f->last_tab_bar_item ? 0 : 1;
13672 if (EQ (f->tab_bar_window, hlinfo->mouse_face_window)
13673 && *vpos >= hlinfo->mouse_face_beg_row
13674 && *vpos <= hlinfo->mouse_face_end_row
13675 && (*vpos > hlinfo->mouse_face_beg_row
13676 || *hpos >= hlinfo->mouse_face_beg_col)
13677 && (*vpos < hlinfo->mouse_face_end_row
13678 || *hpos < hlinfo->mouse_face_end_col
13679 || hlinfo->mouse_face_past_end))
13680 return 0;
13681
13682 return 1;
13683} 13672}
13684 13673
13685 13674
@@ -13693,7 +13682,6 @@ void
13693handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, 13682handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13694 int modifiers) 13683 int modifiers)
13695{ 13684{
13696 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
13697 struct window *w = XWINDOW (f->tab_bar_window); 13685 struct window *w = XWINDOW (f->tab_bar_window);
13698 int hpos, vpos, prop_idx; 13686 int hpos, vpos, prop_idx;
13699 bool close_p; 13687 bool close_p;
@@ -13701,47 +13689,27 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13701 Lisp_Object enabled_p; 13689 Lisp_Object enabled_p;
13702 int ts; 13690 int ts;
13703 13691
13704 /* If not on the highlighted tab-bar item, and mouse-highlight is
13705 non-nil, return. This is so we generate the tab-bar button
13706 click only when the mouse button is released on the same item as
13707 where it was pressed. However, when mouse-highlight is disabled,
13708 generate the click when the button is released regardless of the
13709 highlight, since tab-bar items are not highlighted in that
13710 case. */
13711 frame_to_window_pixel_xy (w, &x, &y); 13692 frame_to_window_pixel_xy (w, &x, &y);
13712 ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); 13693 ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p);
13713 if (ts == -1 13694 if (ts == -1
13714 || (ts != 0 && !NILP (Vmouse_highlight))) 13695 /* If the button is released on a tab other than the one where
13696 it was pressed, don't generate the tab-bar button click event. */
13697 || (ts != 0 && !down_p))
13715 return; 13698 return;
13716 13699
13717 /* When mouse-highlight is off, generate the click for the item
13718 where the button was pressed, disregarding where it was
13719 released. */
13720 if (NILP (Vmouse_highlight) && !down_p)
13721 prop_idx = f->last_tab_bar_item;
13722
13723 /* If item is disabled, do nothing. */ 13700 /* If item is disabled, do nothing. */
13724 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); 13701 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
13725 if (NILP (enabled_p)) 13702 if (NILP (enabled_p))
13726 return; 13703 return;
13727 13704
13728 if (down_p) 13705 if (down_p)
13729 { 13706 f->last_tab_bar_item = prop_idx; /* record the pressed tab */
13730 /* Show item in pressed state. */
13731 if (!NILP (Vmouse_highlight))
13732 show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
13733 f->last_tab_bar_item = prop_idx;
13734 }
13735 else 13707 else
13736 { 13708 {
13737 Lisp_Object key, frame; 13709 Lisp_Object key, frame;
13738 struct input_event event; 13710 struct input_event event;
13739 EVENT_INIT (event); 13711 EVENT_INIT (event);
13740 13712
13741 /* Show item in released state. */
13742 if (!NILP (Vmouse_highlight))
13743 show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
13744
13745 key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY); 13713 key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY);
13746 13714
13747 XSETFRAME (frame, f); 13715 XSETFRAME (frame, f);
@@ -13754,97 +13722,6 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13754 } 13722 }
13755} 13723}
13756 13724
13757
13758/* Possibly highlight a tab-bar item on frame F when mouse moves to
13759 tab-bar window-relative coordinates X/Y. Called from
13760 note_mouse_highlight. */
13761
13762static void
13763note_tab_bar_highlight (struct frame *f, int x, int y)
13764{
13765 Lisp_Object window = f->tab_bar_window;
13766 struct window *w = XWINDOW (window);
13767 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
13768 int hpos, vpos;
13769 struct glyph *glyph;
13770 struct glyph_row *row;
13771 int i;
13772 Lisp_Object enabled_p;
13773 int prop_idx;
13774 bool close_p;
13775 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
13776 int rc;
13777
13778 /* Function note_mouse_highlight is called with negative X/Y
13779 values when mouse moves outside of the frame. */
13780 if (x <= 0 || y <= 0)
13781 {
13782 clear_mouse_face (hlinfo);
13783 return;
13784 }
13785
13786 rc = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p);
13787 if (rc < 0)
13788 {
13789 /* Not on tab-bar item. */
13790 clear_mouse_face (hlinfo);
13791 return;
13792 }
13793 else if (rc == 0)
13794 /* On same tab-bar item as before. */
13795 goto set_help_echo;
13796
13797 clear_mouse_face (hlinfo);
13798
13799 bool mouse_down_p = false;
13800#ifndef HAVE_NS
13801 /* Mouse is down, but on different tab-bar item? */
13802 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
13803 mouse_down_p = (gui_mouse_grabbed (dpyinfo)
13804 && f == dpyinfo->last_mouse_frame);
13805
13806 if (mouse_down_p && f->last_tab_bar_item != prop_idx)
13807 return;
13808#endif
13809 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
13810
13811 /* If tab-bar item is not enabled, don't highlight it. */
13812 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
13813 if (!NILP (enabled_p) && !NILP (Vmouse_highlight))
13814 {
13815 /* Compute the x-position of the glyph. In front and past the
13816 image is a space. We include this in the highlighted area. */
13817 row = MATRIX_ROW (w->current_matrix, vpos);
13818 for (i = x = 0; i < hpos; ++i)
13819 x += row->glyphs[TEXT_AREA][i].pixel_width;
13820
13821 /* Record this as the current active region. */
13822 hlinfo->mouse_face_beg_col = hpos;
13823 hlinfo->mouse_face_beg_row = vpos;
13824 hlinfo->mouse_face_beg_x = x;
13825 hlinfo->mouse_face_past_end = false;
13826
13827 hlinfo->mouse_face_end_col = hpos + 1;
13828 hlinfo->mouse_face_end_row = vpos;
13829 hlinfo->mouse_face_end_x = x + glyph->pixel_width;
13830 hlinfo->mouse_face_window = window;
13831 hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID;
13832
13833 /* Display it as active. */
13834 show_mouse_face (hlinfo, draw);
13835 }
13836
13837 set_help_echo:
13838
13839 /* Set help_echo_string to a help string to display for this tab-bar item.
13840 XTread_socket does the rest. */
13841 help_echo_object = help_echo_window = Qnil;
13842 help_echo_pos = -1;
13843 help_echo_string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_HELP);
13844 if (NILP (help_echo_string))
13845 help_echo_string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION);
13846}
13847
13848#endif /* HAVE_WINDOW_SYSTEM */ 13725#endif /* HAVE_WINDOW_SYSTEM */
13849 13726
13850/* Find the tab-bar item at X coordinate and return its information. */ 13727/* Find the tab-bar item at X coordinate and return its information. */
@@ -33537,13 +33414,9 @@ note_mouse_highlight (struct frame *f, int x, int y)
33537 frame_to_window_pixel_xy (w, &x, &y); 33414 frame_to_window_pixel_xy (w, &x, &y);
33538 33415
33539#if defined (HAVE_WINDOW_SYSTEM) 33416#if defined (HAVE_WINDOW_SYSTEM)
33540 /* Handle tab-bar window differently since it doesn't display a 33417 /* We don't highlight tab-bar buttons. */
33541 buffer. */
33542 if (EQ (window, f->tab_bar_window)) 33418 if (EQ (window, f->tab_bar_window))
33543 { 33419 return;
33544 note_tab_bar_highlight (f, x, y);
33545 return;
33546 }
33547#endif 33420#endif
33548 33421
33549#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) 33422#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)